Commit a59c1230 authored by Clement Ho's avatar Clement Ho

Merge branch 'master' into 'webpack-mirrors'

# Conflicts:
#   config/webpack.config.js
parents ec3a5335 824eeb4a
import U2FRegister from './u2f/register';
import U2FRegister from '~/u2f/register';
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
......
......@@ -62,19 +62,27 @@ module UploadsActions
end
def build_uploader_from_upload
return nil unless params[:secret] && params[:filename]
return unless uploader = build_uploader
upload_path = uploader_class.upload_path(params[:secret], params[:filename])
upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_path)
upload_paths = uploader.upload_paths(params[:filename])
upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_paths)
upload&.build_uploader
end
def build_uploader_from_params
return unless uploader = build_uploader
uploader.retrieve_from_store!(params[:filename])
uploader
end
def build_uploader
return unless params[:secret] && params[:filename]
uploader = uploader_class.new(model, secret: params[:secret])
return nil unless uploader.model_valid?
return unless uploader.model_valid?
uploader.retrieve_from_store!(params[:filename])
uploader
end
......
......@@ -32,8 +32,11 @@ class FileUploader < GitlabUploader
)
end
def self.base_dir(model)
model_path_segment(model)
def self.base_dir(model, store = Store::LOCAL)
decorated_model = model
decorated_model = Storage::HashedProject.new(model) if store == Store::REMOTE
model_path_segment(decorated_model)
end
# used in migrations and import/exports
......@@ -51,21 +54,24 @@ class FileUploader < GitlabUploader
#
# Returns a String without a trailing slash
def self.model_path_segment(model)
if model.hashed_storage?(:attachments)
model.disk_path
case model
when Storage::HashedProject then model.disk_path
else
model.full_path
model.hashed_storage?(:attachments) ? model.disk_path : model.full_path
end
end
def self.upload_path(secret, identifier)
File.join(secret, identifier)
end
def self.generate_secret
SecureRandom.hex
end
def upload_paths(filename)
[
File.join(secret, filename),
File.join(base_dir(Store::REMOTE), secret, filename)
]
end
attr_accessor :model
def initialize(model, mounted_as = nil, **uploader_context)
......@@ -75,8 +81,10 @@ class FileUploader < GitlabUploader
apply_context!(uploader_context)
end
def base_dir
self.class.base_dir(@model)
# enforce the usage of Hashed storage when storing to
# remote store as the FileMover doesn't support OS
def base_dir(store = nil)
self.class.base_dir(@model, store || object_store)
end
# we don't need to know the actual path, an uploader instance should be
......@@ -86,15 +94,19 @@ class FileUploader < GitlabUploader
end
def upload_path
self.class.upload_path(dynamic_segment, identifier)
end
def model_path_segment
self.class.model_path_segment(@model)
if file_storage?
# Legacy path relative to project.full_path
File.join(dynamic_segment, identifier)
else
File.join(store_dir, identifier)
end
end
def store_dir
File.join(base_dir, dynamic_segment)
def store_dirs
{
Store::LOCAL => File.join(base_dir, dynamic_segment),
Store::REMOTE => File.join(base_dir(ObjectStorage::Store::REMOTE), dynamic_segment)
}
end
def markdown_link
......
......@@ -4,7 +4,7 @@ class NamespaceFileUploader < FileUploader
options.storage_path
end
def self.base_dir(model)
def self.base_dir(model, _store = nil)
File.join(options.base_dir, 'namespace', model_path_segment(model))
end
......@@ -20,7 +20,7 @@ class NamespaceFileUploader < FileUploader
def store_dirs
{
Store::LOCAL => File.join(base_dir, dynamic_segment),
Store::REMOTE => File.join('namespace', model_path_segment, dynamic_segment)
Store::REMOTE => File.join('namespace', self.class.model_path_segment(model), dynamic_segment)
}
end
end
......@@ -4,7 +4,7 @@ class PersonalFileUploader < FileUploader
options.storage_path
end
def self.base_dir(model)
def self.base_dir(model, _store = nil)
File.join(options.base_dir, model_path_segment(model))
end
......@@ -34,7 +34,7 @@ class PersonalFileUploader < FileUploader
def store_dirs
{
Store::LOCAL => File.join(base_dir, dynamic_segment),
Store::REMOTE => File.join(model_path_segment, dynamic_segment)
Store::REMOTE => File.join(self.class.model_path_segment(model), dynamic_segment)
}
end
......
......@@ -2,10 +2,6 @@
- add_to_breadcrumbs("Two-Factor Authentication", profile_account_path)
- @content_class = "limit-container-width" unless fluid_layout
- content_for :page_specific_javascripts do
= webpack_bundle_tag('two_factor_auth')
.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path }
.row.prepend-top-default
.col-lg-4
......
---
title: expose more metrics in merge requests api
merge_request: 16589
author: haseebeqx
type: added
......@@ -51,7 +51,6 @@ function generateEntries() {
monitoring: './monitoring/monitoring_bundle.js',
mr_notes: './mr_notes/index.js',
terminal: './terminal/terminal_bundle.js',
two_factor_auth: './two_factor_auth.js',
common: './commons/index.js',
common_vue: './vue_shared/vue_resource_interceptor.js',
......@@ -63,10 +62,7 @@ function generateEntries() {
webpack_runtime: './webpack.js',
// EE-only
add_gitlab_slack_application: 'ee/add_gitlab_slack_application/index.js',
burndown_chart: 'ee/burndown_chart/index.js',
geo_nodes: 'ee/geo_nodes',
ldap_group_links: 'ee/groups/ldap_group_links.js',
service_desk: 'ee/projects/settings_service_desk/service_desk_bundle.js',
};
......
This diff is collapsed.
......@@ -89,18 +89,24 @@ created in snippets, wikis, and repos.
- [Authentication/Authorization](../topics/authentication/index.md#gitlab-administrators): Enforce 2FA, configure external authentication with LDAP, SAML, CAS and additional Omniauth providers.
- **(Starter/Premium)** [Sync LDAP](auth/ldap-ee.md)
- **(Starter/Premium)** [Kerberos authentication](../integration/kerberos.md)
- [Reply by email](reply_by_email.md): Allow users to comment on issues and merge requests by replying to notification emails.
- [Postfix for Reply by email](reply_by_email_postfix_setup.md): Set up a basic Postfix mail
server with IMAP authentication on Ubuntu, to be used with Reply by email.
- **(Starter/Premium)** [Email users](../tools/email.md): Email GitLab users from within GitLab.
- [User Cohorts](../user/admin_area/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
- **(Starter/Premium)** [Audit logs and events](audit_events.md): View the changes made within the GitLab server.
- **(Premium)** [Auditor users](auditor_users.md): Users with read-only access to all projects, groups, and other resources on the GitLab instance.
- [Reply by email](reply_by_email.md): Allow users to comment on issues and merge requests by replying to notification emails.
- [Postfix for Reply by email](reply_by_email_postfix_setup.md): Set up a basic Postfix mail
- [Incoming email](incoming_email.md): Configure incoming emails to allow
users to [reply by email], create [issues by email] and
[merge requests by email], and to enable [Service Desk].
- [Postfix for incoming email](reply_by_email_postfix_setup.md): Set up a
basic Postfix mail server with IMAP authentication on Ubuntu for incoming
emails.
server with IMAP authentication on Ubuntu, to be used with Reply by email.
- [User Cohorts](../user/admin_area/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
[reply by email]: reply_by_email.md
[issues by email]: ../user/project/issues/create_new_issue.md#new-issue-via-email
[merge requests by email]: ../user/project/merge_requests/index.md#create-new-merge-requests-by-email
[Service Desk]: ../user/project/service_desk.md
## Project settings
- [Container Registry](container_registry.md): Configure Container Registry with GitLab.
......
This diff is collapsed.
# Set up Postfix for Reply by email
# Set up Postfix for incoming email
This document will take you through the steps of setting up a basic Postfix mail
server with IMAP authentication on Ubuntu, to be used with [Reply by email].
server with IMAP authentication on Ubuntu, to be used with [incoming email].
The instructions make the assumption that you will be using the email address `incoming@gitlab.example.com`, that is, username `incoming` on host `gitlab.example.com`. Don't forget to change it to your actual host when executing the example code snippets.
......@@ -177,12 +177,12 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
```sh
sudo apt-get install courier-imap
```
And start `imapd`:
```sh
imapd start
```
1. The courier-authdaemon isn't started after installation. Without it, imap authentication will fail:
```sh
sudo service courier-authdaemon start
......@@ -329,10 +329,10 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
## Done!
If all the tests were successful, Postfix is all set up and ready to receive email! Continue with the [Reply by email](./reply_by_email.md) guide to configure GitLab.
If all the tests were successful, Postfix is all set up and ready to receive email! Continue with the [incoming email] guide to configure GitLab.
---
_This document was adapted from https://help.ubuntu.com/community/PostfixBasicSetupHowto, by contributors to the Ubuntu documentation wiki._
[reply by email]: reply_by_email.md
[incoming email]: incoming_email.md
......@@ -263,20 +263,20 @@ Parameters:
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
"state" : "active",
"web_url" : "https://gitlab.example.com/root",
"avatar_url" : null,
"username" : "root",
"id" : 1,
"name" : "Administrator"
},
"assignee": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
"state" : "active",
"web_url" : "https://gitlab.example.com/root",
"avatar_url" : null,
"username" : "root",
"id" : 1,
"name" : "Administrator"
},
"source_project_id": 2,
"target_project_id": 3,
......@@ -313,6 +313,27 @@ Parameters:
"human_total_time_spent": null
},
"approvals_before_merge": null
},
"closed_at": "2018-01-19T14:36:11.086Z",
"latest_build_started_at": null,
"latest_build_finished_at": null,
"first_deployed_to_production_at": null,
"pipeline": {
"id": 8,
"ref": "master",
"sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0",
"status": "created"
},
"merged_by": null,
"merged_at": null,
"closed_by": {
"state" : "active",
"web_url" : "https://gitlab.example.com/root",
"avatar_url" : null,
"username" : "root",
"id" : 1,
"name" : "Administrator"
}
}
```
......
......@@ -18,6 +18,68 @@ See the [Rails guides] for more info.
[previews]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/spec/mailers/previews
[Rails guides]: http://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails
## Incoming email
1. Go to the GitLab installation directory.
1. Find the `incoming_email` section in `config/gitlab.yml`, enable the
feature and fill in the details for your specific IMAP server and email
account:
Configuration for Gmail / Google Apps, assumes mailbox gitlab-incoming@gmail.com
```yaml
incoming_email:
enabled: true
# The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
# The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`).
address: "gitlab-incoming+%{key}@gmail.com"
# Email account username
# With third party providers, this is usually the full email address.
# With self-hosted email servers, this is usually the user part of the email address.
user: "gitlab-incoming@gmail.com"
# Email account password
password: "[REDACTED]"
# IMAP server host
host: "imap.gmail.com"
# IMAP server port
port: 993
# Whether the IMAP server uses SSL
ssl: true
# Whether the IMAP server uses StartTLS
start_tls: false
# The mailbox where incoming mail will end up. Usually "inbox".
mailbox: "inbox"
# The IDLE command timeout.
idle_timeout: 60
```
As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
1. Uncomment the `mail_room` line in your `Procfile`:
```yaml
mail_room: bundle exec mail_room -q -c config/mail_room.yml
```
1. Restart GitLab:
```sh
bundle exec foreman start
```
1. Verify that everything is configured correctly:
```sh
bundle exec rake gitlab:incoming_email:check RAILS_ENV=development
```
1. Reply by email should now be working.
---
[Return to Development documentation](README.md)
......@@ -37,6 +37,28 @@ It opens a new issue for that project labeled after its respective list.
![From the issue board](img/new_issue_from_issue_board.png)
## New issue via email
*This feature needs [incoming email](../../../administration/incoming_email.md)
to be configured by a GitLab administrator to be available for CE/EE users, and
it's available on GitLab.com.*
At the bottom of a project's issue page, click
**Email a new issue to this project**, and you will find an email address
which belongs to you. You could add this address to your contact.
This is a private email address, generated just for you.
**Keep it to yourself** as anyone who gets ahold of it can create issues or
merge requests as if they were you. You can add this address to your contact
list for easy access.
Sending an email to this address will create a new issue on your behalf for
this project, where the email subject becomes the issue title, and the email
body becomes the issue description. [Markdown] and [quick actions] are
supported.
![Bottom of a project issues page](img/new_issue_from_email.png)
## New issue via Service Desk
Enable [Service Desk](../service_desk.md) to your project and offer email support.
......@@ -60,5 +82,5 @@ create issues for the same project.
![Create issue from group-level issue tracker](img/create_issue_from_group_level_issue_tracker.png)
[Markdown]: ../../markdown.md
[quick actions]: ../quick_actions.md
......@@ -142,6 +142,10 @@ those conflicts in the GitLab UI.
## Create new merge requests by email
*This feature needs [incoming email](../../../administration/incoming_email.md)
to be configured by a GitLab administrator to be available for CE/EE users, and
it's available on GitLab.com.*
You can create a new merge request by sending an email to a user-specific email
address. The address can be obtained on the merge requests page by clicking on
a **Email a new merge request to this project** button. The subject will be
......
......@@ -53,7 +53,7 @@ Service Desk is enabled on GitLab.com. If you're a
[Silver subscriber](https://about.gitlab.com/gitlab-com/),
you can skip the step 1 below; you only need to enable it per project.
1. [Set up reply by email][reply-by-email] for the GitLab instance. This must
1. [Set up incoming email][incoming-email] for the GitLab instance. This must
support [email sub-addressing][email-sub-addressing].
2. Navigate to your project's **Settings** and scroll down to the **Service Desk**
section.
......@@ -119,7 +119,7 @@ does not count toward the license limit count.
[ee-149]: https://gitlab.com/gitlab-org/gitlab-ee/issues/149 "Service Desk with email"
[ee]: https://about.gitlab.com/products/ "GitLab Enterprise Edition landing page"
[eep-9.1]: https://about.gitlab.com/2017/04/22/gitlab-9-1-released/#service-desk-eep
[reply-by-email]: ../../administration/reply_by_email.md#set-it-up
[incoming-email]: ../../administration/incoming_email.md#set-it-up
[email-sub-addressing]: ../../administration/reply_by_email.md#email-sub-addressing
[confidential]: ./issues/confidential_issues.md "Confidential issues"
[akismet]: ../../integration/akismet.md
import Vue from 'vue';
import AddGitlabSlackApplication from './components/add_gitlab_slack_application.vue';
function mountAddGitlabSlackApplication() {
export default () => {
const el = document.getElementById('js-add-gitlab-slack-application-entry-point');
if (!el) return;
......@@ -23,8 +23,4 @@ function mountAddGitlabSlackApplication() {
docsPath: initialData.docs_path,
},
}).$mount(el);
}
document.addEventListener('DOMContentLoaded', mountAddGitlabSlackApplication);
export default mountAddGitlabSlackApplication;
};
import Cookies from 'js-cookie';
import BurndownChart from './burndown_chart';
$(() => {
export default () => {
// handle hint dismissal
const hint = $('.burndown-hint');
hint.on('click', '.dismiss-icon', () => {
......@@ -47,4 +47,4 @@ $(() => {
window.addEventListener('resize', () => chart.animateResize(1));
$(document).on('click', '.js-sidebar-toggle', () => chart.animateResize(2));
}
});
};
document.addEventListener('DOMContentLoaded', () => {
export default () => {
const showGroupLink = () => {
const $cnLink = $('.cn-link');
const $filterLink = $('.filter-link');
......@@ -12,4 +12,4 @@ document.addEventListener('DOMContentLoaded', () => {
$('input[name="sync_method"]').on('change', showGroupLink);
showGroupLink();
});
};
import initLDAPGroupsSelect from 'ee/ldap_groups_select';
import initLDAPGroupLinks from 'ee/groups/ldap_group_links';
document.addEventListener('DOMContentLoaded', initLDAPGroupsSelect);
document.addEventListener('DOMContentLoaded', () => {
initLDAPGroupsSelect();
initLDAPGroupLinks();
});
import '~/pages/admin/groups/new/index';
import initLDAPGroupLinks from 'ee/groups/ldap_group_links';
document.addEventListener('DOMContentLoaded', initLDAPGroupLinks);
import initLDAPGroupsSelect from 'ee/ldap_groups_select';
import initLDAPGroupLinks from 'ee/groups/ldap_group_links';
document.addEventListener('DOMContentLoaded', initLDAPGroupsSelect);
document.addEventListener('DOMContentLoaded', () => {
initLDAPGroupsSelect();
initLDAPGroupLinks();
});
import mountAddGitlabSlackApplication from 'ee/add_gitlab_slack_application';
document.addEventListener('DOMContentLoaded', () => mountAddGitlabSlackApplication());
import '~/pages/projects/milestones/show/index';
import UserCallout from '~/user_callout';
import initBurndownChart from 'ee/burndown_chart';
document.addEventListener('DOMContentLoaded', () => new UserCallout());
document.addEventListener('DOMContentLoaded', () => {
new UserCallout(); // eslint-disable-line no-new
initBurndownChart();
});
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'ldap_group_links'
%section.ldap-group-links
= form_for [group, LdapGroupLink.new], html: { class: 'form-horizontal' } do |f|
.form-holder
......
= webpack_bundle_tag 'add_gitlab_slack_application'
-# haml-lint:disable InlineJavaScript
%script#js-add-gitlab-slack-application-entry-data{ type: "application/json" }
= add_to_slack_data(@projects)
......
......@@ -3,9 +3,6 @@
- burndown = local_assigns[:burndown]
- warning = data_warning_for(burndown)
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'burndown_chart'
= warning
- if can_generate_chart?(burndown)
......
---
title: File uploads in remote storage now support project renaming.
merge_request: 4597
author:
type: fixed
......@@ -483,6 +483,10 @@ module API
expose :id
end
class PipelineBasic < Grape::Entity
expose :id, :sha, :ref, :status
end
class MergeRequestSimple < ProjectEntity
expose :title
expose :web_url do |merge_request, options|
......@@ -548,6 +552,42 @@ module API
expose :changes_count do |merge_request, _options|
merge_request.merge_request_diff.real_size
end
expose :merged_by, using: Entities::UserBasic do |merge_request, _options|
merge_request.metrics&.merged_by
end
expose :merged_at do |merge_request, _options|
merge_request.metrics&.merged_at
end
expose :closed_by, using: Entities::UserBasic do |merge_request, _options|
merge_request.metrics&.latest_closed_by
end
expose :closed_at do |merge_request, _options|
merge_request.metrics&.latest_closed_at
end
expose :latest_build_started_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.latest_build_started_at
end
expose :latest_build_finished_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.latest_build_finished_at
end
expose :first_deployed_to_production_at, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.first_deployed_to_production_at
end
expose :pipeline, using: Entities::PipelineBasic, if: -> (_, options) { build_available?(options) } do |merge_request, _options|
merge_request.metrics&.pipeline
end
def build_available?(options)
options[:project]&.feature_available?(:builds, options[:current_user])
end
end
class MergeRequestChanges < MergeRequest
......@@ -911,10 +951,6 @@ module API
expose :filename, :size
end
class PipelineBasic < Grape::Entity
expose :id, :sha, :ref, :status
end
class JobBasic < Grape::Entity
expose :id, :status, :stage, :name, :ref, :tag, :coverage
expose :created_at, :started_at, :finished_at
......
......@@ -234,7 +234,7 @@ module API
get ':id/merge_requests/:merge_request_iid/changes' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user, project: user_project
end
desc 'Get the merge request pipelines' do
......
......@@ -9,6 +9,7 @@ describe API::MergeRequests do
let(:non_member) { create(:user) }
let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) }
let(:milestone) { create(:milestone, title: '1.0.0', project: project) }
let(:pipeline) { create(:ci_empty_pipeline) }
let(:milestone1) { create(:milestone, title: '0.9', project: project) }
let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
......@@ -501,6 +502,45 @@ describe API::MergeRequests do
expect(json_response['changes_count']).to eq(merge_request.merge_request_diff.real_size)
end
context 'merge_request_metrics' do
before do
merge_request.metrics.update!(merged_by: user,
latest_closed_by: user,
latest_closed_at: 1.hour.ago,
merged_at: 2.hours.ago,
pipeline: pipeline,
latest_build_started_at: 3.hours.ago,
latest_build_finished_at: 1.hour.ago,
first_deployed_to_production_at: 3.minutes.ago)
end
it 'has fields from merge request metrics' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
expect(json_response).to include('merged_by',
'merged_at',
'closed_by',
'closed_at',
'latest_build_started_at',
'latest_build_finished_at',
'first_deployed_to_production_at',
'pipeline')
end
it 'returns correct values' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.reload.iid}", user)
expect(json_response['merged_by']['id']).to eq(merge_request.metrics.merged_by_id)
expect(Time.parse json_response['merged_at']).to be_like_time(merge_request.metrics.merged_at)
expect(json_response['closed_by']['id']).to eq(merge_request.metrics.latest_closed_by_id)
expect(Time.parse json_response['closed_at']).to be_like_time(merge_request.metrics.latest_closed_at)
expect(json_response['pipeline']['id']).to eq(merge_request.metrics.pipeline_id)
expect(Time.parse json_response['latest_build_started_at']).to be_like_time(merge_request.metrics.latest_build_started_at)
expect(Time.parse json_response['latest_build_finished_at']).to be_like_time(merge_request.metrics.latest_build_finished_at)
expect(Time.parse json_response['first_deployed_to_production_at']).to be_like_time(merge_request.metrics.first_deployed_to_production_at)
end
end
it "returns a 404 error if merge_request_iid not found" do
get api("/projects/#{project.id}/merge_requests/999", user)
expect(response).to have_gitlab_http_status(404)
......
......@@ -11,34 +11,30 @@ describe FileUploader do
shared_examples 'builds correct legacy storage paths' do
include_examples 'builds correct paths',
store_dir: %r{awesome/project/\h+},
upload_path: %r{\h+/<filename>},
absolute_path: %r{#{described_class.root}/awesome/project/secret/foo.jpg}
end
shared_examples 'uses hashed storage' do
context 'when rolled out attachments' do
let(:project) { build_stubbed(:project, namespace: group, name: 'project') }
context 'legacy storage' do
it_behaves_like 'builds correct legacy storage paths'
before do
allow(project).to receive(:disk_path).and_return('ca/fe/fe/ed')
end
context 'uses hashed storage' do
context 'when rolled out attachments' do
let(:project) { build_stubbed(:project, namespace: group, name: 'project') }
it_behaves_like 'builds correct paths',
store_dir: %r{ca/fe/fe/ed/\h+},
absolute_path: %r{#{described_class.root}/ca/fe/fe/ed/secret/foo.jpg}
end
include_examples 'builds correct paths',
store_dir: %r{@hashed/\h{2}/\h{2}/\h+},
upload_path: %r{\h+/<filename>}
end
context 'when only repositories are rolled out' do
let(:project) { build_stubbed(:project, namespace: group, name: 'project', storage_version: Project::HASHED_STORAGE_FEATURES[:repository]) }
context 'when only repositories are rolled out' do
let(:project) { build_stubbed(:project, namespace: group, name: 'project', storage_version: Project::HASHED_STORAGE_FEATURES[:repository]) }
it_behaves_like 'builds correct legacy storage paths'
it_behaves_like 'builds correct legacy storage paths'
end
end
end
context 'legacy storage' do
it_behaves_like 'builds correct legacy storage paths'
include_examples 'uses hashed storage'
end
context 'object store is remote' do
before do
stub_uploads_object_storage
......@@ -46,8 +42,10 @@ describe FileUploader do
include_context 'with storage', described_class::Store::REMOTE
it_behaves_like 'builds correct legacy storage paths'
include_examples 'uses hashed storage'
# always use hashed storage path for remote uploads
it_behaves_like 'builds correct paths',
store_dir: %r{@hashed/\h{2}/\h{2}/\h+},
upload_path: %r{@hashed/\h{2}/\h{2}/\h+/\h+/<filename>}
end
describe 'initialize' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment