summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2017-07-19 13:21:01 +0200
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2017-07-19 13:21:01 +0200
commit98f5c00e7ac860c7ac78b8245b171f2f27681563 (patch)
treea416e87601f76ba04f1401bc03df23dfb0759449
parenta6d1e92d98e71098c5a32999294bcdce6c7a092d (diff)
parent2ddcb1f1a6b68f67e6e50283b4ab0c8df29f6b43 (diff)
downloadgitlab-ce-backstage/gb/build-stage-id-ref-bg-migration-cleanup.tar.gz
Merge branch 'master' into backstage/gb/build-stage-id-ref-bg-migration-cleanupbackstage/gb/build-stage-id-ref-bg-migration-cleanup
* master: (59 commits) Resolve "Clarify k8s service keys" Add Portuguese Brazil translations of Commits Page & Pipeline Charts Add Japanese Translation to i18n Update Prometheus gem to version that explicitly calls `munmap` Simplify width for dropdown-menu on mobile Update CHANGELOG.md for 9.3.7 Remove developer documentation about not describing symbols Incorporate Gitaly's Commits#between RPC Adapt to new Gitaly commit message format Remove transitions on nav link hover Provide option to trigger build only for official CE and EE repos in .com Fix queries duration sorting in Performance Bar Rename Project nav items Add structured logging for Rails processes Disable Rails logging in CI test environments Fix download artifacts button alignment Update avatar border to be opaque for better stacking Fixed typos Fix typos Fix external issue trackers redirect ... Conflicts: db/schema.rb
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--CHANGELOG.md5
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock13
-rw-r--r--app/assets/javascripts/lib/utils/http_status.js1
-rw-r--r--app/assets/javascripts/lib/utils/poll.js3
-rw-r--r--app/assets/stylesheets/framework/avatar.scss4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss11
-rw-r--r--app/assets/stylesheets/framework/lists.scss8
-rw-r--r--app/assets/stylesheets/framework/nav.scss2
-rw-r--r--app/assets/stylesheets/framework/typography.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/new_sidebar.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss6
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/models/commit.rb19
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb2
-rw-r--r--app/models/project_services/issue_tracker_service.rb4
-rw-r--r--app/models/project_services/kubernetes_service.rb20
-rw-r--r--app/policies/ci/build_policy.rb10
-rw-r--r--app/services/metrics_service.rb2
-rw-r--r--app/uploaders/gitlab_uploader.rb2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml4
-rw-r--r--app/views/layouts/nav/_new_group_sidebar.html.haml8
-rw-r--r--app/views/layouts/nav/_new_project_sidebar.html.haml8
-rw-r--r--app/views/projects/artifacts/browse.html.haml12
-rw-r--r--changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md4
-rw-r--r--changelogs/unreleased/33741-clarify-k8s-service-keys.yml5
-rw-r--r--changelogs/unreleased/34173-add-portuguese-brazil-translations-of-commits-page.yml4
-rw-r--r--changelogs/unreleased/34325-reinstate-is_admin-for-user-api.yml4
-rw-r--r--changelogs/unreleased/34468-remove-extra-blank-on-admin-on-mobile.yml4
-rw-r--r--changelogs/unreleased/34728-fix-application-setting-created-when-redis-down.yml4
-rw-r--r--changelogs/unreleased/34789-add-japanese-translations-of-commits-page.yml4
-rw-r--r--changelogs/unreleased/34881-add-russian-translations-to-i18n.yml4
-rw-r--r--changelogs/unreleased/34927-protect-manual-actions-on-tags.yml4
-rw-r--r--changelogs/unreleased/35087-mr-status-misaligned.yml4
-rw-r--r--changelogs/unreleased/35225-transient-poll.yml4
-rw-r--r--changelogs/unreleased/bvl-free-system-namespace.yml4
-rw-r--r--changelogs/unreleased/request-store-wrap.yml4
-rw-r--r--changelogs/unreleased/sh-structured-logging.yml4
-rw-r--r--config/boot.rb5
-rw-r--r--config/environments/test.rb5
-rw-r--r--config/initializers/7_prometheus_metrics.rb12
-rw-r--r--config/initializers/lograge.rb21
-rw-r--r--config/initializers/peek.rb4
-rw-r--r--config/routes/uploads.rb4
-rw-r--r--db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb45
-rw-r--r--db/migrate/20170717074009_move_system_upload_folder.rb60
-rw-r--r--db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb40
-rw-r--r--db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb20
-rw-r--r--db/schema.rb3
-rw-r--r--doc/administration/monitoring/prometheus/index.md3
-rw-r--r--doc/ci/environments.md3
-rw-r--r--doc/ci/img/environments_monitoring.pngbin94408 -> 243491 bytes
-rw-r--r--doc/development/gotchas.md29
-rw-r--r--doc/development/testing.md6
-rw-r--r--doc/user/project/integrations/kubernetes.md4
-rw-r--r--doc/user/project/integrations/prometheus.md66
-rw-r--r--doc/user/project/integrations/prometheus_library/cloudwatch.md25
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md26
-rw-r--r--doc/user/project/integrations/prometheus_library/metrics.md25
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx.md23
-rw-r--r--doc/user/project/integrations/samples/cloudwatch.yml26
-rw-r--r--doc/user/project/integrations/samples/prometheus.yml38
-rw-r--r--features/steps/groups.rb2
-rw-r--r--features/steps/profile/profile.rb2
-rw-r--r--features/steps/project/project.rb2
-rw-r--r--lib/declarative_policy.rb40
-rw-r--r--lib/declarative_policy/cache.rb13
-rw-r--r--lib/declarative_policy/condition.rb15
-rw-r--r--lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb26
-rw-r--r--lib/gitlab/cache/request_cache.rb94
-rw-r--r--lib/gitlab/database/migration_helpers.rb4
-rw-r--r--lib/gitlab/git/commit.rb28
-rw-r--r--lib/gitlab/git/repository.rb16
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb15
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb8
-rw-r--r--lib/gitlab/i18n.rb4
-rw-r--r--lib/gitlab/metrics/prometheus.rb8
-rw-r--r--lib/gitlab/path_regex.rb1
-rw-r--r--lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb22
-rw-r--r--lib/gitlab/performance_bar/peek_query_tracker.rb2
-rw-r--r--lib/gitlab/user_access.rb14
-rw-r--r--locale/ja/gitlab.po1184
-rw-r--r--locale/ja/gitlab.po.time_stamp0
-rw-r--r--locale/pt_BR/gitlab.po109
-rw-r--r--locale/ru/gitlab.po1233
-rw-r--r--locale/ru/gitlab.po.time_stamp0
-rw-r--r--scripts/prepare_build.sh2
-rw-r--r--spec/controllers/metrics_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb16
-rw-r--r--spec/factories/commits.rb9
-rw-r--r--spec/factories/uploads.rb2
-rw-r--r--spec/features/admin/admin_appearance_spec.rb4
-rw-r--r--spec/features/participants_autocomplete_spec.rb3
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_group_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb16
-rw-r--r--spec/helpers/emails_helper_spec.rb2
-rw-r--r--spec/helpers/groups_helper_spec.rb2
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/javascripts/lib/utils/poll_spec.js52
-rw-r--r--spec/javascripts/vue_shared/components/commit_spec.js4
-rw-r--r--spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb19
-rw-r--r--spec/lib/gitlab/cache/request_cache_spec.rb133
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb12
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb46
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb16
-rw-r--r--spec/migrations/add_foreign_key_to_merge_requests_spec.rb39
-rw-r--r--spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb35
-rw-r--r--spec/migrations/move_system_upload_folder_spec.rb62
-rw-r--r--spec/models/commit_spec.rb8
-rw-r--r--spec/models/group_spec.rb2
-rw-r--r--spec/models/namespace_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/policies/ci/build_policy_spec.rb44
-rw-r--r--spec/requests/api/projects_spec.rb2
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/services/git_push_service_spec.rb4
-rw-r--r--spec/services/notification_service_spec.rb2
-rw-r--r--spec/services/projects/participants_service_spec.rb4
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/uploaders/attachment_uploader_spec.rb2
-rw-r--r--spec/uploaders/avatar_uploader_spec.rb2
129 files changed, 3792 insertions, 336 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a54b38d284d..1a65e0473c4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -160,6 +160,9 @@ build-package:
when: manual
script:
- scripts/trigger-build
+ only:
+ - //@gitlab-org/gitlab-ce
+ - //@gitlab-org/gitlab-ee
# Prepare and merge knapsack tests
knapsack:
@@ -180,6 +183,7 @@ update-knapsack:
<<: *only-canonical-masters
stage: post-test
script:
+ - retry gem install fog-aws mime-types
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach-pg_node_*.json
- '[[ -z ${KNAPSACK_S3_BUCKET} ]] || scripts/sync-reports put $KNAPSACK_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c181aba0205..b6f955553e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.3.7 (2017-07-18)
+
+- Prevent bad data being added to application settings when Redis is unavailable. !12750
+- Return `is_admin` attribute in the GET /user endpoint for admins. !12811
+
## 9.3.6 (2017-07-12)
- Fix API Scoping. !12300
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index c5523bd09b1..59dad104b0b 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.17.0
+0.21.2
diff --git a/Gemfile b/Gemfile
index abf9f323fb4..0d6b38897ef 100644
--- a/Gemfile
+++ b/Gemfile
@@ -268,7 +268,7 @@ gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2'
gem 'peek-host', '~> 1.0.0'
gem 'peek-mysql2', '~> 1.1.0', group: :mysql
-gem 'peek-performance_bar', '~> 1.2.1'
+gem 'peek-performance_bar', '~> 1.3.0'
gem 'peek-pg', '~> 1.3.0', group: :postgres
gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0'
@@ -281,7 +281,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false
# Prometheus
- gem 'prometheus-client-mmap', '~>0.7.0.beta5'
+ gem 'prometheus-client-mmap', '~>0.7.0.beta9'
gem 'raindrops', '~> 0.18'
end
@@ -390,3 +390,6 @@ gem 'toml-rb', '~> 0.3.15', require: false
# Feature toggles
gem 'flipper', '~> 0.10.2'
gem 'flipper-active_record', '~> 0.10.2'
+
+# Structured logging
+gem 'lograge', '~> 0.5'
diff --git a/Gemfile.lock b/Gemfile.lock
index a24636ad512..69e4c4416ba 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -443,6 +443,10 @@ GEM
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
+ lograge (0.5.1)
+ actionpack (>= 4, < 5.2)
+ activesupport (>= 4, < 5.2)
+ railties (>= 4, < 5.2)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.5)
@@ -553,7 +557,7 @@ GEM
atomic (>= 1.0.0)
mysql2
peek
- peek-performance_bar (1.2.1)
+ peek-performance_bar (1.3.0)
peek (>= 0.1.0)
peek-pg (1.3.0)
concurrent-ruby
@@ -588,7 +592,7 @@ GEM
premailer-rails (1.9.7)
actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9)
- prometheus-client-mmap (0.7.0.beta8)
+ prometheus-client-mmap (0.7.0.beta9)
mmap2 (~> 2.2, >= 2.2.7)
pry (0.10.4)
coderay (~> 1.1.0)
@@ -998,6 +1002,7 @@ DEPENDENCIES
letter_opener_web (~> 1.3.0)
license_finder (~> 2.1.0)
licensee (~> 8.7.0)
+ lograge (~> 0.5)
loofah (~> 2.0.3)
mail_room (~> 0.9.1)
method_source (~> 0.8)
@@ -1029,7 +1034,7 @@ DEPENDENCIES
peek-gc (~> 0.0.2)
peek-host (~> 1.0.0)
peek-mysql2 (~> 1.1.0)
- peek-performance_bar (~> 1.2.1)
+ peek-performance_bar (~> 1.3.0)
peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0)
@@ -1037,7 +1042,7 @@ DEPENDENCIES
pg (~> 0.18.2)
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.7)
- prometheus-client-mmap (~> 0.7.0.beta5)
+ prometheus-client-mmap (~> 0.7.0.beta9)
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js
index 415e50f32ae..625e53ee9de 100644
--- a/app/assets/javascripts/lib/utils/http_status.js
+++ b/app/assets/javascripts/lib/utils/http_status.js
@@ -3,6 +3,7 @@
*/
export default {
+ ABORTED: 0,
NO_CONTENT: 204,
OK: 200,
};
diff --git a/app/assets/javascripts/lib/utils/poll.js b/app/assets/javascripts/lib/utils/poll.js
index e31cc5fbabe..97666e13ebe 100644
--- a/app/assets/javascripts/lib/utils/poll.js
+++ b/app/assets/javascripts/lib/utils/poll.js
@@ -81,6 +81,9 @@ export default class Poll {
})
.catch((error) => {
notificationCallback(false);
+ if (error.status === httpStatusCodes.ABORTED) {
+ return;
+ }
errorCallback(error);
});
}
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 4ae2b164d2e..06f7af33f94 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -60,7 +60,7 @@
}
&:not([href]):hover {
- border-color: rgba($avatar-border, .2);
+ border-color: darken($avatar-border, 10%);
}
}
@@ -99,7 +99,7 @@
.avatar-counter {
background-color: $gray-darkest;
color: $white-light;
- border: 1px solid $border-color;
+ border: 1px solid $avatar-border;
border-radius: 1em;
font-family: $regular_font;
font-size: 9px;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index fbf49f3a813..5e410cbf563 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -205,6 +205,7 @@
@media (max-width: $screen-sm-min) {
width: 100%;
+ min-width: 180px;
}
&.dropdown-open-left {
@@ -288,12 +289,6 @@
padding: 5px 8px;
color: $gl-text-color-secondary;
}
-
- .badge {
- position: absolute;
- right: 8px;
- top: 5px;
- }
}
.droplab-dropdown {
@@ -466,10 +461,6 @@
left: auto;
right: 0;
margin-top: -5px;
-
- @media (max-width: $screen-xs-max) {
- left: 0;
- }
}
.dropdown-menu-selectable {
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index e59cd0eea82..868e65a8f46 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -236,6 +236,8 @@ ul.content-list {
ul.controls {
float: right;
list-style: none;
+ display: flex;
+ align-items: center;
.btn {
padding: 10px 14px;
@@ -259,6 +261,12 @@ ul.controls {
}
}
}
+
+ .issuable-pipeline-broken a,
+ .issuable-pipeline-status a,
+ .author_link {
+ display: flex;
+ }
}
ul.indent-list {
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 28b2a7cfacd..e71bf04aec7 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -325,7 +325,7 @@
position: absolute;
top: 7px;
right: 15px;
- z-index: 2;
+ z-index: 300;
li.active {
font-weight: bold;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 785b09e622f..77b7d901f9a 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -2,6 +2,10 @@
color: $gl-text-color;
word-wrap: break-word;
+ [dir="auto"] {
+ text-align: initial;
+ }
+
a {
color: $md-link-color;
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 8bd69faf84c..7016208f624 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -379,7 +379,7 @@ $issue-boards-card-shadow: rgba(186, 186, 186, 0.5);
* Avatar
*/
$avatar_radius: 50%;
-$avatar-border: rgba(0, 0, 0, .1);
+$avatar-border: $border-color;
$gl-avatar-size: 40px;
/*
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index 82cabefa129..bd9a5d7392d 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -65,7 +65,6 @@ $new-sidebar-width: 220px;
.settings-avatar {
background-color: $white-light;
- transition: background-color 100ms linear;
i {
font-size: 20px;
@@ -73,7 +72,6 @@ $new-sidebar-width: 220px;
color: $gl-text-color-secondary;
text-align: center;
align-self: center;
- transition: color 100ms linear;
}
}
@@ -90,6 +88,7 @@ $new-sidebar-width: 220px;
box-shadow: inset -2px 0 0 $border-color;
a {
+ transition: none;
text-decoration: none;
}
@@ -177,7 +176,6 @@ $new-sidebar-width: 220px;
color: $hover-color;
.badge {
- transition: background-color 100ms linear, color 100ms linear;
background-color: $indigo-500;
color: $hover-color;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index e858ef427b0..aa04e490649 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -346,13 +346,9 @@
display: none;
}
- .avatar:hover,
- .avatar-counter:hover {
- border-color: $issuable-sidebar-color;
- }
-
.avatar-counter:hover {
color: $issuable-sidebar-color;
+ border-color: $issuable-sidebar-color;
}
.btn-clipboard {
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 13f03e7e63e..0ac9da2ff0f 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -266,7 +266,7 @@ class Projects::IssuesController < Projects::ApplicationController
if action_name == 'new'
redirect_to external.new_issue_path
else
- redirect_to external.project_path
+ redirect_to external.issue_tracker_path
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 26d11f9ab46..9a8d296d514 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -195,7 +195,7 @@ module ProjectsHelper
controller.controller_name,
controller.action_name,
current_application_settings.cache_key,
- 'v2.4'
+ 'v2.5'
]
key << pipeline_status_cache_key(project.pipeline_status) if project.pipeline_status.has_status?
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 21b906e1110..1e19f00106a 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -1,5 +1,6 @@
class Commit
extend ActiveModel::Naming
+ extend Gitlab::Cache::RequestCache
include ActiveModel::Conversion
include Noteable
@@ -169,19 +170,9 @@ class Commit
end
def author
- if RequestStore.active?
- key = "commit_author:#{author_email.downcase}"
- # nil is a valid value since no author may exist in the system
- if RequestStore.store.key?(key)
- @author = RequestStore.store[key]
- else
- @author = find_author_by_any_email
- RequestStore.store[key] = @author
- end
- else
- @author ||= find_author_by_any_email
- end
+ User.find_by_any_email(author_email.downcase)
end
+ request_cache(:author) { author_email.downcase }
def committer
@committer ||= User.find_by_any_email(committer_email.downcase)
@@ -368,10 +359,6 @@ class Commit
end
end
- def find_author_by_any_email
- User.find_by_any_email(author_email.downcase)
- end
-
def repo_changes
changes = { added: [], modified: [], removed: [] }
diff --git a/app/models/note.rb b/app/models/note.rb
index 3d39047d32f..d0e3bc0bfed 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -190,7 +190,7 @@ class Note < ActiveRecord::Base
# override to return commits, which are not active record
def noteable
if for_commit?
- project.commit(commit_id)
+ @commit ||= project.commit(commit_id)
else
super
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 420102875a5..88c428b4aae 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -23,7 +23,7 @@ class GitlabIssueTrackerService < IssueTrackerService
project_issue_url(project, id: iid)
end
- def project_path
+ def issue_tracker_path
project_issues_path(project)
end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 1fa4cd4db30..6d6a3ae3647 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -20,8 +20,8 @@ class IssueTrackerService < Service
self.issues_url.gsub(':id', iid.to_s)
end
- def project_path
- read_attribute(:project_url)
+ def issue_tracker_path
+ project_url
end
def new_issue_path
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index 62f7c057c5b..dee99bbb859 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -59,21 +59,21 @@ class KubernetesService < DeploymentService
def fields
[
{ type: 'text',
- name: 'namespace',
- title: 'Kubernetes namespace',
- placeholder: namespace_placeholder },
- { type: 'text',
name: 'api_url',
title: 'API URL',
placeholder: 'Kubernetes API URL, like https://kube.example.com/' },
- { type: 'text',
- name: 'token',
- title: 'Service token',
- placeholder: 'Service token' },
{ type: 'textarea',
name: 'ca_pem',
- title: 'Custom CA bundle',
- placeholder: 'Certificate Authority bundle (PEM format)' }
+ title: 'CA Certificate',
+ placeholder: 'Certificate Authority bundle (PEM format)' },
+ { type: 'text',
+ name: 'namespace',
+ title: 'Project namespace (optional/unique)',
+ placeholder: namespace_placeholder },
+ { type: 'text',
+ name: 'token',
+ title: 'Token',
+ placeholder: 'Service token' }
]
end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index a886efc1360..386822d3ff6 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -3,9 +3,13 @@ module Ci
condition(:protected_action) do
next false unless @subject.action?
- !::Gitlab::UserAccess
- .new(@user, project: @subject.project)
- .can_merge_to_branch?(@subject.ref)
+ access = ::Gitlab::UserAccess.new(@user, project: @subject.project)
+
+ if @subject.tag?
+ !access.can_create_tag?(@subject.ref)
+ else
+ !access.can_merge_to_branch?(@subject.ref)
+ end
end
rule { protected_action }.prevent :update_build
diff --git a/app/services/metrics_service.rb b/app/services/metrics_service.rb
index c92f070601c..a02eee4961b 100644
--- a/app/services/metrics_service.rb
+++ b/app/services/metrics_service.rb
@@ -31,6 +31,6 @@ class MetricsService
end
def multiprocess_metrics_path
- @multiprocess_metrics_path ||= Rails.root.join(ENV['prometheus_multiproc_dir']).freeze
+ ::Prometheus::Client.configuration.multiprocess_files_dir
end
end
diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb
index 0da7a025591..05a2091633a 100644
--- a/app/uploaders/gitlab_uploader.rb
+++ b/app/uploaders/gitlab_uploader.rb
@@ -16,7 +16,7 @@ class GitlabUploader < CarrierWave::Uploader::Base
def self.base_dir
return root_dir unless file_storage?
- File.join(root_dir, 'system')
+ File.join(root_dir, '-', 'system')
end
def self.file_storage?
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index ac222ad8c82..be7d27df2a0 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -42,18 +42,18 @@
.key
= icon('arrow-up', 'aria-label' => 'hidden')
I
+ %span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:issues))
%span
Issues
- .badge= number_with_delimiter(assigned_issuables_count(:issues))
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
M
+ %span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:merge_requests))
%span
Merge Requests
- .badge= number_with_delimiter(assigned_issuables_count(:merge_requests))
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
.shortcut-mappings
diff --git a/app/views/layouts/nav/_new_group_sidebar.html.haml b/app/views/layouts/nav/_new_group_sidebar.html.haml
index c80308ed0de..6e0c45739f1 100644
--- a/app/views/layouts/nav/_new_group_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_group_sidebar.html.haml
@@ -6,15 +6,15 @@
= @group.name
%ul.sidebar-top-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
- = link_to group_path(@group), title: 'Home' do
+ = link_to group_path(@group), title: 'About group' do
%span
- Group
+ About
%ul.sidebar-sub-level-items
= nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
- = link_to group_path(@group), title: 'Group Home' do
+ = link_to group_path(@group), title: 'Group details' do
%span
- Home
+ Details
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml
index 7c9822c5a6a..882123c0b0a 100644
--- a/app/views/layouts/nav/_new_project_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_project_sidebar.html.haml
@@ -7,14 +7,14 @@
= @project.name
%ul.sidebar-top-level-items
= nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
- = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
+ = link_to project_path(@project), title: 'About project', class: 'shortcuts-project' do
%span
- Project
+ About
%ul.sidebar-sub-level-items
= nav_link(path: 'projects#show') do
- = link_to project_path(@project), title: _('Project home'), class: 'shortcuts-project' do
- %span= _('Home')
+ = link_to project_path(@project), title: _('Project details'), class: 'shortcuts-project' do
+ %span= _('Details')
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index 576e5b385af..a33743c2f57 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -5,12 +5,6 @@
.tree-holder
.nav-block
- .tree-controls
- = link_to download_project_job_artifacts_path(@project, @build),
- rel: 'nofollow', download: '', class: 'btn btn-default download' do
- = icon('download')
- Download artifacts archive
-
%ul.breadcrumb.repo-breadcrumb
%li
= link_to 'Artifacts', browse_project_job_artifacts_path(@project, @build)
@@ -18,6 +12,12 @@
%li
= link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path)
+ .tree-controls
+ = link_to download_project_job_artifacts_path(@project, @build),
+ rel: 'nofollow', download: '', class: 'btn btn-default download' do
+ = icon('download')
+ Download artifacts archive
+
.tree-content-holder
%table.table.tree-table
%thead
diff --git a/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md b/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md
new file mode 100644
index 00000000000..87e95240bba
--- /dev/null
+++ b/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md
@@ -0,0 +1,4 @@
+---
+title: "reset text-align to initial to let elements with dir="auto" align texts to right in RTL languages ( default is left )"
+merge_request: 12892
+author: goshhob
diff --git a/changelogs/unreleased/33741-clarify-k8s-service-keys.yml b/changelogs/unreleased/33741-clarify-k8s-service-keys.yml
new file mode 100644
index 00000000000..91142a0d580
--- /dev/null
+++ b/changelogs/unreleased/33741-clarify-k8s-service-keys.yml
@@ -0,0 +1,5 @@
+---
+title: Clarifies and rearranges the input variables on the kubernetes integration
+ page and adjusts the docs slightly to meet the same order
+merge_request: !12188
+author:
diff --git a/changelogs/unreleased/34173-add-portuguese-brazil-translations-of-commits-page.yml b/changelogs/unreleased/34173-add-portuguese-brazil-translations-of-commits-page.yml
new file mode 100644
index 00000000000..16a9216852d
--- /dev/null
+++ b/changelogs/unreleased/34173-add-portuguese-brazil-translations-of-commits-page.yml
@@ -0,0 +1,4 @@
+---
+title: Add Portuguese Brazil translations of Commits Page
+merge_request: 12408
+author: Huang Tao
diff --git a/changelogs/unreleased/34325-reinstate-is_admin-for-user-api.yml b/changelogs/unreleased/34325-reinstate-is_admin-for-user-api.yml
deleted file mode 100644
index 3bed1fbe16e..00000000000
--- a/changelogs/unreleased/34325-reinstate-is_admin-for-user-api.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Return `is_admin` attribute in the GET /user endpoint for admins
-merge_request: 12811
-author:
diff --git a/changelogs/unreleased/34468-remove-extra-blank-on-admin-on-mobile.yml b/changelogs/unreleased/34468-remove-extra-blank-on-admin-on-mobile.yml
new file mode 100644
index 00000000000..99291b4c75a
--- /dev/null
+++ b/changelogs/unreleased/34468-remove-extra-blank-on-admin-on-mobile.yml
@@ -0,0 +1,4 @@
+---
+title: Use smaller min-width for dropdown-menu-nav only on mobile
+merge_request: 12528
+author: Takuya Noguchi
diff --git a/changelogs/unreleased/34728-fix-application-setting-created-when-redis-down.yml b/changelogs/unreleased/34728-fix-application-setting-created-when-redis-down.yml
deleted file mode 100644
index 4fddabebf36..00000000000
--- a/changelogs/unreleased/34728-fix-application-setting-created-when-redis-down.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Prevent bad data being added to application settings when Redis is unavailable
-merge_request: 12750
-author:
diff --git a/changelogs/unreleased/34789-add-japanese-translations-of-commits-page.yml b/changelogs/unreleased/34789-add-japanese-translations-of-commits-page.yml
new file mode 100644
index 00000000000..40a24847580
--- /dev/null
+++ b/changelogs/unreleased/34789-add-japanese-translations-of-commits-page.yml
@@ -0,0 +1,4 @@
+---
+title: Add Japanese translations for Cycle Analytics & Project pages & Repository pages & Commits pages & Pipeline Charts.
+merge_request: 12693
+author: Huang Tao
diff --git a/changelogs/unreleased/34881-add-russian-translations-to-i18n.yml b/changelogs/unreleased/34881-add-russian-translations-to-i18n.yml
new file mode 100644
index 00000000000..aed05dd1031
--- /dev/null
+++ b/changelogs/unreleased/34881-add-russian-translations-to-i18n.yml
@@ -0,0 +1,4 @@
+---
+title: Add Russian translations for Cycle Analytics & Project pages & Repository pages & Commits pages & Pipeline Charts.
+merge_request: 12743
+author: Huang Tao
diff --git a/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml b/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml
new file mode 100644
index 00000000000..d996ae2826a
--- /dev/null
+++ b/changelogs/unreleased/34927-protect-manual-actions-on-tags.yml
@@ -0,0 +1,4 @@
+---
+title: Protect manual actions against protected tag too
+merge_request: 12908
+author:
diff --git a/changelogs/unreleased/35087-mr-status-misaligned.yml b/changelogs/unreleased/35087-mr-status-misaligned.yml
new file mode 100644
index 00000000000..3be43125a61
--- /dev/null
+++ b/changelogs/unreleased/35087-mr-status-misaligned.yml
@@ -0,0 +1,4 @@
+---
+title: Fix alignment of controls in mr issuable list
+merge_request:
+author:
diff --git a/changelogs/unreleased/35225-transient-poll.yml b/changelogs/unreleased/35225-transient-poll.yml
new file mode 100644
index 00000000000..59e2e738c7b
--- /dev/null
+++ b/changelogs/unreleased/35225-transient-poll.yml
@@ -0,0 +1,4 @@
+---
+title: fix transient js error in rspec tests
+merge_request:
+author:
diff --git a/changelogs/unreleased/bvl-free-system-namespace.yml b/changelogs/unreleased/bvl-free-system-namespace.yml
new file mode 100644
index 00000000000..6c2d1e0e61f
--- /dev/null
+++ b/changelogs/unreleased/bvl-free-system-namespace.yml
@@ -0,0 +1,4 @@
+---
+title: "Move uploads from `uploads/system` to `uploads/-/system` to free up `system` as a group name"
+merge_request: 11713
+author:
diff --git a/changelogs/unreleased/request-store-wrap.yml b/changelogs/unreleased/request-store-wrap.yml
new file mode 100644
index 00000000000..8017054b77b
--- /dev/null
+++ b/changelogs/unreleased/request-store-wrap.yml
@@ -0,0 +1,4 @@
+---
+title: Add RequestCache which makes caching with RequestStore easier
+merge_request: 12920
+author:
diff --git a/changelogs/unreleased/sh-structured-logging.yml b/changelogs/unreleased/sh-structured-logging.yml
new file mode 100644
index 00000000000..d89eb93f689
--- /dev/null
+++ b/changelogs/unreleased/sh-structured-logging.yml
@@ -0,0 +1,4 @@
+---
+title: Add structured logging for Rails processes
+merge_request:
+author:
diff --git a/config/boot.rb b/config/boot.rb
index 2d01092acd5..f2830ae3166 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -4,8 +4,3 @@ require 'rubygems'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
-
-# set default directory for multiproces metrics gathering
-if ENV['RAILS_ENV'] == 'development' || ENV['RAILS_ENV'] == 'test'
- ENV['prometheus_multiproc_dir'] ||= 'tmp/prometheus_multiproc_dir'
-end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index c3b788c038e..986107150cf 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -43,4 +43,9 @@ Rails.application.configure do
config.cache_store = :null_store
config.active_job.queue_adapter = :test
+
+ if ENV['CI'] && !ENV['RAILS_ENABLE_TEST_LOG']
+ config.logger = Logger.new(nil)
+ config.log_level = :fatal
+ end
end
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
new file mode 100644
index 00000000000..987324a86c9
--- /dev/null
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -0,0 +1,12 @@
+require 'prometheus/client'
+
+Prometheus::Client.configure do |config|
+ config.logger = Rails.logger
+
+ config.initial_mmap_file_size = 4 * 1024
+ config.multiprocess_files_dir = ENV['prometheus_multiproc_dir']
+
+ if Rails.env.development? && Rails.env.test?
+ config.multiprocess_files_dir ||= Rails.root.join('tmp/prometheus_multiproc_dir')
+ end
+end
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
new file mode 100644
index 00000000000..14902316240
--- /dev/null
+++ b/config/initializers/lograge.rb
@@ -0,0 +1,21 @@
+# Only use Lograge for Rails
+unless Sidekiq.server?
+ filename = File.join(Rails.root, 'log', "#{Rails.env}_json.log")
+
+ Rails.application.configure do
+ config.lograge.enabled = true
+ # Store the lograge JSON files in a separate file
+ config.lograge.keep_original_rails_log = true
+ # Don't use the Logstash formatter since this requires logstash-event, an
+ # unmaintained gem that monkey patches `Time`
+ config.lograge.formatter = Lograge::Formatters::Json.new
+ config.lograge.logger = ActiveSupport::Logger.new(filename)
+ # Add request parameters to log output
+ config.lograge.custom_options = lambda do |event|
+ {
+ time: event.time,
+ params: event.payload[:params].except(%w(controller action format))
+ }
+ end
+ end
+end
diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb
index da8282ec924..a54d53cbbe2 100644
--- a/config/initializers/peek.rb
+++ b/config/initializers/peek.rb
@@ -26,7 +26,3 @@ class PEEK_DB_CLIENT
end
PEEK_DB_VIEW.prepend ::Gitlab::PerformanceBar::PeekQueryTracker
-
-class Peek::Views::PerformanceBar::ProcessUtilization
- prepend ::Gitlab::PerformanceBar::PeekPerformanceBarWithRackBody
-end
diff --git a/config/routes/uploads.rb b/config/routes/uploads.rb
index a49e244af1a..ed5476c8f71 100644
--- a/config/routes/uploads.rb
+++ b/config/routes/uploads.rb
@@ -1,6 +1,6 @@
scope path: :uploads do
# Note attachments and User/Group/Project avatars
- get "system/:model/:mounted_as/:id/:filename",
+ get "-/system/:model/:mounted_as/:id/:filename",
to: "uploads#show",
constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /[^\/]+/ }
@@ -15,7 +15,7 @@ scope path: :uploads do
constraints: { filename: /[^\/]+/ }
# Appearance
- get "system/:model/:mounted_as/:id/:filename",
+ get "-/system/:model/:mounted_as/:id/:filename",
to: "uploads#show",
constraints: { model: /appearance/, mounted_as: /logo|header_logo/, filename: /.+/ }
diff --git a/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb b/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb
new file mode 100644
index 00000000000..c25d4fd5986
--- /dev/null
+++ b/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb
@@ -0,0 +1,45 @@
+class AddForeignKeyToMergeRequests < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class MergeRequest < ActiveRecord::Base
+ self.table_name = 'merge_requests'
+ include ::EachBatch
+ end
+
+ def up
+ scope = <<-SQL.strip_heredoc
+ head_pipeline_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1 FROM ci_pipelines
+ WHERE ci_pipelines.id = merge_requests.head_pipeline_id
+ )
+ SQL
+
+ MergeRequest.where(scope).each_batch(of: 1000) do |merge_requests|
+ merge_requests.update_all(head_pipeline_id: nil)
+ end
+
+ unless foreign_key_exists?(:merge_requests, :head_pipeline_id)
+ add_concurrent_foreign_key(:merge_requests, :ci_pipelines,
+ column: :head_pipeline_id, on_delete: :nullify)
+ end
+ end
+
+ def down
+ if foreign_key_exists?(:merge_requests, :head_pipeline_id)
+ remove_foreign_key(:merge_requests, column: :head_pipeline_id)
+ end
+ end
+
+ private
+
+ def foreign_key_exists?(table, column)
+ foreign_keys(table).any? do |key|
+ key.options[:column] == column.to_s
+ end
+ end
+end
diff --git a/db/migrate/20170717074009_move_system_upload_folder.rb b/db/migrate/20170717074009_move_system_upload_folder.rb
new file mode 100644
index 00000000000..cce31794115
--- /dev/null
+++ b/db/migrate/20170717074009_move_system_upload_folder.rb
@@ -0,0 +1,60 @@
+class MoveSystemUploadFolder < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ unless file_storage?
+ say 'Using object storage, no need to move.'
+ return
+ end
+
+ unless File.directory?(old_directory)
+ say "#{old_directory} doesn't exist, no need to move it."
+ return
+ end
+
+ FileUtils.mkdir_p(File.join(base_directory, '-'))
+
+ say "Moving #{old_directory} -> #{new_directory}"
+ FileUtils.mv(old_directory, new_directory)
+ FileUtils.ln_s(new_directory, old_directory)
+ end
+
+ def down
+ unless file_storage?
+ say 'Using object storage, no need to move.'
+ return
+ end
+
+ unless File.directory?(new_directory)
+ say "#{new_directory} doesn't exist, no need to move it."
+ return
+ end
+
+ if File.symlink?(old_directory)
+ say "Removing #{old_directory} -> #{new_directory} symlink"
+ FileUtils.rm(old_directory)
+ end
+
+ say "Moving #{new_directory} -> #{old_directory}"
+ FileUtils.mv(new_directory, old_directory)
+ end
+
+ def new_directory
+ File.join(base_directory, '-', 'system')
+ end
+
+ def old_directory
+ File.join(base_directory, 'system')
+ end
+
+ def base_directory
+ File.join(Rails.root, 'public', 'uploads')
+ end
+
+ def file_storage?
+ CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
+ end
+end
diff --git a/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb b/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb
new file mode 100644
index 00000000000..26b99b61424
--- /dev/null
+++ b/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb
@@ -0,0 +1,40 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class CleanupMoveSystemUploadFolderSymlink < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ if File.symlink?(old_directory)
+ say "Removing #{old_directory} -> #{new_directory} symlink"
+ FileUtils.rm(old_directory)
+ else
+ say "Symlink #{old_directory} non existant, nothing to do."
+ end
+ end
+
+ def down
+ if File.directory?(new_directory)
+ say "Symlinking #{old_directory} -> #{new_directory}"
+ FileUtils.ln_s(new_directory, old_directory)
+ else
+ say "#{new_directory} doesn't exist, skipping."
+ end
+ end
+
+ def new_directory
+ File.join(base_directory, '-', 'system')
+ end
+
+ def old_directory
+ File.join(base_directory, 'system')
+ end
+
+ def base_directory
+ File.join(Rails.root, 'public', 'uploads')
+ end
+end
diff --git a/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb b/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb
new file mode 100644
index 00000000000..87069dce006
--- /dev/null
+++ b/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb
@@ -0,0 +1,20 @@
+class EnqueueMigrateSystemUploadsToNewFolder < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ OLD_FOLDER = 'uploads/system/'
+ NEW_FOLDER = 'uploads/-/system/'
+
+ disable_ddl_transaction!
+
+ def up
+ BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder',
+ [OLD_FOLDER, NEW_FOLDER])
+ end
+
+ def down
+ BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder',
+ [NEW_FOLDER, OLD_FOLDER])
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 623f22289ba..284b2068166 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170710083355) do
+ActiveRecord::Schema.define(version: 20170717150329) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1615,6 +1615,7 @@ ActiveRecord::Schema.define(version: 20170710083355) do
add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade
add_foreign_key "merge_request_metrics", "ci_pipelines", column: "pipeline_id", on_delete: :cascade
add_foreign_key "merge_request_metrics", "merge_requests", on_delete: :cascade
+ add_foreign_key "merge_requests", "ci_pipelines", column: "head_pipeline_id", name: "fk_fd82eae0b9", on_delete: :nullify
add_foreign_key "merge_requests", "projects", column: "target_project_id", name: "fk_a6963e8447", on_delete: :cascade
add_foreign_key "merge_requests_closing_issues", "issues", on_delete: :cascade
add_foreign_key "merge_requests_closing_issues", "merge_requests", on_delete: :cascade
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index 695fdf09a87..f43c89dad87 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -95,8 +95,9 @@ Sample Prometheus queries:
## Configuring Prometheus to monitor Kubernetes
> Introduced in GitLab 9.0.
+> Pod monitoring introduced in GitLab 9.4.
-If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes in the cluster including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them.
+If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/operating/configuration/#<kubernetes_sd_config>) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them.
To disable the monitoring of Kubernetes:
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index 3393030210e..df5c66a4c85 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -602,9 +602,8 @@ exist, you should see something like:
>**Notes:**
>
- For the monitor dashboard to appear, you need to:
- - Have enabled the [Kubernetes integration][kube]
- - Have your app deployed on Kubernetes
- Have enabled the [Prometheus integration][prom]
+ - Configured Prometheus to collect at least one [supported metric](../user/project/integrations/prometheus_library/metrics.md)
- With GitLab 9.2, all deployments to an environment are shown directly on the
monitoring dashboard
diff --git a/doc/ci/img/environments_monitoring.png b/doc/ci/img/environments_monitoring.png
index 387b6c54b61..d9c46ea4c95 100644
--- a/doc/ci/img/environments_monitoring.png
+++ b/doc/ci/img/environments_monitoring.png
Binary files differ
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index 565d4b33457..c2ca8966a3f 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -3,35 +3,6 @@
The purpose of this guide is to document potential "gotchas" that contributors
might encounter or should avoid during development of GitLab CE and EE.
-## Do not `describe` symbols
-
-Consider the following model spec:
-
-```ruby
-require 'rails_helper'
-
-describe User do
- describe :to_param do
- it 'converts the username to a param' do
- user = described_class.new(username: 'John Smith')
-
- expect(user.to_param).to eq 'john-smith'
- end
- end
-end
-```
-
-When run, this spec doesn't do what we might expect:
-
-```sh
-spec/models/user_spec.rb|6 error| Failure/Error: u = described_class.new NoMethodError: undefined method `new' for :to_param:Symbol
-```
-
-### Solution
-
-Except for the top-level `describe` block, always provide a String argument to
-`describe`.
-
## Do not assert against the absolute value of a sequence-generated attribute
Consider the following factory:
diff --git a/doc/development/testing.md b/doc/development/testing.md
index cf3ea2ccfc2..e6aa4ae8f2f 100644
--- a/doc/development/testing.md
+++ b/doc/development/testing.md
@@ -195,7 +195,6 @@ Please consult the [dedicated "Frontend testing" guide](./fe_guide/testing.md).
- Use `context` to test branching logic.
- Use multi-line `do...end` blocks for `before` and `after`, even when it would
fit on a single line.
-- Don't `describe` symbols (see [Gotchas](gotchas.md#dont-describe-symbols)).
- Don't assert against the absolute value of a sequence-generated attribute (see [Gotchas](gotchas.md#dont-assert-against-the-absolute-value-of-a-sequence-generated-attribute)).
- Don't supply the `:each` argument to hooks since it's the default.
- Prefer `not_to` to `to_not` (_this is enforced by RuboCop_).
@@ -479,6 +478,11 @@ slowest test files and try to improve them.
run the suite against MySQL for tags, `master`, and any branch that includes
`mysql` in the name.
- On EE, the test suite always runs both PostgreSQL and MySQL.
+- Rails logging to `log/test.log` is disabled by default in CI [for
+ performance reasons][logging]. To override this setting, provide the
+ `RAILS_ENABLE_TEST_LOG` environment variable.
+
+[logging]: https://jtway.co/speed-up-your-rails-test-suite-by-6-in-1-line-13fedb869ec4
## Spinach (feature) tests
diff --git a/doc/user/project/integrations/kubernetes.md b/doc/user/project/integrations/kubernetes.md
index bfe2672e098..f4000523938 100644
--- a/doc/user/project/integrations/kubernetes.md
+++ b/doc/user/project/integrations/kubernetes.md
@@ -19,10 +19,10 @@ of your project and select the **Kubernetes** service to configure it.
The Kubernetes service takes the following arguments:
-1. Kubernetes namespace
1. API URL
-1. Service token
1. Custom CA bundle
+1. Kubernetes namespace
+1. Service token
The API URL is the URL that GitLab uses to access the Kubernetes API. Kubernetes
exposes several APIs - we want the "base" URL that is common to all of them,
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 86ceb14b965..6f15765751c 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -17,35 +17,30 @@ the settings page with a default template. To configure the template, see the
Integration with Prometheus requires the following:
1. GitLab 9.0 or higher
-1. The [Kubernetes integration must be enabled][kube] on your project
-1. Your app must be deployed on [Kubernetes][]
-1. Prometheus must be configured to collect Kubernetes metrics
+1. Prometheus must be configured to collect one of the [supported metrics](prometheus_library/metrics.md)
1. Each metric must be have a label to indicate the environment
-1. GitLab must have network connectivity to the Prometheus sever
+1. GitLab must have network connectivity to the Prometheus server
-There are a few steps necessary to set up integration between Prometheus and
-GitLab.
+## Getting started with Prometheus monitoring
-## Configuring Prometheus to collect Kubernetes metrics
+Depending on your deployment and where you have located your GitLab server, there are a few options to get started with Prometheus monitoring.
-In order for Prometheus to collect Kubernetes metrics, you first must have a
-Prometheus server up and running. You have two options here:
+* If both GitLab and your applications are installed in the same Kubernetes cluster, you can leverage the [bundled Prometheus server within GitLab](#configuring-omnibus-gitlab-prometheus-to-monitor-kubernetes).
+* If your applications are deployed on Kubernetes, but GitLab is not in the same cluster, then you can [configure a Prometheus server in your Kubernetes cluster](#configuring-your-own-prometheus-server-within-kubernetes).
+* If your applications are not running in Kubernetes, [get started with Prometheus](#getting-started-with-prometheus-outside-of-kubernetes).
-- If you installed Omnibus GitLab inside of Kubernetes, you can simply use the
- [bundled version of Prometheus][promgldocs]. In that case, follow the info in the
- [Omnibus GitLab section](#configuring-omnibus-gitlab-prometheus-to-monitor-kubernetes)
- below.
-- If you are using GitLab.com or installed GitLab outside of Kubernetes, you
- will likely need to run a Prometheus server within the Kubernetes cluster.
- Once installed, the easiest way to monitor Kubernetes is to simply use
- Prometheus' support for [Kubernetes Service Discovery][prometheus-k8s-sd].
- In that case, follow the instructions on
- [configuring your own Prometheus server within Kubernetes](#configuring-your-own-prometheus-server-within-kubernetes).
+### Getting started with Prometheus outside of Kubernetes
-### Configuring Omnibus GitLab Prometheus to monitor Kubernetes
+Installing and configuring Prometheus to monitor applications is fairly straight forward.
+
+1. [Install Prometheus](https://prometheus.io/docs/introduction/install/)
+1. Set up one of the [supported monitoring targets](prometheus_library/metrics.md)
+1. Configure the Prometheus server to [collect their metrics](https://prometheus.io/docs/operating/configuration/#scrape_config)
+
+### Configuring Omnibus GitLab Prometheus to monitor Kubernetes deployments
With Omnibus GitLab running inside of Kubernetes, you can leverage the bundled
-version of Prometheus to collect the required metrics.
+version of Prometheus to collect the supported metrics. Once enabled, Prometheus will automatically begin monitoring Kubernetes Nodes and any [annotated Pods](https://prometheus.io/docs/operating/configuration/#<kubernetes_sd_config>).
1. Read how to configure the bundled Prometheus server in the
[Administration guide][gitlab-prometheus-k8s-monitor].
@@ -74,7 +69,7 @@ kubectl apply -f path/to/prometheus.yml
Once deployed, you should see the Prometheus service, deployment, and
pod start within the `prometheus` namespace. The server will begin to collect
metrics from each Kubernetes Node in the cluster, based on the configuration
-provided in the template.
+provided in the template. It will also attempt to collect metrics from any Kubernetes Pods that have been [annotated for Prometheus](https://prometheus.io/docs/operating/configuration/#pod).
Since GitLab is not running within Kubernetes, the template provides external
network access via a `NodePort` running on `30090`. This method allows access
@@ -133,30 +128,6 @@ to integrate with.
![Configure Prometheus Service](img/prometheus_service_configuration.png)
-## Metrics and Labels
-
-GitLab retrieves performance data from two metrics, `container_cpu_usage_seconds_total`
-and `container_memory_usage_bytes`. These metrics are collected from the
-Kubernetes pods via Prometheus, and report CPU and Memory utilization of each
-container or Pod running in the cluster.
-
-In order to isolate and only display relevant metrics for a given environment
-however, GitLab needs a method to detect which pods are associated. To do that,
-GitLab will specifically request metrics that have an `environment` tag that
-matches the [$CI_ENVIRONMENT_SLUG][ci-environment-slug].
-
-If you are using [GitLab Auto-Deploy][autodeploy] and one of the methods of
-configuring Prometheus above, the `environment` will be automatically added.
-
-### GitLab Prometheus queries
-
-The queries utilized by GitLab are shown in the following table.
-
-| Metric | Query |
-| ------ | ----- |
-| Average Memory (MB) | `(sum(container_memory_usage_bytes{container_name!="POD",environment="$CI_ENVIRONMENT_SLUG"}) / count(container_memory_usage_bytes{container_name!="POD",environment="$CI_ENVIRONMENT_SLUG"})) /1024/1024` |
-| Average CPU Utilization (%) | `sum(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="$CI_ENVIRONMENT_SLUG"}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",environment="$CI_ENVIRONMENT_SLUG"}) * 100` |
-
## Monitoring CI/CD Environments
Once configured, GitLab will attempt to retrieve performance metrics for any
@@ -168,8 +139,9 @@ environment which has had a successful deployment.
> [Introduced][ce-10408] in GitLab 9.2.
> GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-ce/issues/27439) of the 30 minute averages.
+> Requires [Kubernetes](prometheus_library/kubernetes.md) metrics
-Developers can view the performance impact of their changes within the merge
+Developers can view theperformance impact of their changes within the merge
request workflow. When a source branch has been deployed to an environment, a sparkline and numeric comparison of the average memory consumption will appear. On the sparkline, a dot
indicates when the current changes were deployed, with up to 30 minutes of
performance data displayed before and after. The comparison shows the difference between the 30 minute average before and after the deployment. This information is updated after
diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md
new file mode 100644
index 00000000000..cc5cee36d28
--- /dev/null
+++ b/doc/user/project/integrations/prometheus_library/cloudwatch.md
@@ -0,0 +1,25 @@
+# Monitoring AWS Resources
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12621) in GitLab 9.4
+
+GitLab has support for automatically detecting and monitoring AWS resources, starting with the [Elastic Load Balancer](https://aws.amazon.com/elasticloadbalancing/). This is provided by leveraging the official [Cloudwatch exporter](https://github.com/prometheus/cloudwatch_exporter), which translates [Cloudwatch metrics](https://aws.amazon.com/cloudwatch/) into a Prometheus readable form.
+
+## Metrics supported
+
+| Name | Query |
+| ---- | ----- |
+| Throughput (req/sec) | sum(aws_elb_request_count_sum{%{environment_filter}}) / 60 |
+| Latency (ms) | avg(aws_elb_latency_average{%{environment_filter}}) * 1000 |
+| HTTP Error Rate (%) | sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}}) |
+
+## Configuring Prometheus to monitor for Cloudwatch metrics
+
+To get started with Cloudwatch monitoring, you should install and configure the [Cloudwatch exporter](https://github.com/hnlq715/nginx-vts-exporter) which retrieves and parses the specified Cloudwatch metrics and translates them into a Prometheus monitoring endpoint.
+
+Right now, the only AWS resource supported is the Elastic Load Balancer, whose Cloudwatch metrics can be found [here](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html).
+
+A sample Cloudwatch Exporter configuration file, configured for basic AWS ELB monitoring, is [available for download](../samples/cloudwatch.yml).
+
+## Specifying the Environment label
+
+In order to isolate and only display relevant metrics for a given environment
+however, GitLab needs a method to detect which labels are associated. To do this, GitLab will [look for an `environment` label](metrics.md#identifying-environments).
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
new file mode 100644
index 00000000000..eb8cd821ddc
--- /dev/null
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -0,0 +1,26 @@
+# Monitoring Kubernetes
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8935) in GitLab 9.0
+
+GitLab has support for automatically detecting and monitoring Kubernetes metrics. Kubernetes exposes Node level metrics out of the box via the built-in [Prometheus metrics support in cAdvisor](https://github.com/google/cadvisor). No additional services or exporters are needed.
+
+## Metrics supported
+
+| Name | Query |
+| ---- | ----- |
+| Average Memory Usage (MB) | (sum(container_memory_usage_bytes{container_name!="POD",%{environment_filter}}) / count(container_memory_usage_bytes{container_name!="POD",%{environment_filter}})) /1024/1024 |
+| Average CPU Utilization (%) | sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100 |
+
+## Configuring Prometheus to monitor for Kubernetes node metrics
+
+In order for Prometheus to collect Kubernetes metrics, you first must have a
+Prometheus server up and running. You have two options here:
+
+- If you have an Omnibus based GitLab installation within your Kubernetes cluster, you can leverage the bundled Prometheus server to [monitor Kubernetes](../../../../administration/monitoring/prometheus/index.md#configuring-prometheus-to-monitor-kubernetes).
+- To configure your own Prometheus server, you can follow the [Prometheus documentation](https://prometheus.io/docs/introduction/overview/) or [our guide](../../../../administration/monitoring/prometheus/index.md#configuring-your-own-prometheus-server-within-kubernetes).
+
+## Specifying the Environment label
+
+In order to isolate and only display relevant metrics for a given environment
+however, GitLab needs a method to detect which labels are associated. To do this, GitLab will [look for an `environment` label](metrics.md#identifying-environments).
+
+If you are using [GitLab Auto-Deploy][autodeploy] and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
diff --git a/doc/user/project/integrations/prometheus_library/metrics.md b/doc/user/project/integrations/prometheus_library/metrics.md
new file mode 100644
index 00000000000..55146e57370
--- /dev/null
+++ b/doc/user/project/integrations/prometheus_library/metrics.md
@@ -0,0 +1,25 @@
+# Prometheus Metrics library
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8935) in GitLab 9.0
+
+GitLab offers automatic detection of select [Prometheus exporters](https://prometheus.io/docs/instrumenting/exporters/). Currently supported exporters are:
+* [Kubernetes](kubernetes.md)
+* [NGINX](nginx.md)
+* [Amazon Cloud Watch](cloudwatch.md)
+
+We have tried to surface the most important metrics for each exporter, and will be continuing to add support for additional exporters in future releases. If you would like to add support for other official exporters, [contributions](#adding-to-the-library) are welcome.
+
+## Identifying Environments
+
+GitLab retrieves performance data from the configured Prometheus server, and attempts to identifying the presence of known metrics. Once identified, GitLab then needs to be able to map the data to a particular environment.
+
+In order to isolate and only display relevant metrics for a given environment, GitLab needs a method to detect which labels are associated. To do that,
+GitLab will look for the required metrics which have a label that
+matches the [$CI_ENVIRONMENT_SLUG][ci-environment-slug].
+
+For example if you are deploying to an environment named `production`, there must be a label for the metric with the value of `production`.
+
+## Adding to the library
+
+We strive to support the 2-4 most important metrics for each common system service that supports Prometheus. If you are looking for support for a particular exporter which has not yet been added to the library, additions can be made [to the `additional_metrics.yml`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/prometheus/additional_metrics.yml) file.
+
+> Note: The library is only for monitoring public, common, system services which all customers can benefit from. Support for monitoring [customer proprietary metrics](https://gitlab.com/gitlab-org/gitlab-ee/issues/2273) will be added in a subsequent release.
diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md
new file mode 100644
index 00000000000..fe238e74e36
--- /dev/null
+++ b/doc/user/project/integrations/prometheus_library/nginx.md
@@ -0,0 +1,23 @@
+# Monitoring NGINX
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12621) in GitLab 9.4
+
+GitLab has support for automatically detecting and monitoring NGINX. This is provided by leveraging the [NGINX VTS exporter](https://github.com/hnlq715/nginx-vts-exporter), which translates [VTS statistics](https://github.com/vozlt/nginx-module-vts) into a Prometheus readable form.
+
+## Metrics supported
+
+| Name | Query |
+| ---- | ----- |
+| Throughput (req/sec) | sum(rate(nginx_requests_total{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) |
+| Latency (ms) | avg(nginx_upstream_response_msecs_avg{%{environment_filter}}) * 1000 |
+| HTTP Error Rate (%) | sum(nginx_responses_total{status_code="5xx", %{environment_filter}}) / sum(nginx_responses_total{server_zone!="*", server_zone!="_", %{environment_filter}}) |
+
+## Configuring Prometheus to monitor for NGINX metrics
+
+To get started with NGINX monitoring, you should first enable the [VTS statistics](https://github.com/vozlt/nginx-module-vts)) module for your NGINX server. This will capture and display statistics in an HTML readable form. Next, you should install and configure the [NGINX VTS exporter](https://github.com/hnlq715/nginx-vts-exporter) which parses these statistics and translates them into a Prometheus monitoring endpoint.
+
+If you are using NGINX as your Kubernetes ingress, there is [upcoming direct support](https://github.com/kubernetes/ingress/pull/423) for enabling Prometheus monitoring in the 0.9.0 release.
+
+## Specifying the Environment label
+
+In order to isolate and only display relevant metrics for a given environment
+however, GitLab needs a method to detect which labels are associated. To do this, GitLab will [look for an `environment` label](metrics.md#identifying-environments).
diff --git a/doc/user/project/integrations/samples/cloudwatch.yml b/doc/user/project/integrations/samples/cloudwatch.yml
new file mode 100644
index 00000000000..d9b58f52c32
--- /dev/null
+++ b/doc/user/project/integrations/samples/cloudwatch.yml
@@ -0,0 +1,26 @@
+region: us-east-1
+ metrics:
+ - aws_namespace: AWS/ELB
+ aws_metric_name: RequestCount
+ aws_dimensions: [AvailabilityZone, LoadBalancerName]
+ aws_dimension_select:
+ LoadBalancerName: [gitlab-ha-lb]
+ aws_statistics: [Sum]
+ - aws_namespace: AWS/ELB
+ aws_metric_name: Latency
+ aws_dimensions: [AvailabilityZone, LoadBalancerName]
+ aws_dimension_select:
+ LoadBalancerName: [gitlab-ha-lb]
+ aws_statistics: [Average]
+ - aws_namespace: AWS/ELB
+ aws_metric_name: HTTPCode_Backend_2XX
+ aws_dimensions: [AvailabilityZone, LoadBalancerName]
+ aws_dimension_select:
+ LoadBalancerName: [gitlab-ha-lb]
+ aws_statistics: [Sum]
+ - aws_namespace: AWS/ELB
+ aws_metric_name: HTTPCode_Backend_5XX
+ aws_dimensions: [AvailabilityZone, LoadBalancerName]
+ aws_dimension_select:
+ LoadBalancerName: [gitlab-ha-lb]
+ aws_statistics: [Sum]
diff --git a/doc/user/project/integrations/samples/prometheus.yml b/doc/user/project/integrations/samples/prometheus.yml
index 01bbcaffe1e..30b59e172a1 100644
--- a/doc/user/project/integrations/samples/prometheus.yml
+++ b/doc/user/project/integrations/samples/prometheus.yml
@@ -24,6 +24,44 @@ data:
target_label: environment
regex: (.+)-.+-.+
replacement: $1
+ - job_name: kubernetes-pods
+ tls_config:
+ ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+ insecure_skip_verify: true
+ bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+ kubernetes_sd_configs:
+ - role: pod
+ api_server: https://kubernetes.default.svc:443
+ tls_config:
+ ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+ bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+ relabel_configs:
+ - source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scrape
+ action: keep
+ regex: 'true'
+ - source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_path
+ action: replace
+ target_label: __metrics_path__
+ regex: "(.+)"
+ - source_labels:
+ - __address__
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ action: replace
+ regex: "([^:]+)(?::[0-9]+)?;([0-9]+)"
+ replacement: "$1:$2"
+ target_label: __address__
+ - action: labelmap
+ regex: __meta_kubernetes_pod_label_(.+)
+ - source_labels:
+ - __meta_kubernetes_namespace
+ action: replace
+ target_label: kubernetes_namespace
+ - source_labels:
+ - __meta_kubernetes_pod_name
+ action: replace
+ target_label: kubernetes_pod_name
---
apiVersion: v1
kind: Service
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index 0aedc422563..6b288b47da4 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -81,7 +81,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
step 'I should see new group "Owned" avatar' do
expect(owned_group.avatar).to be_instance_of AvatarUploader
- expect(owned_group.avatar.url).to eq "/uploads/system/group/avatar/#{Group.find_by(name: "Owned").id}/banana_sample.gif"
+ expect(owned_group.avatar.url).to eq "/uploads/-/system/group/avatar/#{Group.find_by(name: "Owned").id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 254c26bb6af..4b88cb5e27f 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -36,7 +36,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I should see new avatar' do
expect(@user.avatar).to be_instance_of AvatarUploader
- expect(@user.avatar.url).to eq "/uploads/system/user/avatar/#{@user.id}/banana_sample.gif"
+ expect(@user.avatar.url).to eq "/uploads/-/system/user/avatar/#{@user.id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 7d34331db46..170e2f16c80 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -38,7 +38,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should see new project avatar' do
expect(@project.avatar).to be_instance_of AvatarUploader
url = @project.avatar.url
- expect(url).to eq "/uploads/system/project/avatar/#{@project.id}/banana_sample.gif"
+ expect(url).to eq "/uploads/-/system/project/avatar/#{@project.id}/banana_sample.gif"
end
step 'I should see the "Remove avatar" button' do
diff --git a/lib/declarative_policy.rb b/lib/declarative_policy.rb
index d9959bc1aff..b1eb1a6cef1 100644
--- a/lib/declarative_policy.rb
+++ b/lib/declarative_policy.rb
@@ -8,7 +8,12 @@ require_dependency 'declarative_policy/step'
require_dependency 'declarative_policy/base'
+require 'thread'
+
module DeclarativePolicy
+ CLASS_CACHE_MUTEX = Mutex.new
+ CLASS_CACHE_IVAR = :@__DeclarativePolicy_CLASS_CACHE
+
class << self
def policy_for(user, subject, opts = {})
cache = opts[:cache] || {}
@@ -23,7 +28,36 @@ module DeclarativePolicy
subject = find_delegate(subject)
- subject.class.ancestors.each do |klass|
+ class_for_class(subject.class)
+ end
+
+ private
+
+ # This method is heavily cached because there are a lot of anonymous
+ # modules in play in a typical rails app, and #name performs quite
+ # slowly for anonymous classes and modules.
+ #
+ # See https://bugs.ruby-lang.org/issues/11119
+ #
+ # if the above bug is resolved, this caching could likely be removed.
+ def class_for_class(subject_class)
+ unless subject_class.instance_variable_defined?(CLASS_CACHE_IVAR)
+ CLASS_CACHE_MUTEX.synchronize do
+ # re-check in case of a race
+ break if subject_class.instance_variable_defined?(CLASS_CACHE_IVAR)
+
+ policy_class = compute_class_for_class(subject_class)
+ subject_class.instance_variable_set(CLASS_CACHE_IVAR, policy_class)
+ end
+ end
+
+ policy_class = subject_class.instance_variable_get(CLASS_CACHE_IVAR)
+ raise "no policy for #{subject.class.name}" if policy_class.nil?
+ policy_class
+ end
+
+ def compute_class_for_class(subject_class)
+ subject_class.ancestors.each do |klass|
next unless klass.name
begin
@@ -37,12 +71,8 @@ module DeclarativePolicy
nil
end
end
-
- raise "no policy for #{subject.class.name}"
end
- private
-
def find_delegate(subject)
seen = Set.new
diff --git a/lib/declarative_policy/cache.rb b/lib/declarative_policy/cache.rb
index b8cc60074c7..0804edba016 100644
--- a/lib/declarative_policy/cache.rb
+++ b/lib/declarative_policy/cache.rb
@@ -21,11 +21,14 @@ module DeclarativePolicy
private
def id_for(obj)
- if obj.respond_to?(:id) && obj.id
- obj.id.to_s
- else
- "##{obj.object_id}"
- end
+ id =
+ begin
+ obj.id
+ rescue NoMethodError
+ nil
+ end
+
+ id || "##{obj.object_id}"
end
end
end
diff --git a/lib/declarative_policy/condition.rb b/lib/declarative_policy/condition.rb
index 9d7cf6b9726..51c4a8b2bbe 100644
--- a/lib/declarative_policy/condition.rb
+++ b/lib/declarative_policy/condition.rb
@@ -82,13 +82,14 @@ module DeclarativePolicy
# depending on the scope, we may cache only by the user or only by
# the subject, resulting in sharing across different policy objects.
def cache_key
- case @condition.scope
- when :normal then "/dp/condition/#{@condition.key}/#{user_key},#{subject_key}"
- when :user then "/dp/condition/#{@condition.key}/#{user_key}"
- when :subject then "/dp/condition/#{@condition.key}/#{subject_key}"
- when :global then "/dp/condition/#{@condition.key}"
- else raise 'invalid scope'
- end
+ @cache_key ||=
+ case @condition.scope
+ when :normal then "/dp/condition/#{@condition.key}/#{user_key},#{subject_key}"
+ when :user then "/dp/condition/#{@condition.key}/#{user_key}"
+ when :subject then "/dp/condition/#{@condition.key}/#{subject_key}"
+ when :global then "/dp/condition/#{@condition.key}"
+ else raise 'invalid scope'
+ end
end
def user_key
diff --git a/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb b/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb
new file mode 100644
index 00000000000..0881244ed49
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb
@@ -0,0 +1,26 @@
+module Gitlab
+ module BackgroundMigration
+ class MigrateSystemUploadsToNewFolder
+ include Gitlab::Database::MigrationHelpers
+ attr_reader :old_folder, :new_folder
+
+ class Upload < ActiveRecord::Base
+ self.table_name = 'uploads'
+ include EachBatch
+ end
+
+ def perform(old_folder, new_folder)
+ replace_sql = replace_sql(uploads[:path], old_folder, new_folder)
+ affected_uploads = Upload.where(uploads[:path].matches("#{old_folder}%"))
+
+ affected_uploads.each_batch do |batch|
+ batch.update_all("path = #{replace_sql}")
+ end
+ end
+
+ def uploads
+ Arel::Table.new('uploads')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cache/request_cache.rb b/lib/gitlab/cache/request_cache.rb
new file mode 100644
index 00000000000..f1a04affd38
--- /dev/null
+++ b/lib/gitlab/cache/request_cache.rb
@@ -0,0 +1,94 @@
+module Gitlab
+ module Cache
+ # This module provides a simple way to cache values in RequestStore,
+ # and the cache key would be based on the class name, method name,
+ # optionally customized instance level values, optionally customized
+ # method level values, and optional method arguments.
+ #
+ # A simple example:
+ #
+ # class UserAccess
+ # extend Gitlab::Cache::RequestCache
+ #
+ # request_cache_key do
+ # [user&.id, project&.id]
+ # end
+ #
+ # request_cache def can_push_to_branch?(ref)
+ # # ...
+ # end
+ # end
+ #
+ # This way, the result of `can_push_to_branch?` would be cached in
+ # `RequestStore.store` based on the cache key. If RequestStore is not
+ # currently active, then it would be stored in a hash saved in an
+ # instance variable, so the cache logic would be the same.
+ # Here's another example using customized method level values:
+ #
+ # class Commit
+ # extend Gitlab::Cache::RequestCache
+ #
+ # def author
+ # User.find_by_any_email(author_email.downcase)
+ # end
+ # request_cache(:author) { author_email.downcase }
+ # end
+ #
+ # So that we could have different strategies for different methods
+ #
+ module RequestCache
+ def self.extended(klass)
+ return if klass < self
+
+ extension = Module.new
+ klass.const_set(:RequestCacheExtension, extension)
+ klass.prepend(extension)
+ end
+
+ def request_cache_key(&block)
+ if block_given?
+ @request_cache_key = block
+ else
+ @request_cache_key
+ end
+ end
+
+ def request_cache(method_name, &method_key_block)
+ const_get(:RequestCacheExtension).module_eval do
+ cache_key_method_name = "#{method_name}_cache_key"
+
+ define_method(method_name) do |*args|
+ store =
+ if RequestStore.active?
+ RequestStore.store
+ else
+ ivar_name = # ! and ? cannot be used as ivar name
+ "@cache_#{method_name.to_s.tr('!?', "\u2605\u2606")}"
+
+ instance_variable_get(ivar_name) ||
+ instance_variable_set(ivar_name, {})
+ end
+
+ key = __send__(cache_key_method_name, args)
+
+ store.fetch(key) { store[key] = super(*args) }
+ end
+
+ define_method(cache_key_method_name) do |args|
+ klass = self.class
+
+ instance_key = instance_exec(&klass.request_cache_key) if
+ klass.request_cache_key
+
+ method_key = instance_exec(&method_key_block) if method_key_block
+
+ [klass.name, method_name, *instance_key, *method_key, *args]
+ .join(':')
+ end
+
+ private cache_key_method_name
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 0643c56db9b..69ca9aa596b 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -140,6 +140,8 @@ module Gitlab
return add_foreign_key(source, target,
column: column,
on_delete: on_delete)
+ else
+ on_delete = 'SET NULL' if on_delete == :nullify
end
disable_statement_timeout
@@ -155,7 +157,7 @@ module Gitlab
ADD CONSTRAINT #{key_name}
FOREIGN KEY (#{column})
REFERENCES #{target} (id)
- #{on_delete ? "ON DELETE #{on_delete}" : ''}
+ #{on_delete ? "ON DELETE #{on_delete.upcase}" : ''}
NOT VALID;
EOF
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index d0f04d25db2..76a562f356e 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -98,7 +98,15 @@ module Gitlab
# Commit.between(repo, '29eda46b', 'master')
#
def between(repo, base, head)
- repo.commits_between(base, head).map do |commit|
+ commits = Gitlab::GitalyClient.migrate(:commits_between) do |is_enabled|
+ if is_enabled
+ repo.gitaly_commit_client.between(base, head)
+ else
+ repo.commits_between(base, head)
+ end
+ end
+
+ commits.map do |commit|
decorate(commit)
end
rescue Rugged::ReferenceError
@@ -210,6 +218,8 @@ module Gitlab
init_from_hash(raw_commit)
elsif raw_commit.is_a?(Rugged::Commit)
init_from_rugged(raw_commit)
+ elsif raw_commit.is_a?(Gitaly::GitCommit)
+ init_from_gitaly(raw_commit)
else
raise "Invalid raw commit type: #{raw_commit.class}"
end
@@ -371,6 +381,22 @@ module Gitlab
@parent_ids = commit.parents.map(&:oid)
end
+ def init_from_gitaly(commit)
+ @raw_commit = commit
+ @id = commit.id
+ # TODO: Once gitaly "takes over" Rugged consider separating the
+ # subject from the message to make it clearer when there's one
+ # available but not the other.
+ @message = (commit.body.presence || commit.subject).dup
+ @authored_date = Time.at(commit.author.date.seconds)
+ @author_name = commit.author.name.dup
+ @author_email = commit.author.email.dup
+ @committed_date = Time.at(commit.committer.date.seconds)
+ @committer_name = commit.committer.name.dup
+ @committer_email = commit.committer.email.dup
+ @parent_ids = commit.parent_ids
+ end
+
def serialize_keys
SERIALIZE_KEYS
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index c091bb9dcfe..63eebadff2e 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -807,6 +807,14 @@ module Gitlab
Gitlab::GitalyClient::Util.repository(@storage, @relative_path)
end
+ def gitaly_ref_client
+ @gitaly_ref_client ||= Gitlab::GitalyClient::RefService.new(self)
+ end
+
+ def gitaly_commit_client
+ @gitaly_commit_client ||= Gitlab::GitalyClient::CommitService.new(self)
+ end
+
private
# Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'.
@@ -1105,14 +1113,6 @@ module Gitlab
end
end
- def gitaly_ref_client
- @gitaly_ref_client ||= Gitlab::GitalyClient::RefService.new(self)
- end
-
- def gitaly_commit_client
- @gitaly_commit_client ||= Gitlab::GitalyClient::CommitService.new(self)
- end
-
def gitaly_migrate(method, &block)
Gitlab::GitalyClient.migrate(method, &block)
rescue GRPC::NotFound => e
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 470e3ac8779..8f5738fed06 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -65,6 +65,17 @@ module Gitlab
GitalyClient.call(@repository.storage, :commit_service, :count_commits, request).count
end
+ def between(from, to)
+ request = Gitaly::CommitsBetweenRequest.new(
+ repository: @gitaly_repo,
+ from: from,
+ to: to
+ )
+
+ response = GitalyClient.call(@repository.storage, :commit_service, :commits_between, request)
+ consume_commits_response(response)
+ end
+
private
def commit_diff_request_params(commit, options = {})
@@ -77,6 +88,10 @@ module Gitlab
paths: options.fetch(:paths, [])
}
end
+
+ def consume_commits_response(response)
+ response.flat_map { |r| r.commits }
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index f541887843d..2c3d53410ac 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -96,11 +96,11 @@ module Gitlab
id: response.commit_id,
message: message,
authored_date: Time.at(response.commit_author.date.seconds),
- author_name: response.commit_author.name,
- author_email: response.commit_author.email,
+ author_name: response.commit_author.name.dup,
+ author_email: response.commit_author.email.dup,
committed_date: Time.at(response.commit_committer.date.seconds),
- committer_name: response.commit_committer.name,
- committer_email: response.commit_committer.email
+ committer_name: response.commit_committer.name.dup,
+ committer_email: response.commit_committer.email.dup
}
Gitlab::Git::Commit.decorate(hash)
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index f3d489aad0d..7e868190477 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -12,8 +12,10 @@ module Gitlab
'zh_HK' => '繁體中文(香港)',
'zh_TW' => '繁體中文(臺灣)',
'bg' => 'български',
+ 'ru' => 'Русский',
'eo' => 'Esperanto',
- 'it' => 'Italiano'
+ 'it' => 'Italiano',
+ 'ja' => '日本語'
}.freeze
def available_locales
diff --git a/lib/gitlab/metrics/prometheus.rb b/lib/gitlab/metrics/prometheus.rb
index fb7bbc7cfc7..460dab47276 100644
--- a/lib/gitlab/metrics/prometheus.rb
+++ b/lib/gitlab/metrics/prometheus.rb
@@ -6,9 +6,11 @@ module Gitlab
include Gitlab::CurrentSettings
def metrics_folder_present?
- ENV.has_key?('prometheus_multiproc_dir') &&
- ::Dir.exist?(ENV['prometheus_multiproc_dir']) &&
- ::File.writable?(ENV['prometheus_multiproc_dir'])
+ multiprocess_files_dir = ::Prometheus::Client.configuration.multiprocess_files_dir
+
+ multiprocess_files_dir &&
+ ::Dir.exist?(multiprocess_files_dir) &&
+ ::File.writable?(multiprocess_files_dir)
end
def prometheus_metrics_enabled?
diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb
index d81f825ef96..60a32d5d5ea 100644
--- a/lib/gitlab/path_regex.rb
+++ b/lib/gitlab/path_regex.rb
@@ -49,7 +49,6 @@ module Gitlab
sent_notifications
services
snippets
- system
teams
u
unicorn_test
diff --git a/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb b/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb
deleted file mode 100644
index d939a6ea18d..00000000000
--- a/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# This solves a bug with a X-Senfile header that wouldn't be set properly, see
-# https://github.com/peek/peek-performance_bar/pull/27
-module Gitlab
- module PerformanceBar
- module PeekPerformanceBarWithRackBody
- def call(env)
- @env = env
- reset_stats
-
- @total_requests += 1
- first_request if @total_requests == 1
-
- env['process.request_start'] = @start.to_f
- env['process.total_requests'] = total_requests
-
- status, headers, body = @app.call(env)
- body = Rack::BodyProxy.new(body) { record_request }
- [status, headers, body]
- end
- end
- end
-end
diff --git a/lib/gitlab/performance_bar/peek_query_tracker.rb b/lib/gitlab/performance_bar/peek_query_tracker.rb
index f97e895dbd0..67fee8c227d 100644
--- a/lib/gitlab/performance_bar/peek_query_tracker.rb
+++ b/lib/gitlab/performance_bar/peek_query_tracker.rb
@@ -37,7 +37,7 @@ module Gitlab
def track_query(raw_query, bindings, start, finish)
query = Gitlab::Sherlock::Query.new(raw_query, start, finish)
- query_info = { duration: '%.3f' % query.duration, sql: query.formatted_query }
+ query_info = { duration: query.duration.round(3), sql: query.formatted_query }
PEEK_DB_CLIENT.query_details << query_info
end
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 3b922da7ced..8e91ee7287c 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -1,5 +1,11 @@
module Gitlab
class UserAccess
+ extend Gitlab::Cache::RequestCache
+
+ request_cache_key do
+ [user&.id, project&.id]
+ end
+
attr_reader :user, :project
def initialize(user, project: nil)
@@ -28,7 +34,7 @@ module Gitlab
true
end
- def can_create_tag?(ref)
+ request_cache def can_create_tag?(ref)
return false unless can_access_git?
if ProtectedTag.protected?(project, ref)
@@ -38,7 +44,7 @@ module Gitlab
end
end
- def can_delete_branch?(ref)
+ request_cache def can_delete_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
@@ -48,7 +54,7 @@ module Gitlab
end
end
- def can_push_to_branch?(ref)
+ request_cache def can_push_to_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
@@ -60,7 +66,7 @@ module Gitlab
end
end
- def can_merge_to_branch?(ref)
+ request_cache def can_merge_to_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
new file mode 100644
index 00000000000..b880fc703ec
--- /dev/null
+++ b/locale/ja/gitlab.po
@@ -0,0 +1,1184 @@
+# Arthur Charron <arthur.charron@hotmail.fr>, 2017. #zanata
+# Huang Tao <htve@outlook.com>, 2017. #zanata
+# Kohei Ota <inductor@kela.jp>, 2017. #zanata
+# Taisuke Inoue <taisuke.inoue.jp@gmail.com>, 2017. #zanata
+# Takuya Noguchi <takninnovationresearch@gmail.com>, 2017. #zanata
+# YANO TETTER <tetuyano+zana@gmail.com>, 2017. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab 1.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-05 08:50-0500\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language-Team: Japanese (https://translate.zanata.org/project/view/GitLab)\n"
+"PO-Revision-Date: 2017-07-18 09:27-0400\n"
+"Last-Translator: YANO TETTER <tetuyano+zana@gmail.com>\n"
+"Language: ja\n"
+"X-Generator: Zanata 3.9.6\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural ""
+"%s additional commits have been omitted to prevent performance issues."
+msgstr[0] "パフォーマンス低下を避けるため %s 個のコミットを省略しました。"
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] "%d個のコミット"
+
+msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr "%{commit_author_link}は%{commit_timeago}前、コミットしました。"
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] "%d 個のパイプライン"
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr "CIについてのグラフ"
+
+msgid "About auto deploy"
+msgstr "自動デプロイについて"
+
+msgid "Active"
+msgstr "有効"
+
+msgid "Activity"
+msgstr "アクティビティー"
+
+msgid "Add Changelog"
+msgstr "変更履歴を追加"
+
+msgid "Add Contribution guide"
+msgstr "貢献者向けガイドを追加"
+
+msgid "Add License"
+msgstr "ライセンスを追加"
+
+msgid "Add an SSH key to your profile to pull or push via SSH."
+msgstr "SSHでプルやプッシュする場合は、プロフィールにSSH鍵を追加してください。"
+
+msgid "Add new directory"
+msgstr "新規ディレクトリを追加"
+
+msgid "Archived project! Repository is read-only"
+msgstr "アーカイブ済みプロジェクト!(レポジトリーは読み取り専用です)"
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr "このパイプラインスケジュールを削除しますか?"
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr "ドラッグ&ドロップまたは %{upload_link} でファイルを添付"
+
+msgid "Branch"
+msgid_plural "Branches"
+msgstr[0] "ブランチ"
+
+msgid ""
+"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, "
+"choose a GitLab CI Yaml template and commit your changes. "
+"%{link_to_autodeploy_doc}"
+msgstr ""
+"<strong>%{branch_name}</strong> ブランチが作成されました。自動デプロイを設定するには、GitLab CI Yaml "
+"テンプレートを選択して、変更をコミットしてください。 %{link_to_autodeploy_doc}"
+
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr "ブランチを検索"
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr "ブランチを切替"
+
+msgid "Branches"
+msgstr "ブランチ"
+
+msgid "Browse Directory"
+msgstr "ディレクトリを表示"
+
+msgid "Browse File"
+msgstr "ファイルを表示"
+
+msgid "Browse Files"
+msgstr "ファイルを表示"
+
+msgid "Browse files"
+msgstr "ファイルを表示"
+
+msgid "ByAuthor|by"
+msgstr "作者"
+
+msgid "CI configuration"
+msgstr "CI 設定"
+
+msgid "Cancel"
+msgstr "キャンセル"
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr "ピック先ブランチ:"
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr "リバート先ブランチ:"
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr "チェリーピック"
+
+msgid "ChangeTypeAction|Revert"
+msgstr "リバート"
+
+msgid "Changelog"
+msgstr "変更履歴"
+
+msgid "Charts"
+msgstr "チャート"
+
+msgid "Cherry-pick this commit"
+msgstr "このコミットをチェリーピック"
+
+msgid "Cherry-pick this merge request"
+msgstr "このマージリクエストをチェリーピック"
+
+msgid "CiStatusLabel|canceled"
+msgstr "キャンセル"
+
+msgid "CiStatusLabel|created"
+msgstr "作成済み"
+
+msgid "CiStatusLabel|failed"
+msgstr "失敗"
+
+msgid "CiStatusLabel|manual action"
+msgstr "手動実行"
+
+msgid "CiStatusLabel|passed"
+msgstr "成功"
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr "成功(警告あり)"
+
+msgid "CiStatusLabel|pending"
+msgstr "開始待ち"
+
+msgid "CiStatusLabel|skipped"
+msgstr "スキップ済み"
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr "手動実行待ち"
+
+msgid "CiStatusText|blocked"
+msgstr "ブロック"
+
+msgid "CiStatusText|canceled"
+msgstr "キャンセル"
+
+msgid "CiStatusText|created"
+msgstr "作成済み"
+
+msgid "CiStatusText|failed"
+msgstr "失敗"
+
+msgid "CiStatusText|manual"
+msgstr "手動"
+
+msgid "CiStatusText|passed"
+msgstr "成功"
+
+msgid "CiStatusText|pending"
+msgstr "実行待ち"
+
+msgid "CiStatusText|skipped"
+msgstr "スキップ済み"
+
+msgid "CiStatus|running"
+msgstr "実行中"
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] "コミット"
+
+msgid "Commit duration in minutes for last 30 commits"
+msgstr "直近30コミットの所要時間(分)"
+
+msgid "Commit message"
+msgstr "コミットメッセージ"
+
+msgid "CommitBoxTitle|Commit"
+msgstr "コミット"
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr "%{file_name} を追加"
+
+msgid "Commits"
+msgstr "コミット"
+
+msgid "Commits feed"
+msgstr "コミットフィード"
+
+msgid "Commits|History"
+msgstr "履歴"
+
+msgid "Committed by"
+msgstr "コミット担当者: "
+
+msgid "Compare"
+msgstr "比較"
+
+msgid "Contribution guide"
+msgstr "貢献者向けガイド"
+
+msgid "Contributors"
+msgstr "貢献者"
+
+msgid "Copy URL to clipboard"
+msgstr "クリップボードにURLをコピー"
+
+msgid "Copy commit SHA to clipboard"
+msgstr "コミットのSHAをクリップボードにコピー"
+
+msgid "Create New Directory"
+msgstr "新規ディレクトリを作成"
+
+msgid ""
+"Create a personal access token on your account to pull or push via "
+"%{protocol}."
+msgstr "%{protocol} でプッシュやプルするためのあなた個人用アクセストークンを作成"
+
+msgid "Create directory"
+msgstr "ディレクトリを作成"
+
+msgid "Create empty bare repository"
+msgstr "空のbareレポジトリーを作成"
+
+msgid "Create merge request"
+msgstr "マージリクエストを作成"
+
+msgid "Create new..."
+msgstr "新規作成"
+
+msgid "CreateNewFork|Fork"
+msgstr "フォーク"
+
+msgid "CreateTag|Tag"
+msgstr "タグ"
+
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr "個人用アクセストークンを作成"
+
+msgid "Cron Timezone"
+msgstr "Cron のタイムゾーン"
+
+msgid "Cron syntax"
+msgstr "Cron の構文"
+
+msgid "Custom notification events"
+msgstr "カスタム通知設定"
+
+msgid ""
+"Custom notification levels are the same as participating levels. With custom "
+"notification levels you will also receive notifications for select events. "
+"To find out more, check out %{notification_link}."
+msgstr ""
+"\"カスタム\" の通知レベルの基本は \"参加\" "
+"と同じです。また、カスタム通知に設定することで選択したカスタムイベントの通知を受け取ることもできます。もっと詳しく知りたい場合は "
+"%{notification_link} を見てください。"
+
+msgid "Cycle Analytics"
+msgstr "サイクル分析"
+
+msgid ""
+"Cycle Analytics gives an overview of how much time it takes to go from idea "
+"to production in your project."
+msgstr ""
+"サイクル分析により、あなたのプロジェクトがアイディアの段階からプロダクション環境にリリースされるまでどれぐらい時間がかかったか俯瞰することができます。"
+
+msgid "CycleAnalyticsStage|Code"
+msgstr "コード"
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr "課題"
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr "計画"
+
+msgid "CycleAnalyticsStage|Production"
+msgstr "プロダクション"
+
+msgid "CycleAnalyticsStage|Review"
+msgstr "レビュー"
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr "ステージング"
+
+msgid "CycleAnalyticsStage|Test"
+msgstr "テスト"
+
+msgid "Define a custom pattern with cron syntax"
+msgstr "Cron 構文でカスタムなパターンを指定する"
+
+msgid "Delete"
+msgstr "削除"
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] "デプロイ"
+
+msgid "Description"
+msgstr "説明"
+
+msgid "Directory name"
+msgstr "ディレクトリ名"
+
+msgid "Don't show again"
+msgstr "次回から表示しない"
+
+msgid "Download"
+msgstr "ダウンロード"
+
+msgid "Download tar"
+msgstr "tar形式でダウンロード"
+
+msgid "Download tar.bz2"
+msgstr "tar.bz2形式でダウンロード"
+
+msgid "Download tar.gz"
+msgstr "tar.gz形式でダウンロード"
+
+msgid "Download zip"
+msgstr "zip形式でダウンロード"
+
+msgid "DownloadArtifacts|Download"
+msgstr "ダウンロード"
+
+msgid "DownloadCommit|Email Patches"
+msgstr "パッチをメールで送信"
+
+msgid "DownloadCommit|Plain Diff"
+msgstr "プレーン差分"
+
+msgid "DownloadSource|Download"
+msgstr "ダウンロード"
+
+msgid "Edit"
+msgstr "編集"
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr "パイプラインスケジュール %{id} を編集"
+
+msgid "Every day (at 4:00am)"
+msgstr "毎日 (午前4:00)"
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr "毎月 (1日の午前4:00)"
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr "毎週 (日曜日の午前4:00)"
+
+msgid "Failed to change the owner"
+msgstr "オーナーを変更できませんでした"
+
+msgid "Failed to remove the pipeline schedule"
+msgstr "パイプラインスケジュールを削除できませんでした"
+
+msgid "Files"
+msgstr "ファイル"
+
+msgid "Filter by commit message"
+msgstr "コミットメッセージで絞り込み"
+
+msgid "Find by path"
+msgstr "パスで検索"
+
+msgid "Find file"
+msgstr "ファイルを検索"
+
+msgid "FirstPushedBy|First"
+msgstr "初回"
+
+msgid "FirstPushedBy|pushed by"
+msgstr "プッシュした人"
+
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] "フォーク"
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr "フォーク元"
+
+msgid "From issue creation until deploy to production"
+msgstr "課題が登録されてからプロダクションにデプロイされるまで"
+
+msgid "From merge request merge until deploy to production"
+msgstr "マージリクエストがマージされてからプロダクションにデプロイされるまで"
+
+msgid "Go to your fork"
+msgstr "自分のフォークへ移動"
+
+msgid "GoToYourFork|Fork"
+msgstr "フォーク"
+
+msgid "Home"
+msgstr "ホーム"
+
+msgid "Housekeeping successfully started"
+msgstr "ハウスキーピングは正常に起動しました。"
+
+msgid "Import repository"
+msgstr "レポジトリーをインポート"
+
+msgid "Interval Pattern"
+msgstr "間隔のパターン"
+
+msgid "Introducing Cycle Analytics"
+msgstr "サイクル分析のご紹介"
+
+msgid "Jobs for last month"
+msgstr "先月のジョブ"
+
+msgid "Jobs for last week"
+msgstr "先週のジョブ"
+
+msgid "Jobs for last year"
+msgstr "昨年のジョブ"
+
+msgid "LFSStatus|Disabled"
+msgstr "無効"
+
+msgid "LFSStatus|Enabled"
+msgstr "有効"
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] "過去%d日間"
+
+msgid "Last Pipeline"
+msgstr "最新パイプライン"
+
+msgid "Last Update"
+msgstr "最新アップデート"
+
+msgid "Last commit"
+msgstr "最新コミット"
+
+msgid "Learn more in the"
+msgstr "詳しく見る:"
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr "詳しくはパイプラインスケジュールのドキュメントを参照"
+
+msgid "Leave group"
+msgstr "グループを離脱"
+
+msgid "Leave project"
+msgstr "プロジェクトを離脱"
+
+msgid "Limited to showing %d event at most"
+msgid_plural "Limited to showing %d events at most"
+msgstr[0] "イベント表示数を最大 %d 個に制限"
+
+msgid "Median"
+msgstr "中央値"
+
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr "SSH 鍵を追加"
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] "新規課題"
+
+msgid "New Pipeline Schedule"
+msgstr "新規パイプラインスケジュール"
+
+msgid "New branch"
+msgstr "新規ブランチ"
+
+msgid "New directory"
+msgstr "新規ディレクトリ"
+
+msgid "New file"
+msgstr "新規ファイル"
+
+msgid "New issue"
+msgstr "新規課題"
+
+msgid "New merge request"
+msgstr "新規マージリクエスト"
+
+msgid "New schedule"
+msgstr "新規スケジュール"
+
+msgid "New snippet"
+msgstr "新規スニペット"
+
+msgid "New tag"
+msgstr "新規タグ"
+
+msgid "No repository"
+msgstr "レポジトリーはありません"
+
+msgid "No schedules"
+msgstr "スケジュールなし"
+
+msgid "Not available"
+msgstr "利用できません"
+
+msgid "Not enough data"
+msgstr "データ不足"
+
+msgid "Notification events"
+msgstr "イベント通知"
+
+msgid "NotificationEvent|Close issue"
+msgstr "課題をクローズ"
+
+msgid "NotificationEvent|Close merge request"
+msgstr "マージリクエストをクローズ"
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr "パイプラインに失敗"
+
+msgid "NotificationEvent|Merge merge request"
+msgstr "マージリクエストをマージ"
+
+msgid "NotificationEvent|New issue"
+msgstr "新規課題"
+
+msgid "NotificationEvent|New merge request"
+msgstr "新規マージリクエスト"
+
+msgid "NotificationEvent|New note"
+msgstr "新規ノート"
+
+msgid "NotificationEvent|Reassign issue"
+msgstr "課題の担当者を変更"
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr "マージリクエスト担当者を変更"
+
+msgid "NotificationEvent|Reopen issue"
+msgstr "課題を再オープン"
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr "パイプライン成功"
+
+msgid "NotificationLevel|Custom"
+msgstr "カスタム"
+
+msgid "NotificationLevel|Disabled"
+msgstr "無効"
+
+msgid "NotificationLevel|Global"
+msgstr "全体設定"
+
+msgid "NotificationLevel|On mention"
+msgstr "メンション時"
+
+msgid "NotificationLevel|Participate"
+msgstr "参加"
+
+msgid "NotificationLevel|Watch"
+msgstr "すべて通知"
+
+msgid "OfSearchInADropdown|Filter"
+msgstr "フィルター"
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr "オープンされたのは"
+
+msgid "Options"
+msgstr "オプション"
+
+msgid "Owner"
+msgstr "オーナー"
+
+msgid "Pipeline"
+msgstr "パイプライン"
+
+msgid "Pipeline Health"
+msgstr "パイプラインの進捗状況"
+
+msgid "Pipeline Schedule"
+msgstr "パイプラインスケジュール"
+
+msgid "Pipeline Schedules"
+msgstr "パイプラインスケジュール"
+
+msgid "PipelineCharts|Failed:"
+msgstr "失敗:"
+
+msgid "PipelineCharts|Overall statistics"
+msgstr "全体統計"
+
+msgid "PipelineCharts|Success ratio:"
+msgstr "成功比率:"
+
+msgid "PipelineCharts|Successful:"
+msgstr "成功:"
+
+msgid "PipelineCharts|Total:"
+msgstr "合計:"
+
+msgid "PipelineSchedules|Activated"
+msgstr "アクティブ"
+
+msgid "PipelineSchedules|Active"
+msgstr "アクティブ"
+
+msgid "PipelineSchedules|All"
+msgstr "全件"
+
+msgid "PipelineSchedules|Inactive"
+msgstr "無効"
+
+msgid "PipelineSchedules|Next Run"
+msgstr "次の実行"
+
+msgid "PipelineSchedules|None"
+msgstr "なし"
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr "このパイプラインについて簡単に記述してください。"
+
+msgid "PipelineSchedules|Take ownership"
+msgstr "権限を取得する"
+
+msgid "PipelineSchedules|Target"
+msgstr "ターゲット"
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr "カスタム"
+
+msgid "Pipelines"
+msgstr "パイプライン"
+
+msgid "Pipelines charts"
+msgstr "パイプラインチャート"
+
+msgid "Pipeline|all"
+msgstr "全件"
+
+msgid "Pipeline|success"
+msgstr "成功"
+
+msgid "Pipeline|with stage"
+msgstr "ステージあり"
+
+msgid "Pipeline|with stages"
+msgstr "ステージあり"
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr "'%{project_name}' プロジェクトは削除処理待ちです。"
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr "'%{project_name}' プロジェクトは正常に作成されました。"
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr "'%{project_name}' プロジェクトは正常に更新されました。"
+
+msgid "Project '%{project_name}' will be deleted."
+msgstr "'%{project_name}' プロジェクトは削除されます。"
+
+msgid "Project access must be granted explicitly to each user."
+msgstr "ユーザーごとにプロジェクトアクセスの権限を指定しなければなりません。"
+
+msgid "Project export could not be deleted."
+msgstr "プロジェクトのエクスポートを削除できませんでした。"
+
+msgid "Project export has been deleted."
+msgstr "プロジェクトのエクスポートを削除しました。"
+
+msgid ""
+"Project export link has expired. Please generate a new export from your "
+"project settings."
+msgstr "プロジェクトのエクスポートリンクは期限切れになりました。プロジェクト設定にて新しくエクスポートリンクを作成してください。"
+
+msgid "Project export started. A download link will be sent by email."
+msgstr "プロジェクトのエクスポートを開始しました。ダウンロードのリンクはメールで送信します"
+
+msgid "Project home"
+msgstr "プロジェクトホーム"
+
+msgid "ProjectFeature|Disabled"
+msgstr "無効"
+
+msgid "ProjectFeature|Everyone with access"
+msgstr "アクセス権限を持っている人"
+
+msgid "ProjectFeature|Only team members"
+msgstr "チームメンバーのみ"
+
+msgid "ProjectFileTree|Name"
+msgstr "名前"
+
+msgid "ProjectLastActivity|Never"
+msgstr "記録なし"
+
+msgid "ProjectLifecycle|Stage"
+msgstr "ステージ"
+
+msgid "ProjectNetworkGraph|Graph"
+msgstr "ネットワークグラフ"
+
+msgid "Read more"
+msgstr "続きを読む"
+
+msgid "Readme"
+msgstr "Readme"
+
+msgid "RefSwitcher|Branches"
+msgstr "ブランチ"
+
+msgid "RefSwitcher|Tags"
+msgstr "タグ"
+
+msgid "Related Commits"
+msgstr "関連するコミット"
+
+msgid "Related Deployed Jobs"
+msgstr "関連するデプロイ済ジョブ"
+
+msgid "Related Issues"
+msgstr "関連する課題"
+
+msgid "Related Jobs"
+msgstr "関連するジョブ"
+
+msgid "Related Merge Requests"
+msgstr "関連するマージリクエスト"
+
+msgid "Related Merged Requests"
+msgstr "関連するマージリクエスト"
+
+msgid "Remind later"
+msgstr "後で通知"
+
+msgid "Remove project"
+msgstr "プロジェクトを削除"
+
+msgid "Request Access"
+msgstr "アクセス権限をリクエストする"
+
+msgid "Revert this commit"
+msgstr "このコミットをリバート"
+
+msgid "Revert this merge request"
+msgstr "このマージリクエストをリバート"
+
+msgid "Save pipeline schedule"
+msgstr "パイプラインスケジュールを保存"
+
+msgid "Schedule a new pipeline"
+msgstr "新しいパイプラインのスケジュールを作成"
+
+msgid "Scheduling Pipelines"
+msgstr "パイプラインスケジューリング"
+
+msgid "Search branches and tags"
+msgstr "ブランチまたはタグを検索"
+
+msgid "Select Archive Format"
+msgstr "アーカイブのフォーマットを選択"
+
+msgid "Select a timezone"
+msgstr "タイムゾーンを選択"
+
+msgid "Select target branch"
+msgstr "ターゲットブランチを選択"
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr "%{protocol} プロコトル経由でプル、プッシュするためにアカウントのパスワードを設定。"
+
+msgid "Set up CI"
+msgstr "CI を設定"
+
+msgid "Set up Koding"
+msgstr "Koding を設定"
+
+msgid "Set up auto deploy"
+msgstr "自動デプロイを設定"
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr "パスワードを設定"
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] "%d のイベントを表示中"
+
+msgid "Source code"
+msgstr "ソースコード"
+
+msgid "StarProject|Star"
+msgstr "スターを付ける"
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr "この変更で %{new_merge_request} を作成する"
+
+msgid "Switch branch/tag"
+msgstr "ブランチ・タグ切り替え"
+
+msgid "Tag"
+msgid_plural "Tags"
+msgstr[0] "タグ"
+
+msgid "Tags"
+msgstr "タグ"
+
+msgid "Target Branch"
+msgstr "ターゲットブランチ"
+
+msgid ""
+"The coding stage shows the time from the first commit to creating the merge "
+"request. The data will automatically be added here once you create your "
+"first merge request."
+msgstr ""
+"コーディングステージでは、最初のコミットからマージリクエストが作成されるまでの時間が表示されます。このデータは最初のマージリクエストが作成されたときに自動的に追加されます。"
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr "このステージで計測データに追加されたイベントリスト"
+
+msgid "The fork relationship has been removed."
+msgstr "フォークのリレーションが削除されました。"
+
+msgid ""
+"The issue stage shows the time it takes from creating an issue to assigning "
+"the issue to a milestone, or add the issue to a list on your Issue Board. "
+"Begin creating issues to see data for this stage."
+msgstr ""
+"課題ステージでは、課題が登録されてからマイルストーンに割り当てられるか、課題ボードのリストに追加されるまでの時間が表示されます。このリストに表示するには課題を最初に作成してください。"
+
+msgid "The phase of the development lifecycle."
+msgstr "開発ライフサイクルの段階"
+
+msgid ""
+"The pipelines schedule runs pipelines in the future, repeatedly, for "
+"specific branches or tags. Those scheduled pipelines will inherit limited "
+"project access based on their associated user."
+msgstr ""
+"パイプラインスケジュールは指定のブランチまたはタグに対して自動的にパイプラインを実行します。計画済みパイプラインはそれらの紐付けられたユーザーのプロジェクトと同じ権限を継承します。"
+
+msgid ""
+"The planning stage shows the time from the previous step to pushing your "
+"first commit. This time will be added automatically once you push your first "
+"commit."
+msgstr ""
+"計画ステージでは、課題ステージに登録されてからプッシュされた最初のコミット時刻までの時間が表示されます。最初のコミットがプッシュされときに自動的に追加されます。"
+
+msgid ""
+"The production stage shows the total time it takes between creating an issue "
+"and deploying the code to production. The data will be automatically added "
+"once you have completed the full idea to production cycle."
+msgstr ""
+"プロダクションステージでは、課題が作成されてからプロダクションへデプロイされるまでの時間が表示されます。アイディアの時点からプロダクションまでの全ステージが完了したときに自動的に追加されます。"
+
+msgid "The project can be accessed by any logged in user."
+msgstr "プロジェクトは、ログインユーザーであれば誰でもアクセスできます。"
+
+msgid "The project can be accessed without any authentication."
+msgstr "プロジェクトは、ログインなしに誰でもアクセスできます。"
+
+msgid "The repository for this project does not exist."
+msgstr "このプロジェクトにレポジトリーはありません。"
+
+msgid ""
+"The review stage shows the time from creating the merge request to merging "
+"it. The data will automatically be added after you merge your first merge "
+"request."
+msgstr ""
+"レビューステージとは、マージリクエストを作成してからマージするまでの時間です。このデータは最初のマージリクエストがマージされたときに自動的に追加されます。"
+
+msgid ""
+"The staging stage shows the time between merging the MR and deploying code "
+"to the production environment. The data will be automatically added once you "
+"deploy to production for the first time."
+msgstr ""
+"ステージングステージでは、マージリクエストがマージされてからコードがプロダクション環境にデプロイされるまでの時間が表示されます。このデータは最初にプロダクションにデプロイしたときに自動的に追加されます。"
+
+msgid ""
+"The testing stage shows the time GitLab CI takes to run every pipeline for "
+"the related merge request. The data will automatically be added after your "
+"first pipeline finishes running."
+msgstr ""
+"テスティングステージでは、GitLab CI "
+"が関連するマージリクエストの各パイプラインを実行する時間が表示されます。このデータは最初のパイプラインが完了したときに自動的に追加されます。"
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr "このステージに収集されたデータ毎の時間"
+
+msgid ""
+"The value lying at the midpoint of a series of observed values. E.g., "
+"between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 ="
+" 6."
+msgstr ""
+"得られた一連のデータを小さい順に並べたときに中央に位置する値。例えば、3, 5, 9の中央値は5。3, 5, 7, 8の中央値は (5+7)/2 = "
+"6。"
+
+msgid ""
+"This means you can not push code until you create an empty repository or "
+"import existing one."
+msgstr "空レポジトリーを作成または既存レポジトリーをインポートをしなければ、コードのプッシュはできません。"
+
+msgid "Time before an issue gets scheduled"
+msgstr "課題が計画されるまでの時間"
+
+msgid "Time before an issue starts implementation"
+msgstr "課題の実装が開始されるまでの時間"
+
+msgid "Time between merge request creation and merge/close"
+msgstr "マージリクエストが作成されてからマージまたはクローズされるまでの時間"
+
+msgid "Time until first merge request"
+msgstr "最初のマージリクエストまでの時間"
+
+msgid "Timeago|%s days ago"
+msgstr "%s日前"
+
+msgid "Timeago|%s days remaining"
+msgstr "残り %s日間"
+
+msgid "Timeago|%s hours remaining"
+msgstr "残り %s時間"
+
+msgid "Timeago|%s minutes ago"
+msgstr "%s分前"
+
+msgid "Timeago|%s minutes remaining"
+msgstr "残り %s分間"
+
+msgid "Timeago|%s months ago"
+msgstr "%sヶ月前"
+
+msgid "Timeago|%s months remaining"
+msgstr "残り %sヶ月"
+
+msgid "Timeago|%s seconds remaining"
+msgstr "残り %s 秒"
+
+msgid "Timeago|%s weeks ago"
+msgstr "%s週間前"
+
+msgid "Timeago|%s weeks remaining"
+msgstr "残り %s週間"
+
+msgid "Timeago|%s years ago"
+msgstr "%s年前"
+
+msgid "Timeago|%s years remaining"
+msgstr "残り %s年間"
+
+msgid "Timeago|1 day remaining"
+msgstr "残り 1日間"
+
+msgid "Timeago|1 hour remaining"
+msgstr "残り 1時間"
+
+msgid "Timeago|1 minute remaining"
+msgstr "残り 1分間"
+
+msgid "Timeago|1 month remaining"
+msgstr "残り 1ヶ月"
+
+msgid "Timeago|1 week remaining"
+msgstr "残り 1週間"
+
+msgid "Timeago|1 year remaining"
+msgstr "残り 1年間"
+
+msgid "Timeago|Past due"
+msgstr "期限オーバー"
+
+msgid "Timeago|a day ago"
+msgstr "1日前"
+
+msgid "Timeago|a month ago"
+msgstr "1ヶ月前"
+
+msgid "Timeago|a week ago"
+msgstr "1週間前"
+
+msgid "Timeago|a while"
+msgstr "しばらく前"
+
+msgid "Timeago|a year ago"
+msgstr "1年前"
+
+msgid "Timeago|about %s hours ago"
+msgstr "約%s時間前"
+
+msgid "Timeago|about a minute ago"
+msgstr "約1分間前"
+
+msgid "Timeago|about an hour ago"
+msgstr "約1時間前"
+
+msgid "Timeago|in %s days"
+msgstr "%s日間以内"
+
+msgid "Timeago|in %s hours"
+msgstr "%s時間以内"
+
+msgid "Timeago|in %s minutes"
+msgstr "%s分間以内"
+
+msgid "Timeago|in %s months"
+msgstr "%sヶ月以内"
+
+msgid "Timeago|in %s seconds"
+msgstr "%s秒以内"
+
+msgid "Timeago|in %s weeks"
+msgstr "%s週間以内"
+
+msgid "Timeago|in %s years"
+msgstr "%s年間以内"
+
+msgid "Timeago|in 1 day"
+msgstr "1日以内"
+
+msgid "Timeago|in 1 hour"
+msgstr "1時間以内"
+
+msgid "Timeago|in 1 minute"
+msgstr "1分以内"
+
+msgid "Timeago|in 1 month"
+msgstr "1ヶ月以内"
+
+msgid "Timeago|in 1 week"
+msgstr "1週間以内"
+
+msgid "Timeago|in 1 year"
+msgstr "1年以内"
+
+msgid "Timeago|less than a minute ago"
+msgstr "1分未満"
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] "時間"
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] "分"
+
+msgid "Time|s"
+msgstr "秒"
+
+msgid "Total Time"
+msgstr "合計時間"
+
+msgid "Total test time for all commits/merges"
+msgstr "すべてのコミット/マージの合計テスト時間"
+
+msgid "Unstar"
+msgstr "スターを外す"
+
+msgid "Upload New File"
+msgstr "新規ファイルをアップロード"
+
+msgid "Upload file"
+msgstr "ファイルをアップロード"
+
+msgid "UploadLink|click to upload"
+msgstr "クリックしてアップロード"
+
+msgid "Use your global notification setting"
+msgstr "全体通知設定を利用"
+
+msgid "View open merge request"
+msgstr "オープンなマージリクエストを表示"
+
+msgid "VisibilityLevel|Internal"
+msgstr "内部"
+
+msgid "VisibilityLevel|Private"
+msgstr "プライベート"
+
+msgid "VisibilityLevel|Public"
+msgstr "パブリック"
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr "このデータを参照したいですか?アクセスするには管理者に問い合わせてください。"
+
+msgid "We don't have enough data to show this stage."
+msgstr "データ不足のため、このステージの表示はできません。"
+
+msgid "Withdraw Access Request"
+msgstr "アクセスリクエストを取り消す"
+
+msgid ""
+"You are going to remove %{project_name_with_namespace}.\n"
+"Removed project CANNOT be restored!\n"
+"Are you ABSOLUTELY sure?"
+msgstr ""
+"%{project_name_with_namespace} プロジェクトを削除しようとしています。\n"
+"削除されたプロジェクトは絶対に元には戻せません!\n"
+"本当によろしいですか?"
+
+msgid ""
+"You are going to remove the fork relationship to source project "
+"%{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr "元のプロジェクト (%{forked_from_project}) とのリレーションを削除しようとしています。\n"
+"本当によろしいですか?"
+
+msgid ""
+"You are going to transfer %{project_name_with_namespace} to another owner. "
+"Are you ABSOLUTELY sure?"
+msgstr "%{project_name_with_namespace} プロジェクトを別のオーナーに移譲しようとしています。本当によろしいですか?"
+
+msgid "You can only add files when you are on a branch"
+msgstr "ファイルを追加するには、どこかのブランチにいなければいけません"
+
+msgid "You have reached your project limit"
+msgstr "プロジェクト数の上限に達しています"
+
+msgid "You must sign in to star a project"
+msgstr "プロジェクトにスターをつけたい場合はログインしてください"
+
+msgid "You need permission."
+msgstr "権限が必要です"
+
+msgid "You will not get any notifications via email"
+msgstr "通知メールを送信しません"
+
+msgid "You will only receive notifications for the events you choose"
+msgstr "選択したイベントのみ通知します"
+
+msgid ""
+"You will only receive notifications for threads you have participated in"
+msgstr "参加したスレッドのみ通知します"
+
+msgid "You will receive notifications for any activity"
+msgstr "全てのアクティビティーを通知します"
+
+msgid ""
+"You will receive notifications only for comments in which you were "
+"@mentioned"
+msgstr "あなたが @mentioned でコメントされた時のみ通知します"
+
+msgid ""
+"You won't be able to pull or push project code via %{protocol} until you "
+"%{set_password_link} on your account"
+msgstr ""
+"%{set_password_link} でアカウントのパスワードがセットされていないので、プロジェクトに %{protocol} "
+"でソースコードをプッシュ、プルできません"
+
+msgid ""
+"You won't be able to pull or push project code via SSH until you "
+"%{add_ssh_key_link} to your profile"
+msgstr "%{add_ssh_key_link} をプロファイルに追加していないので、プロジェクトにソースコードをプッシュ、プルできません"
+
+msgid "Your name"
+msgstr "名前"
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] "日"
+
+msgid "new merge request"
+msgstr "新規マージリクエスト"
+
+msgid "notification emails"
+msgstr "メール通知"
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] "親"
+
diff --git a/locale/ja/gitlab.po.time_stamp b/locale/ja/gitlab.po.time_stamp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/locale/ja/gitlab.po.time_stamp
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 1ea39894bb8..c4918a4c920 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -6,20 +6,41 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-06-15 21:59-0500\n"
+"POT-Creation-Date: 2017-06-28 13:32+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2017-07-05 02:56-0400\n"
-"Last-Translator: Huang Tao <htve@outlook.com>\n"
-"Language-Team: Portuguese (Brazil)\n"
+"PO-Revision-Date: 2017-07-12 09:05-0400\n"
+"Last-Translator: Leandro Nunes dos Santos <leandronunes@gmail.com>\n"
+"Language-Team: Portuguese (Brazil) (https://translate.zanata.org/project/view/GitLab)\n"
"Language: pt-BR\n"
"X-Generator: Zanata 3.9.6\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural ""
+"%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+"%s commit adicional foi omitido para prevenir problemas de performance."
+msgstr[1] ""
+"%s commits adicionais foram omitidos para prevenir problemas de performance."
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] "%d commit"
+msgstr[1] "%d commits"
+
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} fez commit %{commit_timeago}"
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] "1 pipeline"
+msgstr[1] "%d pipelines"
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr "Uma coleção de gráficos sobre Integração Contínua"
+
msgid "About auto deploy"
msgstr "Sobre a implantação automática"
@@ -67,9 +88,24 @@ msgstr ""
"implantação automática, selecione um modelo de Yaml do GitLab CI e registre "
"suas mudanças. %{link_to_autodeploy_doc}"
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr "BranchSwitcherPlaceholder|Procurar por branches"
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr "BranchSwitcherTitle|Mudar de branch"
+
msgid "Branches"
msgstr "Branches"
+msgid "Browse Directory"
+msgstr "Navegar no Diretório"
+
+msgid "Browse File"
+msgstr "Pesquisar Arquivo"
+
+msgid "Browse Files"
+msgstr "Pesquisar Arquivos"
+
msgid "Browse files"
msgstr "Navegar pelos arquivos"
@@ -165,6 +201,9 @@ msgid_plural "Commits"
msgstr[0] "Commit"
msgstr[1] "Commits"
+msgid "Commit duration in minutes for last 30 commits"
+msgstr "Duração do commit em minutos para os últimos 30 commits"
+
msgid "Commit message"
msgstr "Mensagem de commit"
@@ -177,6 +216,9 @@ msgstr "Adicionar %{file_name}"
msgid "Commits"
msgstr "Commits"
+msgid "Commits feed"
+msgstr "Feed de commits"
+
msgid "Commits|History"
msgstr "Histórico"
@@ -201,6 +243,13 @@ msgstr "Copiar SHA do commit para a área de transferência"
msgid "Create New Directory"
msgstr "Criar Novo Diretório"
+msgid ""
+"Create a personal access token on your account to pull or push via "
+"%{protocol}."
+msgstr ""
+"Crie um token de acesso pessoal na sua conta para dar pull ou push via "
+"%{protocol}."
+
msgid "Create directory"
msgstr "Criar diretório"
@@ -219,6 +268,9 @@ msgstr "Fork"
msgid "CreateTag|Tag"
msgstr "Tag"
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr "CreateTokenToCloneLink|criar um token de acesso pessoal"
+
msgid "Cron Timezone"
msgstr "Fuso horário do cron"
@@ -340,6 +392,9 @@ msgstr "Erro ao excluir o agendamento do pipeline"
msgid "Files"
msgstr "Arquivos"
+msgid "Filter by commit message"
+msgstr "Filtrar por mensagem de commit"
+
msgid "Find by path"
msgstr "Localizar por caminho"
@@ -388,6 +443,15 @@ msgstr "Padrão de intervalo"
msgid "Introducing Cycle Analytics"
msgstr "Apresentando a Análise de Ciclo"
+msgid "Jobs for last month"
+msgstr "Jobs no último mês"
+
+msgid "Jobs for last week"
+msgstr "Jobs na última semana"
+
+msgid "Jobs for last year"
+msgstr "Jobs no último ano"
+
msgid "LFSStatus|Disabled"
msgstr "Desabilitado"
@@ -553,6 +617,21 @@ msgstr "Agendamento da Pipeline"
msgid "Pipeline Schedules"
msgstr "Agendamentos da Pipeline"
+msgid "PipelineCharts|Failed:"
+msgstr "PipelineCharts|Falhou:"
+
+msgid "PipelineCharts|Overall statistics"
+msgstr "PipelineCharts|Estatísticas gerais"
+
+msgid "PipelineCharts|Success ratio:"
+msgstr "PipelineCharts|Taxa de sucesso:"
+
+msgid "PipelineCharts|Successful:"
+msgstr "PipelineCharts|Sucesso:"
+
+msgid "PipelineCharts|Total:"
+msgstr "PipelineCharts|Total:"
+
msgid "PipelineSchedules|Activated"
msgstr "Ativado"
@@ -583,6 +662,18 @@ msgstr "Destino"
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr "Personalizado"
+msgid "Pipelines"
+msgstr "Pipelines"
+
+msgid "Pipelines charts"
+msgstr "Gráficos de pipelines"
+
+msgid "Pipeline|all"
+msgstr "Pipeline|todos"
+
+msgid "Pipeline|success"
+msgstr "Pipeline|sucesso"
+
msgid "Pipeline|with stage"
msgstr "com etapa"
@@ -713,10 +804,10 @@ msgstr "Selecionar fuso horário"
msgid "Select target branch"
msgstr "Selecionar branch de destino"
-msgid "Set a password on your account to pull or push via %{protocol}"
+msgid "Set a password on your account to pull or push via %{protocol}."
msgstr ""
"Defina uma senha para sua conta para aceitar ou entregar código via "
-"%{protocol}"
+"%{protocol}."
msgid "Set up CI"
msgstr "Configurar CI"
@@ -1032,9 +1123,15 @@ msgstr "Enviar Novo Arquivo"
msgid "Upload file"
msgstr "Enviar arquivo"
+msgid "UploadLink|click to upload"
+msgstr "UploadLink|clique para fazer upload"
+
msgid "Use your global notification setting"
msgstr "Utilizar configuração de notificação global"
+msgid "View open merge request"
+msgstr "Ver merge request aberto"
+
msgid "VisibilityLevel|Internal"
msgstr "Interno"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
new file mode 100644
index 00000000000..4643bed98e2
--- /dev/null
+++ b/locale/ru/gitlab.po
@@ -0,0 +1,1233 @@
+# SAS <Stepanov.sa@bashkortostan.ru>, 2017. #zanata
+# Huang Tao <htve@outlook.com>, 2017. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab 1.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-06-28 13:32+0200\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2017-07-11 05:13-0400\n"
+"Last-Translator: SAS <Stepanov.sa@bashkortostan.ru>\n"
+"Language-Team: Russian (https://translate.zanata.org/project/view/GitLab)\n"
+"Language: ru\n"
+"X-Generator: Zanata 3.9.6\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural ""
+"%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+"%s добавленный коммит был исключен для предотвращения проблем с "
+"производительностью."
+msgstr[1] ""
+"%s добавленные коммиты были исключены для предотвращения проблем с "
+"производительностью."
+msgstr[2] ""
+"%s добавленные коммиты были исключены для предотвращения проблем с "
+"производительностью."
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] "%d коммит"
+msgstr[1] "%d коммит(а|ов)"
+msgstr[2] "%d коммит(а|ов)"
+
+msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr "%{commit_author_link} закоммичено %{commit_timeago}"
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr "Автоматическое развертывание"
+
+msgid "Active"
+msgstr "Активный"
+
+msgid "Activity"
+msgstr "Активность"
+
+msgid "Add Changelog"
+msgstr "Добавить в журнал изменений"
+
+msgid "Add Contribution guide"
+msgstr "Добавить руководство для контрибьютеров"
+
+msgid "Add License"
+msgstr "Добавить лицензию"
+
+msgid "Add an SSH key to your profile to pull or push via SSH."
+msgstr ""
+"Добавьте ключ SSH в свой профиль, чтобы отправлять или получать код через "
+"SSH."
+
+msgid "Add new directory"
+msgstr "Добавить новую директорию"
+
+msgid "Archived project! Repository is read-only"
+msgstr "Архивный проект! Репозиторий доступен только для чтения"
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr "Вы действительно хотите удалить это расписание конвейера?"
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr "Приложить файл через drag &amp; drop или %{upload_link}"
+
+msgid "Branch"
+msgid_plural "Branches"
+msgstr[0] "Ветка"
+msgstr[1] "Ветки"
+msgstr[2] "Ветки"
+
+msgid ""
+"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, "
+"choose a GitLab CI Yaml template and commit your changes. "
+"%{link_to_autodeploy_doc}"
+msgstr ""
+"Ветка <strong>%{branch_name}</strong> создана. Для настройки автоматического "
+"развертывания выберете GitLab CI Yaml-шаблон и зафиксируйте изменения. "
+"%{link_to_autodeploy_doc}"
+
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr "BranchSwitcherPlaceholder|Поиск веток"
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr "BranchSwitcherTitle|Переключить ветку"
+
+msgid "Branches"
+msgstr "Ветки"
+
+msgid "Browse Directory"
+msgstr "Просмотр директории"
+
+msgid "Browse File"
+msgstr "Просмотр файла"
+
+msgid "Browse Files"
+msgstr "Просмотр файлов"
+
+msgid "Browse files"
+msgstr "Просмотр файлов"
+
+msgid "ByAuthor|by"
+msgstr "ByAuthor|по автору"
+
+msgid "CI configuration"
+msgstr "Настройка CI"
+
+msgid "Cancel"
+msgstr "Отмена"
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr "ChangeTypeActionLabel|Выбрать в ветке"
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr "ChangeTypeActionLabel|Отменить в ветке"
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr "ChangeTypeAction|Подобрать"
+
+msgid "ChangeTypeAction|Revert"
+msgstr "ChangeTypeAction|Отменить"
+
+msgid "Changelog"
+msgstr "Журнал изменений"
+
+msgid "Charts"
+msgstr "Графики"
+
+msgid "Cherry-pick this commit"
+msgstr "Подобрать в этом коммите"
+
+msgid "Cherry-pick this merge request"
+msgstr "Побрать в этом запросе на слияние"
+
+msgid "CiStatusLabel|canceled"
+msgstr "CiStatusLabel|отменено"
+
+msgid "CiStatusLabel|created"
+msgstr "CiStatusLabel|создано"
+
+msgid "CiStatusLabel|failed"
+msgstr "CiStatusLabel|неудачно"
+
+msgid "CiStatusLabel|manual action"
+msgstr "CiStatusLabel|ручное действие"
+
+msgid "CiStatusLabel|passed"
+msgstr "CiStatusLabel|пройдено"
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr "CiStatusLabel|пройдено с предупреждениями"
+
+msgid "CiStatusLabel|pending"
+msgstr "CiStatusLabel|в ожидании"
+
+msgid "CiStatusLabel|skipped"
+msgstr "CiStatusLabel|пропущено"
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr "CiStatusLabel|ожидание ручных действий"
+
+msgid "CiStatusText|blocked"
+msgstr "CiStatusText|блокировано"
+
+msgid "CiStatusText|canceled"
+msgstr "CiStatusText|отменено"
+
+msgid "CiStatusText|created"
+msgstr "CiStatusText|создано"
+
+msgid "CiStatusText|failed"
+msgstr "CiStatusText|неудачно"
+
+msgid "CiStatusText|manual"
+msgstr "CiStatusText|ручное"
+
+msgid "CiStatusText|passed"
+msgstr "CiStatusText|пройдено"
+
+msgid "CiStatusText|pending"
+msgstr "CiStatusText|в ожидании"
+
+msgid "CiStatusText|skipped"
+msgstr "CiStatusText|пропущено"
+
+msgid "CiStatus|running"
+msgstr "CiStatus|выполняется"
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] "Коммит"
+msgstr[1] "Коммиты"
+msgstr[2] "Коммиты"
+
+msgid "Commit duration in minutes for last 30 commits"
+msgstr ""
+
+msgid "Commit message"
+msgstr "Описание коммита"
+
+msgid "CommitBoxTitle|Commit"
+msgstr "CommitBoxTitle|Коммит"
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr "CommitMessage|Добавить %{file_name}"
+
+msgid "Commits"
+msgstr "Коммиты"
+
+msgid "Commits feed"
+msgstr ""
+
+msgid "Commits|History"
+msgstr "Commits|История"
+
+msgid "Committed by"
+msgstr "Коммит"
+
+msgid "Compare"
+msgstr "Сравнение"
+
+msgid "Contribution guide"
+msgstr "Руководство контрибьютора"
+
+msgid "Contributors"
+msgstr "Контрибьюторы"
+
+msgid "Copy URL to clipboard"
+msgstr "Копировать URL в буфер обмена"
+
+msgid "Copy commit SHA to clipboard"
+msgstr "Копировать SHA коммита в буфер обмена"
+
+msgid "Create New Directory"
+msgstr "Создать новую директорию"
+
+msgid ""
+"Create a personal access token on your account to pull or push via "
+"%{protocol}."
+msgstr ""
+
+msgid "Create directory"
+msgstr "Создать директорию"
+
+msgid "Create empty bare repository"
+msgstr "Создать пустой пустой репозиторий"
+
+msgid "Create merge request"
+msgstr "Создать запрос на объединение"
+
+msgid "Create new..."
+msgstr "Новый"
+
+msgid "CreateNewFork|Fork"
+msgstr "CreateNewFork|Форк"
+
+msgid "CreateTag|Tag"
+msgstr "CreateTag|Тэг"
+
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr ""
+
+msgid "Cron Timezone"
+msgstr "Временная зона Cron"
+
+msgid "Cron syntax"
+msgstr "Синтаксис Cron"
+
+msgid "Custom notification events"
+msgstr " Настраиваемые уведомления о событиях"
+
+msgid ""
+"Custom notification levels are the same as participating levels. With custom "
+"notification levels you will also receive notifications for select events. "
+"To find out more, check out %{notification_link}."
+msgstr ""
+"Настраиваемые уровни уведомлений аналогичны уровню уведомлений в "
+"соответствии с участием. С настраиваемыми уровнями уведомлений вы также "
+"будете получать уведомления о выбранных событиях. Чтобы узнать больше, "
+"посмотрите %{notification_link}."
+
+msgid "Cycle Analytics"
+msgstr "Аналитика цикла разработки"
+
+msgid ""
+"Cycle Analytics gives an overview of how much time it takes to go from idea "
+"to production in your project."
+msgstr ""
+
+msgid "CycleAnalyticsStage|Code"
+msgstr "CycleAnalyticsStage|Код"
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr "CycleAnalyticsStage|Обращение"
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Production"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Review"
+msgstr "CycleAnalyticsStage|Ревьюв"
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Test"
+msgstr ""
+
+msgid "Define a custom pattern with cron syntax"
+msgstr "Определить настраиваемый шаблон с синтаксисом cron"
+
+msgid "Delete"
+msgstr "Удалить"
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Description"
+msgstr "Описание"
+
+msgid "Directory name"
+msgstr "Наименование директории"
+
+msgid "Don't show again"
+msgstr "Не показывать снова"
+
+msgid "Download"
+msgstr "Загрузить"
+
+msgid "Download tar"
+msgstr "Загрузить tar"
+
+msgid "Download tar.bz2"
+msgstr "Загрузить tar.bz2"
+
+msgid "Download tar.gz"
+msgstr "Загрузить tar.gz"
+
+msgid "Download zip"
+msgstr "Загрузить zip"
+
+msgid "DownloadArtifacts|Download"
+msgstr "DownloadArtifacts|Загрузка"
+
+msgid "DownloadCommit|Email Patches"
+msgstr "DownloadCommit|Email-патчи"
+
+msgid "DownloadCommit|Plain Diff"
+msgstr "DownloadCommit|Plain Diff"
+
+msgid "DownloadSource|Download"
+msgstr "DownloadSource|Загрузка"
+
+msgid "Edit"
+msgstr "Редактировать"
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr "Изменить расписание конвейера %{id}"
+
+msgid "Every day (at 4:00am)"
+msgstr "Ежедневно (в 4:00)"
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr "Ежемесячно (каждое 1-е число в 4:00)"
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr "Еженедельно (по воскресениями в 4:00)"
+
+msgid "Failed to change the owner"
+msgstr "Не удалось изменить владельца"
+
+msgid "Failed to remove the pipeline schedule"
+msgstr "Не удалось удалить расписание конвейера"
+
+msgid "Files"
+msgstr "Файлы"
+
+msgid "Filter by commit message"
+msgstr "Фильтр по комментариями к коммитам"
+
+msgid "Find by path"
+msgstr "Поиск по пути"
+
+msgid "Find file"
+msgstr "Найти файл"
+
+msgid "FirstPushedBy|First"
+msgstr ""
+
+msgid "FirstPushedBy|pushed by"
+msgstr ""
+
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] "Форк"
+msgstr[1] "Форки"
+msgstr[2] "Форки"
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr "ForkedFromProjectPath|Форк от "
+
+msgid "From issue creation until deploy to production"
+msgstr ""
+
+msgid "From merge request merge until deploy to production"
+msgstr ""
+
+msgid "Go to your fork"
+msgstr "Перейти к вашему форку"
+
+msgid "GoToYourFork|Fork"
+msgstr "GoToYourFork|Форк"
+
+msgid "Home"
+msgstr "Домашняя"
+
+msgid "Housekeeping successfully started"
+msgstr "Очистка успешно запущена"
+
+msgid "Import repository"
+msgstr "Импорт репозитория"
+
+msgid "Interval Pattern"
+msgstr "Шаблон интервала"
+
+msgid "Introducing Cycle Analytics"
+msgstr ""
+
+msgid "Jobs for last month"
+msgstr ""
+
+msgid "Jobs for last week"
+msgstr ""
+
+msgid "Jobs for last year"
+msgstr ""
+
+msgid "LFSStatus|Disabled"
+msgstr "LFSStatus|Отключено"
+
+msgid "LFSStatus|Enabled"
+msgstr "LFSStatus|Включено"
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Last Pipeline"
+msgstr "Последний конвейер"
+
+msgid "Last Update"
+msgstr "Последнее обновление"
+
+msgid "Last commit"
+msgstr "Последний коммит"
+
+msgid "Learn more in the"
+msgstr "Узнайте больше в"
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr "Подробнее в|документации по расписаниям конвейеров"
+
+msgid "Leave group"
+msgstr "Покинуть группу"
+
+msgid "Leave project"
+msgstr "Покинуть проект"
+
+msgid "Limited to showing %d event at most"
+msgid_plural "Limited to showing %d events at most"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Median"
+msgstr "Медиана"
+
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr "MissingSSHKeyWarningLink|добавить ключ SSH"
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] "Новое обращение"
+msgstr[1] "Новые обращения"
+msgstr[2] "Новые обращения"
+
+msgid "New Pipeline Schedule"
+msgstr "Новое расписание конвейера"
+
+msgid "New branch"
+msgstr "Новая ветка"
+
+msgid "New directory"
+msgstr "Новая директория"
+
+msgid "New file"
+msgstr "Новый файл"
+
+msgid "New issue"
+msgstr "Новое обращение"
+
+msgid "New merge request"
+msgstr "Новый запрос на объединение"
+
+msgid "New schedule"
+msgstr "Новое расписание"
+
+msgid "New snippet"
+msgstr "Новый сниппет"
+
+msgid "New tag"
+msgstr "Новый тэг"
+
+msgid "No repository"
+msgstr "Нет репозитория"
+
+msgid "No schedules"
+msgstr "Нет расписания"
+
+msgid "Not available"
+msgstr ""
+
+msgid "Not enough data"
+msgstr ""
+
+msgid "Notification events"
+msgstr "Уведомления о событиях"
+
+msgid "NotificationEvent|Close issue"
+msgstr "NotificationEvent|Обращение закрыто"
+
+msgid "NotificationEvent|Close merge request"
+msgstr "Запрос на объединение закрыт"
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr "NotificationEvent|Неудача в конвейере"
+
+msgid "NotificationEvent|Merge merge request"
+msgstr "NotificationEvent|Объединить запрос на слияние"
+
+msgid "NotificationEvent|New issue"
+msgstr "NotificationEvent|Новое обращение"
+
+msgid "NotificationEvent|New merge request"
+msgstr "NotificationEvent|Новый запрос на слияние"
+
+msgid "NotificationEvent|New note"
+msgstr "NotificationEvent|Новая заметка"
+
+msgid "NotificationEvent|Reassign issue"
+msgstr "NotificationEvent|Переназначить обращение"
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr "NotificationEvent|Переназначить запрос на слияние"
+
+msgid "NotificationEvent|Reopen issue"
+msgstr "NotificationEvent|Переоткрыть обращение"
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr "NotificationEvent|Успешно в конвейере"
+
+msgid "NotificationLevel|Custom"
+msgstr "NotificationLevel|Настраиваемый"
+
+msgid "NotificationLevel|Disabled"
+msgstr "NotificationLevel|Отключено"
+
+msgid "NotificationLevel|Global"
+msgstr "NotificationLevel|Глобальный"
+
+msgid "NotificationLevel|On mention"
+msgstr "NotificationLevel|С упоминанием"
+
+msgid "NotificationLevel|Participate"
+msgstr "NotificationLevel|По участию"
+
+msgid "NotificationLevel|Watch"
+msgstr "NotificationLevel|Отслеживать"
+
+msgid "OfSearchInADropdown|Filter"
+msgstr "OfSearchInADropdown|Фильтр"
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr "OpenedNDaysAgo|Открыто"
+
+msgid "Options"
+msgstr "Настройки"
+
+msgid "Owner"
+msgstr "Владелец"
+
+msgid "Pipeline"
+msgstr "Конвейер"
+
+msgid "Pipeline Health"
+msgstr ""
+
+msgid "Pipeline Schedule"
+msgstr "Расписание конвейера"
+
+msgid "Pipeline Schedules"
+msgstr "Расписания конвейеров"
+
+msgid "PipelineCharts|Failed:"
+msgstr ""
+
+msgid "PipelineCharts|Overall statistics"
+msgstr ""
+
+msgid "PipelineCharts|Success ratio:"
+msgstr ""
+
+msgid "PipelineCharts|Successful:"
+msgstr ""
+
+msgid "PipelineCharts|Total:"
+msgstr ""
+
+msgid "PipelineSchedules|Activated"
+msgstr "PipelineSchedules|Активировано"
+
+msgid "PipelineSchedules|Active"
+msgstr "PipelineSchedules|Активно"
+
+msgid "PipelineSchedules|All"
+msgstr "PipelineSchedules|Все"
+
+msgid "PipelineSchedules|Inactive"
+msgstr "PipelineSchedules|Неактивно"
+
+msgid "PipelineSchedules|Next Run"
+msgstr "PipelineSchedules|Следующий запуск"
+
+msgid "PipelineSchedules|None"
+msgstr "PipelineSchedules|None"
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr "PipelineSchedules|Предоставьте краткое описание этого конвейера"
+
+msgid "PipelineSchedules|Take ownership"
+msgstr "PipelineSchedules|Стать владельцем"
+
+msgid "PipelineSchedules|Target"
+msgstr "PipelineSchedules|Цель"
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr "PipelineSheduleIntervalPattern|Настраиваемый"
+
+msgid "Pipelines"
+msgstr ""
+
+msgid "Pipelines charts"
+msgstr ""
+
+msgid "Pipeline|all"
+msgstr ""
+
+msgid "Pipeline|success"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr "Pipeline|со стадией"
+
+msgid "Pipeline|with stages"
+msgstr "Pipeline|со стадиями"
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr "Проект '%{project_name}' добавлен в очередь на удаление."
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr "Проект '%{project_name}' успешно создан."
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr "Проект '%{project_name}' успешно обновлен."
+
+msgid "Project '%{project_name}' will be deleted."
+msgstr "Проект '%{project_name}' удален."
+
+msgid "Project access must be granted explicitly to each user."
+msgstr "Доступ к проекту должен предоставляться явно каждому пользователю."
+
+msgid "Project export could not be deleted."
+msgstr "Невозможно удалить экспорт проекта."
+
+msgid "Project export has been deleted."
+msgstr "Экспорт проекта удален."
+
+msgid ""
+"Project export link has expired. Please generate a new export from your "
+"project settings."
+msgstr ""
+"Истек срок действия ссылки на проект. Создайте новый экспорт в ваших "
+"настройках проекта."
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+"Начат экспорт проекта. Ссылка для скачивания будет отправлена по электронной "
+"почте."
+
+msgid "Project home"
+msgstr "Домашняя страница проекта"
+
+msgid "ProjectFeature|Disabled"
+msgstr "ProjectFeature|Отключено"
+
+msgid "ProjectFeature|Everyone with access"
+msgstr "ProjectFeature|Все с доступом"
+
+msgid "ProjectFeature|Only team members"
+msgstr "ProjectFeature|Только члены команды"
+
+msgid "ProjectFileTree|Name"
+msgstr "ProjectFileTree|Имя"
+
+msgid "ProjectLastActivity|Never"
+msgstr "ProjectLastActivity|Никогда"
+
+msgid "ProjectLifecycle|Stage"
+msgstr ""
+
+msgid "ProjectNetworkGraph|Graph"
+msgstr "ProjectNetworkGraph|Граф"
+
+msgid "Read more"
+msgstr ""
+
+msgid "Readme"
+msgstr "Readme"
+
+msgid "RefSwitcher|Branches"
+msgstr "RefSwitcher|Ветки"
+
+msgid "RefSwitcher|Tags"
+msgstr "RefSwitcher|Тэги"
+
+msgid "Related Commits"
+msgstr ""
+
+msgid "Related Deployed Jobs"
+msgstr ""
+
+msgid "Related Issues"
+msgstr ""
+
+msgid "Related Jobs"
+msgstr ""
+
+msgid "Related Merge Requests"
+msgstr "Связанные запросы на слияние"
+
+msgid "Related Merged Requests"
+msgstr "Связанные объединенные запросы"
+
+msgid "Remind later"
+msgstr "Напомнить позже"
+
+msgid "Remove project"
+msgstr "Удалить проект"
+
+msgid "Request Access"
+msgstr "Запрос доступа"
+
+msgid "Revert this commit"
+msgstr "Отменить это изменение"
+
+msgid "Revert this merge request"
+msgstr "Отменить этот запрос на слияние"
+
+msgid "Save pipeline schedule"
+msgstr "Сохранить расписание конвейра"
+
+msgid "Schedule a new pipeline"
+msgstr "Расписание нового конвейера"
+
+msgid "Scheduling Pipelines"
+msgstr "Планирование конвейеров"
+
+msgid "Search branches and tags"
+msgstr "Найти ветки и тэги"
+
+msgid "Select Archive Format"
+msgstr "Выбрать формат архива"
+
+msgid "Select a timezone"
+msgstr "Выбор временной зоны"
+
+msgid "Select target branch"
+msgstr "Выбор целевой ветки"
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr ""
+"Установите пароль в своем аккаунте, чтобы отправлять или получать код через "
+"%{protocol}."
+
+msgid "Set up CI"
+msgstr "Настройка CI"
+
+msgid "Set up Koding"
+msgstr "Настройка Koding"
+
+msgid "Set up auto deploy"
+msgstr "Настройка автоматического развертывания"
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr "SetPasswordToCloneLink|установить пароль"
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Source code"
+msgstr "Исходный код"
+
+msgid "StarProject|Star"
+msgstr "StarProject|Отметить"
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr "Начать %{new_merge_request} с этих изменений"
+
+msgid "Switch branch/tag"
+msgstr "Переключить ветка/тэг"
+
+msgid "Tag"
+msgid_plural "Tags"
+msgstr[0] "Тэг"
+msgstr[1] "Тэги"
+msgstr[2] "Тэги"
+
+msgid "Tags"
+msgstr "Тэги"
+
+msgid "Target Branch"
+msgstr "Целевая ветка"
+
+msgid ""
+"The coding stage shows the time from the first commit to creating the merge "
+"request. The data will automatically be added here once you create your "
+"first merge request."
+msgstr ""
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr ""
+
+msgid "The fork relationship has been removed."
+msgstr "Связь форка удалена."
+
+msgid ""
+"The issue stage shows the time it takes from creating an issue to assigning "
+"the issue to a milestone, or add the issue to a list on your Issue Board. "
+"Begin creating issues to see data for this stage."
+msgstr ""
+"Стадия обращения время, которое потребуется с момента создания обращения до "
+"назначения обращению вехи, или добавления обращения в вашу доску обращений. "
+"Начните создавать обращения, чтобы увидеть сведения для этой стадии. "
+
+msgid "The phase of the development lifecycle."
+msgstr "Фаза жизненного цикла разработки."
+
+msgid ""
+"The pipelines schedule runs pipelines in the future, repeatedly, for "
+"specific branches or tags. Those scheduled pipelines will inherit limited "
+"project access based on their associated user."
+msgstr ""
+"Расписание конвейеров запускает в будущем неоднократно конвейеры, для "
+"определенных ветвей или тэгов. Запланированные конвейеры наследуют "
+"ограничения на доступ к проекту на основе связанного с ними пользователя."
+
+msgid ""
+"The planning stage shows the time from the previous step to pushing your "
+"first commit. This time will be added automatically once you push your first "
+"commit."
+msgstr ""
+
+msgid ""
+"The production stage shows the total time it takes between creating an issue "
+"and deploying the code to production. The data will be automatically added "
+"once you have completed the full idea to production cycle."
+msgstr ""
+
+msgid "The project can be accessed by any logged in user."
+msgstr "Доступ к проекту возможен любым зарегистрированным пользователем."
+
+msgid "The project can be accessed without any authentication."
+msgstr "Доступ к проекту возможен без какой-либо проверки подлинности."
+
+msgid "The repository for this project does not exist."
+msgstr "Репозиторий для этого проекта не существует."
+
+msgid ""
+"The review stage shows the time from creating the merge request to merging "
+"it. The data will automatically be added after you merge your first merge "
+"request."
+msgstr ""
+
+msgid ""
+"The staging stage shows the time between merging the MR and deploying code "
+"to the production environment. The data will be automatically added once you "
+"deploy to production for the first time."
+msgstr ""
+
+msgid ""
+"The testing stage shows the time GitLab CI takes to run every pipeline for "
+"the related merge request. The data will automatically be added after your "
+"first pipeline finishes running."
+msgstr ""
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr ""
+
+msgid ""
+"The value lying at the midpoint of a series of observed values. E.g., "
+"between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 ="
+" 6."
+msgstr ""
+
+msgid ""
+"This means you can not push code until you create an empty repository or "
+"import existing one."
+msgstr ""
+"Это означает, что вы не можете пушить код, пока не создадите пустой "
+"репозиторий или не импортируете существующий."
+
+msgid "Time before an issue gets scheduled"
+msgstr ""
+
+msgid "Time before an issue starts implementation"
+msgstr ""
+
+msgid "Time between merge request creation and merge/close"
+msgstr "Время между созданием запроса слияния и слиянием / закрытием"
+
+msgid "Time until first merge request"
+msgstr ""
+
+msgid "Timeago|%s days ago"
+msgstr "Timeago|%s дн(я|ей) назад"
+
+msgid "Timeago|%s days remaining"
+msgstr "Timeago|Осталось %s дн(я|ей)"
+
+msgid "Timeago|%s hours remaining"
+msgstr "Timeago|Осталось %s часов"
+
+msgid "Timeago|%s minutes ago"
+msgstr "Timeago|%s минут назад"
+
+msgid "Timeago|%s minutes remaining"
+msgstr "Timeago|Осталось %s минут(а|ы)"
+
+msgid "Timeago|%s months ago"
+msgstr "Timeago|%s минут(а|ы) назад"
+
+msgid "Timeago|%s months remaining"
+msgstr "Timeago|Осталось %s месяцев(а)"
+
+msgid "Timeago|%s seconds remaining"
+msgstr "Timeago|Осталось %s секунд(ы)"
+
+msgid "Timeago|%s weeks ago"
+msgstr "Timeago|%s недель(и) назад"
+
+msgid "Timeago|%s weeks remaining"
+msgstr "Timeago|Осталось %s недель(и)"
+
+msgid "Timeago|%s years ago"
+msgstr "Timeago|%s лет/года назад"
+
+msgid "Timeago|%s years remaining"
+msgstr "Timeago|Осталось %s лет/года"
+
+msgid "Timeago|1 day remaining"
+msgstr "Timeago|Остался день"
+
+msgid "Timeago|1 hour remaining"
+msgstr "Timeago|Остался час"
+
+msgid "Timeago|1 minute remaining"
+msgstr "Timeago|Осталась одна минута"
+
+msgid "Timeago|1 month remaining"
+msgstr "Timeago|Остался месяц"
+
+msgid "Timeago|1 week remaining"
+msgstr "Timeago|Осталась неделя"
+
+msgid "Timeago|1 year remaining"
+msgstr "Timeago|Остался год"
+
+msgid "Timeago|Past due"
+msgstr "Timeago|Просрочено"
+
+msgid "Timeago|a day ago"
+msgstr "Timeago|день назад"
+
+msgid "Timeago|a month ago"
+msgstr "Timeago|месяц назад"
+
+msgid "Timeago|a week ago"
+msgstr "Timeago|неделю назад"
+
+msgid "Timeago|a while"
+msgstr "Timeago|какое-то время"
+
+msgid "Timeago|a year ago"
+msgstr "Timeago|год назад"
+
+msgid "Timeago|about %s hours ago"
+msgstr "Timeago|около %s часов назад"
+
+msgid "Timeago|about a minute ago"
+msgstr "Timeago|около минуты назад"
+
+msgid "Timeago|about an hour ago"
+msgstr "Timeago|около часа назад"
+
+msgid "Timeago|in %s days"
+msgstr "Timeago|через %s дня(ей)"
+
+msgid "Timeago|in %s hours"
+msgstr "Timeago|через %s часа(ов)"
+
+msgid "Timeago|in %s minutes"
+msgstr "Timeago|через %s минут(ы)"
+
+msgid "Timeago|in %s months"
+msgstr "Timeago|через %s месяц(а|ев)"
+
+msgid "Timeago|in %s seconds"
+msgstr "Timeago|через %s секунд(ы)"
+
+msgid "Timeago|in %s weeks"
+msgstr "Timeago|через %s недели"
+
+msgid "Timeago|in %s years"
+msgstr "Timeago|через %s лет/года"
+
+msgid "Timeago|in 1 day"
+msgstr "Timeago|через день"
+
+msgid "Timeago|in 1 hour"
+msgstr "Timeago|через час"
+
+msgid "Timeago|in 1 minute"
+msgstr "Timeago|через минуту"
+
+msgid "Timeago|in 1 month"
+msgstr "Timeago|через месяц"
+
+msgid "Timeago|in 1 week"
+msgstr "Timeago|через неделю"
+
+msgid "Timeago|in 1 year"
+msgstr "Timeago|через год"
+
+msgid "Timeago|less than a minute ago"
+msgstr "Timeago|менее чем минуту назад"
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] "ч"
+msgstr[1] "ч"
+msgstr[2] "ч"
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] "мин"
+msgstr[1] "мин"
+msgstr[2] "мин"
+
+msgid "Time|s"
+msgstr "с"
+
+msgid "Total Time"
+msgstr "Общее время"
+
+msgid "Total test time for all commits/merges"
+msgstr ""
+
+msgid "Unstar"
+msgstr "Снять отметку"
+
+msgid "Upload New File"
+msgstr "Выгрузить новый файл"
+
+msgid "Upload file"
+msgstr "Выгрузить файл"
+
+msgid "UploadLink|click to upload"
+msgstr "UploadLink|кликните для выгрузки"
+
+msgid "Use your global notification setting"
+msgstr "Используются глобальный настройки уведомлений"
+
+msgid "View open merge request"
+msgstr "Просмотреть открытый запрос на слияние"
+
+msgid "VisibilityLevel|Internal"
+msgstr "VisibilityLevel|Ограниченный"
+
+msgid "VisibilityLevel|Private"
+msgstr "VisibilityLevel|Приватный"
+
+msgid "VisibilityLevel|Public"
+msgstr "VisibilityLevel|Публичный"
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr ""
+
+msgid "We don't have enough data to show this stage."
+msgstr ""
+
+msgid "Withdraw Access Request"
+msgstr "Отменить запрос доступа"
+
+msgid ""
+"You are going to remove %{project_name_with_namespace}.\n"
+"Removed project CANNOT be restored!\n"
+"Are you ABSOLUTELY sure?"
+msgstr ""
+"Вы хотите удалить %{project_name_with_namespace}.\n"
+"Удаленный проект НЕ МОЖЕТ быть восстановлен!\n"
+"Вы АБСОЛЮТНО уверены?"
+
+msgid ""
+"You are going to remove the fork relationship to source project "
+"%{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+"Вы собираетесь удалить связь форка с исходным проектом "
+"%{forked_from_project}. Вы АБСОЛЮТНО уверены?"
+
+msgid ""
+"You are going to transfer %{project_name_with_namespace} to another owner. "
+"Are you ABSOLUTELY sure?"
+msgstr ""
+"Вы собираетесь передать проект %{project_name_with_namespace} другому "
+"владельцу. Вы АБСОЛЮТНО уверены?"
+
+msgid "You can only add files when you are on a branch"
+msgstr "Вы можете добавлять только файлы, когда находитесь в ветке"
+
+msgid "You have reached your project limit"
+msgstr "Вы достигли ограничения в вашем проекте"
+
+msgid "You must sign in to star a project"
+msgstr "Необходимо войти, чтобы оценить проект"
+
+msgid "You need permission."
+msgstr "Вам нужно разрешение."
+
+msgid "You will not get any notifications via email"
+msgstr "Вы не получите никаких уведомлений по электронной почте"
+
+msgid "You will only receive notifications for the events you choose"
+msgstr "Вы будете получать уведомления только о выбранных вами событиях"
+
+msgid ""
+"You will only receive notifications for threads you have participated in"
+msgstr ""
+"Вы будете получать уведомления только о тех тредах, в которых вы участвовали"
+
+msgid "You will receive notifications for any activity"
+msgstr "Вы будете получать уведомления о любых действиях"
+
+msgid ""
+"You will receive notifications only for comments in which you were "
+"@mentioned"
+msgstr ""
+"Вы будете получать уведомления только для комментариев, в которых вы были "
+"@упомянуты"
+
+msgid ""
+"You won't be able to pull or push project code via %{protocol} until you "
+"%{set_password_link} on your account"
+msgstr ""
+"Вы не сможете получать и отправлять код проекта через %{protocol} пока "
+"%{set_password_link} в ваш аккаунт"
+
+msgid ""
+"You won't be able to pull or push project code via SSH until you "
+"%{add_ssh_key_link} to your profile"
+msgstr ""
+"Вы не сможете получать и отправлять код проекта через SSH пока "
+"%{add_ssh_key_link} в ваш профиль."
+
+msgid "Your name"
+msgstr "Ваше имя"
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] "день"
+msgstr[1] "дни"
+msgstr[2] "дни"
+
+msgid "new merge request"
+msgstr "новый запрос на слияние"
+
+msgid "notification emails"
+msgstr "email для уведомлений"
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] "источник"
+msgstr[1] "источники"
+msgstr[2] "источники"
+
diff --git a/locale/ru/gitlab.po.time_stamp b/locale/ru/gitlab.po.time_stamp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/locale/ru/gitlab.po.time_stamp
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 68114d149c4..39806901274 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -10,7 +10,7 @@ fi
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
-retry gem install knapsack fog-aws mime-types
+retry gem install knapsack
cp config/gitlab.yml.example config/gitlab.yml
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
index 8964d89b438..7b0976e3e67 100644
--- a/spec/controllers/metrics_controller_spec.rb
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -12,7 +12,7 @@ describe MetricsController do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- stub_env('prometheus_multiproc_dir', metrics_multiproc_dir)
+ allow(Prometheus::Client.configuration).to receive(:multiprocess_files_dir).and_return(metrics_multiproc_dir)
allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true)
allow(Settings.monitoring).to receive(:ip_whitelist).and_return([whitelisted_ip, whitelisted_ip_range])
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 22aad0b3225..1f9ca765233 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -7,14 +7,16 @@ describe Projects::IssuesController do
describe "GET #index" do
context 'external issue tracker' do
+ let!(:service) do
+ create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', project_url: 'http://test.com')
+ end
+
it 'redirects to the external issue tracker' do
- external = double(project_path: 'https://example.com/project')
- allow(project).to receive(:external_issue_tracker).and_return(external)
controller.instance_variable_set(:@project, project)
get :index, namespace_id: project.namespace, project_id: project
- expect(response).to redirect_to('https://example.com/project')
+ expect(response).to redirect_to(service.issue_tracker_path)
end
end
@@ -139,19 +141,21 @@ describe Projects::IssuesController do
end
context 'external issue tracker' do
+ let!(:service) do
+ create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', new_issue_url: 'http://test.com')
+ end
+
before do
sign_in(user)
project.team << [user, :developer]
end
it 'redirects to the external issue tracker' do
- external = double(new_issue_path: 'https://example.com/issues/new')
- allow(project).to receive(:external_issue_tracker).and_return(external)
controller.instance_variable_set(:@project, project)
get :new, namespace_id: project.namespace, project_id: project
- expect(response).to redirect_to('https://example.com/issues/new')
+ expect(response).to redirect_to('http://test.com')
end
end
end
diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb
index 36b9645438a..89e260cf65b 100644
--- a/spec/factories/commits.rb
+++ b/spec/factories/commits.rb
@@ -4,14 +4,19 @@ FactoryGirl.define do
factory :commit do
git_commit RepoHelpers.sample_commit
project factory: :empty_project
- author { build(:author) }
initialize_with do
new(git_commit, project)
end
+ after(:build) do |commit|
+ allow(commit).to receive(:author).and_return build(:author)
+ end
+
trait :without_author do
- author nil
+ after(:build) do |commit|
+ allow(commit).to receive(:author).and_return nil
+ end
end
end
end
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
index 1383420fb44..3222c41c3d8 100644
--- a/spec/factories/uploads.rb
+++ b/spec/factories/uploads.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
factory :upload do
model { build(:project) }
- path { "uploads/system/project/avatar/avatar.jpg" }
+ path { "uploads/-/system/project/avatar/avatar.jpg" }
size 100.kilobytes
uploader "AvatarUploader"
end
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb
index 1e2cb8569ec..b9e361328df 100644
--- a/spec/features/admin/admin_appearance_spec.rb
+++ b/spec/features/admin/admin_appearance_spec.rb
@@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do
end
def logo_selector
- '//img[@src^="/uploads/system/appearance/logo"]'
+ '//img[@src^="/uploads/-/system/appearance/logo"]'
end
def header_logo_selector
- '//img[@src^="/uploads/system/appearance/header_logo"]'
+ '//img[@src^="/uploads/-/system/appearance/header_logo"]'
end
def logo_fixture
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index 382d83ca051..81b0a2f541b 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -54,7 +54,8 @@ feature 'Member autocomplete', :js do
let(:note) { create(:note_on_commit, project: project, commit_id: project.commit.id) }
before do
- allow_any_instance_of(Commit).to receive(:author).and_return(author)
+ allow(User).to receive(:find_by_any_email)
+ .with(noteable.author_email.downcase).and_return(author)
visit project_commit_path(project, noteable)
end
diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
index 32784de1613..5843f18d89f 100644
--- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
@@ -18,7 +18,7 @@ feature 'User uploads avatar to group', feature: true do
visit group_path(group)
- expect(page).to have_selector(%Q(img[src$="/uploads/system/group/avatar/#{group.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[src$="/uploads/-/system/group/avatar/#{group.id}/dk.png"]))
# Cheating here to verify something that isn't user-facing, but is important
expect(group.reload.avatar.file).to exist
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index 82c356735b9..e8171dcaeb0 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -16,7 +16,7 @@ feature 'User uploads avatar to profile', feature: true do
visit user_path(user)
- expect(page).to have_selector(%Q(img[src$="/uploads/system/user/avatar/#{user.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[src$="/uploads/-/system/user/avatar/#{user.id}/dk.png"]))
# Cheating here to verify something that isn't user-facing, but is important
expect(user.reload.avatar.file).to exist
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index e0cad1da86a..f5e139685e8 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -59,13 +59,13 @@ describe ApplicationHelper do
describe 'project_icon' do
it 'returns an url for the avatar' do
project = create(:empty_project, avatar: File.open(uploaded_image_temp_path))
- avatar_url = "/uploads/system/project/avatar/#{project.id}/banana_sample.gif"
+ avatar_url = "/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon(project.full_path).to_s)
.to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)
- avatar_url = "#{gitlab_host}/uploads/system/project/avatar/#{project.id}/banana_sample.gif"
+ avatar_url = "#{gitlab_host}/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon(project.full_path).to_s)
.to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
@@ -88,7 +88,7 @@ describe ApplicationHelper do
context 'when there is a matching user' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon(user.email).to_s)
- .to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
context 'when an asset_host is set in the config' do
@@ -100,14 +100,14 @@ describe ApplicationHelper do
it 'returns an absolute URL on that asset host' do
expect(helper.avatar_icon(user.email, only_path: false).to_s)
- .to eq("#{asset_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{asset_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
context 'when only_path is set to false' do
it 'returns an absolute URL for the avatar' do
expect(helper.avatar_icon(user.email, only_path: false).to_s)
- .to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
@@ -120,7 +120,7 @@ describe ApplicationHelper do
it 'returns a relative URL with the correct prefix' do
expect(helper.avatar_icon(user.email).to_s)
- .to eq("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/gitlab/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
end
@@ -138,14 +138,14 @@ describe ApplicationHelper do
context 'when only_path is true' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon(user, only_path: true).to_s)
- .to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
context 'when only_path is false' do
it 'returns an absolute URL for the avatar' do
expect(helper.avatar_icon(user, only_path: false).to_s)
- .to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
end
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index c68e4f56b05..2390c1f3e5d 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -52,7 +52,7 @@ describe EmailsHelper do
)
expect(header_logo).to eq(
- %{<img style="height: 50px" src="/uploads/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
+ %{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
)
end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index e3f9d9db9eb..3a246f10283 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -11,7 +11,7 @@ describe GroupsHelper do
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
expect(group_icon(group.path).to_s)
- .to match("/uploads/system/group/avatar/#{group.id}/banana_sample.gif")
+ .to match("/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif")
end
it 'gives default avatar_icon when no avatar is present' do
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index 95b4032616e..9aca3987657 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -60,7 +60,7 @@ describe PageLayoutHelper do
%w(project user group).each do |type|
context "with @#{type} assigned" do
it "uses #{type.titlecase} avatar if available" do
- object = double(avatar_url: 'http://example.com/uploads/system/avatar.png')
+ object = double(avatar_url: 'http://example.com/uploads/-/system/avatar.png')
assign(type, object)
expect(helper.page_image).to eq object.avatar_url
diff --git a/spec/javascripts/lib/utils/poll_spec.js b/spec/javascripts/lib/utils/poll_spec.js
index 22f30191ab9..2aa7011ca51 100644
--- a/spec/javascripts/lib/utils/poll_spec.js
+++ b/spec/javascripts/lib/utils/poll_spec.js
@@ -25,23 +25,28 @@ function mockServiceCall(service, response, shouldFail = false) {
describe('Poll', () => {
const service = jasmine.createSpyObj('service', ['fetch']);
- const callbacks = jasmine.createSpyObj('callbacks', ['success', 'error']);
+ const callbacks = jasmine.createSpyObj('callbacks', ['success', 'error', 'notification']);
+
+ function setup() {
+ return new Poll({
+ resource: service,
+ method: 'fetch',
+ successCallback: callbacks.success,
+ errorCallback: callbacks.error,
+ notificationCallback: callbacks.notification,
+ }).makeRequest();
+ }
afterEach(() => {
callbacks.success.calls.reset();
callbacks.error.calls.reset();
+ callbacks.notification.calls.reset();
service.fetch.calls.reset();
});
it('calls the success callback when no header for interval is provided', (done) => {
mockServiceCall(service, { status: 200 });
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest();
+ setup();
waitForAllCallsToFinish(service, 1, () => {
expect(callbacks.success).toHaveBeenCalled();
@@ -51,15 +56,9 @@ describe('Poll', () => {
});
});
- it('calls the error callback whe the http request returns an error', (done) => {
+ it('calls the error callback when the http request returns an error', (done) => {
mockServiceCall(service, { status: 500 }, true);
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest();
+ setup();
waitForAllCallsToFinish(service, 1, () => {
expect(callbacks.success).not.toHaveBeenCalled();
@@ -69,15 +68,22 @@ describe('Poll', () => {
});
});
+ it('skips the error callback when request is aborted', (done) => {
+ mockServiceCall(service, { status: 0 }, true);
+ setup();
+
+ waitForAllCallsToFinish(service, 1, () => {
+ expect(callbacks.success).not.toHaveBeenCalled();
+ expect(callbacks.error).not.toHaveBeenCalled();
+ expect(callbacks.notification).toHaveBeenCalled();
+
+ done();
+ });
+ });
+
it('should call the success callback when the interval header is -1', (done) => {
mockServiceCall(service, { status: 200, headers: { 'poll-interval': -1 } });
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest().then(() => {
+ setup().then(() => {
expect(callbacks.success).toHaveBeenCalled();
expect(callbacks.error).not.toHaveBeenCalled();
diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js
index 1c3188cdda2..d5754aaa9e7 100644
--- a/spec/javascripts/vue_shared/components/commit_spec.js
+++ b/spec/javascripts/vue_shared/components/commit_spec.js
@@ -22,7 +22,7 @@ describe('Commit component', () => {
shortSha: 'b7836edd',
title: 'Commit message',
author: {
- avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png',
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
web_url: 'https://gitlab.com/jschatz1',
path: '/jschatz1',
username: 'jschatz1',
@@ -45,7 +45,7 @@ describe('Commit component', () => {
shortSha: 'b7836edd',
title: 'Commit message',
author: {
- avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png',
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
web_url: 'https://gitlab.com/jschatz1',
path: '/jschatz1',
username: 'jschatz1',
diff --git a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
new file mode 100644
index 00000000000..a910fb105a5
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::MigrateSystemUploadsToNewFolder do
+ let(:migration) { described_class.new }
+
+ before do
+ allow(migration).to receive(:logger).and_return(Logger.new(nil))
+ end
+
+ describe '#perform' do
+ it 'renames the path of system-uploads', truncate: true do
+ upload = create(:upload, model: create(:empty_project), path: 'uploads/system/project/avatar.jpg')
+
+ migration.perform('uploads/system/', 'uploads/-/system/')
+
+ expect(upload.reload.path).to eq('uploads/-/system/project/avatar.jpg')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cache/request_cache_spec.rb b/spec/lib/gitlab/cache/request_cache_spec.rb
new file mode 100644
index 00000000000..5b82c216a13
--- /dev/null
+++ b/spec/lib/gitlab/cache/request_cache_spec.rb
@@ -0,0 +1,133 @@
+require 'spec_helper'
+
+describe Gitlab::Cache::RequestCache do
+ let(:klass) do
+ Class.new do
+ extend Gitlab::Cache::RequestCache
+
+ attr_accessor :id, :name, :result, :extra
+
+ def self.name
+ 'ExpensiveAlgorithm'
+ end
+
+ def initialize(id, name, result, extra = nil)
+ self.id = id
+ self.name = name
+ self.result = result
+ self.extra = nil
+ end
+
+ request_cache def compute(arg)
+ result << arg
+ end
+
+ request_cache def repute(arg)
+ result << arg
+ end
+
+ def dispute(arg)
+ result << arg
+ end
+ request_cache(:dispute) { extra }
+ end
+ end
+
+ let(:algorithm) { klass.new('id', 'name', []) }
+
+ shared_examples 'cache for the same instance' do
+ it 'does not compute twice for the same argument' do
+ algorithm.compute(true)
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true])
+ end
+
+ it 'computes twice for the different argument' do
+ algorithm.compute(true)
+ result = algorithm.compute(false)
+
+ expect(result).to eq([true, false])
+ end
+
+ it 'computes twice for the different class name' do
+ algorithm.compute(true)
+ allow(klass).to receive(:name).and_return('CheapAlgo')
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'computes twice for the different method' do
+ algorithm.compute(true)
+ result = algorithm.repute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ context 'when request_cache_key is provided' do
+ before do
+ klass.request_cache_key do
+ [id, name]
+ end
+ end
+
+ it 'computes twice for the different keys, id' do
+ algorithm.compute(true)
+ algorithm.id = 'ad'
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'computes twice for the different keys, name' do
+ algorithm.compute(true)
+ algorithm.name = 'same'
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'uses extra method cache key if provided' do
+ algorithm.dispute(true) # miss
+ algorithm.extra = true
+ algorithm.dispute(true) # miss
+ result = algorithm.dispute(true) # hit
+
+ expect(result).to eq([true, true])
+ end
+ end
+ end
+
+ context 'when RequestStore is active', :request_store do
+ it_behaves_like 'cache for the same instance'
+
+ it 'computes once for different instances when keys are the same' do
+ algorithm.compute(true)
+ result = klass.new('id', 'name', algorithm.result).compute(true)
+
+ expect(result).to eq([true])
+ end
+
+ it 'computes twice if RequestStore starts over' do
+ algorithm.compute(true)
+ RequestStore.end!
+ RequestStore.clear!
+ RequestStore.begin!
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+ end
+
+ context 'when RequestStore is inactive' do
+ it_behaves_like 'cache for the same instance'
+
+ it 'computes twice for different instances even if keys are the same' do
+ algorithm.compute(true)
+ result = klass.new('id', 'name', algorithm.result).compute(true)
+
+ expect(result).to eq([true, true])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 4259be3f522..a2acd15c8fb 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -174,13 +174,23 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
allow(Gitlab::Database).to receive(:mysql?).and_return(false)
end
- it 'creates a concurrent foreign key' do
+ it 'creates a concurrent foreign key and validates it' do
expect(model).to receive(:disable_statement_timeout)
expect(model).to receive(:execute).ordered.with(/NOT VALID/)
expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end
+
+ it 'appends a valid ON DELETE statement' do
+ expect(model).to receive(:disable_statement_timeout)
+ expect(model).to receive(:execute).with(/ON DELETE SET NULL/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+
+ model.add_concurrent_foreign_key(:projects, :users,
+ column: :user_id,
+ on_delete: :nullify)
+ end
end
end
end
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index f20a14155dc..60de91324f0 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -64,6 +64,52 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
+ describe "Commit info from gitaly commit" do
+ let(:id) { 'f00' }
+ let(:subject) { "My commit".force_encoding('ASCII-8BIT') }
+ let(:body) { subject + "My body".force_encoding('ASCII-8BIT') }
+ let(:committer) do
+ Gitaly::CommitAuthor.new(
+ name: generate(:name),
+ email: generate(:email),
+ date: Google::Protobuf::Timestamp.new(seconds: 123)
+ )
+ end
+ let(:author) do
+ Gitaly::CommitAuthor.new(
+ name: generate(:name),
+ email: generate(:email),
+ date: Google::Protobuf::Timestamp.new(seconds: 456)
+ )
+ end
+ let(:gitaly_commit) do
+ Gitaly::GitCommit.new(
+ id: id,
+ subject: subject,
+ body: body,
+ author: author,
+ committer: committer
+ )
+ end
+ let(:commit) { described_class.new(gitaly_commit) }
+
+ it { expect(commit.short_id).to eq(id[0..10]) }
+ it { expect(commit.id).to eq(id) }
+ it { expect(commit.sha).to eq(id) }
+ it { expect(commit.safe_message).to eq(body) }
+ it { expect(commit.created_at).to eq(Time.at(committer.date.seconds)) }
+ it { expect(commit.author_email).to eq(author.email) }
+ it { expect(commit.author_name).to eq(author.name) }
+ it { expect(commit.committer_name).to eq(committer.name) }
+ it { expect(commit.committer_email).to eq(committer.email) }
+
+ context 'no body' do
+ let(:body) { "".force_encoding('ASCII-8BIT') }
+
+ it { expect(commit.safe_message).to eq(subject) }
+ end
+ end
+
context 'Class methods' do
describe '.find' do
it "should return first head commit if without params" do
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index fee5bb45fe5..93affb12f2b 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
describe Gitlab::GitalyClient::CommitService do
- let(:diff_stub) { double('Gitaly::DiffService::Stub') }
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:repository_message) { repository.gitaly_repository }
@@ -82,4 +81,19 @@ describe Gitlab::GitalyClient::CommitService do
end
end
end
+
+ describe '#between' do
+ let(:from) { 'master' }
+ let(:to) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' }
+ it 'sends an RPC request' do
+ request = Gitaly::CommitsBetweenRequest.new(
+ repository: repository_message, from: from, to: to
+ )
+
+ expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:commits_between)
+ .with(request, kind_of(Hash)).and_return([])
+
+ described_class.new(repository).between(from, to)
+ end
+ end
end
diff --git a/spec/migrations/add_foreign_key_to_merge_requests_spec.rb b/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
new file mode 100644
index 00000000000..d9ad9a585f0
--- /dev/null
+++ b/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20170713104829_add_foreign_key_to_merge_requests.rb')
+
+describe AddForeignKeyToMergeRequests, :migration do
+ let(:projects) { table(:projects) }
+ let(:merge_requests) { table(:merge_requests) }
+ let(:pipelines) { table(:ci_pipelines) }
+
+ before do
+ projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce')
+ pipelines.create!(project_id: projects.first.id,
+ ref: 'some-branch',
+ sha: 'abc12345')
+
+ # merge request without a pipeline
+ create_merge_request(head_pipeline_id: nil)
+
+ # merge request with non-existent pipeline
+ create_merge_request(head_pipeline_id: 1234)
+
+ # merge reqeust with existing pipeline assigned
+ create_merge_request(head_pipeline_id: pipelines.first.id)
+ end
+
+ it 'correctly adds a foreign key to head_pipeline_id' do
+ migrate!
+
+ expect(merge_requests.first.head_pipeline_id).to be_nil
+ expect(merge_requests.second.head_pipeline_id).to be_nil
+ expect(merge_requests.third.head_pipeline_id).to eq pipelines.first.id
+ end
+
+ def create_merge_request(**opts)
+ merge_requests.create!(source_project_id: projects.first.id,
+ target_project_id: projects.first.id,
+ source_branch: 'some-branch',
+ target_branch: 'master', **opts)
+ end
+end
diff --git a/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb b/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
new file mode 100644
index 00000000000..3a9fa8c7113
--- /dev/null
+++ b/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+require Rails.root.join("db", "post_migrate", "20170717111152_cleanup_move_system_upload_folder_symlink.rb")
+
+describe CleanupMoveSystemUploadFolderSymlink do
+ let(:migration) { described_class.new }
+ let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
+ let(:test_folder) { File.join(test_base, '-', 'system') }
+
+ before do
+ allow(migration).to receive(:base_directory).and_return(test_base)
+ FileUtils.rm_rf(test_base)
+ FileUtils.mkdir_p(test_folder)
+ allow(migration).to receive(:say)
+ end
+
+ describe '#up' do
+ before do
+ FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
+ end
+
+ it 'removes the symlink' do
+ migration.up
+
+ expect(File.exist?(File.join(test_base, 'system'))).to be_falsey
+ end
+ end
+
+ describe '#down' do
+ it 'creates the symlink' do
+ migration.down
+
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
+ end
+ end
+end
diff --git a/spec/migrations/move_system_upload_folder_spec.rb b/spec/migrations/move_system_upload_folder_spec.rb
new file mode 100644
index 00000000000..b622b4e9536
--- /dev/null
+++ b/spec/migrations/move_system_upload_folder_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+require Rails.root.join("db", "migrate", "20170717074009_move_system_upload_folder.rb")
+
+describe MoveSystemUploadFolder do
+ let(:migration) { described_class.new }
+ let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
+
+ before do
+ allow(migration).to receive(:base_directory).and_return(test_base)
+ FileUtils.rm_rf(test_base)
+ FileUtils.mkdir_p(test_base)
+ allow(migration).to receive(:say)
+ end
+
+ describe '#up' do
+ let(:test_folder) { File.join(test_base, 'system') }
+ let(:test_file) { File.join(test_folder, 'file') }
+
+ before do
+ FileUtils.mkdir_p(test_folder)
+ FileUtils.touch(test_file)
+ end
+
+ it 'moves the related folder' do
+ migration.up
+
+ expect(File.exist?(File.join(test_base, '-', 'system', 'file'))).to be_truthy
+ end
+
+ it 'creates a symlink linking making the new folder available on the old path' do
+ migration.up
+
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
+ expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
+ end
+ end
+
+ describe '#down' do
+ let(:test_folder) { File.join(test_base, '-', 'system') }
+ let(:test_file) { File.join(test_folder, 'file') }
+
+ before do
+ FileUtils.mkdir_p(test_folder)
+ FileUtils.touch(test_file)
+ end
+
+ it 'moves the system folder back to the old location' do
+ migration.down
+
+ expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
+ end
+
+ it 'removes the symlink if it existed' do
+ FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
+
+ migration.down
+
+ expect(File.directory?(File.join(test_base, 'system'))).to be_truthy
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_falsey
+ end
+ end
+end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6056d78da4e..528b211c9d6 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -19,17 +19,15 @@ describe Commit, models: true do
expect(commit.author).to eq(user)
end
- it 'caches the author' do
- allow(RequestStore).to receive(:active?).and_return(true)
+ it 'caches the author', :request_store do
user = create(:user, email: commit.author_email)
- expect_any_instance_of(Commit).to receive(:find_author_by_any_email).and_call_original
+ expect(User).to receive(:find_by_any_email).and_call_original
expect(commit.author).to eq(user)
- key = "commit_author:#{commit.author_email}"
+ key = "Commit:author:#{commit.author_email.downcase}"
expect(RequestStore.store[key]).to eq(user)
expect(commit.author).to eq(user)
- RequestStore.store.clear
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 066d7b9307f..770176451fe 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -189,7 +189,7 @@ describe Group, models: true do
let!(:group) { create(:group, :access_requestable, :with_avatar) }
let(:user) { create(:user) }
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
- let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/group/avatar/#{group.id}/dk.png" }
context 'when avatar file is uploaded' do
before do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 89ea5ceda95..a4090b37f65 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -44,7 +44,7 @@ describe Namespace, models: true do
end
context "is case insensitive" do
- let(:group) { build(:group, path: "System") }
+ let(:group) { build(:group, path: "Groups") }
it { expect(group).not_to be_valid }
end
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 6ee30e86495..d45e0a441d4 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -43,7 +43,7 @@ describe GitlabIssueTrackerService, models: true do
end
it 'gives the correct path' do
- expect(service.project_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
expect(service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
expect(service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index e636250c37d..90769b580cd 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -807,7 +807,7 @@ describe Project, models: true do
context 'when avatar file is uploaded' do
let(:project) { create(:empty_project, :with_avatar) }
- let(:avatar_path) { "/uploads/system/project/avatar/#{project.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/project/avatar/#{project.id}/dk.png" }
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
it 'shows correct url' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 69f2570eec2..a1d6d7e6e0b 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1028,7 +1028,7 @@ describe User, models: true do
context 'when avatar file is uploaded' do
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
- let(:avatar_path) { "/uploads/system/user/avatar/#{user.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/user/avatar/#{user.id}/dk.png" }
it 'shows correct avatar url' do
expect(user.avatar_url).to eq(avatar_path)
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index ace95ac7067..9f3212b1a63 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -103,12 +103,7 @@ describe Ci::BuildPolicy, :models do
project.add_developer(user)
end
- context 'when branch build is assigned to is protected' do
- before do
- create(:protected_branch, :no_one_can_push,
- name: 'some-ref', project: project)
- end
-
+ shared_examples 'protected ref' do
context 'when build is a manual action' do
let(:build) do
create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline)
@@ -130,6 +125,43 @@ describe Ci::BuildPolicy, :models do
end
end
+ context 'when build is against a protected branch' do
+ before do
+ create(:protected_branch, :no_one_can_push,
+ name: 'some-ref', project: project)
+ end
+
+ it_behaves_like 'protected ref'
+ end
+
+ context 'when build is against a protected tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: 'some-ref', project: project)
+
+ build.update(tag: true)
+ end
+
+ it_behaves_like 'protected ref'
+ end
+
+ context 'when build is against a protected tag but it is not a tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: 'some-ref', project: project)
+ end
+
+ context 'when build is a manual action' do
+ let(:build) do
+ create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline)
+ end
+
+ it 'includes ability to update build' do
+ expect(policy).to be_allowed :update_build
+ end
+ end
+ end
+
context 'when branch build is assigned to is not protected' do
context 'when build is a manual action' do
let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index fa704f23857..6dbde8bad31 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -442,7 +442,7 @@ describe API::Projects do
post api('/projects', user), project
project_id = json_response['id']
- expect(json_response['avatar_url']).to eq("http://localhost/uploads/system/project/avatar/#{project_id}/banana_sample.gif")
+ expect(json_response['avatar_url']).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif")
end
it 'sets a project as allowing merge even if build fails' do
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index ebba28ba8ce..a927de952d0 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -79,7 +79,7 @@ describe 'OpenID Connect requests' do
'email_verified' => true,
'website' => 'https://example.com',
'profile' => 'http://localhost/alice',
- 'picture' => "http://localhost/uploads/system/user/avatar/#{user.id}/dk.png"
+ 'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png"
})
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 3f77ed10069..c493c08a7ae 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -108,7 +108,7 @@ describe GitPushService, services: true do
it { is_expected.to include(id: @commit.id) }
it { is_expected.to include(message: @commit.safe_message) }
- it { is_expected.to include(timestamp: @commit.date.xmlschema) }
+ it { expect(subject[:timestamp].in_time_zone).to eq(@commit.date.in_time_zone) }
it do
is_expected.to include(
url: [
@@ -163,7 +163,7 @@ describe GitPushService, services: true do
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
end
end
-
+
context "Sends System Push data" do
it "when pushing on a branch" do
expect(SystemHookPushWorker).to receive(:perform_async).with(@push_data, :push_hooks)
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index f1e00c1163b..4fc5eb0a527 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -383,7 +383,7 @@ describe NotificationService, services: true do
before do
build_team(note.project)
reset_delivered_emails!
- allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer)
+ allow(note.noteable).to receive(:author).and_return(@u_committer)
update_custom_notification(:new_note, @u_guest_custom, resource: project)
update_custom_notification(:new_note, @u_custom_global)
end
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index d75851134ee..3688f6d4e23 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -13,7 +13,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/uploads/system/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
it 'should return an url for the avatar with relative url' do
@@ -24,7 +24,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/system/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b8ed1e18de0..5d5715b10ff 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -3,7 +3,6 @@ SimpleCovEnv.start!
ENV["RAILS_ENV"] ||= 'test'
ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
-# ENV['prometheus_multiproc_dir'] = 'tmp/prometheus_multiproc_dir_test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb
index d82dbe871d5..04ee6e9bfad 100644
--- a/spec/uploaders/attachment_uploader_spec.rb
+++ b/spec/uploaders/attachment_uploader_spec.rb
@@ -5,7 +5,7 @@ describe AttachmentUploader do
describe "#store_dir" do
it "stores in the system dir" do
- expect(uploader.store_dir).to start_with("uploads/system/user")
+ expect(uploader.store_dir).to start_with("uploads/-/system/user")
end
it "uses the old path when using object storage" do
diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb
index 201fe6949aa..1dc574699d8 100644
--- a/spec/uploaders/avatar_uploader_spec.rb
+++ b/spec/uploaders/avatar_uploader_spec.rb
@@ -5,7 +5,7 @@ describe AvatarUploader do
describe "#store_dir" do
it "stores in the system dir" do
- expect(uploader.store_dir).to start_with("uploads/system/user")
+ expect(uploader.store_dir).to start_with("uploads/-/system/user")
end
it "uses the old path when using object storage" do