diff options
151 files changed, 4962 insertions, 652 deletions
diff --git a/.babelrc.js b/.babelrc.js index 27caf378b99..bfcc7d96634 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -35,4 +35,10 @@ if (BABEL_ENV === 'karma' || BABEL_ENV === 'coverage') { plugins.push('babel-plugin-rewire'); } +// Jest is running in node environment +if (BABEL_ENV === 'jest') { + plugins.push('transform-es2015-modules-commonjs'); + plugins.push('dynamic-import-node'); +} + module.exports = { presets, plugins }; diff --git a/.eslintignore b/.eslintignore index 33a8186fade..f78840e67be 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,6 +2,7 @@ /config/ /builds/ /coverage/ +/coverage-frontend/ /coverage-javascript/ /node_modules/ /public/ diff --git a/.gitignore b/.gitignore index aecaae95b8c..65f61e1fade 100644 --- a/.gitignore +++ b/.gitignore @@ -78,5 +78,5 @@ eslint-report.html /plugins/* /.gitlab_pages_secret package-lock.json -/junit_rspec.xml -/junit_karma.xml +/junit_*.xml +/coverage-frontend/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9eac37df74b..a97414cbba8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -699,6 +699,32 @@ karma: reports: junit: junit_karma.xml +jest: + <<: *dedicated-no-docs-and-no-qa-pull-cache-job + <<: *use-pg + dependencies: + - compile-assets + - setup-test-env + script: + - scripts/gitaly-test-spawn + - date + - bundle exec rake karma:fixtures + - date + - yarn jest --ci --coverage + artifacts: + name: coverage-frontend + expire_in: 31d + when: always + paths: + - coverage-frontend/ + - junit_jest.xml + reports: + junit: junit_jest.xml + cache: + key: jest + paths: + - tmp/jest/jest/ + code_quality: <<: *dedicated-no-docs-no-db-pull-cache-job image: docker:stable @@ -1027,27 +1053,3 @@ schedule:review-cleanup: - gem install gitlab --no-document script: - ruby -rrubygems scripts/review_apps/automated_cleanup.rb - -merge:master: - image: registry.gitlab.com/gitlab-org/merge-train - stage: merge - # The global before_script/after_script blocks break this job, or aren't - # necessary. These two lines result in them being ignored. - before_script: [] - after_script: [] - only: - refs: - - master - - schedules - variables: - - $CI_PROJECT_PATH == "gitlab-org/gitlab-ce" - - $MERGE_TRAIN_SSH_PUBLIC_KEY - - $MERGE_TRAIN_SSH_PRIVATE_KEY - - $MERGE_TRAIN_API_TOKEN - - $MERGE_FORCE_ENABLE - script: - - scripts/merge-train - cache: - paths: - - gitlab-ee - key: "merge:master" diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index f0895661bf2..331fb052371 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -130,7 +130,7 @@ export default { if (file.highlighted_diff_lines) { file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => { - if (lineCheck(line)) { + if (!line.discussions.some(({ id }) => discussion.id === id) && lineCheck(line)) { return { ...line, discussions: line.discussions.concat(discussion), @@ -150,11 +150,17 @@ export default { return { left: { ...line.left, - discussions: left ? line.left.discussions.concat(discussion) : [], + discussions: + left && !line.left.discussions.some(({ id }) => id === discussion.id) + ? line.left.discussions.concat(discussion) + : (line.left && line.left.discussions) || [], }, right: { ...line.right, - discussions: right && !left ? line.right.discussions.concat(discussion) : [], + discussions: + right && !left && !line.right.discussions.some(({ id }) => id === discussion.id) + ? line.right.discussions.concat(discussion) + : (line.right && line.right.discussions) || [], }, }; } diff --git a/app/controllers/groups/clusters_controller.rb b/app/controllers/groups/clusters_controller.rb index 50c44b7a58b..b846fb21266 100644 --- a/app/controllers/groups/clusters_controller.rb +++ b/app/controllers/groups/clusters_controller.rb @@ -3,8 +3,8 @@ class Groups::ClustersController < Clusters::ClustersController include ControllerWithCrossProjectAccessCheck - prepend_before_action :check_group_clusters_feature_flag! prepend_before_action :group + prepend_before_action :check_group_clusters_feature_flag! requires_cross_project_access layout 'group' @@ -20,6 +20,10 @@ class Groups::ClustersController < Clusters::ClustersController end def check_group_clusters_feature_flag! - render_404 unless Feature.enabled?(:group_clusters) + render_404 unless group_clusters_enabled? + end + + def group_clusters_enabled? + group.group_clusters_enabled? end end diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 95a014d24da..a6bfb913900 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -22,7 +22,7 @@ class Projects::BranchesController < Projects::ApplicationController # Fetch branches for the specified mode fetch_branches_by_mode - @refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name)) + @refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name)) @merged_branch_names = repository.merged_branch_names(@branches.map(&:name)) # n+1: https://gitlab.com/gitlab-org/gitaly/issues/992 diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index b3d77335c2a..ddffbb17ace 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -22,12 +22,9 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic def render_diffs @environment = @merge_request.environments_for(current_user).last - notes_grouped_by_path = renderable_notes.group_by { |note| note.position.file_path } - @diffs.diff_files.each do |diff_file| - notes = notes_grouped_by_path.fetch(diff_file.file_path, []) - notes.each { |note| diff_file.unfold_diff_lines(note.position) } - end + note_positions = renderable_notes.map(&:position).compact + @diffs.unfold_diff_files(note_positions) @diffs.write_cache diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 53b29d4146e..67827b1d3bb 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -46,7 +46,7 @@ class Projects::PipelinesController < Projects::ApplicationController end def new - @pipeline = project.pipelines.new(ref: @project.default_branch) + @pipeline = project.all_pipelines.new(ref: @project.default_branch) end def create @@ -142,9 +142,9 @@ class Projects::PipelinesController < Projects::ApplicationController @charts[:pipeline_times] = Gitlab::Ci::Charts::PipelineTime.new(project) @counts = {} - @counts[:total] = @project.pipelines.count(:all) - @counts[:success] = @project.pipelines.success.count(:all) - @counts[:failed] = @project.pipelines.failed.count(:all) + @counts[:total] = @project.all_pipelines.count(:all) + @counts[:success] = @project.all_pipelines.success.count(:all) + @counts[:failed] = @project.all_pipelines.failed.count(:all) end private @@ -164,7 +164,7 @@ class Projects::PipelinesController < Projects::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def pipeline @pipeline ||= project - .pipelines + .all_pipelines .includes(user: :status) .find_by!(id: params[:id]) .present(current_user: current_user) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 2b28670a49b..686d66b10a3 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -20,7 +20,7 @@ class Projects::TagsController < Projects::ApplicationController @tags = Kaminari.paginate_array(@tags).page(params[:page]) tag_names = @tags.map(&:name) - @tags_pipelines = @project.pipelines.latest_successful_for_refs(tag_names) + @tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names) @releases = project.releases.where(tag: tag_names) respond_to do |format| diff --git a/app/finders/pipelines_finder.rb b/app/finders/pipelines_finder.rb index 35d0e1acce5..f5aadc42ff0 100644 --- a/app/finders/pipelines_finder.rb +++ b/app/finders/pipelines_finder.rb @@ -8,7 +8,7 @@ class PipelinesFinder def initialize(project, current_user, params = {}) @project = project @current_user = current_user - @pipelines = project.pipelines + @pipelines = project.all_pipelines @params = params end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index e9b9b9b7721..866fc555856 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -140,7 +140,7 @@ module GroupsHelper can?(current_user, "read_group_#{resource}".to_sym, @group) end - if can?(current_user, :read_cluster, @group) && Feature.enabled?(:group_clusters) + if can?(current_user, :read_cluster, @group) && @group.group_clusters_enabled? links << :kubernetes end diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index 8ed2a2ec9f4..74113aee89d 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -120,6 +120,18 @@ module SortingHelper } end + def users_sort_options_hash + { + sort_value_name => sort_title_name, + sort_value_recently_signin => sort_title_recently_signin, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_recently_created => sort_title_recently_created, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_recently_updated => sort_title_recently_updated, + sort_value_oldest_updated => sort_title_oldest_updated + } + end + def sortable_item(item, path, sorted_by) link_to item, path, class: sorted_by == item ? 'is-active' : '' end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index a0b2acd502b..60ff2181a95 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -12,13 +12,14 @@ module Ci include AtomicInternalId include EnumWithNil - belongs_to :project, inverse_of: :pipelines + belongs_to :project, inverse_of: :all_pipelines belongs_to :user belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule' + belongs_to :merge_request, class_name: 'MergeRequest' has_internal_id :iid, scope: :project, presence: false, init: ->(s) do - s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count + s&.project&.all_pipelines&.maximum(:iid) || s&.project&.all_pipelines&.count end has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline @@ -50,6 +51,9 @@ module Ci validates :sha, presence: { unless: :importing? } validates :ref, presence: { unless: :importing? } + validates :merge_request, presence: { if: :merge_request? } + validates :merge_request, absence: { unless: :merge_request? } + validates :tag, inclusion: { in: [false], if: :merge_request? } validates :status, presence: { unless: :importing? } validate :valid_commit_sha, unless: :importing? @@ -170,6 +174,14 @@ module Ci end scope :internal, -> { where(source: internal_sources) } + scope :ci_sources, -> { where(config_source: ci_sources_values) } + + scope :sort_by_merge_request_pipelines, -> do + sql = 'CASE ci_pipelines.source WHEN (?) THEN 0 ELSE 1 END, ci_pipelines.id DESC' + query = ActiveRecord::Base.send(:sanitize_sql_array, [sql, sources[:merge_request]]) # rubocop:disable GitlabSecurity/PublicSend + + order(query) + end scope :for_user, -> (user) { where(user: user) } @@ -260,6 +272,10 @@ module Ci sources.reject { |source| source == "external" }.values end + def self.ci_sources_values + config_sources.values_at(:repository_source, :auto_devops_source, :unknown_source) + end + def stages_count statuses.select(:stage).distinct.count end @@ -372,7 +388,7 @@ module Ci end def branch? - !tag? + !tag? && !merge_request? end def stuck? @@ -619,7 +635,12 @@ module Ci # All the merge requests for which the current pipeline runs/ran against def all_merge_requests - @all_merge_requests ||= project.merge_requests.where(source_branch: ref) + @all_merge_requests ||= + if merge_request? + project.merge_requests.where(id: merge_request.id) + else + project.merge_requests.where(source_branch: ref) + end end def detailed_status(current_user) @@ -696,6 +717,8 @@ module Ci def git_ref if branch? Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s + elsif merge_request? + Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s elsif tag? Gitlab::Git::TAG_REF_PREFIX + ref.to_s else diff --git a/app/models/ci/pipeline_enums.rb b/app/models/ci/pipeline_enums.rb index 8d8d16e2ec1..c0f16066e0b 100644 --- a/app/models/ci/pipeline_enums.rb +++ b/app/models/ci/pipeline_enums.rb @@ -21,7 +21,8 @@ module Ci trigger: 3, schedule: 4, api: 5, - external: 6 + external: 6, + merge_request: 10 } end end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 260348c97b2..2693386443a 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -114,7 +114,8 @@ module Ci cached_attr_reader :version, :revision, :platform, :architecture, :ip_address, :contacted_at - chronic_duration_attr :maximum_timeout_human_readable, :maximum_timeout + chronic_duration_attr :maximum_timeout_human_readable, :maximum_timeout, + error_message: 'Maximum job timeout has a value which could not be accepted' validates :maximum_timeout, allow_nil: true, numericality: { greater_than_or_equal_to: 600, diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 13906c903b9..c9bd1728dbd 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -4,6 +4,7 @@ module Clusters class Cluster < ActiveRecord::Base include Presentable include Gitlab::Utils::StrongMemoize + include FromUnion self.table_name = 'clusters' @@ -86,6 +87,19 @@ module Clusters scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) } + scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do + subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.cluster_id = clusters.id') + + where('NOT EXISTS (?)', subquery) + end + + def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc) + hierarchy_groups = clusterable.ancestors_upto(hierarchy_order: hierarchy_order).eager_load(:clusters) + hierarchy_groups = hierarchy_groups.merge(current_scope) if current_scope + + hierarchy_groups.flat_map(&:clusters) + end + def status_name if provider provider.status_name @@ -122,6 +136,16 @@ module Clusters !user? end + def all_projects + if project_type? + projects + elsif group_type? + first_group.all_projects + else + Project.none + end + end + def first_project strong_memoize(:first_project) do projects.first @@ -140,11 +164,17 @@ module Clusters platform_kubernetes.kubeclient if kubernetes? end - def find_or_initialize_kubernetes_namespace(cluster_project) - kubernetes_namespaces.find_or_initialize_by( - project: cluster_project.project, - cluster_project: cluster_project - ) + def find_or_initialize_kubernetes_namespace_for_project(project) + if project_type? + kubernetes_namespaces.find_or_initialize_by( + project: project, + cluster_project: cluster_project + ) + else + kubernetes_namespaces.find_or_initialize_by( + project: project + ) + end end def allow_user_defined_namespace? diff --git a/app/models/commit.rb b/app/models/commit.rb index 546fcc54a15..2c89da88b9b 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -298,7 +298,7 @@ class Commit end def pipelines - project.pipelines.where(sha: sha) + project.ci_pipelines.where(sha: sha) end def last_pipeline @@ -312,7 +312,7 @@ class Commit end def status_for_project(ref, pipeline_project) - pipeline_project.pipelines.latest_status_per_commit(id, ref)[id] + pipeline_project.ci_pipelines.latest_status_per_commit(id, ref)[id] end def set_status_for_ref(ref, status) diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb index dd93af9df64..e349f0fe971 100644 --- a/app/models/commit_collection.rb +++ b/app/models/commit_collection.rb @@ -24,7 +24,7 @@ class CommitCollection # Setting this status ahead of time removes the need for running a query for # every commit we're displaying. def with_pipeline_status - statuses = project.pipelines.latest_status_per_commit(map(&:id), ref) + statuses = project.ci_pipelines.latest_status_per_commit(map(&:id), ref) each do |commit| commit.set_status_for_ref(ref, statuses[commit.id]) diff --git a/app/models/concerns/chronic_duration_attribute.rb b/app/models/concerns/chronic_duration_attribute.rb index edf6ac96730..af4905115b1 100644 --- a/app/models/concerns/chronic_duration_attribute.rb +++ b/app/models/concerns/chronic_duration_attribute.rb @@ -24,7 +24,7 @@ module ChronicDurationAttribute end end - validates virtual_attribute, allow_nil: true, duration: true + validates virtual_attribute, allow_nil: true, duration: { message: parameters[:error_message] } end alias_method :chronic_duration_attr, :chronic_duration_attr_writer diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb index e57a3383544..0107af5f8ec 100644 --- a/app/models/concerns/deployment_platform.rb +++ b/app/models/concerns/deployment_platform.rb @@ -13,6 +13,7 @@ module DeploymentPlatform def find_deployment_platform(environment) find_cluster_platform_kubernetes(environment: environment) || + find_group_cluster_platform_kubernetes_with_feature_guard(environment: environment) || find_kubernetes_service_integration || build_cluster_and_deployment_platform end @@ -23,6 +24,18 @@ module DeploymentPlatform .last&.platform_kubernetes end + def find_group_cluster_platform_kubernetes_with_feature_guard(environment: nil) + return unless group_clusters_enabled? + + find_group_cluster_platform_kubernetes(environment: environment) + end + + # EE would override this and utilize environment argument + def find_group_cluster_platform_kubernetes(environment: nil) + Clusters::Cluster.enabled.default_environment.ancestor_clusters_for_clusterable(self) + .first&.platform_kubernetes + end + def find_kubernetes_service_integration services.deployment.reorder(nil).find_by(active: true) end diff --git a/app/models/group.rb b/app/models/group.rb index 02ddc8762af..233747cc2c2 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -400,6 +400,10 @@ class Group < Namespace ensure_runners_token! end + def group_clusters_enabled? + Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true) + end + private def update_two_factor_requirement diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 92add079a02..f40dff7c1bd 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -63,6 +63,7 @@ class MergeRequest < ActiveRecord::Base dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent has_many :cached_closes_issues, through: :merge_requests_closing_issues, source: :issue + has_many :merge_request_pipelines, foreign_key: 'merge_request_id', class_name: 'Ci::Pipeline' belongs_to :assignee, class_name: "User" @@ -1052,12 +1053,17 @@ class MergeRequest < ActiveRecord::Base diverged_commits_count > 0 end - def all_pipelines + def all_pipelines(shas: all_commit_shas) return Ci::Pipeline.none unless source_project - @all_pipelines ||= source_project.pipelines - .where(sha: all_commit_shas, ref: source_branch) - .order(id: :desc) + @all_pipelines ||= source_project.ci_pipelines + .where(sha: shas, ref: source_branch) + .where(merge_request: [nil, self]) + .sort_by_merge_request_pipelines + end + + def merge_request_pipeline_exists? + merge_request_pipelines.exists?(sha: diff_head_sha) end def has_test_reports? @@ -1214,7 +1220,7 @@ class MergeRequest < ActiveRecord::Base end def base_pipeline - @base_pipeline ||= project.pipelines + @base_pipeline ||= project.ci_pipelines .order(id: :desc) .find_by(sha: diff_base_sha) end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 11b03846f0b..8865c164b11 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -192,9 +192,9 @@ class Namespace < ActiveRecord::Base # returns all ancestors upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned - def ancestors_upto(top = nil) + def ancestors_upto(top = nil, hierarchy_order: nil) Gitlab::GroupHierarchy.new(self.class.where(id: id)) - .ancestors(upto: top) + .ancestors(upto: top, hierarchy_order: hierarchy_order) end def self_and_ancestors @@ -243,7 +243,7 @@ class Namespace < ActiveRecord::Base end def root_ancestor - ancestors.reorder(nil).find_by(parent_id: nil) + self_and_ancestors.reorder(nil).find_by(parent_id: nil) end def subgroup? diff --git a/app/models/project.rb b/app/models/project.rb index 6ec323b58c2..587bada469e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -238,6 +238,7 @@ class Project < ActiveRecord::Base has_one :cluster_project, class_name: 'Clusters::Project' has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster' has_many :cluster_ingresses, through: :clusters, source: :application_ingress, class_name: 'Clusters::Applications::Ingress' + has_many :kubernetes_namespaces, class_name: 'Clusters::KubernetesNamespace' has_many :prometheus_metrics @@ -247,7 +248,17 @@ class Project < ActiveRecord::Base has_many :container_repositories, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :commit_statuses - has_many :pipelines, class_name: 'Ci::Pipeline', inverse_of: :project + # The relation :all_pipelines is intented to be used when we want to get the + # whole list of pipelines associated to the project + has_many :all_pipelines, class_name: 'Ci::Pipeline', inverse_of: :project + # The relation :ci_pipelines is intented to be used when we want to get only + # those pipeline which are directly related to CI. There are + # other pipelines, like webide ones, that we won't retrieve + # if we use this relation. + has_many :ci_pipelines, + -> { Feature.enabled?(:pipeline_ci_sources_only, default_enabled: true) ? ci_sources : all }, + class_name: 'Ci::Pipeline', + inverse_of: :project has_many :stages, class_name: 'Ci::Stage', inverse_of: :project # Ci::Build objects store data on the file system such as artifact files and @@ -290,6 +301,8 @@ class Project < ActiveRecord::Base delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team delegate :add_master, to: :team # @deprecated delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings + delegate :group_clusters_enabled?, to: :group, allow_nil: true + delegate :root_ancestor, to: :namespace, allow_nil: true # Validations validates :creator, presence: true, on: :create @@ -382,9 +395,16 @@ class Project < ActiveRecord::Base .where(project_ci_cd_settings: { group_runners_enabled: true }) end + scope :missing_kubernetes_namespace, -> (kubernetes_namespaces) do + subquery = kubernetes_namespaces.select('1').where('clusters_kubernetes_namespaces.project_id = projects.id') + + where('NOT EXISTS (?)', subquery) + end + enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } - chronic_duration_attr :build_timeout_human_readable, :build_timeout, default: 3600 + chronic_duration_attr :build_timeout_human_readable, :build_timeout, + default: 3600, error_message: 'Maximum job timeout has a value which could not be accepted' validates :build_timeout, allow_nil: true, numericality: { greater_than_or_equal_to: 10.minutes, @@ -545,9 +565,9 @@ class Project < ActiveRecord::Base # returns all ancestor-groups upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned - def ancestors_upto(top = nil) + def ancestors_upto(top = nil, hierarchy_order: nil) Gitlab::GroupHierarchy.new(Group.where(id: namespace_id)) - .base_and_ancestors(upto: top) + .base_and_ancestors(upto: top, hierarchy_order: hierarchy_order) end def lfs_enabled? @@ -620,7 +640,7 @@ class Project < ActiveRecord::Base # ref can't be HEAD, can only be branch/tag name or SHA def latest_successful_builds_for(ref = default_branch) - latest_pipeline = pipelines.latest_successful_for(ref) + latest_pipeline = ci_pipelines.latest_successful_for(ref) if latest_pipeline latest_pipeline.builds.latest.with_artifacts_archive @@ -1060,6 +1080,12 @@ class Project < ActiveRecord::Base path end + def all_clusters + group_clusters = Clusters::Cluster.joins(:groups).where(cluster_groups: { group_id: ancestors_upto } ) + + Clusters::Cluster.from_union([clusters, group_clusters]) + end + def items_for(entity) case entity when 'issue' then @@ -1375,7 +1401,7 @@ class Project < ActiveRecord::Base return unless sha - pipelines.order(id: :desc).find_by(sha: sha, ref: ref) + ci_pipelines.order(id: :desc).find_by(sha: sha, ref: ref) end def latest_successful_pipeline_for_default_branch @@ -1384,12 +1410,12 @@ class Project < ActiveRecord::Base end @latest_successful_pipeline_for_default_branch = - pipelines.latest_successful_for(default_branch) + ci_pipelines.latest_successful_for(default_branch) end def latest_successful_pipeline_for(ref = nil) if ref && ref != default_branch - pipelines.latest_successful_for(ref) + ci_pipelines.latest_successful_for(ref) else latest_successful_pipeline_for_default_branch end diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb index 6f39a5e6e83..d60a6a7efa3 100644 --- a/app/models/project_services/pipelines_email_service.rb +++ b/app/models/project_services/pipelines_email_service.rb @@ -38,11 +38,11 @@ class PipelinesEmailService < Service end def can_test? - project.pipelines.any? + project.ci_pipelines.any? end def test_data(project, user) - data = Gitlab::DataBuilder::Pipeline.build(project.pipelines.last) + data = Gitlab::DataBuilder::Pipeline.build(project.ci_pipelines.last) data[:user] = user.hook_attrs data end diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb index aef838409e0..477b6710168 100644 --- a/app/serializers/pipeline_entity.rb +++ b/app/serializers/pipeline_entity.rb @@ -48,6 +48,7 @@ class PipelineEntity < Grape::Entity expose :tag?, as: :tag expose :branch?, as: :branch + expose :merge_request?, as: :merge_request end expose :commit, using: CommitEntity diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 46a82377c10..19b5552887f 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -14,7 +14,7 @@ module Ci Gitlab::Ci::Pipeline::Chain::Populate, Gitlab::Ci::Pipeline::Chain::Create].freeze - def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block) + def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, merge_request: nil, &block) @pipeline = Ci::Pipeline.new command = Gitlab::Ci::Pipeline::Chain::Command.new( @@ -25,6 +25,7 @@ module Ci before_sha: params[:before], trigger_request: trigger_request, schedule: schedule, + merge_request: merge_request, ignore_skip_ci: ignore_skip_ci, save_incompleted: save_on_errors, seeds_block: block, @@ -77,7 +78,7 @@ module Ci # rubocop: disable CodeReuse/ActiveRecord def auto_cancelable_pipelines - project.pipelines + project.ci_pipelines .where(ref: pipeline.ref) .where.not(id: pipeline.id) .where.not(sha: project.commit(pipeline.ref).try(:id)) diff --git a/app/services/clusters/refresh_service.rb b/app/services/clusters/refresh_service.rb new file mode 100644 index 00000000000..7c82b98a33f --- /dev/null +++ b/app/services/clusters/refresh_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Clusters + class RefreshService + def self.create_or_update_namespaces_for_cluster(cluster) + projects_with_missing_kubernetes_namespaces_for_cluster(cluster).each do |project| + create_or_update_namespace(cluster, project) + end + end + + def self.create_or_update_namespaces_for_project(project) + clusters_with_missing_kubernetes_namespaces_for_project(project).each do |cluster| + create_or_update_namespace(cluster, project) + end + end + + def self.projects_with_missing_kubernetes_namespaces_for_cluster(cluster) + cluster.all_projects.missing_kubernetes_namespace(cluster.kubernetes_namespaces) + end + + private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster + + def self.clusters_with_missing_kubernetes_namespaces_for_project(project) + project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces) + end + + private_class_method :clusters_with_missing_kubernetes_namespaces_for_project + + def self.create_or_update_namespace(cluster, project) + kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace_for_project(project) + + ::Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( + cluster: cluster, + kubernetes_namespace: kubernetes_namespace + ).execute + end + + private_class_method :create_or_update_namespace + end +end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 28c3219b37b..fe19abf50f6 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -54,6 +54,24 @@ module MergeRequests merge_request, merge_request.project, current_user, merge_request.assignee) end + def create_merge_request_pipeline(merge_request, user) + return unless Feature.enabled?(:ci_merge_request_pipeline, + merge_request.source_project, + default_enabled: true) + + ## + # UpdateMergeRequestsWorker could be retried by an exception. + # MR pipelines should not be recreated in such case. + return if merge_request.merge_request_pipeline_exists? + + Ci::CreatePipelineService + .new(merge_request.source_project, user, ref: merge_request.source_branch) + .execute(:merge_request, + ignore_skip_ci: true, + save_on_errors: false, + merge_request: merge_request) + end + # Returns all origin and fork merge requests from `@project` satisfying passed arguments. # rubocop: disable CodeReuse/ActiveRecord def merge_requests_for(source_branch, mr_states: [:opened]) diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index 6081a7d1de0..7bb9fa60515 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -25,6 +25,7 @@ module MergeRequests def after_create(issuable) todo_service.new_merge_request(issuable, current_user) issuable.cache_merge_request_closes_issues!(current_user) + create_merge_request_pipeline(issuable, current_user) update_merge_requests_head_pipeline(issuable) super @@ -49,18 +50,14 @@ module MergeRequests merge_request.update(head_pipeline_id: pipeline.id) if pipeline end - # rubocop: disable CodeReuse/ActiveRecord def head_pipeline_for(merge_request) return unless merge_request.source_project sha = merge_request.source_branch_sha return unless sha - pipelines = merge_request.source_project.pipelines.where(ref: merge_request.source_branch, sha: sha) - - pipelines.order(id: :desc).first + merge_request.all_pipelines(shas: sha).first end - # rubocop: enable CodeReuse/ActiveRecord def set_projects! # @project is used to determine whether the user can set the merge request's diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 5fe48da1cd6..667b5916f38 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -92,6 +92,7 @@ module MergeRequests end merge_request.mark_as_unchecked + create_merge_request_pipeline(merge_request, current_user) UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id) end diff --git a/app/services/projects/auto_devops/disable_service.rb b/app/services/projects/auto_devops/disable_service.rb index 1b578a3c5ce..6608b3da1a8 100644 --- a/app/services/projects/auto_devops/disable_service.rb +++ b/app/services/projects/auto_devops/disable_service.rb @@ -34,7 +34,7 @@ module Projects end def auto_devops_pipelines - @auto_devops_pipelines ||= project.pipelines.auto_devops_source + @auto_devops_pipelines ||= project.ci_pipelines.auto_devops_source end end end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 9e77a3237e3..d03137b63b2 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -96,6 +96,8 @@ module Projects current_user.invalidate_personal_projects_count create_readme if @initialize_with_readme + + configure_group_clusters_for_project end # Refresh the current user's authorizations inline (so they can access the @@ -121,6 +123,10 @@ module Projects Files::CreateService.new(@project, current_user, commit_attrs).execute end + def configure_group_clusters_for_project + ClusterProjectConfigureWorker.perform_async(@project.id) + end + def skip_wiki? !@project.feature_available?(:wiki, current_user) || @skip_wiki end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 9d40ab166ff..9db3fd9cf17 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -54,6 +54,7 @@ module Projects end attempt_transfer_transaction + configure_group_clusters_for_project end # rubocop: enable CodeReuse/ActiveRecord @@ -162,5 +163,9 @@ module Projects @new_namespace.full_path ) end + + def configure_group_clusters_for_project + ClusterProjectConfigureWorker.perform_async(project.id) + end end end diff --git a/app/services/test_hooks/project_service.rb b/app/services/test_hooks/project_service.rb index 45e0e61e5c4..7e14ddcd017 100644 --- a/app/services/test_hooks/project_service.rb +++ b/app/services/test_hooks/project_service.rb @@ -49,7 +49,7 @@ module TestHooks end def pipeline_events_data - pipeline = project.pipelines.first + pipeline = project.ci_pipelines.first throw(:validation_error, 'Ensure the project has CI pipelines.') unless pipeline.present? Gitlab::DataBuilder::Pipeline.build(pipeline) diff --git a/app/validators/duration_validator.rb b/app/validators/duration_validator.rb index 811828169ca..defd28d7d3b 100644 --- a/app/validators/duration_validator.rb +++ b/app/validators/duration_validator.rb @@ -14,6 +14,10 @@ class DurationValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) ChronicDuration.parse(value) rescue ChronicDuration::DurationParseError - record.errors.add(attribute, "is not a correct duration") + if options[:message] + record.errors.add(:base, options[:message]) + else + record.errors.add(attribute, "is not a correct duration") + end end end diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index f910e90d6ca..600120c4f05 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -9,28 +9,20 @@ .search-holder .search-field-holder = search_field_tag :search_query, params[:search_query], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false + - if @sort.present? + = hidden_field_tag :sort, @sort = icon("search", class: "search-icon") - .dropdown - - toggle_text = if @sort.present? then sort_options_hash[@sort] else sort_title_name end + = button_tag 'Search users' if Rails.env.test? + .dropdown.user-sort-dropdown + - toggle_text = if @sort.present? then users_sort_options_hash[@sort] else sort_title_name end = dropdown_toggle(toggle_text, { toggle: 'dropdown' }) %ul.dropdown-menu.dropdown-menu-right %li.dropdown-header Sort by %li - = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do - = sort_title_name - = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do - = sort_title_recently_signin - = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do - = sort_title_oldest_signin - = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do - = sort_title_recently_created - = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do - = sort_title_oldest_created - = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do - = sort_title_recently_updated - = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do - = sort_title_oldest_updated + - users_sort_options_hash.each do |value, title| + = link_to admin_users_path(sort: value, filter: params[:filter], search_query: params[:search_query]) do + = title = link_to 'New user', new_admin_user_path, class: 'btn btn-success btn-search' .top-area.scrolling-tabs-container.inner-page-scroll-tabs diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml index 621b7922072..bb328f5344c 100644 --- a/app/views/projects/settings/ci_cd/_form.html.haml +++ b/app/views/projects/settings/ci_cd/_form.html.haml @@ -29,7 +29,7 @@ = f.label :build_timeout_human_readable, _('Timeout'), class: 'label-bold' = f.text_field :build_timeout_human_readable, class: 'form-control' %p.form-text.text-muted - = _("Per job. If a job passes this threshold, it will be marked as failed") + = _('If any job surpasses this timeout threshold, it will be marked as failed. Human readable time input language is accepted like "1 hour". Values without specification represent seconds.') = link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'timeout'), target: '_blank' %hr diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml index daf08d9bb2c..559b5aa9c1e 100644 --- a/app/views/shared/runners/_form.html.haml +++ b/app/views/shared/runners/_form.html.haml @@ -45,7 +45,7 @@ = _('Maximum job timeout') .col-sm-10 = f.text_field :maximum_timeout_human_readable, class: 'form-control' - .form-text.text-muted= _('This timeout will take precedence when lower than Project-defined timeout') + .form-text.text-muted= _('This timeout will take precedence when lower than project-defined timeout and accepts a human readable time input language like "1 hour". Values without specification represent seconds.') .form-group.row = label_tag :tag_list, class: 'col-form-label col-sm-2' do = _('Tags') diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index c0b410472eb..e51da79c6b5 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -29,6 +29,7 @@ - gcp_cluster:wait_for_cluster_creation - gcp_cluster:cluster_wait_for_ingress_ip_address - gcp_cluster:cluster_platform_configure +- gcp_cluster:cluster_project_configure - github_import_advance_stage - github_importer:github_import_import_diff_note diff --git a/app/workers/cluster_platform_configure_worker.rb b/app/workers/cluster_platform_configure_worker.rb index 8f3689f0166..aa7570caa79 100644 --- a/app/workers/cluster_platform_configure_worker.rb +++ b/app/workers/cluster_platform_configure_worker.rb @@ -6,17 +6,7 @@ class ClusterPlatformConfigureWorker def perform(cluster_id) Clusters::Cluster.find_by_id(cluster_id).try do |cluster| - next unless cluster.cluster_project - - kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace(cluster.cluster_project) - - Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( - cluster: cluster, - kubernetes_namespace: kubernetes_namespace - ).execute + Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster) end - - rescue ::Kubeclient::HttpError => err - Rails.logger.error "Failed to create/update Kubernetes namespace for cluster_id: #{cluster_id} with error: #{err.message}" end end diff --git a/app/workers/cluster_project_configure_worker.rb b/app/workers/cluster_project_configure_worker.rb new file mode 100644 index 00000000000..497e57c0d0b --- /dev/null +++ b/app/workers/cluster_project_configure_worker.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class ClusterProjectConfigureWorker + include ApplicationWorker + include ClusterQueue + + def perform(project_id) + project = Project.find(project_id) + + ::Clusters::RefreshService.create_or_update_namespaces_for_project(project) + end +end diff --git a/app/workers/update_head_pipeline_for_merge_request_worker.rb b/app/workers/update_head_pipeline_for_merge_request_worker.rb index 9ce51662969..e8494ffa002 100644 --- a/app/workers/update_head_pipeline_for_merge_request_worker.rb +++ b/app/workers/update_head_pipeline_for_merge_request_worker.rb @@ -6,10 +6,11 @@ class UpdateHeadPipelineForMergeRequestWorker queue_namespace :pipeline_processing - # rubocop: disable CodeReuse/ActiveRecord def perform(merge_request_id) merge_request = MergeRequest.find(merge_request_id) - pipeline = Ci::Pipeline.where(project: merge_request.source_project, ref: merge_request.source_branch).last + + sha = merge_request.diff_head_sha + pipeline = merge_request.all_pipelines(shas: sha).first return unless pipeline && pipeline.latest? @@ -21,7 +22,6 @@ class UpdateHeadPipelineForMergeRequestWorker merge_request.update_attribute(:head_pipeline_id, pipeline.id) end - # rubocop: enable CodeReuse/ActiveRecord def log_error_message_for(merge_request) Rails.logger.error( diff --git a/changelogs/unreleased/34758-deployment-cluster.yml b/changelogs/unreleased/34758-deployment-cluster.yml new file mode 100644 index 00000000000..06374098343 --- /dev/null +++ b/changelogs/unreleased/34758-deployment-cluster.yml @@ -0,0 +1,5 @@ +--- +title: Use group clusters when deploying (DeploymentPlatform) +merge_request: 22308 +author: +type: changed diff --git a/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml b/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml new file mode 100644 index 00000000000..c3251fea54d --- /dev/null +++ b/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml @@ -0,0 +1,5 @@ +--- +title: Allow search and sort users at same time on admin users page +merge_request: 23439 +author: +type: fixed diff --git a/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml b/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml new file mode 100644 index 00000000000..ef8e93fca43 --- /dev/null +++ b/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml @@ -0,0 +1,5 @@ +--- +title: Use read_repository scope on read-only files API +merge_request: 23534 +author: +type: fixed diff --git a/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml b/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml new file mode 100644 index 00000000000..52b431edf2c --- /dev/null +++ b/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml @@ -0,0 +1,5 @@ +--- +title: Improve help and validation sections of maximum build timeout inputs +merge_request: 23586 +author: +type: fixed diff --git a/changelogs/unreleased/mr-pipelines-2.yml b/changelogs/unreleased/mr-pipelines-2.yml new file mode 100644 index 00000000000..683c626c3ce --- /dev/null +++ b/changelogs/unreleased/mr-pipelines-2.yml @@ -0,0 +1,5 @@ +--- +title: Merge request pipelines +merge_request: 23217 +author: +type: added diff --git a/changelogs/unreleased/multiple-diff-line-discussions-fix.yml b/changelogs/unreleased/multiple-diff-line-discussions-fix.yml new file mode 100644 index 00000000000..870a8ab3815 --- /dev/null +++ b/changelogs/unreleased/multiple-diff-line-discussions-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fixed duplicate discussions getting added to diff lines +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/osw-fix-grouping-by-file-path.yml b/changelogs/unreleased/osw-fix-grouping-by-file-path.yml new file mode 100644 index 00000000000..dff3116e7c6 --- /dev/null +++ b/changelogs/unreleased/osw-fix-grouping-by-file-path.yml @@ -0,0 +1,5 @@ +--- +title: Avoid 500's when serializing legacy diff notes +merge_request: 23544 +author: +type: fixed diff --git a/config/jest.config.js b/config/jest.config.js new file mode 100644 index 00000000000..23e62f49be1 --- /dev/null +++ b/config/jest.config.js @@ -0,0 +1,27 @@ +/* eslint-disable filenames/match-regex */ + +const reporters = ['default']; + +if (process.env.CI) { + reporters.push([ + 'jest-junit', + { + output: './junit_jest.xml', + }, + ]); +} + +// eslint-disable-next-line import/no-commonjs +module.exports = { + testMatch: ['<rootDir>/spec/frontend/**/*_spec.js'], + moduleNameMapper: { + '^~(.*)$': '<rootDir>/app/assets/javascripts$1', + }, + collectCoverageFrom: ['<rootDir>/app/assets/javascripts/**/*.{js,vue}'], + coverageDirectory: '<rootDir>/coverage-frontend/', + coverageReporters: ['json', 'lcov', 'text-summary', 'clover'], + cacheDirectory: '<rootDir>/tmp/cache/jest', + modulePathIgnorePatterns: ['<rootDir>/.yarn-cache/'], + reporters, + rootDir: '..', // necessary because this file is in the config/ subdirectory +}; diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile index 713ed95a04c..530c6638653 100644 --- a/danger/changelog/Dangerfile +++ b/danger/changelog/Dangerfile @@ -2,7 +2,7 @@ require 'yaml' -NO_CHANGELOG_LABELS = %w[backstage Documentation QA test].freeze +NO_CHANGELOG_LABELS = %w[backstage ci-build Documentation meta QA test].freeze SEE_DOC = "See [the documentation](https://docs.gitlab.com/ce/development/changelog.html).".freeze CREATE_CHANGELOG_MESSAGE = <<~MSG.freeze You can create one with: diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb index 5af77c49913..bdc0a2db7db 100644 --- a/db/fixtures/development/14_pipelines.rb +++ b/db/fixtures/development/14_pipelines.rb @@ -104,7 +104,7 @@ class Gitlab::Seeder::Pipelines def create_pipeline!(project, ref, commit) - project.pipelines.create!(sha: commit.id, ref: ref, source: :push) + project.ci_pipelines.create!(sha: commit.id, ref: ref, source: :push) end def build_create!(pipeline, opts = {}) diff --git a/db/migrate/20181119081539_add_merge_request_id_to_ci_pipelines.rb b/db/migrate/20181119081539_add_merge_request_id_to_ci_pipelines.rb new file mode 100644 index 00000000000..65476109c61 --- /dev/null +++ b/db/migrate/20181119081539_add_merge_request_id_to_ci_pipelines.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddMergeRequestIdToCiPipelines < ActiveRecord::Migration + DOWNTIME = false + + def up + add_column :ci_pipelines, :merge_request_id, :integer + end + + def down + remove_column :ci_pipelines, :merge_request_id, :integer + end +end diff --git a/db/migrate/20181120091639_add_foreign_key_to_ci_pipelines_merge_requests.rb b/db/migrate/20181120091639_add_foreign_key_to_ci_pipelines_merge_requests.rb new file mode 100644 index 00000000000..c2b5b239279 --- /dev/null +++ b/db/migrate/20181120091639_add_foreign_key_to_ci_pipelines_merge_requests.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AddForeignKeyToCiPipelinesMergeRequests < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :ci_pipelines, :merge_request_id + add_concurrent_foreign_key :ci_pipelines, :merge_requests, column: :merge_request_id, on_delete: :cascade + end + + def down + if foreign_key_exists?(:ci_pipelines, :merge_requests, column: :merge_request_id) + remove_foreign_key :ci_pipelines, :merge_requests + end + + remove_concurrent_index :ci_pipelines, :merge_request_id + end +end diff --git a/db/schema.rb b/db/schema.rb index d048be08d77..65a69c2850c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -474,7 +474,9 @@ ActiveRecord::Schema.define(version: 20181126153547) do t.boolean "protected" t.integer "failure_reason" t.integer "iid" + t.integer "merge_request_id" t.index ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree + t.index ["merge_request_id"], name: "index_ci_pipelines_on_merge_request_id", using: :btree t.index ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree t.index ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree t.index ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree @@ -2292,6 +2294,7 @@ ActiveRecord::Schema.define(version: 20181126153547) do add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify + add_foreign_key "ci_pipelines", "merge_requests", name: "fk_a23be95014", on_delete: :cascade add_foreign_key "ci_pipelines", "projects", name: "fk_86635dbd80", on_delete: :cascade add_foreign_key "ci_runner_namespaces", "ci_runners", column: "runner_id", on_delete: :cascade add_foreign_key "ci_runner_namespaces", "namespaces", on_delete: :cascade diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md index c3624f1a535..5f587f480b6 100644 --- a/doc/api/repository_files.md +++ b/doc/api/repository_files.md @@ -4,6 +4,16 @@ **Create, read, update and delete repository files using this API** +The different scopes available using [personal access tokens](../user/profile/personal_access_tokens.md) are depicted +in the following table. + +| Scope | Description | +| ----- | ----------- | +| `read_repository` | Allows read-access to the repository files. | +| `api` | Allows read-write access to the repository files. | + +> `read_repository` scope was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23534) in GitLab 11.6. + ## Get file from repository Allows you to receive information about file in repository like name, size, diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md index 082acbedcd2..0d98180add0 100644 --- a/doc/development/new_fe_guide/development/testing.md +++ b/doc/development/new_fe_guide/development/testing.md @@ -6,9 +6,15 @@ Tests relevant for frontend development can be found at two places: - [frontend unit tests](#frontend-unit-tests) - [frontend component tests](#frontend-component-tests) - [frontend integration tests](#frontend-integration-tests) +- `spec/frontend/` which are run by Jest and contain + - [frontend unit tests](#frontend-unit-tests) + - [frontend component tests](#frontend-component-tests) + - [frontend integration tests](#frontend-integration-tests) - `spec/features/` which are run by RSpec and contain - [feature tests](#feature-tests) +All tests in `spec/javascripts/` will eventually be migrated to `spec/frontend/` (see also [#53757]). + In addition there were feature tests in `features/` run by Spinach in the past. These have been removed from our codebase in May 2018 ([#23036](https://gitlab.com/gitlab-org/gitlab-ce/issues/23036)). @@ -17,6 +23,8 @@ See also: - [old testing guide](../../testing_guide/frontend_testing.html) - [notes on testing Vue components](../../fe_guide/vue.html#testing-vue-components) +[#53757]: https://gitlab.com/gitlab-org/gitlab-ce/issues/53757 + ## Frontend unit tests Unit tests are on the lowest abstraction level and typically test functionality that is not directly perceivable by a user. diff --git a/doc/install/docker.md b/doc/install/docker.md index c7dc9db70c5..e90f6645b0c 100644 --- a/doc/install/docker.md +++ b/doc/install/docker.md @@ -7,9 +7,10 @@ GitLab provides official Docker images to allowing you to easily take advantage ## Omnibus GitLab based images GitLab maintains a set of [official Docker images](https://hub.docker.com/r/gitlab) based on our [Omnibus GitLab package](https://docs.gitlab.com/omnibus/README.html). These images include: -* [GitLab Community Edition](https://hub.docker.com/r/gitlab/gitlab-ce/) -* [GitLab Enterprise Edition](https://hub.docker.com/r/gitlab/gitlab-ee/) -* [GitLab Runner](https://hub.docker.com/r/gitlab/gitlab-runner/) + +- [GitLab Community Edition](https://hub.docker.com/r/gitlab/gitlab-ce/). +- [GitLab Enterprise Edition](https://hub.docker.com/r/gitlab/gitlab-ee/). +- [GitLab Runner](https://hub.docker.com/r/gitlab/gitlab-runner/). A [complete usage guide](https://docs.gitlab.com/omnibus/docker/) to these images is available, as well as the [Dockerfile used for building the images](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker). diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md index b770f2544d2..4b65b901487 100644 --- a/doc/security/two_factor_authentication.md +++ b/doc/security/two_factor_authentication.md @@ -6,7 +6,7 @@ password to login, they'll be prompted for a code generated by an application on their phone. You can read more about it here: -[Two-factor Authentication (2FA)](../profile/two_factor_authentication.md) +[Two-factor Authentication (2FA)](../user/profile/account/two_factor_authentication.md) ## Enforcing 2FA for all users diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index 1ba2c150cb4..62c966e06b4 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -29,7 +29,7 @@ module API not_found!('Commit') unless user_project.commit(params[:sha]) - pipelines = user_project.pipelines.where(sha: params[:sha]) + pipelines = user_project.ci_pipelines.where(sha: params[:sha]) statuses = ::CommitStatus.where(pipeline: pipelines) statuses = statuses.latest unless to_boolean(params[:all]) statuses = statuses.where(ref: params[:ref]) if params[:ref].present? @@ -75,7 +75,7 @@ module API pipeline = @project.pipeline_for(ref, commit.sha) unless pipeline - pipeline = @project.pipelines.create!( + pipeline = @project.ci_pipelines.create!( source: :external, sha: commit.sha, ref: ref, diff --git a/lib/api/files.rb b/lib/api/files.rb index becf66d1467..ca59d330e1c 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -2,6 +2,8 @@ module API class Files < Grape::API + include APIGuard + FILE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(file_path: API::NO_SLASH_URL_PART_REGEX) # Prevents returning plain/text responses for files with .txt extension @@ -79,6 +81,8 @@ module API requires :id, type: String, desc: 'The project ID' end resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do + allow_access_with_scope :read_repository, if: -> (request) { request.get? || request.head? } + desc 'Get raw file metadata from repository' params do requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index c3f8a84d742..80a5cbd6b19 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -56,7 +56,7 @@ module API end # rubocop: disable CodeReuse/ActiveRecord get ':id/pipelines/:pipeline_id/jobs' do - pipeline = user_project.pipelines.find(params[:pipeline_id]) + pipeline = user_project.ci_pipelines.find(params[:pipeline_id]) builds = pipeline.builds builds = filter_builds(builds, params[:scope]) builds = builds.preload(:job_artifacts_archive, :job_artifacts, project: [:namespace]) diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb index 62d07d945e2..7a7b23d2bbb 100644 --- a/lib/api/pipelines.rb +++ b/lib/api/pipelines.rb @@ -130,7 +130,7 @@ module API helpers do def pipeline - @pipeline ||= user_project.pipelines.find(params[:pipeline_id]) + @pipeline ||= user_project.ci_pipelines.find(params[:pipeline_id]) end end end diff --git a/lib/gitlab/badge/coverage/report.rb b/lib/gitlab/badge/coverage/report.rb index a7fcb6b0fca..7f7cc62c8ef 100644 --- a/lib/gitlab/badge/coverage/report.rb +++ b/lib/gitlab/badge/coverage/report.rb @@ -14,7 +14,7 @@ module Gitlab @ref = ref @job = job - @pipeline = @project.pipelines.latest_successful_for(@ref) + @pipeline = @project.ci_pipelines.latest_successful_for(@ref) end def entity diff --git a/lib/gitlab/badge/pipeline/status.rb b/lib/gitlab/badge/pipeline/status.rb index 37e61f07e5b..a403d839517 100644 --- a/lib/gitlab/badge/pipeline/status.rb +++ b/lib/gitlab/badge/pipeline/status.rb @@ -22,7 +22,7 @@ module Gitlab # rubocop: disable CodeReuse/ActiveRecord def status - @project.pipelines + @project.ci_pipelines .where(sha: @sha) .latest_status(@ref) || 'unknown' end diff --git a/lib/gitlab/ci/charts.rb b/lib/gitlab/ci/charts.rb index a4f01468e8e..7cabaadb122 100644 --- a/lib/gitlab/ci/charts.rb +++ b/lib/gitlab/ci/charts.rb @@ -54,7 +54,7 @@ module Gitlab # rubocop: disable CodeReuse/ActiveRecord def collect - query = project.pipelines + query = project.all_pipelines .where("? > #{::Ci::Pipeline.table_name}.created_at AND #{::Ci::Pipeline.table_name}.created_at > ?", @to, @from) # rubocop:disable GitlabSecurity/SqlInjection totals_count = grouped_count(query) @@ -115,7 +115,7 @@ module Gitlab class PipelineTime < Chart def collect - commits = project.pipelines.last(30) + commits = project.all_pipelines.last(30) commits.each do |commit| @labels << commit.short_sha diff --git a/lib/gitlab/ci/pipeline/chain/build.rb b/lib/gitlab/ci/pipeline/chain/build.rb index b445a872b3d..d33d1edfe35 100644 --- a/lib/gitlab/ci/pipeline/chain/build.rb +++ b/lib/gitlab/ci/pipeline/chain/build.rb @@ -16,6 +16,7 @@ module Gitlab trigger_requests: Array(@command.trigger_request), user: @command.current_user, pipeline_schedule: @command.schedule, + merge_request: @command.merge_request, protected: @command.protected_ref?, variables_attributes: Array(@command.variables_attributes) ) diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb index 05978804d92..100b9521412 100644 --- a/lib/gitlab/ci/pipeline/chain/command.rb +++ b/lib/gitlab/ci/pipeline/chain/command.rb @@ -8,7 +8,7 @@ module Gitlab Command = Struct.new( :source, :project, :current_user, :origin_ref, :checkout_sha, :after_sha, :before_sha, - :trigger_request, :schedule, + :trigger_request, :schedule, :merge_request, :ignore_skip_ci, :save_incompleted, :seeds_block, :variables_attributes ) do diff --git a/lib/gitlab/diff/file_collection/base.rb b/lib/gitlab/diff/file_collection/base.rb index 10df037a0dd..c5bbf522f7c 100644 --- a/lib/gitlab/diff/file_collection/base.rb +++ b/lib/gitlab/diff/file_collection/base.rb @@ -34,6 +34,16 @@ module Gitlab @diff_files ||= diffs.decorate! { |diff| decorate_diff!(diff) } end + # This mutates `diff_files` lines. + def unfold_diff_files(positions) + positions_grouped_by_path = positions.group_by { |position| position.file_path } + + diff_files.each do |diff_file| + positions = positions_grouped_by_path.fetch(diff_file.file_path, []) + positions.each { |position| diff_file.unfold_diff_lines(position) } + end + end + def diff_file_with_old_path(old_path) diff_files.find { |diff_file| diff_file.old_path == old_path } end diff --git a/lib/gitlab/diff/file_collection/compare.rb b/lib/gitlab/diff/file_collection/compare.rb index 586c5cf87af..663bad95db7 100644 --- a/lib/gitlab/diff/file_collection/compare.rb +++ b/lib/gitlab/diff/file_collection/compare.rb @@ -10,6 +10,10 @@ module Gitlab diff_options: diff_options, diff_refs: diff_refs) end + + def unfold_diff_lines(positions) + # no-op + end end end end diff --git a/lib/gitlab/group_hierarchy.rb b/lib/gitlab/group_hierarchy.rb index c940ea7305e..97cbdc6cb39 100644 --- a/lib/gitlab/group_hierarchy.rb +++ b/lib/gitlab/group_hierarchy.rb @@ -34,8 +34,8 @@ module Gitlab # reached. So all ancestors *lower* than the specified ancestor will be # included. # rubocop: disable CodeReuse/ActiveRecord - def ancestors(upto: nil) - base_and_ancestors(upto: upto).where.not(id: ancestors_base.select(:id)) + def ancestors(upto: nil, hierarchy_order: nil) + base_and_ancestors(upto: upto, hierarchy_order: hierarchy_order).where.not(id: ancestors_base.select(:id)) end # rubocop: enable CodeReuse/ActiveRecord @@ -45,11 +45,22 @@ module Gitlab # Passing an `upto` will stop the recursion once the specified parent_id is # reached. So all ancestors *lower* than the specified acestor will be # included. - def base_and_ancestors(upto: nil) + # + # Passing a `hierarchy_order` with either `:asc` or `:desc` will cause the + # recursive query order from most nested group to root or from the root + # ancestor to most nested group respectively. This uses a `depth` column + # where `1` is defined as the depth for the base and increment as we go up + # each parent. + # rubocop: disable CodeReuse/ActiveRecord + def base_and_ancestors(upto: nil, hierarchy_order: nil) return ancestors_base unless Group.supports_nested_groups? - read_only(base_and_ancestors_cte(upto).apply_to(model.all)) + recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all) + recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order + + read_only(recursive_query) end + # rubocop: enable CodeReuse/ActiveRecord # Returns a relation that includes the descendants_base set of groups # and all their descendants (recursively). @@ -107,16 +118,22 @@ module Gitlab private # rubocop: disable CodeReuse/ActiveRecord - def base_and_ancestors_cte(stop_id = nil) + def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil) cte = SQL::RecursiveCTE.new(:base_and_ancestors) + depth_column = :depth + + base_query = ancestors_base.except(:order) + base_query = base_query.select("1 as #{depth_column}", groups_table[Arel.star]) if hierarchy_order - cte << ancestors_base.except(:order) + cte << base_query # Recursively get all the ancestors of the base set. parent_query = model .from([groups_table, cte.table]) .where(groups_table[:id].eq(cte.table[:parent_id])) .except(:order) + + parent_query = parent_query.select(cte.table[depth_column] + 1, groups_table[Arel.star]) if hierarchy_order parent_query = parent_query.where(cte.table[:parent_id].not_eq(stop_id)) if stop_id cte << parent_query diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 4f3298812a8..93065879ec6 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -51,7 +51,7 @@ project_tree: - resource_label_events: - label: :priorities - - pipelines: + - ci_pipelines: - notes: - :author - events: diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index 8cd4efd91cc..a56ec65b9f1 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -26,6 +26,8 @@ module Gitlab @project_members = @tree_hash.delete('project_members') + RelationRenameService.rename(@tree_hash) + ActiveRecord::Base.uncached do ActiveRecord::Base.no_touching do create_relations @@ -214,7 +216,7 @@ module Gitlab end def nil_iid_pipeline?(relation_key, relation_item) - relation_key == 'pipelines' && relation_item['iid'].nil? + relation_key == 'ci_pipelines' && relation_item['iid'].nil? end end end diff --git a/lib/gitlab/import_export/project_tree_saver.rb b/lib/gitlab/import_export/project_tree_saver.rb index 29f2dc80813..2255635acdf 100644 --- a/lib/gitlab/import_export/project_tree_saver.rb +++ b/lib/gitlab/import_export/project_tree_saver.rb @@ -34,6 +34,8 @@ module Gitlab project_json['project_members'] += group_members_json + RelationRenameService.add_new_associations(project_json) + project_json.to_json end diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 9cc781ddf8d..a4902e2104f 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -4,6 +4,7 @@ module Gitlab module ImportExport class RelationFactory OVERRIDES = { snippets: :project_snippets, + ci_pipelines: 'Ci::Pipeline', pipelines: 'Ci::Pipeline', stages: 'Ci::Stage', statuses: 'commit_status', diff --git a/lib/gitlab/import_export/relation_rename_service.rb b/lib/gitlab/import_export/relation_rename_service.rb new file mode 100644 index 00000000000..179bde5e21e --- /dev/null +++ b/lib/gitlab/import_export/relation_rename_service.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# This class is intended to help with relation renames within Gitlab versions +# and allow compatibility between versions. +# If you have to change one relationship name that is imported/exported, +# you should add it to the RENAMES constant indicating the old name and the +# new one. +# The behavior of these renamed relationships should be transient and it should +# only last one release until you completely remove the renaming from the list. +# +# When importing, this class will check the project hash and: +# - if only the old relationship name is found, it will rename it with the new one +# - if only the new relationship name is found, it will do nothing +# - if it finds both, it will use the new relationship data +# +# When exporting, this class will duplicate the keys in the resulting file. +# This way, if we open the file in an old version of the exporter it will work +# and also it will with the newer versions. +module Gitlab + module ImportExport + class RelationRenameService + RENAMES = { + 'pipelines' => 'ci_pipelines' # Added in 11.6, remove in 11.7 + }.freeze + + def self.rename(tree_hash) + return unless tree_hash&.present? + + RENAMES.each do |old_name, new_name| + old_entry = tree_hash.delete(old_name) + + next if tree_hash[new_name] + next unless old_entry + + tree_hash[new_name] = old_entry + end + end + + def self.add_new_associations(tree_hash) + RENAMES.each do |old_name, new_name| + next if tree_hash.key?(old_name) + + tree_hash[old_name] = tree_hash[new_name] + end + end + end + end +end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 9bceec749fc..bfcc8efdc96 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -55,7 +55,11 @@ module Gitlab environments: count(::Environment), clusters: count(::Clusters::Cluster), clusters_enabled: count(::Clusters::Cluster.enabled), + project_clusters_enabled: count(::Clusters::Cluster.enabled.project_type), + group_clusters_enabled: count(::Clusters::Cluster.enabled.group_type), clusters_disabled: count(::Clusters::Cluster.disabled), + project_clusters_disabled: count(::Clusters::Cluster.disabled.project_type), + group_clusters_disabled: count(::Clusters::Cluster.disabled.group_type), clusters_platforms_gke: count(::Clusters::Cluster.gcp_installed.enabled), clusters_platforms_user: count(::Clusters::Cluster.user_provided.enabled), clusters_applications_helm: count(::Clusters::Applications::Helm.installed), diff --git a/lib/system_check/gitaly_check.rb b/lib/system_check/gitaly_check.rb new file mode 100644 index 00000000000..3d2517a7aca --- /dev/null +++ b/lib/system_check/gitaly_check.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module SystemCheck + class GitalyCheck < BaseCheck + set_name 'Gitaly:' + + def multi_check + Gitlab::HealthChecks::GitalyCheck.readiness.each do |result| + $stdout.print "#{result.labels[:shard]} ... " + + if result.success + $stdout.puts 'OK'.color(:green) + else + $stdout.puts "FAIL: #{result.message}".color(:red) + end + end + end + end +end diff --git a/lib/system_check/gitlab_shell_check.rb b/lib/system_check/gitlab_shell_check.rb new file mode 100644 index 00000000000..31c4ec33247 --- /dev/null +++ b/lib/system_check/gitlab_shell_check.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module SystemCheck + # Used by gitlab:gitlab_shell:check rake task + class GitlabShellCheck < BaseCheck + set_name 'GitLab Shell:' + + def multi_check + check_gitlab_shell + check_gitlab_shell_self_test + end + + private + + def check_gitlab_shell + required_version = Gitlab::VersionInfo.parse(Gitlab::Shell.version_required) + current_version = Gitlab::VersionInfo.parse(gitlab_shell_version) + + $stdout.print "GitLab Shell version >= #{required_version} ? ... " + if current_version.valid? && required_version <= current_version + $stdout.puts "OK (#{current_version})".color(:green) + else + $stdout.puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red) + end + end + + def check_gitlab_shell_self_test + gitlab_shell_repo_base = gitlab_shell_path + check_cmd = File.expand_path('bin/check', gitlab_shell_repo_base) + $stdout.puts "Running #{check_cmd}" + + if system(check_cmd, chdir: gitlab_shell_repo_base) + $stdout.puts 'gitlab-shell self-check successful'.color(:green) + else + $stdout.puts 'gitlab-shell self-check failed'.color(:red) + try_fixing_it( + 'Make sure GitLab is running;', + 'Check the gitlab-shell configuration file:', + sudo_gitlab("editor #{File.expand_path('config.yml', gitlab_shell_repo_base)}") + ) + fix_and_rerun + end + end + + # Helper methods + ######################## + + def gitlab_shell_path + Gitlab.config.gitlab_shell.path + end + + def gitlab_shell_version + Gitlab::Shell.new.version + end + end +end diff --git a/lib/system_check/incoming_email_check.rb b/lib/system_check/incoming_email_check.rb new file mode 100644 index 00000000000..155b6547595 --- /dev/null +++ b/lib/system_check/incoming_email_check.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module SystemCheck + # Used by gitlab:incoming_email:check rake task + class IncomingEmailCheck < BaseCheck + set_name 'Incoming Email:' + + def multi_check + if Gitlab.config.incoming_email.enabled + checks = [ + SystemCheck::IncomingEmail::ImapAuthenticationCheck + ] + + if Rails.env.production? + checks << SystemCheck::IncomingEmail::InitdConfiguredCheck + checks << SystemCheck::IncomingEmail::MailRoomRunningCheck + else + checks << SystemCheck::IncomingEmail::ForemanConfiguredCheck + end + + SystemCheck.run('Reply by email', checks) + else + $stdout.puts 'Reply by email is disabled in config/gitlab.yml' + end + end + end +end diff --git a/lib/system_check/ldap_check.rb b/lib/system_check/ldap_check.rb new file mode 100644 index 00000000000..619fb3cccb8 --- /dev/null +++ b/lib/system_check/ldap_check.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module SystemCheck + # Used by gitlab:ldap:check rake task + class LdapCheck < BaseCheck + set_name 'LDAP:' + + def multi_check + if Gitlab::Auth::LDAP::Config.enabled? + # Only show up to 100 results because LDAP directories can be very big. + # This setting only affects the `rake gitlab:check` script. + limit = ENV['LDAP_CHECK_LIMIT'] + limit = 100 if limit.blank? + + check_ldap(limit) + else + $stdout.puts 'LDAP is disabled in config/gitlab.yml' + end + end + + private + + def check_ldap(limit) + servers = Gitlab::Auth::LDAP::Config.providers + + servers.each do |server| + $stdout.puts "Server: #{server}" + + begin + Gitlab::Auth::LDAP::Adapter.open(server) do |adapter| + check_ldap_auth(adapter) + + $stdout.puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)" + + users = adapter.users(adapter.config.uid, '*', limit) + users.each do |user| + $stdout.puts "\tDN: #{user.dn}\t #{adapter.config.uid}: #{user.uid}" + end + end + rescue Net::LDAP::ConnectionRefusedError, Errno::ECONNREFUSED => e + $stdout.puts "Could not connect to the LDAP server: #{e.message}".color(:red) + end + end + end + + def check_ldap_auth(adapter) + auth = adapter.config.has_auth? + + message = if auth && adapter.ldap.bind + 'Success'.color(:green) + elsif auth + 'Failed. Check `bind_dn` and `password` configuration values'.color(:red) + else + 'Anonymous. No `bind_dn` or `password` configured'.color(:yellow) + end + + $stdout.puts "LDAP authentication... #{message}" + end + end +end diff --git a/lib/system_check/orphans/repository_check.rb b/lib/system_check/orphans/repository_check.rb index ef8fe945f61..33020417e95 100644 --- a/lib/system_check/orphans/repository_check.rb +++ b/lib/system_check/orphans/repository_check.rb @@ -4,7 +4,6 @@ module SystemCheck module Orphans class RepositoryCheck < SystemCheck::BaseCheck set_name 'Orphaned repositories:' - attr_accessor :orphans def multi_check Gitlab::GitalyClient::StorageSettings.allow_disk_access do diff --git a/lib/system_check/rake_task/app_task.rb b/lib/system_check/rake_task/app_task.rb new file mode 100644 index 00000000000..cc32feb8604 --- /dev/null +++ b/lib/system_check/rake_task/app_task.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:app:check rake task + module AppTask + extend RakeTaskHelpers + + def self.name + 'GitLab App' + end + + def self.checks + [ + SystemCheck::App::GitConfigCheck, + SystemCheck::App::DatabaseConfigExistsCheck, + SystemCheck::App::MigrationsAreUpCheck, + SystemCheck::App::OrphanedGroupMembersCheck, + SystemCheck::App::GitlabConfigExistsCheck, + SystemCheck::App::GitlabConfigUpToDateCheck, + SystemCheck::App::LogWritableCheck, + SystemCheck::App::TmpWritableCheck, + SystemCheck::App::UploadsDirectoryExistsCheck, + SystemCheck::App::UploadsPathPermissionCheck, + SystemCheck::App::UploadsPathTmpPermissionCheck, + SystemCheck::App::InitScriptExistsCheck, + SystemCheck::App::InitScriptUpToDateCheck, + SystemCheck::App::ProjectsHaveNamespaceCheck, + SystemCheck::App::RedisVersionCheck, + SystemCheck::App::RubyVersionCheck, + SystemCheck::App::GitVersionCheck, + SystemCheck::App::GitUserDefaultSSHConfigCheck, + SystemCheck::App::ActiveUsersCheck + ] + end + end + end +end diff --git a/lib/system_check/rake_task/gitaly_task.rb b/lib/system_check/rake_task/gitaly_task.rb new file mode 100644 index 00000000000..0c3f694f98a --- /dev/null +++ b/lib/system_check/rake_task/gitaly_task.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:gitaly:check rake task + class GitalyTask + extend RakeTaskHelpers + + def self.name + 'Gitaly' + end + + def self.checks + [SystemCheck::GitalyCheck] + end + end + end +end diff --git a/lib/system_check/rake_task/gitlab_shell_task.rb b/lib/system_check/rake_task/gitlab_shell_task.rb new file mode 100644 index 00000000000..120e984c68b --- /dev/null +++ b/lib/system_check/rake_task/gitlab_shell_task.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:gitlab_shell:check rake task + class GitlabShellTask + extend RakeTaskHelpers + + def self.name + 'GitLab Shell' + end + + def self.checks + [SystemCheck::GitlabShellCheck] + end + end + end +end diff --git a/lib/system_check/rake_task/gitlab_task.rb b/lib/system_check/rake_task/gitlab_task.rb new file mode 100644 index 00000000000..7ff36fd6eb5 --- /dev/null +++ b/lib/system_check/rake_task/gitlab_task.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:check rake task + class GitlabTask + extend RakeTaskHelpers + + def self.name + 'GitLab' + end + + def self.manual_run_checks! + start_checking("#{name} subtasks") + + subtasks.each(&:run_checks!) + + finished_checking("#{name} subtasks") + end + + def self.subtasks + [ + SystemCheck::RakeTask::GitlabShellTask, + SystemCheck::RakeTask::GitalyTask, + SystemCheck::RakeTask::SidekiqTask, + SystemCheck::RakeTask::IncomingEmailTask, + SystemCheck::RakeTask::LdapTask, + SystemCheck::RakeTask::AppTask + ] + end + end + end +end diff --git a/lib/system_check/rake_task/incoming_email_task.rb b/lib/system_check/rake_task/incoming_email_task.rb new file mode 100644 index 00000000000..c296c46feab --- /dev/null +++ b/lib/system_check/rake_task/incoming_email_task.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:incoming_email:check rake task + class IncomingEmailTask + extend RakeTaskHelpers + + def self.name + 'Incoming Email' + end + + def self.checks + [SystemCheck::IncomingEmailCheck] + end + end + end +end diff --git a/lib/system_check/rake_task/ldap_task.rb b/lib/system_check/rake_task/ldap_task.rb new file mode 100644 index 00000000000..03a180b9dfb --- /dev/null +++ b/lib/system_check/rake_task/ldap_task.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:ldap:check rake task + class LdapTask + extend RakeTaskHelpers + + def self.name + 'LDAP' + end + + def self.checks + [SystemCheck::LdapCheck] + end + end + end +end diff --git a/lib/system_check/rake_task/orphans/namespace_task.rb b/lib/system_check/rake_task/orphans/namespace_task.rb new file mode 100644 index 00000000000..2822da45bc1 --- /dev/null +++ b/lib/system_check/rake_task/orphans/namespace_task.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + module Orphans + # Used by gitlab:orphans:check_namespaces rake task + class NamespaceTask + extend RakeTaskHelpers + + def self.name + 'Orphans' + end + + def self.checks + [SystemCheck::Orphans::NamespaceCheck] + end + end + end + end +end diff --git a/lib/system_check/rake_task/orphans/repository_task.rb b/lib/system_check/rake_task/orphans/repository_task.rb new file mode 100644 index 00000000000..f14b3af22e8 --- /dev/null +++ b/lib/system_check/rake_task/orphans/repository_task.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + module Orphans + # Used by gitlab:orphans:check_repositories rake task + class RepositoryTask + extend RakeTaskHelpers + + def self.name + 'Orphans' + end + + def self.checks + [SystemCheck::Orphans::RepositoryCheck] + end + end + end + end +end diff --git a/lib/system_check/rake_task/orphans_task.rb b/lib/system_check/rake_task/orphans_task.rb new file mode 100644 index 00000000000..31f8ede25e0 --- /dev/null +++ b/lib/system_check/rake_task/orphans_task.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:orphans:check rake task + class OrphansTask + extend RakeTaskHelpers + + def self.name + 'Orphans' + end + + def self.checks + [ + SystemCheck::Orphans::NamespaceCheck, + SystemCheck::Orphans::RepositoryCheck + ] + end + end + end +end diff --git a/lib/system_check/rake_task/rake_task_helpers.rb b/lib/system_check/rake_task/rake_task_helpers.rb new file mode 100644 index 00000000000..95f2a34a719 --- /dev/null +++ b/lib/system_check/rake_task/rake_task_helpers.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Provides the run! method intended to be called from system check rake tasks + module RakeTaskHelpers + include ::SystemCheck::Helpers + + def run! + warn_user_is_not_gitlab + + if self.respond_to?(:manual_run_checks!) + manual_run_checks! + else + run_checks! + end + end + + def run_checks! + SystemCheck.run(name, checks) + end + + def name + raise NotImplementedError + end + + def checks + raise NotImplementedError + end + end + end +end diff --git a/lib/system_check/rake_task/sidekiq_task.rb b/lib/system_check/rake_task/sidekiq_task.rb new file mode 100644 index 00000000000..3ccf009d4b9 --- /dev/null +++ b/lib/system_check/rake_task/sidekiq_task.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module SystemCheck + module RakeTask + # Used by gitlab:sidekiq:check rake task + class SidekiqTask + extend RakeTaskHelpers + + def self.name + 'Sidekiq' + end + + def self.checks + [SystemCheck::SidekiqCheck] + end + end + end +end diff --git a/lib/system_check/sidekiq_check.rb b/lib/system_check/sidekiq_check.rb new file mode 100644 index 00000000000..2f5fc2cea89 --- /dev/null +++ b/lib/system_check/sidekiq_check.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module SystemCheck + # Used by gitlab:sidekiq:check rake task + class SidekiqCheck < BaseCheck + set_name 'Sidekiq:' + + def multi_check + check_sidekiq_running + only_one_sidekiq_running + end + + private + + def check_sidekiq_running + $stdout.print "Running? ... " + + if sidekiq_process_count > 0 + $stdout.puts "yes".color(:green) + else + $stdout.puts "no".color(:red) + try_fixing_it( + sudo_gitlab("RAILS_ENV=production bin/background_jobs start") + ) + for_more_information( + see_installation_guide_section("Install Init Script"), + "see log/sidekiq.log for possible errors" + ) + fix_and_rerun + end + end + + def only_one_sidekiq_running + process_count = sidekiq_process_count + return if process_count.zero? + + $stdout.print 'Number of Sidekiq processes ... ' + + if process_count == 1 + $stdout.puts '1'.color(:green) + else + $stdout.puts "#{process_count}".color(:red) + try_fixing_it( + 'sudo service gitlab stop', + "sudo pkill -u #{gitlab_user} -f sidekiq", + "sleep 10 && sudo pkill -9 -u #{gitlab_user} -f sidekiq", + 'sudo service gitlab start' + ) + fix_and_rerun + end + end + + def sidekiq_process_count + ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww)) + ps_ux.scan(/sidekiq \d+\.\d+\.\d+/).count + end + end +end diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index a2c3e32948f..b594f150c3b 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -1,299 +1,66 @@ namespace :gitlab do desc 'GitLab | Check the configuration of GitLab and its environment' - task check: %w{gitlab:gitlab_shell:check - gitlab:gitaly:check - gitlab:sidekiq:check - gitlab:incoming_email:check - gitlab:ldap:check - gitlab:app:check} + task check: :gitlab_environment do + SystemCheck::RakeTask::GitlabTask.run! + end namespace :app do desc 'GitLab | Check the configuration of the GitLab Rails app' task check: :gitlab_environment do - warn_user_is_not_gitlab - - checks = [ - SystemCheck::App::GitConfigCheck, - SystemCheck::App::DatabaseConfigExistsCheck, - SystemCheck::App::MigrationsAreUpCheck, - SystemCheck::App::OrphanedGroupMembersCheck, - SystemCheck::App::GitlabConfigExistsCheck, - SystemCheck::App::GitlabConfigUpToDateCheck, - SystemCheck::App::LogWritableCheck, - SystemCheck::App::TmpWritableCheck, - SystemCheck::App::UploadsDirectoryExistsCheck, - SystemCheck::App::UploadsPathPermissionCheck, - SystemCheck::App::UploadsPathTmpPermissionCheck, - SystemCheck::App::InitScriptExistsCheck, - SystemCheck::App::InitScriptUpToDateCheck, - SystemCheck::App::ProjectsHaveNamespaceCheck, - SystemCheck::App::RedisVersionCheck, - SystemCheck::App::RubyVersionCheck, - SystemCheck::App::GitVersionCheck, - SystemCheck::App::GitUserDefaultSSHConfigCheck, - SystemCheck::App::ActiveUsersCheck - ] - - SystemCheck.run('GitLab', checks) + SystemCheck::RakeTask::AppTask.run! end end namespace :gitlab_shell do desc "GitLab | Check the configuration of GitLab Shell" task check: :gitlab_environment do - warn_user_is_not_gitlab - start_checking "GitLab Shell" - - check_gitlab_shell - check_gitlab_shell_self_test - - finished_checking "GitLab Shell" - end - - # Checks - ######################## - - def check_gitlab_shell_self_test - gitlab_shell_repo_base = gitlab_shell_path - check_cmd = File.expand_path('bin/check', gitlab_shell_repo_base) - puts "Running #{check_cmd}" - - if system(check_cmd, chdir: gitlab_shell_repo_base) - puts 'gitlab-shell self-check successful'.color(:green) - else - puts 'gitlab-shell self-check failed'.color(:red) - try_fixing_it( - 'Make sure GitLab is running;', - 'Check the gitlab-shell configuration file:', - sudo_gitlab("editor #{File.expand_path('config.yml', gitlab_shell_repo_base)}") - ) - fix_and_rerun - end - end - - # Helper methods - ######################## - - def gitlab_shell_path - Gitlab.config.gitlab_shell.path - end - - def gitlab_shell_version - Gitlab::Shell.new.version - end - - def gitlab_shell_major_version - Gitlab::Shell.version_required.split('.')[0].to_i - end - - def gitlab_shell_minor_version - Gitlab::Shell.version_required.split('.')[1].to_i - end - - def gitlab_shell_patch_version - Gitlab::Shell.version_required.split('.')[2].to_i + SystemCheck::RakeTask::GitlabShellTask.run! end end namespace :gitaly do desc 'GitLab | Check the health of Gitaly' task check: :gitlab_environment do - warn_user_is_not_gitlab - start_checking 'Gitaly' - - Gitlab::HealthChecks::GitalyCheck.readiness.each do |result| - print "#{result.labels[:shard]} ... " - - if result.success - puts 'OK'.color(:green) - else - puts "FAIL: #{result.message}".color(:red) - end - end - - finished_checking 'Gitaly' + SystemCheck::RakeTask::GitalyTask.run! end end namespace :sidekiq do desc "GitLab | Check the configuration of Sidekiq" task check: :gitlab_environment do - warn_user_is_not_gitlab - start_checking "Sidekiq" - - check_sidekiq_running - only_one_sidekiq_running - - finished_checking "Sidekiq" - end - - # Checks - ######################## - - def check_sidekiq_running - print "Running? ... " - - if sidekiq_process_count > 0 - puts "yes".color(:green) - else - puts "no".color(:red) - try_fixing_it( - sudo_gitlab("RAILS_ENV=production bin/background_jobs start") - ) - for_more_information( - see_installation_guide_section("Install Init Script"), - "see log/sidekiq.log for possible errors" - ) - fix_and_rerun - end - end - - def only_one_sidekiq_running - process_count = sidekiq_process_count - return if process_count.zero? - - print 'Number of Sidekiq processes ... ' - - if process_count == 1 - puts '1'.color(:green) - else - puts "#{process_count}".color(:red) - try_fixing_it( - 'sudo service gitlab stop', - "sudo pkill -u #{gitlab_user} -f sidekiq", - "sleep 10 && sudo pkill -9 -u #{gitlab_user} -f sidekiq", - 'sudo service gitlab start' - ) - fix_and_rerun - end - end - - def sidekiq_process_count - ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww)) - ps_ux.scan(/sidekiq \d+\.\d+\.\d+/).count + SystemCheck::RakeTask::SidekiqTask.run! end end namespace :incoming_email do desc "GitLab | Check the configuration of Reply by email" task check: :gitlab_environment do - warn_user_is_not_gitlab - - if Gitlab.config.incoming_email.enabled - checks = [ - SystemCheck::IncomingEmail::ImapAuthenticationCheck - ] - - if Rails.env.production? - checks << SystemCheck::IncomingEmail::InitdConfiguredCheck - checks << SystemCheck::IncomingEmail::MailRoomRunningCheck - else - checks << SystemCheck::IncomingEmail::ForemanConfiguredCheck - end - - SystemCheck.run('Reply by email', checks) - else - puts 'Reply by email is disabled in config/gitlab.yml' - end + SystemCheck::RakeTask::IncomingEmailTask.run! end end namespace :ldap do task :check, [:limit] => :gitlab_environment do |_, args| - # Only show up to 100 results because LDAP directories can be very big. - # This setting only affects the `rake gitlab:check` script. - args.with_defaults(limit: 100) - warn_user_is_not_gitlab - start_checking "LDAP" - - if Gitlab::Auth::LDAP::Config.enabled? - check_ldap(args.limit) - else - puts 'LDAP is disabled in config/gitlab.yml' - end - - finished_checking "LDAP" - end - - def check_ldap(limit) - servers = Gitlab::Auth::LDAP::Config.providers - - servers.each do |server| - puts "Server: #{server}" + ENV['LDAP_CHECK_LIMIT'] = args.limit if args.limit.present? - begin - Gitlab::Auth::LDAP::Adapter.open(server) do |adapter| - check_ldap_auth(adapter) - - puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)" - - users = adapter.users(adapter.config.uid, '*', limit) - users.each do |user| - puts "\tDN: #{user.dn}\t #{adapter.config.uid}: #{user.uid}" - end - end - rescue Net::LDAP::ConnectionRefusedError, Errno::ECONNREFUSED => e - puts "Could not connect to the LDAP server: #{e.message}".color(:red) - end - end - end - - def check_ldap_auth(adapter) - auth = adapter.config.has_auth? - - message = if auth && adapter.ldap.bind - 'Success'.color(:green) - elsif auth - 'Failed. Check `bind_dn` and `password` configuration values'.color(:red) - else - 'Anonymous. No `bind_dn` or `password` configured'.color(:yellow) - end - - puts "LDAP authentication... #{message}" + SystemCheck::RakeTask::LdapTask.run! end end namespace :orphans do desc 'Gitlab | Check for orphaned namespaces and repositories' task check: :gitlab_environment do - warn_user_is_not_gitlab - checks = [ - SystemCheck::Orphans::NamespaceCheck, - SystemCheck::Orphans::RepositoryCheck - ] - - SystemCheck.run('Orphans', checks) + SystemCheck::RakeTask::OrphansTask.run! end desc 'GitLab | Check for orphaned namespaces in the repositories path' task check_namespaces: :gitlab_environment do - warn_user_is_not_gitlab - checks = [SystemCheck::Orphans::NamespaceCheck] - - SystemCheck.run('Orphans', checks) + SystemCheck::RakeTask::Orphans::NamespaceTask.run! end desc 'GitLab | Check for orphaned repositories in the repositories path' task check_repositories: :gitlab_environment do - warn_user_is_not_gitlab - checks = [SystemCheck::Orphans::RepositoryCheck] - - SystemCheck.run('Orphans', checks) - end - end - - # Helper methods - ########################## - - def check_gitlab_shell - required_version = Gitlab::VersionInfo.new(gitlab_shell_major_version, gitlab_shell_minor_version, gitlab_shell_patch_version) - current_version = Gitlab::VersionInfo.parse(gitlab_shell_version) - - print "GitLab Shell version >= #{required_version} ? ... " - if current_version.valid? && required_version <= current_version - puts "OK (#{current_version})".color(:green) - else - puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red) + SystemCheck::RakeTask::Orphans::RepositoryTask.run! end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8289434fd30..38e7ff740c7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3436,6 +3436,9 @@ msgstr "" msgid "Identities" msgstr "" +msgid "If any job surpasses this timeout threshold, it will be marked as failed. Human readable time input language is accepted like \"1 hour\". Values without specification represent seconds." +msgstr "" + msgid "If disabled, the access level will depend on the user's permissions in the project." msgstr "" @@ -4614,9 +4617,6 @@ msgstr "" msgid "People without permission will never get a notification and won't be able to comment." msgstr "" -msgid "Per job. If a job passes this threshold, it will be marked as failed" -msgstr "" - msgid "Perform advanced options such as changing path, transferring, or removing the group." msgstr "" @@ -6632,7 +6632,7 @@ msgstr "" msgid "This source diff could not be displayed because it is too large." msgstr "" -msgid "This timeout will take precedence when lower than Project-defined timeout" +msgid "This timeout will take precedence when lower than project-defined timeout and accepts a human readable time input language like \"1 hour\". Values without specification represent seconds." msgstr "" msgid "This user has no identities" diff --git a/package.json b/package.json index 520d7c620c2..680a5bb1cde 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "eslint": "eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue .", "eslint-fix": "eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue --fix .", "eslint-report": "eslint --max-warnings 0 --ext .js,.vue --format html --output-file ./eslint-report.html --no-inline-config .", + "jest": "BABEL_ENV=jest jest --config=config/jest.config.js", "karma": "BABEL_ENV=${BABEL_ENV:=karma} karma start --single-run true config/karma.config.js", "karma-coverage": "BABEL_ENV=coverage karma start --single-run true config/karma.config.js", "karma-start": "BABEL_ENV=karma karma start config/karma.config.js", @@ -118,17 +119,23 @@ "@gitlab/eslint-config": "^1.2.0", "@vue/test-utils": "^1.0.0-beta.25", "axios-mock-adapter": "^1.15.0", + "babel-core": "^7.0.0-bridge", + "babel-jest": "^23.6.0", + "babel-plugin-dynamic-import-node": "^2.2.0", "babel-plugin-istanbul": "^5.1.0", "babel-plugin-rewire": "^1.2.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "babel-template": "^6.26.0", "babel-types": "^6.26.0", "chalk": "^2.4.1", "commander": "^2.18.0", "eslint": "~5.6.0", + "eslint-import-resolver-jest": "^2.1.1", "eslint-import-resolver-webpack": "^0.10.1", "eslint-plugin-html": "4.0.5", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jasmine": "^2.10.1", + "eslint-plugin-jest": "^22.1.0", "gettext-extractor": "^3.3.2", "gettext-extractor-vue": "^4.0.1", "graphql-tag": "^2.10.0", @@ -136,6 +143,8 @@ "jasmine-core": "^2.9.0", "jasmine-diff": "^0.1.3", "jasmine-jquery": "^2.1.1", + "jest": "^23.6.0", + "jest-junit": "^5.2.0", "karma": "^3.0.0", "karma-chrome-launcher": "^2.2.0", "karma-coverage-istanbul-reporter": "^2.0.4", diff --git a/scripts/merge-train b/scripts/merge-train deleted file mode 100755 index a934971b869..00000000000 --- a/scripts/merge-train +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/sh - -set -e - -# The name (including namespace) of the EE repository to merge commits into. -EE_PROJECT='gitlab-org/gitlab-ee' - -# The directory to clone GitLab EE into. -EE_DIRECTORY="$CI_PROJECT_DIR/gitlab-ee" - -# The EE branch to merge the changes into. -EE_BRANCH='master' - -# Runs an incremental or periodic merge of CE to EE. This script should be run -# from a container built using https://gitlab.com/gitlab-org/merge-train. - -# Merges (or reverts) commits in a batch (based on CI_COMMIT_BEFORE_SHA and -# CI_COMMIT_SHA), or since a specific commit. -# -# The optional first argument of this function should be a SHA of a commit. When -# specified, all commits since this commit will be processed. -merge() { - # We need to source the configure-ssh script instead of running it with - # `sh`, since it uses `eval` for SSH agent and we want the result of that to - # persist. - # - # shellcheck disable=SC1091 - . /app/bin/configure-ssh - - # We can not perform a shallow clone, as this results in Git sometimes - # refusing to fetch from CE. To work around this, we perform a full clone - # but cache the repository in CI. If a cached repository exists, we simply - # just pull from `master`. - if [ -d "$EE_DIRECTORY" ] - then - echo "Updating existing clone of $EE_PROJECT" - - git -C "$EE_DIRECTORY" pull --quiet origin "$EE_BRANCH" - else - echo "Cloning $EE_PROJECT" - - git clone --quiet --single-branch --branch "$EE_BRANCH" \ - "git@gitlab.com:$EE_PROJECT.git" "$EE_DIRECTORY" - fi - - cd /app - - env GITLAB_TOKEN="$MERGE_TRAIN_API_TOKEN" \ - bundle exec /app/bin/merge-train "$CI_PROJECT_DIR" "$EE_DIRECTORY" \ - --source-name "$CI_PROJECT_PATH" \ - --target-branch "$EE_BRANCH" \ - ${1:+--before "$1"} -} - -# Merges (or reverts) all commits since a point in time as supported by `git log -# --since`, such as "12 hours ago". -merge_since() { - commit="$(git log --since="$MERGE_SINCE" --reverse --format=%H | head -n1)" - - if [ "$commit" = '' ] - then - echo "There are no commits to merge since $MERGE_SINCE" - else - merge "$commit" - fi -} - -if [ "$MERGE_SINCE" ] -then - merge_since -else - merge -fi diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 9dc06436c72..8fc5d302af6 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -36,6 +36,18 @@ describe Projects::MergeRequests::DiffsController do end end + context 'when note has no position' do + before do + create(:legacy_diff_note_on_merge_request, project: project, noteable: merge_request, position: nil) + end + + it 'serializes merge request diff collection' do + expect_any_instance_of(DiffsSerializer).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash)) + + go + end + end + context 'with forked projects with submodules' do render_views diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index d5516b334b9..931095936a6 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe "Admin::Users" do + include Spec::Support::Helpers::Features::ListRowsHelpers + let!(:user) do create(:omniauth_user, provider: 'twitter', extern_uid: '123456') end @@ -30,6 +32,51 @@ describe "Admin::Users" do expect(page).to have_button('Delete user and contributions') end + describe 'search and sort' do + before do + create(:user, name: 'Foo Bar') + create(:user, name: 'Foo Baz') + create(:user, name: 'Dmitriy') + end + + it 'searches users by name' do + visit admin_users_path(search_query: 'Foo') + + expect(page).to have_content('Foo Bar') + expect(page).to have_content('Foo Baz') + expect(page).not_to have_content('Dmitriy') + end + + it 'sorts users by name' do + visit admin_users_path + + sort_by('Name') + + expect(first_row.text).to include('Dmitriy') + expect(second_row.text).to include('Foo Bar') + end + + it 'sorts search results only' do + visit admin_users_path(search_query: 'Foo') + + sort_by('Name') + + expect(page).not_to have_content('Dmitriy') + expect(first_row.text).to include('Foo Bar') + expect(second_row.text).to include('Foo Baz') + end + + it 'searches with respect of sorting' do + visit admin_users_path(sort: 'Name') + + fill_in :search_query, with: 'Foo' + click_button('Search users') + + expect(first_row.text).to include('Foo Bar') + expect(second_row.text).to include('Foo Baz') + end + end + describe 'Two-factor Authentication filters' do it 'counts users who have enabled 2FA' do create(:user, :two_factor) @@ -566,4 +613,10 @@ describe "Admin::Users" do def check_breadcrumb(content) expect(find('.breadcrumbs-sub-title')).to have_content(content) end + + def sort_by(text) + page.within('.user-sort-dropdown') do + click_link text + end + end end diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb index e1587a8b6a5..4ba7161601e 100644 --- a/spec/features/groups/members/list_members_spec.rb +++ b/spec/features/groups/members/list_members_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe 'Groups > Members > List members' do include Select2Helper + include Spec::Support::Helpers::Features::ListRowsHelpers let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } @@ -43,12 +44,4 @@ describe 'Groups > Members > List members' do let(:user_with_status) { user2 } end end - - def first_row - page.all('ul.content-list > li')[0] - end - - def second_row - page.all('ul.content-list > li')[1] - end end diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb index 0eda2c7f26d..e2b4a491a13 100644 --- a/spec/features/groups/members/manage_members_spec.rb +++ b/spec/features/groups/members/manage_members_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe 'Groups > Members > Manage members' do include Select2Helper + include Spec::Support::Helpers::Features::ListRowsHelpers let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } @@ -119,14 +120,6 @@ describe 'Groups > Members > Manage members' do end end - def first_row - page.all('ul.content-list > li')[0] - end - - def second_row - page.all('ul.content-list > li')[1] - end - def add_user(id, role) page.within ".users-group-form" do select2(id, from: "#user_ids", multiple: true) diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb index 65989c36c1e..6eb59ef72c2 100644 --- a/spec/features/ide_spec.rb +++ b/spec/features/ide_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'IDE', :js do - describe 'sub-groups' do + describe 'sub-groups', :nested_groups do let(:user) { create(:user) } let(:group) { create(:group) } let(:subgroup) { create(:group, parent: group) } diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb new file mode 100644 index 00000000000..ae1313cf117 --- /dev/null +++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb @@ -0,0 +1,333 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Merge request > User sees merge request pipelines', :js do + include ProjectForksHelper + include TestReportsHelper + + let(:project) { create(:project, :public, :repository) } + let(:user) { project.creator } + + let(:config) do + { + build: { + script: 'build' + }, + test: { + script: 'test', + only: ['merge_requests'] + }, + deploy: { + script: 'deploy', + except: ['merge_requests'] + } + } + end + + before do + stub_application_setting(auto_devops_enabled: false) + stub_feature_flags(ci_merge_request_pipeline: true) + stub_ci_pipeline_yaml_file(YAML.dump(config)) + project.add_maintainer(user) + sign_in(user) + end + + context 'when a user created a merge request in the parent project' do + let(:merge_request) do + create(:merge_request, + source_project: project, + target_project: project, + source_branch: 'feature', + target_branch: 'master') + end + + let!(:push_pipeline) do + Ci::CreatePipelineService.new(project, user, ref: 'feature') + .execute(:push) + end + + let!(:merge_request_pipeline) do + Ci::CreatePipelineService.new(project, user, ref: 'feature') + .execute(:merge_request, merge_request: merge_request) + end + + before do + visit project_merge_request_path(project, merge_request) + + page.within('.merge-request-tabs') do + click_link('Pipelines') + end + end + + it 'sees branch pipelines and merge request pipelines in correct order' do + page.within('.ci-table') do + expect(page).to have_selector('.ci-pending', count: 2) + expect(first('.js-pipeline-url-link')).to have_content("##{merge_request_pipeline.id}") + end + end + + it 'sees the latest merge request pipeline as the head pipeline' do + page.within('.ci-widget-content') do + expect(page).to have_content("##{merge_request_pipeline.id}") + end + end + + context 'when a user updated a merge request in the parent project' do + let!(:push_pipeline_2) do + Ci::CreatePipelineService.new(project, user, ref: 'feature') + .execute(:push) + end + + let!(:merge_request_pipeline_2) do + Ci::CreatePipelineService.new(project, user, ref: 'feature') + .execute(:merge_request, merge_request: merge_request) + end + + before do + visit project_merge_request_path(project, merge_request) + + page.within('.merge-request-tabs') do + click_link('Pipelines') + end + end + + it 'sees branch pipelines and merge request pipelines in correct order' do + page.within('.ci-table') do + expect(page).to have_selector('.ci-pending', count: 4) + + expect(all('.js-pipeline-url-link')[0]) + .to have_content("##{merge_request_pipeline_2.id}") + + expect(all('.js-pipeline-url-link')[1]) + .to have_content("##{merge_request_pipeline.id}") + + expect(all('.js-pipeline-url-link')[2]) + .to have_content("##{push_pipeline_2.id}") + + expect(all('.js-pipeline-url-link')[3]) + .to have_content("##{push_pipeline.id}") + end + end + + it 'sees the latest merge request pipeline as the head pipeline' do + page.within('.ci-widget-content') do + expect(page).to have_content("##{merge_request_pipeline_2.id}") + end + end + end + + context 'when a user merges a merge request in the parent project' do + before do + click_button 'Merge when pipeline succeeds' + + wait_for_requests + end + + context 'when merge request pipeline is pending' do + it 'waits the head pipeline' do + expect(page).to have_content('to be merged automatically when the pipeline succeeds') + expect(page).to have_link('Cancel automatic merge') + end + end + + context 'when merge request pipeline succeeds' do + before do + merge_request_pipeline.succeed! + + wait_for_requests + end + + it 'merges the merge request' do + expect(page).to have_content('Merged by') + expect(page).to have_link('Revert') + end + end + + context 'when branch pipeline succeeds' do + before do + push_pipeline.succeed! + + wait_for_requests + end + + it 'waits the head pipeline' do + expect(page).to have_content('to be merged automatically when the pipeline succeeds') + expect(page).to have_link('Cancel automatic merge') + end + end + end + + context 'when there are no `merge_requests` keyword in .gitlab-ci.yml' do + let(:config) do + { + build: { + script: 'build' + }, + test: { + script: 'test' + }, + deploy: { + script: 'deploy' + } + } + end + + it 'sees a branch pipeline in pipeline tab' do + page.within('.ci-table') do + expect(page).to have_selector('.ci-pending', count: 1) + expect(first('.js-pipeline-url-link')).to have_content("##{push_pipeline.id}") + end + end + + it 'sees the latest branch pipeline as the head pipeline' do + page.within('.ci-widget-content') do + expect(page).to have_content("##{push_pipeline.id}") + end + end + end + end + + context 'when a user created a merge request from a forked project to the parent project' do + let(:merge_request) do + create(:merge_request, + source_project: forked_project, + target_project: project, + source_branch: 'feature', + target_branch: 'master') + end + + let!(:push_pipeline) do + Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') + .execute(:push) + end + + let!(:merge_request_pipeline) do + Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') + .execute(:merge_request, merge_request: merge_request) + end + + let(:forked_project) { fork_project(project, user2, repository: true) } + let(:user2) { create(:user) } + + before do + forked_project.add_maintainer(user2) + + visit project_merge_request_path(project, merge_request) + + page.within('.merge-request-tabs') do + click_link('Pipelines') + end + end + + it 'sees branch pipelines and merge request pipelines in correct order' do + page.within('.ci-table') do + expect(page).to have_selector('.ci-pending', count: 2) + expect(first('.js-pipeline-url-link')).to have_content("##{merge_request_pipeline.id}") + end + end + + it 'sees the latest merge request pipeline as the head pipeline' do + page.within('.ci-widget-content') do + expect(page).to have_content("##{merge_request_pipeline.id}") + end + end + + it 'sees pipeline list in forked project' do + visit project_pipelines_path(forked_project) + + expect(page).to have_selector('.ci-pending', count: 2) + end + + context 'when a user updated a merge request from a forked project to the parent project' do + let!(:push_pipeline_2) do + Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') + .execute(:push) + end + + let!(:merge_request_pipeline_2) do + Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature') + .execute(:merge_request, merge_request: merge_request) + end + + before do + visit project_merge_request_path(project, merge_request) + + page.within('.merge-request-tabs') do + click_link('Pipelines') + end + end + + it 'sees branch pipelines and merge request pipelines in correct order' do + page.within('.ci-table') do + expect(page).to have_selector('.ci-pending', count: 4) + + expect(all('.js-pipeline-url-link')[0]) + .to have_content("##{merge_request_pipeline_2.id}") + + expect(all('.js-pipeline-url-link')[1]) + .to have_content("##{merge_request_pipeline.id}") + + expect(all('.js-pipeline-url-link')[2]) + .to have_content("##{push_pipeline_2.id}") + + expect(all('.js-pipeline-url-link')[3]) + .to have_content("##{push_pipeline.id}") + end + end + + it 'sees the latest merge request pipeline as the head pipeline' do + page.within('.ci-widget-content') do + expect(page).to have_content("##{merge_request_pipeline_2.id}") + end + end + + it 'sees pipeline list in forked project' do + visit project_pipelines_path(forked_project) + + expect(page).to have_selector('.ci-pending', count: 4) + end + end + + context 'when a user merges a merge request from a forked project to the parent project' do + before do + click_button 'Merge when pipeline succeeds' + + wait_for_requests + end + + context 'when merge request pipeline is pending' do + it 'waits the head pipeline' do + expect(page).to have_content('to be merged automatically when the pipeline succeeds') + expect(page).to have_link('Cancel automatic merge') + end + end + + context 'when merge request pipeline succeeds' do + before do + merge_request_pipeline.succeed! + + wait_for_requests + end + + it 'merges the merge request' do + expect(page).to have_content('Merged by') + expect(page).to have_link('Revert') + end + end + + context 'when branch pipeline succeeds' do + before do + push_pipeline.succeed! + + wait_for_requests + end + + it 'waits the head pipeline' do + expect(page).to have_content('to be merged automatically when the pipeline succeeds') + expect(page).to have_link('Cancel automatic merge') + end + end + end + end +end diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index bd254caddfb..caf69796d52 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -20,7 +20,7 @@ describe 'project commit pipelines', :js do visit pipelines_project_commit_path(project, project.commit.sha) page.within('.table-holder') do - expect(page).to have_content project.pipelines[0].id # pipeline ids + expect(page).to have_content project.ci_pipelines[0].id # pipeline ids end end end diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index c2e980e75b8..cf309492808 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe 'Project members list' do include Select2Helper + include Spec::Support::Helpers::Features::ListRowsHelpers let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } @@ -83,14 +84,6 @@ describe 'Project members list' do end end - def first_row - page.all('ul.content-list > li')[0] - end - - def second_row - page.all('ul.content-list > li')[1] - end - def add_user(id, role) page.within ".users-project-form" do select2(id, from: "#user_ids", multiple: true) diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 831f22a0e69..435fb229b69 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -300,7 +300,7 @@ describe 'Pages' do let(:pipeline) do commit_sha = project.commit('HEAD').sha - project.pipelines.create( + project.ci_pipelines.create( ref: 'HEAD', sha: commit_sha, source: :push, diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 0add129dde2..b56bb272b46 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -277,7 +277,7 @@ describe 'Project' do end end - context 'for subgroups', :js do + context 'for subgroups', :js, :nested_groups do let(:group) { create(:group) } let(:subgroup) { create(:group, parent: group) } let(:project) { create(:project, :repository, group: subgroup) } diff --git a/spec/frontend/.eslintrc.yml b/spec/frontend/.eslintrc.yml new file mode 100644 index 00000000000..6d73977a891 --- /dev/null +++ b/spec/frontend/.eslintrc.yml @@ -0,0 +1,9 @@ +--- +env: + jest/globals: true +plugins: +- jest +settings: + import/resolver: + jest: + jestConfigFile: "config/jest.config.js" diff --git a/spec/frontend/dummy_spec.js b/spec/frontend/dummy_spec.js new file mode 100644 index 00000000000..2bfef25e9c6 --- /dev/null +++ b/spec/frontend/dummy_spec.js @@ -0,0 +1 @@ +it('does nothing', () => {}); diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 7a06c178f0b..23e8761bc55 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -199,6 +199,84 @@ describe('DiffsStoreMutations', () => { expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toEqual(1); }); + it('should not duplicate discussions on line', () => { + const diffPosition = { + base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', + head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130', + new_line: null, + new_path: '500-lines-4.txt', + old_line: 5, + old_path: '500-lines-4.txt', + start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', + }; + + const state = { + latestDiff: true, + diffFiles: [ + { + file_hash: 'ABC', + parallel_diff_lines: [ + { + left: { + line_code: 'ABC_1', + discussions: [], + }, + right: { + line_code: 'ABC_1', + discussions: [], + }, + }, + ], + highlighted_diff_lines: [ + { + line_code: 'ABC_1', + discussions: [], + }, + ], + }, + ], + }; + const discussion = { + id: 1, + line_code: 'ABC_1', + diff_discussion: true, + resolvable: true, + original_position: diffPosition, + position: diffPosition, + diff_file: { + file_hash: state.diffFiles[0].file_hash, + }, + }; + + const diffPositionByLineCode = { + ABC_1: diffPosition, + }; + + mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { + discussion, + diffPositionByLineCode, + }); + + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions[0].id).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].right.discussions).toEqual([]); + + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toEqual(1); + + mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { + discussion, + diffPositionByLineCode, + }); + + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions.length).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].left.discussions[0].id).toEqual(1); + expect(state.diffFiles[0].parallel_diff_lines[0].right.discussions).toEqual([]); + + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions.length).toEqual(1); + expect(state.diffFiles[0].highlighted_diff_lines[0].discussions[0].id).toEqual(1); + }); + it('should add legacy discussions to the given line', () => { const diffPosition = { base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910', diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb index 85d73e5c382..fab071405df 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb @@ -18,6 +18,7 @@ describe Gitlab::Ci::Pipeline::Chain::Build do before_sha: nil, trigger_request: nil, schedule: nil, + merge_request: nil, project: project, current_user: user, variables_attributes: variables_attributes) @@ -76,6 +77,7 @@ describe Gitlab::Ci::Pipeline::Chain::Build do before_sha: nil, trigger_request: nil, schedule: nil, + merge_request: nil, project: project, current_user: user) end @@ -90,4 +92,31 @@ describe Gitlab::Ci::Pipeline::Chain::Build do expect(pipeline).to be_tag end end + + context 'when pipeline is running for a merge request' do + let(:command) do + Gitlab::Ci::Pipeline::Chain::Command.new( + source: :merge_request, + origin_ref: 'feature', + checkout_sha: project.commit.id, + after_sha: nil, + before_sha: nil, + trigger_request: nil, + schedule: nil, + merge_request: merge_request, + project: project, + current_user: user) + end + + let(:merge_request) { build(:merge_request, target_project: project) } + + before do + step.perform! + end + + it 'correctly indicated that this is a merge request pipeline' do + expect(pipeline).to be_merge_request + expect(pipeline.merge_request).to eq(merge_request) + end + end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb index a8dc5356413..053bc421649 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb @@ -106,4 +106,34 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do expect(step.break?).to be false end end + + context 'when pipeline source is merge request' do + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + let(:pipeline) { build_stubbed(:ci_pipeline, project: project) } + + let(:merge_request_pipeline) do + build(:ci_pipeline, source: :merge_request, project: project) + end + + let(:chain) { described_class.new(merge_request_pipeline, command).tap(&:perform!) } + + context "when config contains 'merge_requests' keyword" do + let(:config) { { rspec: { script: 'echo', only: ['merge_requests'] } } } + + it 'does not break the chain' do + expect(chain).not_to be_break + end + end + + context "when config contains 'merge_request' keyword" do + let(:config) { { rspec: { script: 'echo', only: ['merge_request'] } } } + + it 'does not break the chain' do + expect(chain).not_to be_break + end + end + end end diff --git a/spec/lib/gitlab/diff/file_collection/commit_spec.rb b/spec/lib/gitlab/diff/file_collection/commit_spec.rb index 6d1b66deb6a..34ed22b8941 100644 --- a/spec/lib/gitlab/diff/file_collection/commit_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/commit_spec.rb @@ -12,4 +12,8 @@ describe Gitlab::Diff::FileCollection::Commit do let(:diffable) { project.commit } let(:stub_path) { 'bar/branch-test.txt' } end + + it_behaves_like 'unfoldable diff' do + let(:diffable) { project.commit } + end end diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb index fbcf515281e..256166dbad3 100644 --- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb @@ -2,22 +2,29 @@ require 'spec_helper' describe Gitlab::Diff::FileCollection::MergeRequestDiff do let(:merge_request) { create(:merge_request) } - let(:diff_files) { described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files } + let(:subject) { described_class.new(merge_request.merge_request_diff, diff_options: nil) } + let(:diff_files) { subject.diff_files } - it 'does not highlight binary files' do - allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(false) + describe '#diff_files' do + it 'does not highlight binary files' do + allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(false) - expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) + expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) - diff_files - end + diff_files + end + + it 'does not highlight files marked as undiffable in .gitattributes' do + allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(false) - it 'does not highlight files marked as undiffable in .gitattributes' do - allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(false) + expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) - expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) + diff_files + end + end - diff_files + it_behaves_like 'unfoldable diff' do + let(:diffable) { merge_request.merge_request_diff } end it 'it uses a different cache key if diff line keys change' do diff --git a/spec/lib/gitlab/group_hierarchy_spec.rb b/spec/lib/gitlab/group_hierarchy_spec.rb index 30686634af4..f3de7adcec7 100644 --- a/spec/lib/gitlab/group_hierarchy_spec.rb +++ b/spec/lib/gitlab/group_hierarchy_spec.rb @@ -34,6 +34,28 @@ describe Gitlab::GroupHierarchy, :postgresql do expect { relation.update_all(share_with_group_lock: false) } .to raise_error(ActiveRecord::ReadOnlyRecord) end + + describe 'hierarchy_order option' do + let(:relation) do + described_class.new(Group.where(id: child2.id)).base_and_ancestors(hierarchy_order: hierarchy_order) + end + + context ':asc' do + let(:hierarchy_order) { :asc } + + it 'orders by child to parent' do + expect(relation).to eq([child2, child1, parent]) + end + end + + context ':desc' do + let(:hierarchy_order) { :desc } + + it 'orders by parent to child' do + expect(relation).to eq([parent, child1, child2]) + end + end + end end describe '#base_and_descendants' do diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 31ab11bbf8d..7df129da95a 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -94,6 +94,7 @@ merge_requests: - timelogs - head_pipeline - latest_merge_request_diff +- merge_request_pipelines merge_request_diff: - merge_request - merge_request_diff_commits @@ -102,7 +103,7 @@ merge_request_diff_commits: - merge_request_diff merge_request_diff_files: - merge_request_diff -pipelines: +ci_pipelines: - project - user - stages @@ -121,6 +122,7 @@ pipelines: - artifacts - pipeline_schedule - merge_requests +- merge_request - deployments - environments pipeline_variables: @@ -263,7 +265,8 @@ project: - notification_settings - import_data - commit_statuses -- pipelines +- ci_pipelines +- all_pipelines - stages - builds - runner_projects @@ -304,6 +307,7 @@ project: - import_export_upload - repository_languages - pool_repository +- kubernetes_namespaces award_emoji: - awardable - user diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 7171e12a849..242c16c4bdc 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -197,9 +197,9 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end it 'has the correct number of pipelines and statuses' do - expect(@project.pipelines.size).to eq(5) + expect(@project.ci_pipelines.size).to eq(5) - @project.pipelines.zip([2, 2, 2, 2, 2]) + @project.ci_pipelines.zip([2, 2, 2, 2, 2]) .each do |(pipeline, expected_status_size)| expect(pipeline.statuses.size).to eq(expected_status_size) end diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 5dc372263ad..46fdfba953b 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -119,16 +119,16 @@ describe Gitlab::ImportExport::ProjectTreeSaver do end it 'has pipeline stages' do - expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty + expect(saved_project_json.dig('ci_pipelines', 0, 'stages')).not_to be_empty end it 'has pipeline statuses' do - expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty + expect(saved_project_json.dig('ci_pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty end it 'has pipeline builds' do builds_count = saved_project_json - .dig('pipelines', 0, 'stages', 0, 'statuses') + .dig('ci_pipelines', 0, 'stages', 0, 'statuses') .count { |hash| hash['type'] == 'Ci::Build' } expect(builds_count).to eq(1) @@ -142,11 +142,11 @@ describe Gitlab::ImportExport::ProjectTreeSaver do end it 'has pipeline commits' do - expect(saved_project_json['pipelines']).not_to be_empty + expect(saved_project_json['ci_pipelines']).not_to be_empty end it 'has ci pipeline notes' do - expect(saved_project_json['pipelines'].first['notes']).not_to be_empty + expect(saved_project_json['ci_pipelines'].first['notes']).not_to be_empty end it 'has labels with no associations' do diff --git a/spec/lib/gitlab/import_export/relation_rename_service_spec.rb b/spec/lib/gitlab/import_export/relation_rename_service_spec.rb new file mode 100644 index 00000000000..a20a844a492 --- /dev/null +++ b/spec/lib/gitlab/import_export/relation_rename_service_spec.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::RelationRenameService do + let(:renames) do + { + 'example_relation1' => 'new_example_relation1', + 'example_relation2' => 'new_example_relation2' + } + end + + let(:user) { create(:admin) } + let(:group) { create(:group, :nested) } + let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } + let(:shared) { project.import_export_shared } + + before do + stub_const("#{described_class}::RENAMES", renames) + end + + context 'when importing' do + let(:project_tree_restorer) { Gitlab::ImportExport::ProjectTreeRestorer.new(user: user, shared: shared, project: project) } + let(:import_path) { 'spec/lib/gitlab/import_export' } + let(:file_content) { IO.read("#{import_path}/project.json") } + let!(:json_file) { ActiveSupport::JSON.decode(file_content) } + let(:tree_hash) { project_tree_restorer.instance_variable_get(:@tree_hash) } + + before do + allow(shared).to receive(:export_path).and_return(import_path) + allow(ActiveSupport::JSON).to receive(:decode).with(file_content).and_return(json_file) + end + + context 'when the file has only old relationship names' do + # Configuring the json as an old version exported file, with only + # the previous association with the old name + before do + renames.each do |old_name, _| + json_file[old_name.to_s] = [] + end + end + + it 'renames old relationships to the new name' do + expect(json_file.keys).to include(*renames.keys) + + project_tree_restorer.restore + + expect(json_file.keys).to include(*renames.values) + expect(json_file.keys).not_to include(*renames.keys) + end + end + + context 'when the file has both the old and new relationships' do + # Configuring the json as the new version exported file, with both + # the old association name and the new one + before do + renames.each do |old_name, new_name| + json_file[old_name.to_s] = [1] + json_file[new_name.to_s] = [2] + end + end + + it 'uses the new relationships and removes the old ones from the hash' do + expect(json_file.keys).to include(*renames.keys) + + project_tree_restorer.restore + + expect(json_file.keys).to include(*renames.values) + expect(json_file.values_at(*renames.values).flatten.uniq.first).to eq 2 + expect(json_file.keys).not_to include(*renames.keys) + end + end + + context 'when the file has only new relationship names' do + # Configuring the json as the future version exported file, with only + # the new association name + before do + renames.each do |_, new_name| + json_file[new_name.to_s] = [] + end + end + + it 'uses the new relationships' do + expect(json_file.keys).not_to include(*renames.keys) + + project_tree_restorer.restore + + expect(json_file.keys).to include(*renames.values) + end + end + end + + context 'when exporting' do + let(:project_tree_saver) { Gitlab::ImportExport::ProjectTreeSaver.new(project: project, current_user: user, shared: shared) } + let(:project_tree) { project_tree_saver.send(:project_json) } + + it 'adds old relationships to the exported file' do + project_tree.merge!(renames.values.map { |new_name| [new_name, []] }.to_h) + + allow(project_tree_saver).to receive(:save) do |arg| + project_tree_saver.send(:project_json_tree) + end + + result = project_tree_saver.save + + saved_data = ActiveSupport::JSON.decode(result) + + expect(saved_data.keys).to include(*(renames.keys + renames.values)) + end + end +end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index f7935149b23..d3bfde181bc 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -243,6 +243,7 @@ Ci::Pipeline: - failure_reason - protected - iid +- merge_request_id Ci::Stage: - id - name diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 5390f237073..e2de612ff46 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -17,6 +17,9 @@ describe Gitlab::UsageData do gcp_cluster = create(:cluster, :provided_by_gcp) create(:cluster, :provided_by_user) create(:cluster, :provided_by_user, :disabled) + create(:cluster, :group) + create(:cluster, :group, :disabled) + create(:cluster, :group, :disabled) create(:clusters_applications_helm, :installed, cluster: gcp_cluster) create(:clusters_applications_ingress, :installed, cluster: gcp_cluster) create(:clusters_applications_cert_managers, :installed, cluster: gcp_cluster) @@ -77,7 +80,11 @@ describe Gitlab::UsageData do environments clusters clusters_enabled + project_clusters_enabled + group_clusters_enabled clusters_disabled + project_clusters_disabled + group_clusters_disabled clusters_platforms_gke clusters_platforms_user clusters_applications_helm @@ -127,8 +134,13 @@ describe Gitlab::UsageData do expect(count_data[:projects_slack_notifications_active]).to eq(2) expect(count_data[:projects_slack_slash_active]).to eq(1) - expect(count_data[:clusters_enabled]).to eq(6) - expect(count_data[:clusters_disabled]).to eq(1) + expect(count_data[:clusters_enabled]).to eq(7) + expect(count_data[:project_clusters_enabled]).to eq(6) + expect(count_data[:group_clusters_enabled]).to eq(1) + expect(count_data[:clusters_disabled]).to eq(3) + expect(count_data[:project_clusters_disabled]).to eq(1) + expect(count_data[:group_clusters_disabled]).to eq(2) + expect(count_data[:group_clusters_enabled]).to eq(1) expect(count_data[:clusters_platforms_gke]).to eq(1) expect(count_data[:clusters_platforms_user]).to eq(1) expect(count_data[:clusters_applications_helm]).to eq(1) diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 3076a882445..ba9540c84d4 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -14,6 +14,7 @@ describe Ci::Pipeline, :mailer do it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:auto_canceled_by) } it { is_expected.to belong_to(:pipeline_schedule) } + it { is_expected.to belong_to(:merge_request) } it { is_expected.to have_many(:statuses) } it { is_expected.to have_many(:trigger_requests) } @@ -32,8 +33,131 @@ describe Ci::Pipeline, :mailer do describe 'associations' do it 'has a bidirectional relationship with projects' do - expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:pipelines) - expect(Project.reflect_on_association(:pipelines).has_inverse?).to eq(:project) + expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:all_pipelines) + expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project) + expect(Project.reflect_on_association(:ci_pipelines).has_inverse?).to eq(:project) + end + end + + describe '.sort_by_merge_request_pipelines' do + subject { described_class.sort_by_merge_request_pipelines } + + context 'when branch pipelines exist' do + let!(:branch_pipeline_1) { create(:ci_pipeline, source: :push) } + let!(:branch_pipeline_2) { create(:ci_pipeline, source: :push) } + + it 'returns pipelines order by id' do + expect(subject).to eq([branch_pipeline_2, + branch_pipeline_1]) + end + end + + context 'when merge request pipelines exist' do + let!(:merge_request_pipeline_1) do + create(:ci_pipeline, source: :merge_request, merge_request: merge_request) + end + + let!(:merge_request_pipeline_2) do + create(:ci_pipeline, source: :merge_request, merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master') + end + + it 'returns pipelines order by id' do + expect(subject).to eq([merge_request_pipeline_2, + merge_request_pipeline_1]) + end + end + + context 'when both branch pipeline and merge request pipeline exist' do + let!(:branch_pipeline_1) { create(:ci_pipeline, source: :push) } + let!(:branch_pipeline_2) { create(:ci_pipeline, source: :push) } + + let!(:merge_request_pipeline_1) do + create(:ci_pipeline, source: :merge_request, merge_request: merge_request) + end + + let!(:merge_request_pipeline_2) do + create(:ci_pipeline, source: :merge_request, merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master') + end + + it 'returns merge request pipeline first' do + expect(subject).to eq([merge_request_pipeline_2, + merge_request_pipeline_1, + branch_pipeline_2, + branch_pipeline_1]) + end + end + end + + describe '.merge_request' do + subject { described_class.merge_request } + + context 'when there is a merge request pipeline' do + let!(:pipeline) { create(:ci_pipeline, source: :merge_request, merge_request: merge_request) } + let(:merge_request) { create(:merge_request) } + + it 'returns merge request pipeline first' do + expect(subject).to eq([pipeline]) + end + end + + context 'when there are no merge request pipelines' do + let!(:pipeline) { create(:ci_pipeline, source: :push) } + + it 'returns empty array' do + expect(subject).to be_empty + end + end + end + + describe 'Validations for merge request pipelines' do + let(:pipeline) { build(:ci_pipeline, source: source, merge_request: merge_request) } + + context 'when source is merge request' do + let(:source) { :merge_request } + + context 'when merge request is specified' do + let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_project: project, target_branch: 'master') } + + it { expect(pipeline).to be_valid } + end + + context 'when merge request is empty' do + let(:merge_request) { nil } + + it { expect(pipeline).not_to be_valid } + end + end + + context 'when source is web' do + let(:source) { :web } + + context 'when merge request is specified' do + let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_project: project, target_branch: 'master') } + + it { expect(pipeline).not_to be_valid } + end + + context 'when merge request is empty' do + let(:merge_request) { nil } + + it { expect(pipeline).to be_valid } + end end end @@ -760,27 +884,85 @@ describe Ci::Pipeline, :mailer do describe '#branch?' do subject { pipeline.branch? } - context 'is not a tag' do + context 'when ref is not a tag' do before do pipeline.tag = false end - it 'return true when tag is set to false' do + it 'return true' do is_expected.to be_truthy end + + context 'when source is merge request' do + let(:pipeline) do + create(:ci_pipeline, source: :merge_request, merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master') + end + + it 'returns false' do + is_expected.to be_falsey + end + end end - context 'is not a tag' do + context 'when ref is a tag' do before do pipeline.tag = true end - it 'return false when tag is set to true' do + it 'return false' do is_expected.to be_falsey end end end + describe '#git_ref' do + subject { pipeline.send(:git_ref) } + + context 'when ref is branch' do + let(:pipeline) { create(:ci_pipeline, tag: false) } + + it 'returns branch ref' do + is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.ref.to_s) + end + end + + context 'when ref is tag' do + let(:pipeline) { create(:ci_pipeline, tag: true) } + + it 'returns branch ref' do + is_expected.to eq(Gitlab::Git::TAG_REF_PREFIX + pipeline.ref.to_s) + end + end + + context 'when ref is merge request' do + let(:pipeline) do + create(:ci_pipeline, + source: :merge_request, + merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master') + end + + it 'returns branch ref' do + is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.ref.to_s) + end + end + end + describe 'ref_exists?' do context 'when repository exists' do using RSpec::Parameterized::TableSyntax @@ -1005,7 +1187,7 @@ describe Ci::Pipeline, :mailer do create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop') create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline2, name: 'rubocop') - pipelines = project.pipelines.to_a + pipelines = project.ci_pipelines.to_a pipelines.each(&:number_of_warnings) @@ -1855,6 +2037,55 @@ describe Ci::Pipeline, :mailer do expect(pipeline.all_merge_requests).to be_empty end + + context 'when there is a merge request pipeline' do + let(:source_branch) { 'feature' } + let(:target_branch) { 'master' } + + let!(:pipeline) do + create(:ci_pipeline, + source: :merge_request, + project: project, + ref: source_branch, + merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: source_branch, + target_project: project, + target_branch: target_branch) + end + + it 'returns an associated merge request' do + expect(pipeline.all_merge_requests).to eq([merge_request]) + end + + context 'when there is another merge request pipeline that targets a different branch' do + let(:target_branch_2) { 'merge-test' } + + let!(:pipeline_2) do + create(:ci_pipeline, + source: :merge_request, + project: project, + ref: source_branch, + merge_request: merge_request_2) + end + + let(:merge_request_2) do + create(:merge_request, + source_project: project, + source_branch: source_branch, + target_project: project, + target_branch: target_branch_2) + end + + it 'does not return an associated merge request' do + expect(pipeline.all_merge_requests).not_to include(merge_request_2) + end + end + end end describe '#stuck?' do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 7dcf97276b2..840f74c9890 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -92,6 +92,26 @@ describe Clusters::Cluster do it { is_expected.to contain_exactly(cluster) } end + describe '.missing_kubernetes_namespace' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :project) } + let(:project) { cluster.project } + let(:kubernetes_namespaces) { project.kubernetes_namespaces } + + subject do + described_class.joins(:projects).where(projects: { id: project.id }).missing_kubernetes_namespace(kubernetes_namespaces) + end + + it { is_expected.to contain_exactly(cluster) } + + context 'kubernetes namespace exists' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + it { is_expected.to be_empty } + end + end + describe 'validation' do subject { cluster.valid? } @@ -233,6 +253,81 @@ describe Clusters::Cluster do end end + describe '.ancestor_clusters_for_clusterable' do + let(:group_cluster) { create(:cluster, :provided_by_gcp, :group) } + let(:group) { group_cluster.group } + let(:hierarchy_order) { :desc } + let(:clusterable) { project } + + subject do + described_class.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: hierarchy_order) + end + + context 'when project does not belong to this group' do + let(:project) { create(:project, group: create(:group)) } + + it 'returns nothing' do + is_expected.to be_empty + end + end + + context 'when group has a configured kubernetes cluster' do + let(:project) { create(:project, group: group) } + + it 'returns the group cluster' do + is_expected.to eq([group_cluster]) + end + end + + context 'when sub-group has configured kubernetes cluster', :nested_groups do + let(:sub_group_cluster) { create(:cluster, :provided_by_gcp, :group) } + let(:sub_group) { sub_group_cluster.group } + let(:project) { create(:project, group: sub_group) } + + before do + sub_group.update!(parent: group) + end + + it 'returns clusters in order, descending the hierachy' do + is_expected.to eq([group_cluster, sub_group_cluster]) + end + + it 'avoids N+1 queries' do + another_project = create(:project) + control_count = ActiveRecord::QueryRecorder.new do + described_class.ancestor_clusters_for_clusterable(another_project, hierarchy_order: hierarchy_order) + end.count + + cluster2 = create(:cluster, :provided_by_gcp, :group) + child2 = cluster2.group + child2.update!(parent: sub_group) + project = create(:project, group: child2) + + expect do + described_class.ancestor_clusters_for_clusterable(project, hierarchy_order: hierarchy_order) + end.not_to exceed_query_limit(control_count) + end + + context 'for a group' do + let(:clusterable) { sub_group } + + it 'returns clusters in order for a group' do + is_expected.to eq([group_cluster]) + end + end + end + + context 'scope chaining' do + let(:project) { create(:project, group: group) } + + subject { described_class.none.ancestor_clusters_for_clusterable(project) } + + it 'returns nothing' do + is_expected.to be_empty + end + end + end + describe '#provider' do subject { cluster.provider } @@ -265,6 +360,31 @@ describe Clusters::Cluster do end end + describe '#all_projects' do + let(:project) { create(:project) } + let(:cluster) { create(:cluster, projects: [project]) } + + subject { cluster.all_projects } + + context 'project cluster' do + it 'returns project' do + is_expected.to eq([project]) + end + end + + context 'group cluster' do + let(:cluster) { create(:cluster, :group) } + let(:group) { cluster.group } + let(:project) { create(:project, group: group) } + let(:subgroup) { create(:group, parent: group) } + let(:subproject) { create(:project, group: subgroup) } + + it 'returns all projects for group' do + is_expected.to contain_exactly(project, subproject) + end + end + end + describe '#first_project' do subject { cluster.first_project } diff --git a/spec/models/concerns/chronic_duration_attribute_spec.rb b/spec/models/concerns/chronic_duration_attribute_spec.rb index 8847623f705..b14b773b653 100644 --- a/spec/models/concerns/chronic_duration_attribute_spec.rb +++ b/spec/models/concerns/chronic_duration_attribute_spec.rb @@ -54,7 +54,8 @@ shared_examples 'ChronicDurationAttribute writer' do subject.send("#{virtual_field}=", '-10m') expect(subject.valid?).to be_falsey - expect(subject.errors&.messages).to include(virtual_field => ['is not a correct duration']) + expect(subject.errors&.messages) + .to include(base: ['Maximum job timeout has a value which could not be accepted']) end end diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb index 7bb89fe41dc..19ab4382b53 100644 --- a/spec/models/concerns/deployment_platform_spec.rb +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -43,13 +43,86 @@ describe DeploymentPlatform do it { is_expected.to be_nil } end - context 'when user configured kubernetes from CI/CD > Clusters' do + context 'when project has configured kubernetes from CI/CD > Clusters' do let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let(:platform_kubernetes) { cluster.platform_kubernetes } it 'returns the Kubernetes platform' do expect(subject).to eq(platform_kubernetes) end + + context 'with a group level kubernetes cluster' do + let(:group_cluster) { create(:cluster, :provided_by_gcp, :group) } + + before do + project.update!(group: group_cluster.group) + end + + it 'returns the Kubernetes platform from the project cluster' do + expect(subject).to eq(platform_kubernetes) + end + end + end + + context 'when group has configured kubernetes cluster' do + let!(:group_cluster) { create(:cluster, :provided_by_gcp, :group) } + let(:group) { group_cluster.group } + + before do + project.update!(group: group) + end + + it 'returns the Kubernetes platform' do + is_expected.to eq(group_cluster.platform_kubernetes) + end + + context 'when child group has configured kubernetes cluster', :nested_groups do + let!(:child_group1_cluster) { create(:cluster, :provided_by_gcp, :group) } + let(:child_group1) { child_group1_cluster.group } + + before do + project.update!(group: child_group1) + child_group1.update!(parent: group) + end + + it 'returns the Kubernetes platform for the child group' do + is_expected.to eq(child_group1_cluster.platform_kubernetes) + end + + context 'deeply nested group' do + let!(:child_group2_cluster) { create(:cluster, :provided_by_gcp, :group) } + let(:child_group2) { child_group2_cluster.group } + + before do + child_group2.update!(parent: child_group1) + project.update!(group: child_group2) + end + + it 'returns most nested group cluster Kubernetes platform' do + is_expected.to eq(child_group2_cluster.platform_kubernetes) + end + + context 'cluster in the middle of hierarchy is disabled' do + before do + child_group2_cluster.update!(enabled: false) + end + + it 'returns closest enabled Kubenetes platform' do + is_expected.to eq(child_group1_cluster.platform_kubernetes) + end + end + end + end + + context 'feature flag disabled' do + before do + stub_feature_flags(group_clusters: false) + end + + it 'returns nil' do + is_expected.to be_nil + end + end end context 'when user configured kubernetes integration from project services' do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index ada00f03928..0c3a49cd0f2 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -745,4 +745,33 @@ describe Group do let(:uploader_class) { AttachmentUploader } end end + + describe '#group_clusters_enabled?' do + before do + # Override global stub in spec/spec_helper.rb + expect(Feature).to receive(:enabled?).and_call_original + end + + subject { group.group_clusters_enabled? } + + it { is_expected.to be_truthy } + + context 'explicitly disabled for root ancestor' do + before do + feature = Feature.get(:group_clusters) + feature.disable(group.root_ancestor) + end + + it { is_expected.to be_falsey } + end + + context 'explicitly disabled for root ancestor' do + before do + feature = Feature.get(:group_clusters) + feature.enable(group.root_ancestor) + end + + it { is_expected.to be_truthy } + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index ad55c280399..9b60054e14a 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1206,6 +1206,119 @@ describe MergeRequest do expect(subject.all_pipelines).to contain_exactly(pipeline) end end + + context 'when pipelines exist for the branch and merge request' do + let(:source_ref) { 'feature' } + let(:target_ref) { 'master' } + + let!(:branch_pipeline) do + create(:ci_pipeline, + source: :push, + project: project, + ref: source_ref, + sha: shas.second) + end + + let!(:merge_request_pipeline) do + create(:ci_pipeline, + source: :merge_request, + project: project, + ref: source_ref, + sha: shas.second, + merge_request: merge_request) + end + + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: source_ref, + target_project: project, + target_branch: target_ref) + end + + let(:project) { create(:project, :repository) } + let(:shas) { project.repository.commits(source_ref, limit: 2).map(&:id) } + + before do + allow(merge_request).to receive(:all_commit_shas) { shas } + end + + it 'returns merge request pipeline first' do + expect(merge_request.all_pipelines) + .to eq([merge_request_pipeline, + branch_pipeline]) + end + + context 'when there are a branch pipeline and a merge request pipeline' do + let!(:branch_pipeline_2) do + create(:ci_pipeline, + source: :push, + project: project, + ref: source_ref, + sha: shas.first) + end + + let!(:merge_request_pipeline_2) do + create(:ci_pipeline, + source: :merge_request, + project: project, + ref: source_ref, + sha: shas.first, + merge_request: merge_request) + end + + it 'returns merge request pipelines first' do + expect(merge_request.all_pipelines) + .to eq([merge_request_pipeline_2, + merge_request_pipeline, + branch_pipeline_2, + branch_pipeline]) + end + end + + context 'when there are multiple merge request pipelines from the same branch' do + let!(:branch_pipeline_2) do + create(:ci_pipeline, + source: :push, + project: project, + ref: source_ref, + sha: shas.first) + end + + let!(:merge_request_pipeline_2) do + create(:ci_pipeline, + source: :merge_request, + project: project, + ref: source_ref, + sha: shas.first, + merge_request: merge_request_2) + end + + let(:merge_request_2) do + create(:merge_request, + source_project: project, + source_branch: source_ref, + target_project: project, + target_branch: 'stable') + end + + before do + allow(merge_request_2).to receive(:all_commit_shas) { shas } + end + + it 'returns only related merge request pipelines' do + expect(merge_request.all_pipelines) + .to eq([merge_request_pipeline, + branch_pipeline_2, + branch_pipeline]) + + expect(merge_request_2.all_pipelines) + .to eq([merge_request_pipeline_2, + branch_pipeline_2, + branch_pipeline]) + end + end + end end describe '#has_test_reports?' do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 2db42fe802a..6ee19c0ddf4 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -560,6 +560,7 @@ describe Namespace do let!(:project2) { create(:project_empty_repo, namespace: child) } it { expect(group.all_projects.to_a).to match_array([project2, project1]) } + it { expect(child.all_projects.to_a).to match_array([project2]) } end describe '#all_pipelines' do @@ -720,6 +721,7 @@ describe Namespace do deep_nested_group = create(:group, parent: nested_group) very_deep_nested_group = create(:group, parent: deep_nested_group) + expect(root_group.root_ancestor).to eq(root_group) expect(nested_group.root_ancestor).to eq(root_group) expect(deep_nested_group.root_ancestor).to eq(root_group) expect(very_deep_nested_group.root_ancestor).to eq(root_group) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 54ad3c858d5..50920d9d1fc 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -63,7 +63,7 @@ describe Project do it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) } it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') } it { is_expected.to have_many(:commit_statuses) } - it { is_expected.to have_many(:pipelines) } + it { is_expected.to have_many(:ci_pipelines) } it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:build_trace_section_names)} it { is_expected.to have_many(:runner_projects) } @@ -87,6 +87,7 @@ describe Project do it { is_expected.to have_many(:pipeline_schedules) } it { is_expected.to have_many(:members_and_requesters) } it { is_expected.to have_many(:clusters) } + it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_many(:custom_attributes).class_name('ProjectCustomAttribute') } it { is_expected.to have_many(:project_badges).class_name('ProjectBadge') } it { is_expected.to have_many(:lfs_file_locks) } @@ -142,6 +143,29 @@ describe Project do expect(subject.boards.size).to eq 1 end end + + describe 'ci_pipelines association' do + context 'when feature flag pipeline_ci_sources_only is enabled' do + it 'returns only pipelines from ci_sources' do + stub_feature_flags(pipeline_ci_sources_only: true) + + expect(Ci::Pipeline).to receive(:ci_sources).and_call_original + + subject.ci_pipelines + end + end + + context 'when feature flag pipeline_ci_sources_only is disabled' do + it 'returns all pipelines' do + stub_feature_flags(pipeline_ci_sources_only: false) + + expect(Ci::Pipeline).not_to receive(:ci_sources).and_call_original + expect(Ci::Pipeline).to receive(:all).and_call_original.at_least(:once) + + subject.ci_pipelines + end + end + end end describe 'modules' do @@ -154,6 +178,24 @@ describe Project do it { is_expected.to include_module(Sortable) } end + describe '.missing_kubernetes_namespace' do + let!(:project) { create(:project) } + let!(:cluster) { create(:cluster, :provided_by_user, :group) } + let(:kubernetes_namespaces) { project.kubernetes_namespaces } + + subject { described_class.missing_kubernetes_namespace(kubernetes_namespaces) } + + it { is_expected.to contain_exactly(project) } + + context 'kubernetes namespace exists' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + it { is_expected.to be_empty } + end + end + describe 'validation' do let!(:project) { create(:project) } @@ -393,6 +435,8 @@ describe Project do it { is_expected.to delegate_method(:members).to(:team).with_prefix(true) } it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) } + it { is_expected.to delegate_method(:group_clusters_enabled?).to(:group).with_arguments(allow_nil: true) } + it { is_expected.to delegate_method(:root_ancestor).to(:namespace).with_arguments(allow_nil: true) } end describe '#to_reference_with_postfix' do @@ -2098,6 +2142,39 @@ describe Project do it 'includes ancestors upto but excluding the given ancestor' do expect(project.ancestors_upto(parent)).to contain_exactly(child2, child) end + + describe 'with hierarchy_order' do + it 'returns ancestors ordered by descending hierarchy' do + expect(project.ancestors_upto(hierarchy_order: :desc)).to eq([parent, child, child2]) + end + + it 'can be used with upto option' do + expect(project.ancestors_upto(parent, hierarchy_order: :desc)).to eq([child, child2]) + end + end + end + + describe '#root_ancestor' do + let(:project) { create(:project) } + + subject { project.root_ancestor } + + it { is_expected.to eq(project.namespace) } + + context 'in a group' do + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } + + it { is_expected.to eq(group) } + end + + context 'in a nested group', :nested_groups do + let(:root) { create(:group) } + let(:child) { create(:group, parent: root) } + let(:project) { create(:project, group: child) } + + it { is_expected.to eq(root) } + end end describe '#lfs_enabled?' do @@ -3373,7 +3450,7 @@ describe Project do context 'with a ref that is not the default branch' do it 'returns the latest successful pipeline for the given ref' do - expect(project.pipelines).to receive(:latest_successful_for).with('foo') + expect(project.ci_pipelines).to receive(:latest_successful_for).with('foo') project.latest_successful_pipeline_for('foo') end @@ -3401,7 +3478,7 @@ describe Project do it 'memoizes and returns the latest successful pipeline for the default branch' do pipeline = double(:pipeline) - expect(project.pipelines).to receive(:latest_successful_for) + expect(project.ci_pipelines).to receive(:latest_successful_for) .with(project.default_branch) .and_return(pipeline) .once @@ -3994,6 +4071,27 @@ describe Project do end end + describe '#all_clusters' do + let(:project) { create(:project) } + let(:cluster) { create(:cluster, cluster_type: :project_type, projects: [project]) } + + subject { project.all_clusters } + + it 'returns project level cluster' do + expect(subject).to eq([cluster]) + end + + context 'project belongs to a group' do + let(:group_cluster) { create(:cluster, :group) } + let(:group) { group_cluster.group } + let(:project) { create(:project, group: group) } + + it 'returns clusters for groups of this project' do + expect(subject).to contain_exactly(cluster, group_cluster) + end + end + end + def rugged_config rugged_repo(project.repository).config end diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index cd43bec35df..a43304c9b83 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -16,8 +16,8 @@ describe API::CommitStatuses do let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" } context 'ci commit exists' do - let!(:master) { project.pipelines.create(source: :push, sha: commit.id, ref: 'master', protected: false) } - let!(:develop) { project.pipelines.create(source: :push, sha: commit.id, ref: 'develop', protected: false) } + let!(:master) { project.ci_pipelines.create(source: :push, sha: commit.id, ref: 'master', protected: false) } + let!(:develop) { project.ci_pipelines.create(source: :push, sha: commit.id, ref: 'develop', protected: false) } context "reporter user" do let(:statuses_id) { json_response.map { |status| status['id'] } } diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 329d069ef3d..9e599c2175f 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -818,7 +818,7 @@ describe API::Commits do end context 'when the ref has a pipeline' do - let!(:pipeline) { project.pipelines.create(source: :push, ref: 'master', sha: commit.sha, protected: false) } + let!(:pipeline) { project.ci_pipelines.create(source: :push, ref: 'master', sha: commit.sha, protected: false) } it 'includes a "created" status' do get api(route, current_user) diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 334dbb1c34c..620f9f5e1d6 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -121,6 +121,13 @@ describe API::Files do end end + context 'when PATs are used' do + it_behaves_like 'repository files' do + let(:token) { create(:personal_access_token, scopes: ['read_repository'], user: user) } + let(:current_user) { { personal_access_token: token } } + end + end + context 'when authenticated', 'as a developer' do it_behaves_like 'repository files' do let(:current_user) { user } @@ -217,6 +224,13 @@ describe API::Files do end end + context 'when PATs are used' do + it_behaves_like 'repository files' do + let(:token) { create(:personal_access_token, scopes: ['read_repository'], user: user) } + let(:current_user) { { personal_access_token: token } } + end + end + context 'when unauthenticated', 'and project is private' do it_behaves_like '404 response' do let(:request) { get api(route(file_path)), params } @@ -317,6 +331,21 @@ describe API::Files do let(:request) { get api(route(file_path), guest), params } end end + + context 'when PATs are used' do + it 'returns file by commit sha' do + token = create(:personal_access_token, scopes: ['read_repository'], user: user) + + # This file is deleted on HEAD + file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee" + params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" + expect(Gitlab::Workhorse).to receive(:send_git_blob) + + get api(route(file_path) + "/raw", personal_access_token: token), params + + expect(response).to have_gitlab_http_status(200) + end + end end describe "POST /projects/:id/repository/files/:file_path" do @@ -362,6 +391,24 @@ describe API::Files do expect(response).to have_gitlab_http_status(400) end + context 'with PATs' do + it 'returns 403 with `read_repository` scope' do + token = create(:personal_access_token, scopes: ['read_repository'], user: user) + + post api(route(file_path), personal_access_token: token), params + + expect(response).to have_gitlab_http_status(403) + end + + it 'returns 201 with `api` scope' do + token = create(:personal_access_token, scopes: ['api'], user: user) + + post api(route(file_path), personal_access_token: token), params + + expect(response).to have_gitlab_http_status(201) + end + end + context "when specifying an author" do it "creates a new file with the specified author" do params.merge!(author_email: author_email, author_name: author_name) diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 638cc9767d4..2e4fa0f9e16 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -304,7 +304,7 @@ describe API::Pipelines do it 'creates and returns a new pipeline' do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch - end.to change { project.pipelines.count }.by(1) + end.to change { project.ci_pipelines.count }.by(1) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash @@ -317,8 +317,8 @@ describe API::Pipelines do it 'creates and returns a new pipeline using the given variables' do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables - end.to change { project.pipelines.count }.by(1) - expect_variables(project.pipelines.last.variables, variables) + end.to change { project.ci_pipelines.count }.by(1) + expect_variables(project.ci_pipelines.last.variables, variables) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash @@ -338,8 +338,8 @@ describe API::Pipelines do it 'creates and returns a new pipeline using the given variables' do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables - end.to change { project.pipelines.count }.by(1) - expect_variables(project.pipelines.last.variables, variables) + end.to change { project.ci_pipelines.count }.by(1) + expect_variables(project.ci_pipelines.last.variables, variables) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash @@ -353,7 +353,7 @@ describe API::Pipelines do it "doesn't create a job" do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch - end.not_to change { project.pipelines.count } + end.not_to change { project.ci_pipelines.count } expect(response).to have_gitlab_http_status(400) end diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 0ae6796d1e4..658df6945d2 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -39,7 +39,7 @@ describe API::Triggers do end context 'Have a commit' do - let(:pipeline) { project.pipelines.last } + let(:pipeline) { project.ci_pipelines.last } it 'creates pipeline' do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'master') diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index a4582d1bc64..ccc6b0ef1c7 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -18,7 +18,8 @@ describe Ci::CreatePipelineService do message: 'Message', ref: ref_name, trigger_request: nil, - variables_attributes: nil) + variables_attributes: nil, + merge_request: nil) params = { ref: ref, before: '00000000', after: after, @@ -26,7 +27,7 @@ describe Ci::CreatePipelineService do variables_attributes: variables_attributes } described_class.new(project, user, params).execute( - source, trigger_request: trigger_request) + source, trigger_request: trigger_request, merge_request: merge_request) end context 'valid params' do @@ -43,7 +44,7 @@ describe Ci::CreatePipelineService do expect(pipeline).to be_valid expect(pipeline).to be_persisted expect(pipeline).to be_push - expect(pipeline).to eq(project.pipelines.last) + expect(pipeline).to eq(project.ci_pipelines.last) expect(pipeline).to have_attributes(user: user) expect(pipeline).to have_attributes(status: 'pending') expect(pipeline.repository_source?).to be true @@ -60,10 +61,10 @@ describe Ci::CreatePipelineService do context 'when merge requests already exist for this source branch' do let(:merge_request_1) do - create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project) + create(:merge_request, source_branch: 'feature', target_branch: "master", source_project: project) end let(:merge_request_2) do - create(:merge_request, source_branch: 'master', target_branch: "branch_2", source_project: project) + create(:merge_request, source_branch: 'feature', target_branch: "v1.1.0", source_project: project) end context 'when related merge request is already merged' do @@ -83,7 +84,7 @@ describe Ci::CreatePipelineService do merge_request_1 merge_request_2 - head_pipeline = execute_service + head_pipeline = execute_service(ref: 'feature', after: nil) expect(merge_request_1.reload.head_pipeline).to eq(head_pipeline) expect(merge_request_2.reload.head_pipeline).to eq(head_pipeline) @@ -123,12 +124,12 @@ describe Ci::CreatePipelineService do let!(:target_project) { create(:project, :repository) } it 'updates head pipeline for merge request' do - merge_request = create(:merge_request, source_branch: 'master', - target_branch: "branch_1", + merge_request = create(:merge_request, source_branch: 'feature', + target_branch: "master", source_project: project, target_project: target_project) - head_pipeline = execute_service + head_pipeline = execute_service(ref: 'feature', after: nil) expect(merge_request.reload.head_pipeline).to eq(head_pipeline) end @@ -656,6 +657,212 @@ describe Ci::CreatePipelineService do end end end + + describe 'Merge request pipelines' do + let(:pipeline) do + execute_service(source: source, merge_request: merge_request, ref: ref_name) + end + + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + let(:ref_name) { 'feature' } + + context 'when source is merge request' do + let(:source) { :merge_request } + + context "when config has merge_requests keywords" do + let(:config) do + { + build: { + stage: 'build', + script: 'echo' + }, + test: { + stage: 'test', + script: 'echo', + only: ['merge_requests'] + }, + pages: { + stage: 'deploy', + script: 'echo', + except: ['merge_requests'] + } + } + end + + context 'when merge request is specified' do + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: ref_name, + target_project: project, + target_branch: 'master') + end + + it 'creates a merge request pipeline' do + expect(pipeline).to be_persisted + expect(pipeline).to be_merge_request + expect(pipeline.merge_request).to eq(merge_request) + expect(pipeline.builds.order(:stage_id).map(&:name)).to eq(%w[test]) + end + + context 'when ref is tag' do + let(:ref_name) { 'v1.1.0' } + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + expect(pipeline.errors[:tag]).to eq(["is not included in the list"]) + end + end + + context 'when merge request is created from a forked project' do + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: ref_name, + target_project: target_project, + target_branch: 'master') + end + + let!(:project) { fork_project(target_project, nil, repository: true) } + let!(:target_project) { create(:project, :repository) } + + it 'creates a merge request pipeline in the forked project' do + expect(pipeline).to be_persisted + expect(project.ci_pipelines).to eq([pipeline]) + expect(target_project.ci_pipelines).to be_empty + end + end + + context "when there are no matched jobs" do + let(:config) do + { + test: { + stage: 'test', + script: 'echo', + except: ['merge_requests'] + } + } + end + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + expect(pipeline.errors[:base]).to eq(["No stages / jobs for this pipeline."]) + end + end + end + + context 'when merge request is not specified' do + let(:merge_request) { nil } + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + expect(pipeline.errors[:merge_request]).to eq(["can't be blank"]) + end + end + end + + context "when config does not have merge_requests keywords" do + let(:config) do + { + build: { + stage: 'build', + script: 'echo' + }, + test: { + stage: 'test', + script: 'echo' + }, + pages: { + stage: 'deploy', + script: 'echo' + } + } + end + + context 'when merge request is specified' do + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: ref_name, + target_project: project, + target_branch: 'master') + end + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + + expect(pipeline.errors[:base]) + .to eq(['No stages / jobs for this pipeline.']) + end + end + + context 'when merge request is not specified' do + let(:merge_request) { nil } + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + + expect(pipeline.errors[:base]) + .to eq(['No stages / jobs for this pipeline.']) + end + end + end + end + + context 'when source is web' do + let(:source) { :web } + + context "when config has merge_requests keywords" do + let(:config) do + { + build: { + stage: 'build', + script: 'echo' + }, + test: { + stage: 'test', + script: 'echo', + only: ['merge_requests'] + }, + pages: { + stage: 'deploy', + script: 'echo', + except: ['merge_requests'] + } + } + end + + context 'when merge request is specified' do + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: ref_name, + target_project: project, + target_branch: 'master') + end + + it 'does not create a merge request pipeline' do + expect(pipeline).not_to be_persisted + expect(pipeline.errors[:merge_request]).to eq(["must be blank"]) + end + end + + context 'when merge request is not specified' do + let(:merge_request) { nil } + + it 'creates a branch pipeline' do + expect(pipeline).to be_persisted + expect(pipeline).to be_web + expect(pipeline.merge_request).to be_nil + expect(pipeline.builds.order(:stage_id).map(&:name)).to eq(%w[build pages]) + end + end + end + end + end end describe '#execute!' do diff --git a/spec/services/clusters/refresh_service_spec.rb b/spec/services/clusters/refresh_service_spec.rb new file mode 100644 index 00000000000..58ab3c3cf73 --- /dev/null +++ b/spec/services/clusters/refresh_service_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::RefreshService do + shared_examples 'creates a kubernetes namespace' do + let(:token) { 'aaaaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + it 'creates a kubernetes namespace' do + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + + expect { subject }.to change(project.kubernetes_namespaces, :count) + + kubernetes_namespace = cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end + + shared_examples 'does not create a kubernetes namespace' do + it 'does not create a new kubernetes namespace' do + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).not_to receive(:namespace_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).not_to receive(:new) + + expect { subject }.not_to change(Clusters::KubernetesNamespace, :count) + end + end + + describe '.create_or_update_namespaces_for_cluster' do + let(:cluster) { create(:cluster, :provided_by_user, :project) } + let(:project) { cluster.project } + + subject { described_class.create_or_update_namespaces_for_cluster(cluster) } + + context 'cluster is project level' do + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + + context 'cluster is group level' do + let(:cluster) { create(:cluster, :provided_by_user, :group) } + let(:group) { cluster.group } + let(:project) { create(:project, group: group) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + end + + describe '.create_or_update_namespaces_for_project' do + let(:project) { create(:project) } + + subject { described_class.create_or_update_namespaces_for_project(project) } + + it 'creates no kubernetes namespaces' do + expect { subject }.not_to change(project.kubernetes_namespaces, :count) + end + + context 'project has a project cluster' do + let!(:cluster) { create(:cluster, :provided_by_gcp, cluster_type: :project_type, projects: [project]) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + + context 'project belongs to a group cluster' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :group) } + + let(:group) { cluster.group } + let(:project) { create(:project, group: group) } + + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + end +end diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 74bcc15f912..5a3ecb1019b 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -159,6 +159,78 @@ describe MergeRequests::CreateService do end end end + + describe 'Merge request pipelines' do + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + context "when .gitlab-ci.yml has merge_requests keywords" do + let(:config) do + { + test: { + stage: 'test', + script: 'echo', + only: ['merge_requests'] + } + } + end + + it 'creates a merge request pipeline and sets it as a head pipeline' do + expect(merge_request).to be_persisted + + merge_request.reload + expect(merge_request.merge_request_pipelines.count).to eq(1) + expect(merge_request.actual_head_pipeline).to be_merge_request + end + + context "when branch pipeline was created before a merge request pipline has been created" do + before do + create(:ci_pipeline, project: merge_request.source_project, + sha: merge_request.diff_head_sha, + ref: merge_request.source_branch, + tag: false) + + merge_request + end + + it 'sets the latest merge request pipeline as the head pipeline' do + expect(merge_request.actual_head_pipeline).to be_merge_request + end + end + + context "when the 'ci_merge_request_pipeline' feature flag is disabled" do + before do + stub_feature_flags(ci_merge_request_pipeline: false) + end + + it 'does not create a merge request pipeline' do + expect(merge_request).to be_persisted + + merge_request.reload + expect(merge_request.merge_request_pipelines.count).to eq(0) + end + end + end + + context "when .gitlab-ci.yml does not have merge_requests keywords" do + let(:config) do + { + test: { + stage: 'test', + script: 'echo' + } + } + end + + it 'does not create a merge request pipeline' do + expect(merge_request).to be_persisted + + merge_request.reload + expect(merge_request.merge_request_pipelines.count).to eq(0) + end + end + end end it_behaves_like 'new issuable record that supports quick actions' do diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 61c6ba7d550..d29a1091d95 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -132,6 +132,94 @@ describe MergeRequests::RefreshService do end end + describe 'Merge request pipelines' do + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + subject { service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') } + + context "when .gitlab-ci.yml has merge_requests keywords" do + let(:config) do + { + test: { + stage: 'test', + script: 'echo', + only: ['merge_requests'] + } + } + end + + it 'create merge request pipeline' do + expect { subject } + .to change { @merge_request.merge_request_pipelines.count }.by(1) + .and change { @fork_merge_request.merge_request_pipelines.count }.by(1) + .and change { @another_merge_request.merge_request_pipelines.count }.by(1) + end + + context "when branch pipeline was created before a merge request pipline has been created" do + before do + create(:ci_pipeline, project: @merge_request.source_project, + sha: @merge_request.diff_head_sha, + ref: @merge_request.source_branch, + tag: false) + + subject + end + + it 'sets the latest merge request pipeline as a head pipeline' do + @merge_request.reload + expect(@merge_request.actual_head_pipeline).to be_merge_request + end + + it 'returns pipelines in correct order' do + @merge_request.reload + expect(@merge_request.all_pipelines.first).to be_merge_request + expect(@merge_request.all_pipelines.second).to be_push + end + end + + context "when MergeRequestUpdateWorker is retried by an exception" do + it 'does not re-create a duplicate merge request pipeline' do + expect do + service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') + end.to change { @merge_request.merge_request_pipelines.count }.by(1) + + expect do + service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') + end.not_to change { @merge_request.merge_request_pipelines.count } + end + end + + context "when the 'ci_merge_request_pipeline' feature flag is disabled" do + before do + stub_feature_flags(ci_merge_request_pipeline: false) + end + + it 'does not create a merge request pipeline' do + expect { subject } + .not_to change { @merge_request.merge_request_pipelines.count } + end + end + end + + context "when .gitlab-ci.yml does not have merge_requests keywords" do + let(:config) do + { + test: { + stage: 'test', + script: 'echo' + } + } + end + + it 'does not create a merge request pipeline' do + expect { subject } + .not_to change { @merge_request.merge_request_pipelines.count } + end + end + end + context 'push to origin repo source branch when an MR was reopened' do let(:refresh_service) { service.new(@project, @user) } let(:notification_service) { spy('notification_service') } diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 08de27ca44a..f71e2b4bc24 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -261,6 +261,32 @@ describe Projects::CreateService, '#execute' do end end + context 'when group has kubernetes cluster' do + let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { group_cluster.group } + + let(:token) { 'aaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + before do + group.add_owner(user) + + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + end + + it 'creates kubernetes namespace for the project' do + project = create_project(user, opts.merge!(namespace_id: group.id)) + + expect(project).to be_valid + + kubernetes_namespace = group_cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end + context 'when there is an active service template' do before do create(:service, project: nil, template: true, active: true) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 2e07d4f8013..132ad9a2646 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -62,6 +62,32 @@ describe Projects::TransferService do expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" end + + context 'new group has a kubernetes cluster' do + let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { group_cluster.group } + + let(:token) { 'aaaa' } + let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService, execute: true) } + let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } + + subject { transfer_project(project, user, group) } + + before do + expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) + expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) + end + + it 'creates kubernetes namespace for the project' do + subject + + expect(project.kubernetes_namespaces.count).to eq(1) + + kubernetes_namespace = group_cluster.kubernetes_namespaces.first + expect(kubernetes_namespace).to be_present + expect(kubernetes_namespace.project).to eq(project) + end + end end context 'when transfer fails' do diff --git a/spec/support/helpers/features/list_rows_helpers.rb b/spec/support/helpers/features/list_rows_helpers.rb new file mode 100644 index 00000000000..0626415361c --- /dev/null +++ b/spec/support/helpers/features/list_rows_helpers.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# These helpers allow you to access rows in the list +# +# Usage: +# describe "..." do +# include Spec::Support::Helpers::Features::ListRowsHelpers +# ... +# +# expect(first_row.text).to include("John Doe") +# expect(second_row.text).to include("John Smith") +# +module Spec + module Support + module Helpers + module Features + module ListRowsHelpers + def first_row + page.all('ul.content-list > li')[0] + end + + def second_row + page.all('ul.content-list > li')[1] + end + end + end + end + end +end diff --git a/spec/support/shared_examples/diff_file_collections.rb b/spec/support/shared_examples/diff_file_collections.rb index 55ce160add0..367ddf06c28 100644 --- a/spec/support/shared_examples/diff_file_collections.rb +++ b/spec/support/shared_examples/diff_file_collections.rb @@ -45,3 +45,19 @@ shared_examples 'diff statistics' do |test_include_stats_flag: true| end end end + +shared_examples 'unfoldable diff' do + let(:subject) { described_class.new(diffable, diff_options: nil) } + + it 'calls Gitlab::Diff::File#unfold_diff_lines with correct position' do + position = instance_double(Gitlab::Diff::Position, file_path: 'README') + readme_file = instance_double(Gitlab::Diff::File, file_path: 'README') + other_file = instance_double(Gitlab::Diff::File, file_path: 'foo.rb') + nil_path_file = instance_double(Gitlab::Diff::File, file_path: nil) + + allow(subject).to receive(:diff_files) { [readme_file, other_file, nil_path_file] } + expect(readme_file).to receive(:unfold_diff_lines).with(position) + + subject.unfold_diff_files([position]) + end +end diff --git a/spec/tasks/gitlab/check_rake_spec.rb b/spec/tasks/gitlab/check_rake_spec.rb index 4eda618b6d6..06525e3c771 100644 --- a/spec/tasks/gitlab/check_rake_spec.rb +++ b/spec/tasks/gitlab/check_rake_spec.rb @@ -1,51 +1,101 @@ require 'rake_helper' -describe 'gitlab:ldap:check rake task' do - include LdapHelpers - +describe 'check.rake' do before do Rake.application.rake_require 'tasks/gitlab/check' stub_warn_user_is_not_gitlab end - context 'when LDAP is not enabled' do - it 'does not attempt to bind or search for users' do - expect(Gitlab::Auth::LDAP::Config).not_to receive(:providers) - expect(Gitlab::Auth::LDAP::Adapter).not_to receive(:open) - - run_rake_task('gitlab:ldap:check') + shared_examples_for 'system check rake task' do + it 'runs the check' do + expect do + subject + end.to output(/Checking #{name} ... Finished/).to_stdout end end - context 'when LDAP is enabled' do - let(:ldap) { double(:ldap) } - let(:adapter) { ldap_adapter('ldapmain', ldap) } + describe 'gitlab:check rake task' do + subject { run_rake_task('gitlab:check') } + let(:name) { 'GitLab subtasks' } - before do - allow(Gitlab::Auth::LDAP::Config) - .to receive_messages( - enabled?: true, - providers: ['ldapmain'] - ) - allow(Gitlab::Auth::LDAP::Adapter).to receive(:open).and_yield(adapter) - allow(adapter).to receive(:users).and_return([]) - end + it_behaves_like 'system check rake task' + end + + describe 'gitlab:gitlab_shell:check rake task' do + subject { run_rake_task('gitlab:gitlab_shell:check') } + let(:name) { 'GitLab Shell' } + + it_behaves_like 'system check rake task' + end + + describe 'gitlab:gitaly:check rake task' do + subject { run_rake_task('gitlab:gitaly:check') } + let(:name) { 'Gitaly' } + + it_behaves_like 'system check rake task' + end + + describe 'gitlab:sidekiq:check rake task' do + subject { run_rake_task('gitlab:sidekiq:check') } + let(:name) { 'Sidekiq' } - it 'attempts to bind using credentials' do - stub_ldap_config(has_auth?: true) + it_behaves_like 'system check rake task' + end - expect(ldap).to receive(:bind) + describe 'gitlab:incoming_email:check rake task' do + subject { run_rake_task('gitlab:incoming_email:check') } + let(:name) { 'Incoming Email' } - run_rake_task('gitlab:ldap:check') + it_behaves_like 'system check rake task' + end + + describe 'gitlab:ldap:check rake task' do + include LdapHelpers + + subject { run_rake_task('gitlab:ldap:check') } + let(:name) { 'LDAP' } + + it_behaves_like 'system check rake task' + + context 'when LDAP is not enabled' do + it 'does not attempt to bind or search for users' do + expect(Gitlab::Auth::LDAP::Config).not_to receive(:providers) + expect(Gitlab::Auth::LDAP::Adapter).not_to receive(:open) + + subject + end end - it 'searches for 100 LDAP users' do - stub_ldap_config(uid: 'uid') + context 'when LDAP is enabled' do + let(:ldap) { double(:ldap) } + let(:adapter) { ldap_adapter('ldapmain', ldap) } + + before do + allow(Gitlab::Auth::LDAP::Config) + .to receive_messages( + enabled?: true, + providers: ['ldapmain'] + ) + allow(Gitlab::Auth::LDAP::Adapter).to receive(:open).and_yield(adapter) + allow(adapter).to receive(:users).and_return([]) + end + + it 'attempts to bind using credentials' do + stub_ldap_config(has_auth?: true) + + expect(ldap).to receive(:bind) + + subject + end + + it 'searches for 100 LDAP users' do + stub_ldap_config(uid: 'uid') - expect(adapter).to receive(:users).with('uid', '*', 100) + expect(adapter).to receive(:users).with('uid', '*', 100) - run_rake_task('gitlab:ldap:check') + subject + end end end end diff --git a/spec/features/admin/admin_active_tab_spec.rb b/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb index 1215908f5ea..05c2f61a606 100644 --- a/spec/features/admin/admin_active_tab_spec.rb +++ b/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb @@ -1,27 +1,26 @@ require 'spec_helper' -RSpec.describe 'admin active tab' do - before do - sign_in(create(:admin)) - end - +describe 'layouts/nav/sidebar/_admin' do shared_examples 'page has active tab' do |title| it "activates #{title} tab" do - expect(page).to have_selector('.nav-sidebar .sidebar-top-level-items > li.active', count: 1) - expect(page.find('.nav-sidebar .sidebar-top-level-items > li.active')).to have_content(title) + render + + expect(rendered).to have_selector('.nav-sidebar .sidebar-top-level-items > li.active', count: 1) + expect(rendered).to have_css('.nav-sidebar .sidebar-top-level-items > li.active', text: title) end end shared_examples 'page has active sub tab' do |title| it "activates #{title} sub tab" do - expect(page).to have_selector('.sidebar-sub-level-items > li.active', count: 2) - expect(page.all('.sidebar-sub-level-items > li.active')[1]).to have_content(title) + render + + expect(rendered).to have_css('.sidebar-sub-level-items > li.active', text: title) end end context 'on home page' do before do - visit admin_root_path + allow(controller).to receive(:controller_name).and_return('dashboard') end it_behaves_like 'page has active tab', 'Overview' @@ -29,7 +28,8 @@ RSpec.describe 'admin active tab' do context 'on projects' do before do - visit admin_projects_path + allow(controller).to receive(:controller_name).and_return('projects') + allow(controller).to receive(:controller_path).and_return('admin/projects') end it_behaves_like 'page has active tab', 'Overview' @@ -38,7 +38,7 @@ RSpec.describe 'admin active tab' do context 'on groups' do before do - visit admin_groups_path + allow(controller).to receive(:controller_name).and_return('groups') end it_behaves_like 'page has active tab', 'Overview' @@ -47,7 +47,7 @@ RSpec.describe 'admin active tab' do context 'on users' do before do - visit admin_users_path + allow(controller).to receive(:controller_name).and_return('users') end it_behaves_like 'page has active tab', 'Overview' @@ -56,7 +56,7 @@ RSpec.describe 'admin active tab' do context 'on logs' do before do - visit admin_logs_path + allow(controller).to receive(:controller_name).and_return('logs') end it_behaves_like 'page has active tab', 'Monitoring' @@ -65,7 +65,7 @@ RSpec.describe 'admin active tab' do context 'on messages' do before do - visit admin_broadcast_messages_path + allow(controller).to receive(:controller_name).and_return('broadcast_messages') end it_behaves_like 'page has active tab', 'Messages' @@ -73,7 +73,7 @@ RSpec.describe 'admin active tab' do context 'on hooks' do before do - visit admin_hooks_path + allow(controller).to receive(:controller_name).and_return('hooks') end it_behaves_like 'page has active tab', 'Hooks' @@ -81,7 +81,7 @@ RSpec.describe 'admin active tab' do context 'on background jobs' do before do - visit admin_background_jobs_path + allow(controller).to receive(:controller_name).and_return('background_jobs') end it_behaves_like 'page has active tab', 'Monitoring' diff --git a/spec/workers/cluster_platform_configure_worker_spec.rb b/spec/workers/cluster_platform_configure_worker_spec.rb index b51f6e07c6a..0eead0ab13d 100644 --- a/spec/workers/cluster_platform_configure_worker_spec.rb +++ b/spec/workers/cluster_platform_configure_worker_spec.rb @@ -2,7 +2,43 @@ require 'spec_helper' -describe ClusterPlatformConfigureWorker, '#execute' do +describe ClusterPlatformConfigureWorker, '#perform' do + let(:worker) { described_class.new } + + context 'when group cluster' do + let(:cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { cluster.group } + + context 'when group has no projects' do + it 'does not create a namespace' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute) + + worker.perform(cluster.id) + end + end + + context 'when group has a project' do + let!(:project) { create(:project, group: group) } + + it 'creates a namespace for the project' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + + worker.perform(cluster.id) + end + end + + context 'when group has project in a sub-group' do + let!(:subgroup) { create(:group, parent: group) } + let!(:project) { create(:project, group: subgroup) } + + it 'creates a namespace for the project' do + expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + + worker.perform(cluster.id) + end + end + end + context 'when provider type is gcp' do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } @@ -30,18 +66,4 @@ describe ClusterPlatformConfigureWorker, '#execute' do described_class.new.perform(123) end end - - context 'when kubeclient raises error' do - let(:cluster) { create(:cluster, :project) } - - it 'rescues and logs the error' do - allow_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).and_raise(::Kubeclient::HttpError.new(500, 'something baaaad happened', '')) - - expect(Rails.logger) - .to receive(:error) - .with("Failed to create/update Kubernetes namespace for cluster_id: #{cluster.id} with error: something baaaad happened") - - described_class.new.perform(cluster.id) - end - end end diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index bebcbe01009..ff408427926 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -25,12 +25,12 @@ describe PipelineScheduleWorker do context 'when there is a scheduled pipeline within next_run_at' do shared_examples 'successful scheduling' do it 'creates a new pipeline' do - expect { subject }.to change { project.pipelines.count }.by(1) + expect { subject }.to change { project.ci_pipelines.count }.by(1) expect(Ci::Pipeline.last).to be_schedule pipeline_schedule.reload expect(pipeline_schedule.next_run_at).to be > Time.now - expect(pipeline_schedule).to eq(project.pipelines.last.pipeline_schedule) + expect(pipeline_schedule).to eq(project.ci_pipelines.last.pipeline_schedule) expect(pipeline_schedule).to be_active end end @@ -54,7 +54,7 @@ describe PipelineScheduleWorker do end it 'does not creates a new pipeline' do - expect { subject }.not_to change { project.pipelines.count } + expect { subject }.not_to change { project.ci_pipelines.count } end end @@ -64,7 +64,7 @@ describe PipelineScheduleWorker do end it 'creates a failed pipeline with the reason' do - expect { subject }.to change { project.pipelines.count }.by(1) + expect { subject }.to change { project.ci_pipelines.count }.by(1) expect(Ci::Pipeline.last).to be_config_error expect(Ci::Pipeline.last.yaml_errors).not_to be_nil end @@ -105,7 +105,7 @@ describe PipelineScheduleWorker do end it 'does not create a pipeline' do - expect { subject }.not_to change { project.pipelines.count } + expect { subject }.not_to change { project.ci_pipelines.count } end it 'does not raise an exception' do @@ -135,7 +135,7 @@ describe PipelineScheduleWorker do end it 'does not create a pipeline' do - expect { subject }.not_to change { project.pipelines.count } + expect { subject }.not_to change { project.ci_pipelines.count } end it 'does not raise an exception' do diff --git a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb index 9adde5fc21a..a2bc264b0f6 100644 --- a/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb +++ b/spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb @@ -34,5 +34,33 @@ describe UpdateHeadPipelineForMergeRequestWorker do expect { subject.perform(merge_request.id) }.not_to change { merge_request.reload.head_pipeline_id } end end + + context 'when a merge request pipeline exists' do + let!(:merge_request_pipeline) do + create(:ci_pipeline, + project: project, + source: :merge_request, + sha: latest_sha, + merge_request: merge_request) + end + + it 'sets the merge request pipeline as the head pipeline' do + expect { subject.perform(merge_request.id) } + .to change { merge_request.reload.head_pipeline_id } + .from(nil).to(merge_request_pipeline.id) + end + + context 'when branch pipeline exists' do + let!(:branch_pipeline) do + create(:ci_pipeline, project: project, source: :push, sha: latest_sha) + end + + it 'prioritizes the merge request pipeline as the head pipeline' do + expect { subject.perform(merge_request.id) } + .to change { merge_request.reload.head_pipeline_id } + .from(nil).to(merge_request_pipeline.id) + end + end + end end end diff --git a/yarn.lock b/yarn.lock index 0da5e26ebd5..d4906a6a212 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== @@ -882,6 +882,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== +abab@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" + integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w== + abbrev@1, abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" @@ -902,6 +907,14 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" +acorn-globals@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.0.tgz#e3b6f8da3c1552a95ae627571f7dd6923bb54103" + integrity sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + acorn-jsx@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" @@ -909,11 +922,21 @@ acorn-jsx@^4.1.1: dependencies: acorn "^5.0.3" -acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2, acorn@^5.7.3: +acorn-walk@^6.0.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" + integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== + +acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0, acorn@^5.6.2, acorn@^5.7.3: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== +acorn@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" + integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg== + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -939,6 +962,16 @@ ajv@^6.0.1, ajv@^6.1.0, ajv@^6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.5.5: + version "6.5.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1" + integrity sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -986,7 +1019,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1098,6 +1131,13 @@ apollo-utilities@1.0.25, apollo-utilities@^1.0.0, apollo-utilities@^1.0.25, apol dependencies: fast-json-stable-stringify "^2.0.0" +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + integrity sha1-126/jKlNJ24keja61EpLdKthGZE= + dependencies: + default-require-extensions "^1.0.0" + append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -1125,12 +1165,19 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.1.0: +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== @@ -1140,6 +1187,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + array-find@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" @@ -1201,6 +1253,18 @@ asn1.js@^4.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" @@ -1213,6 +1277,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -1228,13 +1297,18 @@ async@1.x, async@^1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.0.0, async@^2.5.0, async@^2.6.1: +async@^2.0.0, async@^2.1.4, async@^2.5.0, async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + atob@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -1245,6 +1319,16 @@ autosize@^4.0.0: resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.0.tgz#7a0599b1ba84d73bd7589b0d9da3870152c69237" integrity sha1-egWZsbqE1zvXWJsNnaOHAVLGkjc= +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + axios-mock-adapter@^1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.15.0.tgz#fbc06825d8302c95c3334d21023bba996255d45d" @@ -1269,6 +1353,36 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" +babel-core@^6.0.0, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-core@^7.0.0-bridge: + version "7.0.0-bridge.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" + integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== + babel-eslint@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" @@ -1281,6 +1395,36 @@ babel-eslint@^10.0.1: eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" +babel-generator@^6.18.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-23.6.0.tgz#a644232366557a2240a0c083da6b25786185a2f1" + integrity sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew== + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.2.0" + babel-loader@^8.0.4: version "8.0.4" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.4.tgz#7bbf20cbe4560629e2e41534147692d3fecbdce6" @@ -1298,6 +1442,23 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz#c0adfb07d95f4a4495e9aaac6ec386c4d7c2524e" + integrity sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + integrity sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ== + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + babel-plugin-istanbul@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz#6892f529eff65a3e2d33d87dc5888ffa2ecd4a30" @@ -1307,11 +1468,39 @@ babel-plugin-istanbul@^5.1.0: istanbul-lib-instrument "^3.0.0" test-exclude "^5.0.0" +babel-plugin-jest-hoist@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" + integrity sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc= + babel-plugin-rewire@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.2.0.tgz#822562d72ed2c84e47c0f95ee232c920853e9d89" integrity sha512-JBZxczHw3tScS+djy6JPLMjblchGhLI89ep15H3SyjujIzlxo5nr6Yjo7AXotdeVczeBmWs0tF8PgJWDdgzAkQ== +babel-plugin-syntax-object-rest-spread@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= + +babel-plugin-transform-es2015-modules-commonjs@^6.26.2: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + babel-polyfill@6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" @@ -1321,6 +1510,27 @@ babel-polyfill@6.23.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" +babel-preset-jest@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" + integrity sha1-jsegOhOPABoaj7HoETZSvxpV2kY= + dependencies: + babel-plugin-jest-hoist "^23.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -1334,7 +1544,7 @@ babel-standalone@^6.26.0: resolved "https://registry.yarnpkg.com/babel-standalone/-/babel-standalone-6.26.0.tgz#15fb3d35f2c456695815ebf1ed96fe7f015b6886" integrity sha1-Ffs9NfLEVmlYFevx7Zb+fwFbaIY= -babel-template@^6.26.0: +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= @@ -1345,7 +1555,7 @@ babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -1360,7 +1570,7 @@ babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.26.0: +babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= @@ -1418,6 +1628,13 @@ batch@0.6.1: resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -1538,6 +1755,15 @@ braces@^0.1.2: dependencies: expand-range "^0.1.0" +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + braces@^2.3.0, braces@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" @@ -1561,6 +1787,18 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-process-hrtime@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4" + integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== + +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" @@ -1628,6 +1866,13 @@ browserslist@^4.1.0: electron-to-chromium "^1.3.62" node-releases "^1.0.0-alpha.11" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" @@ -1761,6 +2006,11 @@ callsites@^0.2.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -1771,11 +2021,23 @@ caniuse-lite@^1.0.30000884: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000888.tgz#22edb50d91dd70612b5898e3b36f460600c6492f" integrity sha512-vftg+5p/lPsQGpnhSo/yBuYL36ai/cyjLvU3dOPJY1kkKrekLWIy8SLm+wzjX0hpCUdFTasC4/ZT7uqw4rKOnQ== +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= + dependencies: + rsvp "^3.3.3" + capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" integrity sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0= +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1853,6 +2115,11 @@ chrome-trace-event@^1.0.0: dependencies: tslib "^1.9.0" +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -1928,6 +2195,11 @@ clone-response@1.0.2: dependencies: mimic-response "^1.0.0" +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1984,6 +2256,13 @@ combine-lists@^1.0.0: dependencies: lodash "^4.5.0" +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + commander@2, commander@^2.18.0, commander@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -2145,7 +2424,7 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.1.0: +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== @@ -2186,7 +2465,7 @@ copy-to-clipboard@^3.0.8: dependencies: toggle-selection "^1.0.3" -core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: +core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== @@ -2196,7 +2475,7 @@ core-js@~2.3.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= -core-util-is@~1.0.0: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -2329,6 +2608,18 @@ cssesc@^0.1.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" + integrity sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog== + +cssstyle@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.1.1.tgz#18b038a9c44d65f7a8e428a653b9f6fe42faf5fb" + integrity sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog== + dependencies: + cssom "0.3.x" + custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" @@ -2596,6 +2887,22 @@ dagre-layout@^0.8.8: graphlibrary "^2.2.0" lodash "^4.17.5" +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + date-format@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" @@ -2637,6 +2944,11 @@ debug@~3.1.0: dependencies: ms "2.0.0" +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + decamelize@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" @@ -2684,6 +2996,13 @@ default-gateway@^2.6.0: execa "^0.10.0" ip-regex "^2.1.0" +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + integrity sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= + dependencies: + strip-bom "^2.0.0" + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -2745,6 +3064,11 @@ del@^3.0.0: pify "^3.0.0" rimraf "^2.2.8" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + delegate@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.2.tgz#1e1bc6f5cadda6cb6cbf7e6d05d0bcdd5712aebe" @@ -2778,11 +3102,23 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= + dependencies: + repeating "^2.0.0" + detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" @@ -2880,6 +3216,13 @@ domelementtype@~1.1.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs= +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + domhandler@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" @@ -2927,6 +3270,14 @@ duplexify@^3.4.2, duplexify@^3.5.3: readable-stream "^2.0.0" stream-shift "^1.0.0" +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + editions@^1.3.3: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" @@ -3135,6 +3486,18 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" +escodegen@^1.9.1: + version "1.11.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" + integrity sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw== + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-airbnb-base@^13.1.0: version "13.1.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" @@ -3151,6 +3514,15 @@ eslint-config-prettier@^3.1.0: dependencies: get-stdin "^6.0.0" +eslint-import-resolver-jest@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-jest/-/eslint-import-resolver-jest-2.1.1.tgz#78c1934e3b5b77283326f036e089cc3b9fae6346" + integrity sha512-yzzZFN37CaMaCjmUZ4Zo7Pw5qCG/hDklVzxIeHYJZkbcdg0sL5MeLaOG8s3ndVBvv1PSdSq4jfkY0QXt/KPbTg== + dependencies: + find-root "^1.0.0" + micromatch "^3.1.6" + resolve "^1.5.0" + eslint-import-resolver-node@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" @@ -3221,6 +3593,11 @@ eslint-plugin-jasmine@^2.10.1: resolved "https://registry.yarnpkg.com/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz#5733b709e751f4bc40e31e1c16989bd2cdfbec97" integrity sha1-VzO3CedR9LxA4x4cFpib0s377Jc= +eslint-plugin-jest@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.1.0.tgz#9a4dfa3367563e8301560a7fb92ec309096dbca3" + integrity sha512-WcQd5LxEoAS20zuWEAd8CX0pVC+gGInZPcsoYvK5w7BrEJNmltyTxYYh1r0ct4GsahD2GvNySlcTcLtK2amFZA== + eslint-plugin-promise@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2" @@ -3321,6 +3698,11 @@ esprima@2.7.x, esprima@^2.7.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -3345,7 +3727,7 @@ estraverse@^1.9.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= @@ -3403,6 +3785,13 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== + dependencies: + merge "^1.2.0" + execa@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" @@ -3429,6 +3818,11 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" @@ -3438,6 +3832,13 @@ expand-braces@^0.1.1: array-unique "^0.2.1" braces "^0.1.2" +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -3459,6 +3860,25 @@ expand-range@^0.1.0: is-number "^0.1.1" repeat-string "^0.2.2" +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +expect@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" + integrity sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w== + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.6.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + exports-loader@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-0.7.0.tgz#84881c784dea6036b8e1cd1dac3da9b6409e21a5" @@ -3518,7 +3938,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -3541,6 +3961,13 @@ external-editor@^3.0.0: iconv-lite "^0.4.22" tmp "^0.0.33" +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -3555,6 +3982,16 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -3589,6 +4026,13 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= + dependencies: + bser "^2.0.0" + figgy-pudding@^3.1.0, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -3617,7 +4061,12 @@ file-loader@^2.0.0: loader-utils "^1.0.2" schema-utils "^1.0.0" -fileset@^2.0.3: +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fileset@^2.0.2, fileset@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= @@ -3630,6 +4079,17 @@ filesize@^3.6.1: resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -3684,7 +4144,7 @@ find-cache-dir@^2.0.0: make-dir "^1.0.0" pkg-dir "^3.0.0" -find-root@^1.1.0: +find-root@^1.0.0, find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== @@ -3736,11 +4196,32 @@ follow-redirects@^1.2.5: dependencies: debug "^3.1.0" -for-in@^1.0.2: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + formdata-polyfill@^3.0.11: version "3.0.11" resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.11.tgz#c82b4b4bea3356c0a6752219e54ce1edb2a7fb5b" @@ -3805,7 +4286,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.2: +fsevents@^1.2.2, fsevents@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== @@ -3862,6 +4343,13 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + gettext-extractor-vue@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/gettext-extractor-vue/-/gettext-extractor-vue-4.0.1.tgz#69d2737eb8f1938803ffcf9317133ed59fb2372f" @@ -3884,6 +4372,21 @@ gettext-extractor@^3.3.2: pofile "^1" typescript "^2" +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -4038,6 +4541,11 @@ graphql@^14.0.2: dependencies: iterall "^1.2.2" +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + gzip-size@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80" @@ -4051,7 +4559,7 @@ handle-thing@^1.2.5: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ= -handlebars@^4.0.1, handlebars@^4.0.11: +handlebars@^4.0.1, handlebars@^4.0.11, handlebars@^4.0.3: version "4.0.12" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== @@ -4062,6 +4570,19 @@ handlebars@^4.0.1, handlebars@^4.0.11: optionalDependencies: uglify-js "^3.1.4" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -4198,6 +4719,14 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + hoopy@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" @@ -4218,6 +4747,13 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + html-entities@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" @@ -4273,6 +4809,15 @@ http-proxy@^1.13.0, http-proxy@^1.16.2: eventemitter3 "1.x.x" requires-port "1.x.x" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -4290,6 +4835,13 @@ iconv-lite@0.4.19: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -4465,13 +5017,18 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" @@ -4535,6 +5092,13 @@ is-callable@^1.1.1, is-callable@^1.1.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-ci@^1.0.10: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.0" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -4572,6 +5136,18 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -4584,11 +5160,23 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -4601,6 +5189,18 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + integrity sha1-lp1J4bszKfa7fwkIm+JleLLd1Go= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -4633,6 +5233,13 @@ is-number@^0.1.1: resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY= +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4693,6 +5300,16 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -4737,6 +5354,16 @@ is-symbol@^1.0.1: dependencies: has-symbols "^1.0.0" +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -4779,6 +5406,28 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-api@^1.3.1: + version "1.3.7" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa" + integrity sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA== + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.1" + istanbul-lib-hook "^1.2.2" + istanbul-lib-instrument "^1.10.2" + istanbul-lib-report "^1.1.5" + istanbul-lib-source-maps "^1.2.6" + istanbul-reports "^1.5.1" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + istanbul-api@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.0.6.tgz#cd7b33ee678f6c01531d05f5e567ebbcd25f8ecc" @@ -4797,11 +5446,23 @@ istanbul-api@^2.0.5: make-dir "^1.3.0" once "^1.4.0" +istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== + istanbul-lib-coverage@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#2aee0e073ad8c5f6a0b00e0dfbf52b4667472eda" integrity sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA== +istanbul-lib-hook@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" + integrity sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== + dependencies: + append-transform "^0.4.0" + istanbul-lib-hook@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.1.tgz#918a57b75a0f951d552a08487ca1fa5336433d72" @@ -4809,6 +5470,19 @@ istanbul-lib-hook@^2.0.1: dependencies: append-transform "^1.0.0" +istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== + 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.2.1" + semver "^5.3.0" + istanbul-lib-instrument@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz#b5f066b2a161f75788be17a9d556f40a0cf2afc9" @@ -4822,6 +5496,16 @@ istanbul-lib-instrument@^3.0.0: istanbul-lib-coverage "^2.0.1" semver "^5.5.0" +istanbul-lib-report@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" + integrity sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== + dependencies: + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + istanbul-lib-report@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.2.tgz#430a2598519113e1da7af274ba861bd42dd97535" @@ -4831,6 +5515,17 @@ istanbul-lib-report@^2.0.2: make-dir "^1.3.0" supports-color "^5.4.0" +istanbul-lib-source-maps@^1.2.4, istanbul-lib-source-maps@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" + integrity sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + istanbul-lib-source-maps@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.1.tgz#ce8b45131d8293fdeaa732f4faf1852d13d0a97e" @@ -4842,6 +5537,13 @@ istanbul-lib-source-maps@^2.0.1: rimraf "^2.6.2" source-map "^0.6.1" +istanbul-reports@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" + integrity sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== + dependencies: + handlebars "^4.0.3" + istanbul-reports@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.0.1.tgz#fb8d6ea850701a3984350b977a969e9a556116a7" @@ -4913,6 +5615,334 @@ jed@^1.1.1: resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4" integrity sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ= +jest-changed-files@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" + integrity sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA== + dependencies: + throat "^4.0.0" + +jest-cli@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.6.0.tgz#61ab917744338f443ef2baa282ddffdd658a5da4" + integrity sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.4.2" + jest-config "^23.6.0" + jest-environment-jsdom "^23.4.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve-dependencies "^23.6.0" + jest-runner "^23.6.0" + jest-runtime "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + jest-watcher "^23.4.0" + jest-worker "^23.2.0" + micromatch "^2.3.11" + node-notifier "^5.2.1" + prompts "^0.1.9" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + +jest-config@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.6.0.tgz#f82546a90ade2d8c7026fbf6ac5207fc22f8eb1d" + integrity sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ== + dependencies: + babel-core "^6.0.0" + babel-jest "^23.6.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.4.0" + jest-environment-node "^23.4.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.6.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + pretty-format "^23.6.0" + +jest-diff@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.6.0.tgz#1500f3f16e850bb3d71233408089be099f610c7d" + integrity sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g== + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-docblock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" + integrity sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c= + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575" + integrity sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg== + dependencies: + chalk "^2.0.1" + pretty-format "^23.6.0" + +jest-environment-jsdom@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" + integrity sha1-BWp5UrP+pROsYqFAosNox52eYCM= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jsdom "^11.5.1" + +jest-environment-node@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" + integrity sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + +jest-get-type@^22.1.0: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + integrity sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== + +jest-haste-map@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.6.0.tgz#2e3eb997814ca696d62afdb3f2529f5bbc935e16" + integrity sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg== + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + invariant "^2.2.4" + jest-docblock "^23.2.0" + jest-serializer "^23.0.1" + jest-worker "^23.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz#840e937f848a6c8638df24360ab869cc718592e0" + integrity sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ== + dependencies: + babel-traverse "^6.0.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^23.6.0" + is-generator-fn "^1.0.0" + jest-diff "^23.6.0" + jest-each "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + pretty-format "^23.6.0" + +jest-junit@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-5.2.0.tgz#980401db7aa69999cf117c6d740a8135c22ae379" + integrity sha512-Mdg0Qpdh1Xm/FA1B/mcLlmEmlr3XzH5pZg7MvcAwZhjHijPRd1z/UwYwkwNHmCV7o4ZOWCf77nLu7ZkhHHrtJg== + dependencies: + jest-config "^23.6.0" + jest-validate "^23.0.1" + mkdirp "^0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.1" + +jest-leak-detector@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz#e4230fd42cf381a1a1971237ad56897de7e171de" + integrity sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg== + dependencies: + pretty-format "^23.6.0" + +jest-matcher-utils@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80" + integrity sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-message-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" + integrity sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8= + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" + integrity sha1-rRxg8p6HGdR8JuETgJi20YsmETQ= + +jest-regex-util@^23.3.0: + version "23.3.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" + integrity sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U= + +jest-resolve-dependencies@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz#b4526af24c8540d9a3fab102c15081cf509b723d" + integrity sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA== + dependencies: + jest-regex-util "^23.3.0" + jest-snapshot "^23.6.0" + +jest-resolve@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.6.0.tgz#cf1d1a24ce7ee7b23d661c33ba2150f3aebfa0ae" + integrity sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA== + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.6.0.tgz#3894bd219ffc3f3cb94dc48a4170a2e6f23a5a38" + integrity sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA== + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-docblock "^23.2.0" + jest-haste-map "^23.6.0" + jest-jasmine2 "^23.6.0" + jest-leak-detector "^23.6.0" + jest-message-util "^23.4.0" + jest-runtime "^23.6.0" + jest-util "^23.4.0" + jest-worker "^23.2.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.6.0.tgz#059e58c8ab445917cd0e0d84ac2ba68de8f23082" + integrity sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw== + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= + +jest-snapshot@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" + integrity sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg== + dependencies: + babel-types "^6.0.0" + chalk "^2.0.1" + jest-diff "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-resolve "^23.6.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.6.0" + semver "^5.5.0" + +jest-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" + integrity sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE= + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.4.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + +jest-validate@^23.0.1, jest-validate@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.6.0.tgz#36761f99d1ed33fcd425b4e4c5595d62b6597474" + integrity sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.6.0" + +jest-watcher@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" + integrity sha1-0uKM50+NrWxq/JIrksq+9u0FyRw= + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= + dependencies: + merge-stream "^1.0.1" + +jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d" + integrity sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw== + dependencies: + import-local "^1.0.0" + jest-cli "^23.6.0" + jquery-ujs@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397" @@ -4960,7 +5990,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.x, js-yaml@^3.12.0: +js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== @@ -4968,6 +5998,48 @@ js-yaml@3.x, js-yaml@^3.12.0: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + jsesc@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" @@ -4993,21 +6065,41 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= -json5@^0.5.0: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + jszip-utils@^0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/jszip-utils/-/jszip-utils-0.0.2.tgz#457d5cbca60a1c2e0706e9da2b544e8e7bc50bf8" @@ -5156,6 +6248,11 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +kleur@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" + integrity sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ== + latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -5170,6 +6267,13 @@ lazy-cache@^2.0.2: dependencies: set-getter "^0.1.0" +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -5177,6 +6281,16 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -5192,6 +6306,17 @@ lie@~3.1.0: dependencies: immediate "~3.0.5" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -5287,6 +6412,11 @@ lodash.snakecase@4.1.1: resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + lodash.startcase@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" @@ -5297,7 +6427,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -5362,6 +6492,13 @@ make-dir@^1.0.0, make-dir@^1.3.0: dependencies: pify "^3.0.0" +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + mamacro@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" @@ -5401,6 +6538,11 @@ match-at@^0.1.1: resolved "https://registry.yarnpkg.com/match-at/-/match-at-0.1.1.tgz#25d040d291777704d5e6556bbb79230ec2de0540" integrity sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q== +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= + md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -5414,6 +6556,13 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + mem@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" @@ -5448,6 +6597,18 @@ merge-source-map@^1.1.0: dependencies: source-map "^0.6.1" +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= + dependencies: + readable-stream "^2.0.1" + +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + mermaid@^8.0.0-rc.8: version "8.0.0-rc.8" resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.0.0-rc.8.tgz#74ed54d0d46e9ee71c4db2730b2d83d516a21e72" @@ -5467,7 +6628,26 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: +micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.4, micromatch@^3.1.6, micromatch@^3.1.8, micromatch@^3.1.9: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -5499,7 +6679,7 @@ miller-rabin@^4.0.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== -mime-types@~2.1.17, mime-types@~2.1.18: +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: version "2.1.21" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== @@ -5548,7 +6728,7 @@ minimist@0.0.8: resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.2.0, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -5745,6 +6925,11 @@ node-forge@0.6.33: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" integrity sha1-RjgRh59XPUUVWtap9D3ClujoXrw= +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + "node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" @@ -5774,6 +6959,16 @@ node-forge@0.6.33: util "^0.10.3" vm-browserify "0.0.4" +node-notifier@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.3.0.tgz#c77a4a7b84038733d5fb351aafd8a268bfe19a01" + integrity sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q== + dependencies: + growly "^1.3.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" @@ -5845,7 +7040,7 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.1.1: +normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -5901,6 +7096,16 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +nwsapi@^2.0.7: + version "2.0.9" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.9.tgz#77ac0cdfdcad52b6a1151a84e73254edc33ed016" + integrity sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5960,6 +7165,14 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.2" es-abstract "^1.5.1" +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -6074,6 +7287,15 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + os-locale@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620" @@ -6083,7 +7305,7 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -6201,6 +7423,16 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -6216,6 +7448,11 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + parse5@^5: version "5.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.0.0.tgz#4d02710d44f3c3846197a11e205d4ef17842b81a" @@ -6267,7 +7504,7 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= -path-is-absolute@^1.0.0: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= @@ -6292,6 +7529,15 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -6324,6 +7570,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6379,6 +7630,11 @@ pluralize@^7.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + pofile@^1: version "1.0.11" resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954" @@ -6472,6 +7728,11 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + prettier@1.13.7: version "1.13.7" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" @@ -6482,6 +7743,14 @@ prettier@1.15.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.2.tgz#d31abe22afa4351efa14c7f8b94b58bb7452205e" integrity sha512-YgPLFFA0CdKL4Eg2IHtUSjzj/BWgszDHiNQAe0VAIBse34148whfdzLagRL+QiKS+YfK5ftB6X4v/MBw8yCoug== +pretty-format@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" + integrity sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + prismjs@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365" @@ -6489,7 +7758,7 @@ prismjs@^1.6.0: optionalDependencies: clipboard "^1.5.5" -private@^0.1.6: +private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -6519,6 +7788,14 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +prompts@^0.1.9: + version "0.1.14" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" + integrity sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w== + dependencies: + kleur "^2.0.1" + sisteransi "^0.1.1" + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -6549,6 +7826,11 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= +psl@^1.1.24, psl@^1.1.28: + version "1.1.29" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" + integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ== + pstree.remy@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.0.tgz#f2af27265bd3e5b32bbfcc10e80bac55ba78688b" @@ -6597,7 +7879,12 @@ punycode@1.3.2, punycode@^1.2.4: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^2.1.0: +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -6612,6 +7899,11 @@ qs@6.5.1: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -6636,6 +7928,15 @@ querystringify@^2.0.0: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" @@ -6693,6 +7994,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -6709,6 +8018,15 @@ read-pkg-up@^4.0.0: find-up "^3.0.0" read-pkg "^3.0.0" +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -6762,6 +8080,13 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +realpath-native@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.2.tgz#cd51ce089b513b45cf9b1516c82989b51ccc6560" + integrity sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g== + dependencies: + util.promisify "^1.0.0" + regenerate-unicode-properties@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" @@ -6791,6 +8116,13 @@ regenerator-transform@^0.13.3: dependencies: private "^0.1.6" +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -6879,11 +8211,60 @@ repeat-string@^0.2.2: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4= -repeat-string@^1.6.1: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + integrity sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY= + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + integrity sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU= + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@^2.87.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6929,7 +8310,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.x: +resolve@1.1.7, resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= @@ -6981,6 +8362,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -7029,11 +8415,27 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sane@^2.0.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + sanitize-html@^1.16.1: version "1.16.3" resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.16.3.tgz#96c1b44a36ff7312e1c22a14b05274370ac8bd56" @@ -7239,6 +8641,11 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -7249,6 +8656,16 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +sisteransi@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" + integrity sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g== + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" @@ -7394,6 +8811,21 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.6: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -7404,12 +8836,12 @@ source-map@0.5.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86" integrity sha1-D+llA6yGpa213mP05BKuSHLNvoY= -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -7495,6 +8927,21 @@ srcset@^1.0.0: array-uniq "^1.0.2" number-is-nan "^1.0.0" +sshpk@^1.7.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629" + integrity sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + ssri@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.2.4.tgz#9985e14041e65fc397af96542be35724ac11da52" @@ -7509,6 +8956,11 @@ ssri@^6.0.0: dependencies: figgy-pudding "^3.5.1" +stack-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -7527,6 +8979,11 @@ statuses@~1.3.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + stickyfilljs@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/stickyfilljs/-/stickyfilljs-2.0.5.tgz#d229e372d2199ddf5d283bbe34ac1f7d2529c2fc" @@ -7586,6 +9043,14 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -7629,11 +9094,18 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-bom@^3.0.0: +strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + strip-css-comments@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-css-comments/-/strip-css-comments-3.0.0.tgz#7a5625eff8a2b226cf8947a11254da96e13dae89" @@ -7664,7 +9136,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0: +supports-color@^3.1.0, supports-color@^3.1.2: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= @@ -7688,6 +9160,11 @@ symbol-observable@^1.0.2: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-tree@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= + table@^4.0.3: version "4.0.3" resolved "http://registry.npmjs.org/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" @@ -7730,6 +9207,17 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" +test-exclude@^4.2.1: + version "4.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" + integrity sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA== + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + test-exclude@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.0.0.tgz#cdce7cece785e0e829cd5c2b27baf18bc583cfb7" @@ -7765,6 +9253,11 @@ three@^0.84.0: resolved "https://registry.yarnpkg.com/three/-/three-0.84.0.tgz#95be85a55a0fa002aa625ed559130957dcffd918" integrity sha1-lb6FpVoPoAKqYl7VWRMJV9z/2Rg= +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + throttle-debounce@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.0.1.tgz#7307ddd6cd9acadb349132fbf6c18d78c88a5e62" @@ -7819,6 +9312,11 @@ tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" @@ -7876,6 +9374,29 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +tough-cookie@>=2.3.3, tough-cookie@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -7896,6 +9417,18 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -8191,6 +9724,15 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + visibilityjs@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/visibilityjs/-/visibilityjs-1.2.4.tgz#bff8663da62c8c10ad4ee5ae6a1ae6fac4259d63" @@ -8297,6 +9839,28 @@ vuex@^3.0.1: resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2" integrity sha512-wLoqz0B7DSZtgbWL1ShIBBCjv22GV5U+vcBFox658g6V0s4wZV9P4YjCNyoHSyIBpj1f29JBoNQIqD82cR4O3w== +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= + dependencies: + browser-process-hrtime "^0.1.2" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + watchpack@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" @@ -8313,6 +9877,11 @@ wbuf@^1.1.0, wbuf@^1.7.2: dependencies: minimalistic-assert "^1.0.0" +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + webpack-bundle-analyzer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.2.tgz#22f19ea6d1b5a15fd7a90baae0bc0f39bd1e4d48" @@ -8455,6 +10024,36 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" integrity sha1-domUmcGEtu91Q3fC27DNbLVdKec= +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" + integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -8467,6 +10066,13 @@ which@^1.1.1, which@^1.2.1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^1.2.12, which@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -8520,7 +10126,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^2.0.0: +write-file-atomic@^2.0.0, write-file-atomic@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== @@ -8536,6 +10142,13 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + ws@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/ws/-/ws-6.0.0.tgz#eaa494aded00ac4289d455bac8d84c7c651cef35" @@ -8557,6 +10170,16 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + xmlbuilder@8.2.2: version "8.2.2" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" @@ -8587,6 +10210,11 @@ xterm@^3.5.0: resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.5.0.tgz#ba3f464bc5730c9d259ebe62131862224db9ddcc" integrity sha512-IpG3P3gkT0/xDPS0j3igpk92JYlUajaEHk3/EQSUeIRJmPiF2lyham3Xt/GD3o98uOrRluvowjNj0AFeYK+AXQ== +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -8609,6 +10237,13 @@ yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= + dependencies: + camelcase "^4.1.0" + yargs@12.0.2, yargs@^12.0.1: version "12.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" @@ -8627,6 +10262,24 @@ yargs@12.0.2, yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" |