diff options
45 files changed, 261 insertions, 117 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4294ccaf9b6..f85b78cb277 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 10.1.4 (2017-11-14) + +### Fixed (4 changes) + +- Don't try to create fork network memberships for forks with a missing source. !15366 +- Formats bytes to human reabale number in registry table. +- Prevent error when authorizing an admin-created OAauth application without a set owner. +- Prevents position update for image diff notes. + + ## 10.1.3 (2017-11-10) - [SECURITY] Prevent OAuth phishing attack by presenting detailed wording about app to user during authorization. diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 15a27998172..bea438e9ade 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -3.3.0 +3.3.1 diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js index f82938aa8a9..1274db2c4c8 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js @@ -61,7 +61,7 @@ export default { return this.mr.hasCI; }, shouldRenderRelatedLinks() { - return this.mr.relatedLinks; + return !!this.mr.relatedLinks; }, shouldRenderDeployments() { return this.mr.deployments.length; diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index f0139b5f33a..2218b5705fc 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -129,7 +129,7 @@ margin: 5px 2px 5px -8px; border-radius: $border-radius-default; - svg { + .tanuki-logo { @media (min-width: $screen-sm-min) { margin-right: 8px; } diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 50f0ef4414a..65b334662c2 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -125,7 +125,7 @@ color: $white-normal; } - &:hover { + &:hover:not(.tree-truncated-warning) { td { background-color: $row-hover; border-top: 1px solid $row-hover-border; @@ -198,6 +198,11 @@ } } + .tree-truncated-warning { + color: $orange-600; + background-color: $orange-100; + } + .tree-time-ago { min-width: 135px; color: $gl-text-color-secondary; diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index c4ea0f5ac53..0e106e2c85d 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -1,14 +1,23 @@ module TreeHelper + FILE_LIMIT = 1_000 + # Sorts a repository's tree so that folders are before files and renders # their corresponding partials # - # contents - A Grit::Tree object for the current tree + # tree - A `Tree` object for the current tree def render_tree(tree) # Sort submodules and folders together by name ahead of files folders, files, submodules = tree.trees, tree.blobs, tree.submodules - tree = "" + tree = '' items = (folders + submodules).sort_by(&:name) + files - tree << render(partial: "projects/tree/tree_row", collection: items) if items.present? + + if items.size > FILE_LIMIT + tree << render(partial: 'projects/tree/truncated_notice_tree_row', + locals: { limit: FILE_LIMIT, total: items.size }) + items = items.take(FILE_LIMIT) + end + + tree << render(partial: 'projects/tree/tree_row', collection: items) if items.present? tree.html_safe end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index c008fb91a16..35090181bd9 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -255,7 +255,7 @@ module Issuable participants(user).include?(user) end - def to_hook_data(user, old_labels: [], old_assignees: []) + def to_hook_data(user, old_labels: [], old_assignees: [], old_total_time_spent: nil) changes = previous_changes if old_labels != labels @@ -270,6 +270,10 @@ module Issuable end end + if old_total_time_spent != total_time_spent + changes[:total_time_spent] = [old_total_time_spent, total_time_spent] + end + Gitlab::HookData::IssuableBuilder.new(self).build(user: user, changes: changes) end diff --git a/app/models/project.rb b/app/models/project.rb index 853f6bc504a..894ded2a9f6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -704,10 +704,6 @@ class Project < ActiveRecord::Base import_type == 'gitea' end - def github_import? - import_type == 'github' - end - def check_limit unless creator.can_create_project? || namespace.kind == 'group' projects_limit = creator.projects_limit diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index 217f753f05f..fa7b3f2bcaf 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -25,7 +25,7 @@ class PrometheusService < MonitoringService end def description - 'Prometheus monitoring' + s_('PrometheusService|Prometheus monitoring') end def self.to_param @@ -38,8 +38,8 @@ class PrometheusService < MonitoringService type: 'text', name: 'api_url', title: 'API URL', - placeholder: 'Prometheus API Base URL, like http://prometheus.example.com/', - help: 'By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server.', + placeholder: s_('PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/'), + help: s_('PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server.'), required: true } ] diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 43de6809178..3eecbea8cbf 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -21,7 +21,7 @@ class ProjectWiki end delegate :empty?, to: :pages - delegate :repository_storage_path, to: :project + delegate :repository_storage_path, :hashed_storage?, to: :project def path @project.path + '.wiki' diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 90865867ff0..39a7299ff60 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -172,6 +172,7 @@ class IssuableBaseService < BaseService old_labels = issuable.labels.to_a old_mentioned_users = issuable.mentioned_users.to_a old_assignees = issuable.assignees.to_a + old_total_time_spent = issuable.total_time_spent label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids) params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids) @@ -208,7 +209,12 @@ class IssuableBaseService < BaseService invalidate_cache_counts(issuable, users: affected_assignees.compact) after_update(issuable) issuable.create_new_cross_references!(current_user) - execute_hooks(issuable, 'update', old_labels: old_labels, old_assignees: old_assignees) + execute_hooks( + issuable, + 'update', + old_labels: old_labels, + old_assignees: old_assignees, + old_total_time_spent: old_total_time_spent) issuable.update_project_counter_caches if update_project_counters end diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index b680eaf5a49..0f711bcc3cf 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -1,7 +1,7 @@ module Issues class BaseService < ::IssuableBaseService - def hook_data(issue, action, old_labels: [], old_assignees: []) - hook_data = issue.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees) + def hook_data(issue, action, old_labels: [], old_assignees: [], old_total_time_spent: nil) + hook_data = issue.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) hook_data[:object_attributes][:action] = action hook_data @@ -22,8 +22,8 @@ module Issues issue, issue.project, current_user, old_assignees) end - def execute_hooks(issue, action = 'open', old_labels: [], old_assignees: []) - issue_data = hook_data(issue, action, old_labels: old_labels, old_assignees: old_assignees) + def execute_hooks(issue, action = 'open', old_labels: [], old_assignees: [], old_total_time_spent: nil) + issue_data = hook_data(issue, action, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks issue.project.execute_hooks(issue_data, hooks_scope) issue.project.execute_services(issue_data, hooks_scope) diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 112606a82d7..d3938b065bc 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -18,8 +18,8 @@ module MergeRequests super if changed_title end - def hook_data(merge_request, action, old_rev: nil, old_labels: [], old_assignees: []) - hook_data = merge_request.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees) + def hook_data(merge_request, action, old_rev: nil, old_labels: [], old_assignees: [], old_total_time_spent: nil) + hook_data = merge_request.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) hook_data[:object_attributes][:action] = action if old_rev && !Gitlab::Git.blank_ref?(old_rev) hook_data[:object_attributes][:oldrev] = old_rev @@ -28,9 +28,9 @@ module MergeRequests hook_data end - def execute_hooks(merge_request, action = 'open', old_rev: nil, old_labels: [], old_assignees: []) + def execute_hooks(merge_request, action = 'open', old_rev: nil, old_labels: [], old_assignees: [], old_total_time_spent: nil) if merge_request.project - merge_data = hook_data(merge_request, action, old_rev: old_rev, old_labels: old_labels, old_assignees: old_assignees) + merge_data = hook_data(merge_request, action, old_rev: old_rev, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) merge_request.project.execute_hooks(merge_data, :merge_request_hooks) merge_request.project.execute_services(merge_data, :merge_request_hooks) end diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index c950da44aba..c3b11341b4d 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -11,13 +11,11 @@ module Projects # supported by an importer class (`Gitlab::GithubImport::ParallelImporter` # for example). def async? - return false unless has_importer? - - !!importer_class.try(:async?) + has_importer? && !!importer_class.try(:async?) end def execute - add_repository_to_project unless project.gitlab_project_import? + add_repository_to_project import_data @@ -29,6 +27,14 @@ module Projects private def add_repository_to_project + if project.external_import? && !unknown_url? + raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url) + end + + # We should skip the repository for a GitHub import or GitLab project import, + # because these importers fetch the project repositories for us. + return if has_importer? && importer_class.try(:imports_repository?) + if unknown_url? # In this case, we only want to import issues, not a repository. create_repository @@ -44,12 +50,6 @@ module Projects end def import_repository - raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url) - - # We should return early for a GitHub import because the new GitHub - # importer fetch the project repositories for us. - return if project.github_import? - begin if project.gitea_import? fetch_repository @@ -88,7 +88,7 @@ module Projects end def importer_class - Gitlab::ImportSources.importer(project.import_type) + @importer_class ||= Gitlab::ImportSources.importer(project.import_type) end def has_importer? diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml index d8e11500964..b0cb5ce5e8f 100644 --- a/app/views/projects/services/prometheus/_show.html.haml +++ b/app/views/projects/services/prometheus/_show.html.haml @@ -4,42 +4,39 @@ .row.prepend-top-default.append-bottom-default.prometheus-metrics-monitoring.js-prometheus-metrics-monitoring .col-lg-3 %h4.prepend-top-0 - Metrics + = s_('PrometheusService|Metrics') %p - Metrics are automatically configured and monitored - based on a library of metrics from popular exporters. - = link_to 'More information', help_page_path('user/project/integrations/prometheus') + = s_('PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters.') + = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus') .col-lg-9 .panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } } .panel-heading %h3.panel-title - Monitored + = s_('PrometheusService|Monitored') %span.badge.js-monitored-count 0 .panel-body .loading-metrics.text-center.js-loading-metrics = icon('spinner spin 3x', class: 'metrics-load-spinner') - %p Finding and configuring metrics... + %p + = s_('PrometheusService|Finding and configuring metrics...') .empty-metrics.text-center.hidden.js-empty-metrics = custom_icon('icon_empty_metrics') - %p No metrics are being monitored. To start monitoring, deploy to an environment. - = link_to project_environments_path(@project), title: 'View environments', class: 'btn btn-success' do - View environments + %p + = s_('PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment.') + = link_to s_('PrometheusService|View environments'), project_environments_path(@project), class: 'btn btn-success' %ul.list-unstyled.metrics-list.hidden.js-metrics-list .panel.panel-default.hidden.js-panel-missing-env-vars .panel-heading %h3.panel-title = icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel') - Missing environment variable + = s_('PrometheusService|Missing environment variable') %span.badge.js-env-var-count 0 .panel-body.hidden .flash-container .flash-notice .flash-text - To set up automatic monitoring, add the environment variable - %code - $CI_ENVIRONMENT_SLUG - to exporter’s queries. - = link_to 'More information', help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels') + = s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries." % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>" }).html_safe + = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels') %ul.list-unstyled.metrics-list.js-missing-var-metrics-list diff --git a/app/views/projects/tree/_truncated_notice_tree_row.html.haml b/app/views/projects/tree/_truncated_notice_tree_row.html.haml new file mode 100644 index 00000000000..693b641888b --- /dev/null +++ b/app/views/projects/tree/_truncated_notice_tree_row.html.haml @@ -0,0 +1,7 @@ +%tr.tree-truncated-warning + %td{ colspan: '3' } + = icon('exclamation-triangle fw') + %span + Too many items to show. To preserve performance only + %strong #{number_with_delimiter(limit)} of #{number_with_delimiter(total)} + items are displayed. diff --git a/app/workers/update_merge_requests_worker.rb b/app/workers/update_merge_requests_worker.rb index 89ae17cef37..afc47fc63d6 100644 --- a/app/workers/update_merge_requests_worker.rb +++ b/app/workers/update_merge_requests_worker.rb @@ -2,6 +2,8 @@ class UpdateMergeRequestsWorker include Sidekiq::Worker include DedicatedSidekiqQueue + LOG_TIME_THRESHOLD = 90 # seconds + def perform(project_id, user_id, oldrev, newrev, ref) project = Project.find_by(id: project_id) return unless project @@ -9,6 +11,20 @@ class UpdateMergeRequestsWorker user = User.find_by(id: user_id) return unless user - MergeRequests::RefreshService.new(project, user).execute(oldrev, newrev, ref) + # TODO: remove this benchmarking when we have rich logging + time = Benchmark.measure do + MergeRequests::RefreshService.new(project, user).execute(oldrev, newrev, ref) + end + + args_log = [ + "elapsed=#{time.real}", + "project_id=#{project_id}", + "user_id=#{user_id}", + "oldrev=#{oldrev}", + "newrev=#{newrev}", + "ref=#{ref}" + ].join(',') + + Rails.logger.info("UpdateMergeRequestsWorker#perform #{args_log}") if time.real > LOG_TIME_THRESHOLD end end diff --git a/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml b/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml new file mode 100644 index 00000000000..d61bbf2e355 --- /dev/null +++ b/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml @@ -0,0 +1,5 @@ +--- +title: Add internationalization support for the prometheus integration +merge_request: 33338 +author: +type: other diff --git a/changelogs/unreleased/39573-hashed-storage-backup.yml b/changelogs/unreleased/39573-hashed-storage-backup.yml new file mode 100644 index 00000000000..40ee589c8cc --- /dev/null +++ b/changelogs/unreleased/39573-hashed-storage-backup.yml @@ -0,0 +1,5 @@ +--- +title: Fix gitlab:backup rake for hashed storage based repositories +merge_request: 15400 +author: +type: fixed diff --git a/changelogs/unreleased/40092-fix-cluster-size.yml b/changelogs/unreleased/40092-fix-cluster-size.yml deleted file mode 100644 index e7a16c6920c..00000000000 --- a/changelogs/unreleased/40092-fix-cluster-size.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Formats bytes to human reabale number in registry table -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml b/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml new file mode 100644 index 00000000000..a2ae2059c47 --- /dev/null +++ b/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml @@ -0,0 +1,5 @@ +--- +title: Add total_time_spent to the `changes` hash in issuable Webhook payloads +merge_request: 15381 +author: +type: changed diff --git a/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml b/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml new file mode 100644 index 00000000000..fdaa90f0d5d --- /dev/null +++ b/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml @@ -0,0 +1,5 @@ +--- +title: Remove extra margin from wordmark in header +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/bvl-fork-network-memberships-for-deleted-source.yml b/changelogs/unreleased/bvl-fork-network-memberships-for-deleted-source.yml deleted file mode 100644 index ae1eb3aedd5..00000000000 --- a/changelogs/unreleased/bvl-fork-network-memberships-for-deleted-source.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't try to create fork network memberships for forks with a missing source -merge_request: 15366 -author: -type: fixed diff --git a/changelogs/unreleased/dm-authorize-admin-oauth-application.yml b/changelogs/unreleased/dm-authorize-admin-oauth-application.yml deleted file mode 100644 index 2787485bc28..00000000000 --- a/changelogs/unreleased/dm-authorize-admin-oauth-application.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Prevent error when authorizing an admin-created OAauth application without - a set owner -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/issue_40058.yml b/changelogs/unreleased/issue_40058.yml deleted file mode 100644 index 46e83d947ba..00000000000 --- a/changelogs/unreleased/issue_40058.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevents position update for image diff notes -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/tree_item_limit.yml b/changelogs/unreleased/tree_item_limit.yml new file mode 100644 index 00000000000..d95c5776075 --- /dev/null +++ b/changelogs/unreleased/tree_item_limit.yml @@ -0,0 +1,5 @@ +--- +title: Truncate tree to max 1,000 items and display notice to users +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/update-merge-worker-metrics.yml b/changelogs/unreleased/update-merge-worker-metrics.yml new file mode 100644 index 00000000000..c733675926a --- /dev/null +++ b/changelogs/unreleased/update-merge-worker-metrics.yml @@ -0,0 +1,5 @@ +--- +title: Add performance logging to UpdateMergeRequestsWorker. +merge_request: 15360 +author: +type: performance diff --git a/doc/development/licensing.md b/doc/development/licensing.md index 902b1c74a42..274923c2d43 100644 --- a/doc/development/licensing.md +++ b/doc/development/licensing.md @@ -4,11 +4,11 @@ GitLab CE is licensed under the terms of the MIT License. GitLab EE is licensed ## Automated Testing -In order to comply with the terms the libraries we use are licensed under, we have to make sure to check new gems for compatible licenses whenever they're added. To automate this process, we use the [license_finder][license_finder] gem by Pivotal. It runs every time a new commit is pushed and verifies that all gems in the bundle use a license that doesn't conflict with the licensing of either GitLab Community Edition or GitLab Enterprise Edition. +In order to comply with the terms the libraries we use are licensed under, we have to make sure to check new gems for compatible licenses whenever they're added. To automate this process, we use the [license_finder][license_finder] gem by Pivotal. It runs every time a new commit is pushed and verifies that all gems and node modules in the bundle use a license that doesn't conflict with the licensing of either GitLab Community Edition or GitLab Enterprise Edition. -There are some limitations with the automated testing, however. CSS and JavaScript libraries, as well as any Ruby libraries not included by way of Bundler, must be verified manually and independently. Take care whenever one such library is used, as automated tests won't catch problematic licenses from them. +There are some limitations with the automated testing, however. CSS, JavaScript, or Ruby libraries which are not included by way of Bundler, NPM, or Yarn (for instance those manually copied into our source tree in the `vendor` directory), must be verified manually and independently. Take care whenever one such library is used, as automated tests won't catch problematic licenses from them. -Some gems may not include their license information in their `gemspec` file. These won't be detected by License Finder, and will have to be verified manually. +Some gems may not include their license information in their `gemspec` file, and some node modules may not include their license information in their `package.json` file. These won't be detected by License Finder, and will have to be verified manually. ### License Finder commands diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 1cfdabac248..28308fc905c 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -321,7 +321,7 @@ Auto DevOps uses [Helm](https://helm.sh/) to deploy your application to Kubernet You can override the Helm chart used by bundling up a chart into your project repo or by specifying a project variable: -- **Bundled chart** - If your project has a `./charts` directory with a `Chart.yaml` +- **Bundled chart** - If your project has a `./chart` directory with a `Chart.yaml` file in it, Auto DevOps will detect the chart and use it instead of the [default one](https://gitlab.com/charts/charts.gitlab.io/tree/master/charts/auto-deploy-app). This can be a great way to control exactly how your application is deployed. diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md index 453e10184f0..1e19f422d94 100644 --- a/doc/user/project/pages/getting_started_part_one.md +++ b/doc/user/project/pages/getting_started_part_one.md @@ -62,7 +62,7 @@ which is highly recommendable and much faster than hardcoding. If you set up a GitLab Pages project on GitLab.com, it will automatically be accessible under a -[subdomain of `namespace.pages.io`](introduction.md#gitlab-pages-on-gitlab-com). +[subdomain of `namespace.gitlab.io`](introduction.md#gitlab-pages-on-gitlab-com). The `namespace` is defined by your username on GitLab.com, or the group name you created this project under. diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 3ad09a1b421..b6d273b98c2 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -7,12 +7,16 @@ module Backup prepare Project.find_each(batch_size: 1000) do |project| - progress.print " * #{project.full_path} ... " + progress.print " * #{display_repo_path(project)} ... " path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) - # Create namespace dir if missing - FileUtils.mkdir_p(File.join(backup_repos_path, project.namespace.full_path)) if project.namespace + # Create namespace dir or hashed path if missing + if project.hashed_storage?(:repository) + FileUtils.mkdir_p(File.dirname(File.join(backup_repos_path, project.disk_path))) + else + FileUtils.mkdir_p(File.join(backup_repos_path, project.namespace.full_path)) if project.namespace + end if empty_repo?(project) progress.puts "[SKIPPED]".color(:cyan) @@ -42,7 +46,7 @@ module Backup path_to_wiki_bundle = path_to_bundle(wiki) if File.exist?(path_to_wiki_repo) - progress.print " * #{wiki.full_path} ... " + progress.print " * #{display_repo_path(wiki)} ... " if empty_repo?(wiki) progress.puts " [SKIPPED]".color(:cyan) else @@ -71,7 +75,7 @@ module Backup end Project.find_each(batch_size: 1000) do |project| - progress.print " * #{project.full_path} ... " + progress.print " * #{display_repo_path(project)} ... " path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) @@ -104,7 +108,7 @@ module Backup path_to_wiki_bundle = path_to_bundle(wiki) if File.exist?(path_to_wiki_bundle) - progress.print " * #{wiki.full_path} ... " + progress.print " * #{display_repo_path(wiki)} ... " # If a wiki bundle exists, first remove the empty repo # that was initialized with ProjectWiki.new() and then @@ -185,14 +189,14 @@ module Backup def progress_warn(project, cmd, output) progress.puts "[WARNING] Executing #{cmd}".color(:orange) - progress.puts "Ignoring error on #{project.full_path} - #{output}".color(:orange) + progress.puts "Ignoring error on #{display_repo_path(project)} - #{output}".color(:orange) end def empty_repo?(project_or_wiki) project_or_wiki.repository.expire_exists_cache # protect backups from stale cache project_or_wiki.repository.empty_repo? rescue => e - progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.full_path} - #{e.message}".color(:orange) + progress.puts "Ignoring repository error and continuing backing up project: #{display_repo_path(project_or_wiki)} - #{e.message}".color(:orange) false end @@ -204,5 +208,9 @@ module Backup def progress $progress end + + def display_repo_path(project) + project.hashed_storage?(:repository) ? "#{project.full_path} (#{project.disk_path})" : project.full_path + end end end diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb index 0ea534a5fd0..efc2e46d289 100644 --- a/lib/gitlab/ee_compat_check.rb +++ b/lib/gitlab/ee_compat_check.rb @@ -193,7 +193,7 @@ module Gitlab # Repository is initially cloned with a depth of 20 so we need to fetch # deeper in the case the branch has more than 20 commits on top of master fetch(branch: branch, depth: depth) - fetch(branch: 'master', depth: depth) + fetch(branch: 'master', depth: depth, remote: DEFAULT_CE_PROJECT_URL) merge_base_found? end @@ -201,10 +201,10 @@ module Gitlab raise "\n#{branch} is too far behind master, please rebase it!\n" unless success end - def fetch(branch:, depth:) + def fetch(branch:, depth:, remote: 'origin') step( "Fetching deeper...", - %W[git fetch --depth=#{depth} --prune origin +refs/heads/#{branch}:refs/remotes/origin/#{branch}] + %W[git fetch --depth=#{depth} --prune #{remote} +refs/heads/#{branch}:refs/remotes/origin/#{branch}] ) do |output, status| raise "Fetch failed: #{output}" unless status.zero? end diff --git a/lib/gitlab/github_import/parallel_importer.rb b/lib/gitlab/github_import/parallel_importer.rb index 81739834b41..6da11e6ef08 100644 --- a/lib/gitlab/github_import/parallel_importer.rb +++ b/lib/gitlab/github_import/parallel_importer.rb @@ -11,6 +11,10 @@ module Gitlab true end + def self.imports_repository? + true + end + def initialize(project) @project = project end diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb index 196f2b6b34c..e29dd0d5b0e 100644 --- a/lib/gitlab/hook_data/issue_builder.rb +++ b/lib/gitlab/hook_data/issue_builder.rb @@ -28,6 +28,7 @@ module Gitlab SAFE_HOOK_RELATIONS = %i[ assignees labels + total_time_spent ].freeze attr_accessor :issue diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb index 503452c8ff3..ae9b68eb648 100644 --- a/lib/gitlab/hook_data/merge_request_builder.rb +++ b/lib/gitlab/hook_data/merge_request_builder.rb @@ -33,6 +33,7 @@ module Gitlab SAFE_HOOK_RELATIONS = %i[ assignee labels + total_time_spent ].freeze attr_accessor :merge_request diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index fbdd74788bc..c14646b0611 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -1,6 +1,10 @@ module Gitlab module ImportExport class Importer + def self.imports_repository? + true + end + def initialize(project) @archive_file = project.import_source @current_user = project.creator diff --git a/qa/qa/specs/config.rb b/qa/qa/specs/config.rb index 591ddde8ab9..9f9fe9844d2 100644 --- a/qa/qa/specs/config.rb +++ b/qa/qa/specs/config.rb @@ -50,7 +50,7 @@ module QA Capybara.configure do |config| config.default_driver = :chrome config.javascript_driver = :chrome - config.default_max_wait_time = 4 + config.default_max_wait_time = 10 # https://github.com/mattheworiordan/capybara-screenshot/issues/164 config.save_path = 'tmp' diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb index d7b66e6f078..c358ccae9c3 100644 --- a/spec/helpers/tree_helper_spec.rb +++ b/spec/helpers/tree_helper_spec.rb @@ -1,10 +1,36 @@ require 'spec_helper' describe TreeHelper do + let(:project) { create(:project, :repository) } + let(:repository) { project.repository } + let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' } + + describe '.render_tree' do + before do + @id = sha + @project = project + end + + it 'displays all entries without a warning' do + tree = repository.tree(sha, 'files') + + html = render_tree(tree) + + expect(html).not_to have_selector('.tree-truncated-warning') + end + + it 'truncates entries and adds a warning' do + stub_const('TreeHelper::FILE_LIMIT', 1) + tree = repository.tree(sha, 'files') + + html = render_tree(tree) + + expect(html).to have_selector('.tree-truncated-warning', count: 1) + expect(html).to have_selector('.tree-item-file-name', count: 1) + end + end + describe 'flatten_tree' do - let(:project) { create(:project, :repository) } - let(:repository) { project.repository } - let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' } let(:tree) { repository.tree(sha, 'files') } let(:root_path) { 'files' } let(:tree_item) { tree.entries.find { |entry| entry.path == path } } diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js index 8832dd161c7..9e6d0aa472c 100644 --- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js @@ -3,13 +3,7 @@ import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options'; import eventHub from '~/vue_merge_request_widget/event_hub'; import notify from '~/lib/utils/notify'; import mockData from './mock_data'; - -const createComponent = () => { - delete mrWidgetOptions.el; // Prevent component mounting - gl.mrWidgetData = mockData; - const Component = Vue.extend(mrWidgetOptions); - return new Component(); -}; +import mountComponent from '../helpers/vue_mount_component_helper'; const returnPromise = data => new Promise((resolve) => { resolve({ @@ -22,9 +16,16 @@ const returnPromise = data => new Promise((resolve) => { describe('mrWidgetOptions', () => { let vm; + let MrWidgetOptions; beforeEach(() => { - vm = createComponent(); + // Prevent component mounting + delete mrWidgetOptions.el; + + MrWidgetOptions = Vue.extend(mrWidgetOptions); + vm = mountComponent(MrWidgetOptions, { + mrData: { ...mockData }, + }); }); describe('data', () => { @@ -77,7 +78,7 @@ describe('mrWidgetOptions', () => { }); it('should return true if there is relatedLinks in MR', () => { - vm.mr.relatedLinks = {}; + Vue.set(vm.mr, 'relatedLinks', {}); expect(vm.shouldRenderRelatedLinks).toBeTruthy(); }); }); diff --git a/spec/lib/gitlab/hook_data/issuable_builder_spec.rb b/spec/lib/gitlab/hook_data/issuable_builder_spec.rb index 30da56bec16..26529c4759d 100644 --- a/spec/lib/gitlab/hook_data/issuable_builder_spec.rb +++ b/spec/lib/gitlab/hook_data/issuable_builder_spec.rb @@ -41,7 +41,8 @@ describe Gitlab::HookData::IssuableBuilder do labels: [ [{ id: 1, title: 'foo' }], [{ id: 1, title: 'foo' }, { id: 2, title: 'bar' }] - ] + ], + total_time_spent: [1, 2] } end let(:data) { builder.build(user: user, changes: changes) } @@ -53,6 +54,10 @@ describe Gitlab::HookData::IssuableBuilder do labels: { previous: [{ id: 1, title: 'foo' }], current: [{ id: 1, title: 'foo' }, { id: 2, title: 'bar' }] + }, + total_time_spent: { + previous: 1, + current: 2 } })) end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index ba57301a3c9..4dfbb14952e 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -265,25 +265,44 @@ describe Issuable do end describe '#to_hook_data' do + let(:builder) { double } + context 'labels are updated' do let(:labels) { create_list(:label, 2) } before do issue.update(labels: [labels[1]]) + expect(Gitlab::HookData::IssuableBuilder) + .to receive(:new).with(issue).and_return(builder) end it 'delegates to Gitlab::HookData::IssuableBuilder#build' do - builder = double + expect(builder).to receive(:build).with( + user: user, + changes: hash_including( + 'labels' => [[labels[0].hook_attrs], [labels[1].hook_attrs]] + )) + issue.to_hook_data(user, old_labels: [labels[0]]) + end + end + + context 'total_time_spent is updated' do + before do + issue.spend_time(duration: 2, user: user, spent_at: Time.now) + issue.save expect(Gitlab::HookData::IssuableBuilder) .to receive(:new).with(issue).and_return(builder) + end + + it 'delegates to Gitlab::HookData::IssuableBuilder#build' do expect(builder).to receive(:build).with( user: user, changes: hash_including( - 'labels' => [[labels[0].hook_attrs], [labels[1].hook_attrs]] + 'total_time_spent' => [1, 2] )) - issue.to_hook_data(user, old_labels: [labels[0]]) + issue.to_hook_data(user, old_total_time_spent: 1) end end @@ -292,13 +311,11 @@ describe Issuable do before do issue.assignees << user << user2 + expect(Gitlab::HookData::IssuableBuilder) + .to receive(:new).with(issue).and_return(builder) end it 'delegates to Gitlab::HookData::IssuableBuilder#build' do - builder = double - - expect(Gitlab::HookData::IssuableBuilder) - .to receive(:new).with(issue).and_return(builder) expect(builder).to receive(:build).with( user: user, changes: hash_including( @@ -316,13 +333,11 @@ describe Issuable do before do merge_request.update(assignee: user) merge_request.update(assignee: user2) + expect(Gitlab::HookData::IssuableBuilder) + .to receive(:new).with(merge_request).and_return(builder) end it 'delegates to Gitlab::HookData::IssuableBuilder#build' do - builder = double - - expect(Gitlab::HookData::IssuableBuilder) - .to receive(:new).with(merge_request).and_return(builder) expect(builder).to receive(:build).with( user: user, changes: hash_including( diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 3d46434fc27..929086305ba 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -10,6 +10,10 @@ describe ProjectWiki do subject { project_wiki } + it { is_expected.to delegate_method(:empty?).to :pages } + it { is_expected.to delegate_method(:repository_storage_path).to :project } + it { is_expected.to delegate_method(:hashed_storage?).to :project } + describe "#path_with_namespace" do it "returns the project path with namespace with the .wiki extension" do expect(subject.path_with_namespace).to eq(project.full_path + '.wiki') diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 98409be4236..5ce6ca70c83 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -80,7 +80,7 @@ describe MergeRequests::UpdateService, :mailer do it 'executes hooks with update action' do expect(service) .to have_received(:execute_hooks) - .with(@merge_request, 'update', old_labels: [], old_assignees: [user3]) + .with(@merge_request, 'update', old_labels: [], old_assignees: [user3], old_total_time_spent: 0) end it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb index 89fb362cf14..1512b3e0620 100644 --- a/spec/support/gitaly.rb +++ b/spec/support/gitaly.rb @@ -1,6 +1,10 @@ RSpec.configure do |config| config.before(:each) do |example| - next if example.metadata[:skip_gitaly_mock] - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) + if example.metadata[:disable_gitaly] + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) + else + next if example.metadata[:skip_gitaly_mock] + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) + end end end diff --git a/spec/workers/update_merge_requests_worker_spec.rb b/spec/workers/update_merge_requests_worker_spec.rb index 558ff9109ec..0fa19ac84bb 100644 --- a/spec/workers/update_merge_requests_worker_spec.rb +++ b/spec/workers/update_merge_requests_worker_spec.rb @@ -23,5 +23,17 @@ describe UpdateMergeRequestsWorker do perform end + + context 'when slow' do + before do + stub_const("UpdateMergeRequestsWorker::LOG_TIME_THRESHOLD", -1) + end + + it 'logs debug info' do + expect(Rails.logger).to receive(:info).with(a_string_matching(/\AUpdateMergeRequestsWorker#perform.*project_id=#{project.id},user_id=#{user.id},oldrev=#{oldrev},newrev=#{newrev},ref=#{ref}/)) + + perform + end + end end end |