summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG26
-rw-r--r--Procfile2
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/dropzone_input.js.coffee15
-rw-r--r--app/assets/javascripts/issue.js.coffee12
-rw-r--r--app/assets/javascripts/merge_request.js.coffee13
-rw-r--r--app/assets/stylesheets/generic/common.scss2
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/application_controller.rb1
-rw-r--r--app/controllers/help_controller.rb28
-rw-r--r--app/controllers/import/base_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_controller.rb5
-rw-r--r--app/controllers/import/github_controller.rb5
-rw-r--r--app/controllers/import/gitlab_controller.rb5
-rw-r--r--app/controllers/namespaces_controller.rb18
-rw-r--r--app/controllers/projects/repositories_controller.rb10
-rw-r--r--app/helpers/gitlab_routing_helper.rb4
-rw-r--r--app/helpers/icons_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb24
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/application_setting.rb4
-rw-r--r--app/models/concerns/mentionable.rb2
-rw-r--r--app/models/event.rb6
-rw-r--r--app/models/namespace.rb47
-rw-r--r--app/models/note.rb10
-rw-r--r--app/models/project.rb6
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb25
-rw-r--r--app/models/project_services/issue_tracker_service.rb12
-rw-r--r--app/models/repository.rb3
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/user.rb20
-rw-r--r--app/services/archive_repository_service.rb64
-rw-r--r--app/services/files/create_service.rb4
-rw-r--r--app/services/projects/upload_service.rb8
-rw-r--r--app/views/admin/application_settings/_form.html.haml5
-rw-r--r--app/views/admin/background_jobs/show.html.haml2
-rw-r--r--app/views/admin/projects/show.html.haml4
-rw-r--r--app/views/dashboard/milestones/_milestone.html.haml20
-rw-r--r--app/views/dashboard/milestones/index.html.haml20
-rw-r--r--app/views/events/event/_created_project.html.haml4
-rw-r--r--app/views/groups/milestones/_milestone.html.haml25
-rw-r--r--app/views/groups/milestones/index.html.haml26
-rw-r--r--app/views/help/show.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/notify/_note_message.html.haml2
-rw-r--r--app/views/notify/new_issue_email.html.haml2
-rw-r--r--app/views/notify/new_merge_request_email.html.haml2
-rw-r--r--app/views/projects/_dropdown.html.haml2
-rw-r--r--app/views/projects/milestones/_milestone.html.haml22
-rw-r--r--app/views/projects/notes/_form.html.haml2
-rw-r--r--app/views/users/_projects.html.haml8
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/repository_archive_worker.rb43
-rwxr-xr-xbin/background_jobs2
-rw-r--r--config/gitlab.yml.example1
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/mime_types.rb1
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb76
-rw-r--r--db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb5
-rw-r--r--db/schema.rb3
-rw-r--r--doc/api/projects.md12
-rw-r--r--doc/raketasks/backup_restore.md7
-rw-r--r--features/project/issues/issues.feature1
-rw-r--r--features/steps/dashboard/help.rb2
-rw-r--r--features/steps/project/issues/issues.rb6
-rw-r--r--features/steps/project/source/browse_files.rb2
-rw-r--r--lib/api/branches.rb6
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/api/repositories.rb11
-rw-r--r--lib/backup/manager.rb42
-rw-r--r--lib/file_size_validator.rb12
-rw-r--r--lib/gitlab/bitbucket_import/project_creator.rb19
-rw-r--r--lib/gitlab/current_settings.rb3
-rw-r--r--lib/gitlab/github_import/project_creator.rb19
-rw-r--r--lib/gitlab/gitlab_import/client.rb4
-rw-r--r--lib/gitlab/gitlab_import/project_creator.rb19
-rw-r--r--lib/gitlab/gitorious_import/project_creator.rb19
-rw-r--r--lib/gitlab/markdown.rb102
-rw-r--r--lib/gitlab/oauth/user.rb2
-rw-r--r--lib/gitlab/regex.rb66
-rw-r--r--lib/tasks/gitlab/backup.rake33
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb113
-rw-r--r--spec/controllers/import/github_controller_spec.rb96
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb106
-rw-r--r--spec/controllers/namespaces_controller_spec.rb121
-rw-r--r--spec/controllers/projects/repositories_controller_spec.rb65
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb2
-rw-r--r--spec/helpers/icons_helper_spec.rb2
-rw-r--r--spec/lib/file_size_validator_spec.rb43
-rw-r--r--spec/lib/gitlab/regex_spec.rb16
-rw-r--r--spec/mailers/notify_spec.rb8
-rw-r--r--spec/models/namespace_spec.rb12
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb17
-rw-r--r--spec/models/user_spec.rb10
-rw-r--r--spec/requests/api/projects_spec.rb13
-rw-r--r--spec/requests/api/users_spec.rb4
-rw-r--r--spec/routing/routing_spec.rb38
-rw-r--r--spec/services/archive_repository_service_spec.rb93
-rw-r--r--spec/services/projects/upload_service_spec.rb10
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb53
-rw-r--r--spec/workers/repository_archive_worker_spec.rb80
103 files changed, 1526 insertions, 448 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 4623a1f1a44..d577a2087b8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,11 +1,14 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.10.0 (unreleased)
+ - Fix bug where error messages from Dropzone would not be displayed on the issues page (Stan Hu)
+ - Add ability to configure Reply-To address in gitlab.yml (Stan Hu)
- Fix broken side-by-side diff view on merge request page (Stan Hu)
- Set Application controller default URL options to ensure all url_for calls are consistent (Stan Hu)
- Allow HTML tags in Markdown input
- Fix code unfold not working on Compare commits page (Stan Hu)
- Fix dots in Wiki slugs causing errors (Stan Hu)
+ - Make maximum attachment size configurable via Application Settings (Stan Hu)
- Update poltergeist to version 1.6.0 to support PhantomJS 2.0 (Zeger-Jan van de Weg)
- Fix cross references when usernames, milestones, or project names contain underscores (Stan Hu)
- Disable reference creation for comments surrounded by code/preformatted blocks (Stan Hu)
@@ -48,13 +51,22 @@ v 7.10.0 (unreleased)
- Prevent note form from being cleared when submitting failed.
- Improve file icons rendering on tree (Sullivan Sénéchal)
- API: Add pagination to project events
+ - Get issue links in notification mail to work again.
+ - Don't show commit comment button when user is not signed in.
+ - Fix admin user projects lists.
+ - Don't leak private group existence by redirecting from namespace controller to group controller.
+ - Ability to skip some items from backup (database, respositories or uploads)
+ - Fix "Hello @username." references not working by no longer allowing usernames to end in period.
+ - Archive repositories in background worker.
+ - Import GitHub, Bitbucket or GitLab.com projects owned by authenticated user into current namespace.
+ - Project labels are now available over the API under the "tag_list" field (Cristian Medina)
+ - Fixed link paths for HTTP and SSH on the admin project view (Jeremy Maziarz)
+ - Fix and improve help rendering (Sullivan Sénéchal)
- Fix final line in EmailsOnPush email diff being rendered as error.
-v 7.9.0
- - Send EmailsOnPush email when branch or tag is created or deleted.
- - Faster merge request processing for large repository
- - Prevent doubling AJAX request with each commit visit via Turbolink
- - Prevent unnecessary doubling of js events on import pages and user calendar
+
+v 7.9.2
+ - Contains no changes
v 7.9.1
- Include missing events and fix save functionality in admin service template settings form (Stan Hu)
@@ -144,6 +156,10 @@ v 7.9.0
- Fix invalid Atom feeds when using emoji, horizontal rules, or images (Christian Walther)
- Backup of repositories with tar instead of git bundle (only now are git-annex files included in the backup)
- Add canceled status for CI
+ - Send EmailsOnPush email when branch or tag is created or deleted.
+ - Faster merge request processing for large repository
+ - Prevent doubling AJAX request with each commit visit via Turbolink
+ - Prevent unnecessary doubling of js events on import pages and user calendar
v 7.8.4
- Fix issue_tracker_id substitution in custom issue trackers
diff --git a/Procfile b/Procfile
index a0ab4a734a4..799b92729fa 100644
--- a/Procfile
+++ b/Procfile
@@ -1,2 +1,2 @@
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
-worker: bundle exec sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default
+worker: bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q common -q default
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 821712f7512..330ebac6f75 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -100,6 +100,8 @@ class Dispatcher
when 'users:show'
new User()
new Activities()
+ when 'admin:users:show'
+ new ProjectsList()
switch path.first()
when 'admin'
diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee
index 06e9f0001ae..fca2a290e2d 100644
--- a/app/assets/javascripts/dropzone_input.js.coffee
+++ b/app/assets/javascripts/dropzone_input.js.coffee
@@ -10,6 +10,7 @@ class @DropzoneInput
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_uploads_path = window.project_uploads_path or null
+ max_file_size = gon.max_file_size or 10
form_textarea = $(form).find("textarea.markdown-area")
form_textarea.wrap "<div class=\"div-dropzone\"></div>"
@@ -76,7 +77,7 @@ class @DropzoneInput
dictDefaultMessage: ""
clickable: true
paramName: "file"
- maxFilesize: 10
+ maxFilesize: max_file_size
uploadMultiple: false
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
@@ -108,9 +109,10 @@ class @DropzoneInput
return
error: (temp, errorMessage) ->
- checkIfMsgExists = $(".error-alert").children().length
+ errorAlert = $(form).find('.error-alert')
+ checkIfMsgExists = errorAlert.children().length
if checkIfMsgExists is 0
- $(".error-alert").append divAlert
+ errorAlert.append divAlert
$(".div-dropzone-alert").append btnAlert + errorMessage
return
@@ -221,9 +223,10 @@ class @DropzoneInput
"display": "none"
showError = (message) ->
- checkIfMsgExists = $(".error-alert").children().length
+ errorAlert = $(form).find('.error-alert')
+ checkIfMsgExists = errorAlert.children().length
if checkIfMsgExists is 0
- $(".error-alert").append divAlert
+ errorAlert.append divAlert
$(".div-dropzone-alert").append btnAlert + message
closeAlertMessage = ->
@@ -237,4 +240,4 @@ class @DropzoneInput
formatLink: (link) ->
text = "[#{link.alt}](#{link.url})"
text = "!#{text}" if link.is_image
- text \ No newline at end of file
+ text
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index bf71c144eaf..4e2e6550eb2 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -9,12 +9,8 @@ class @Issue
if $("a.btn-close").length
$("li.task-list-item input:checkbox").prop("disabled", false)
- $(".task-list-item input:checkbox").on(
- "click"
- null
- "issue"
- updateTaskState
- )
+ $('.task-list-item input:checkbox').off('change')
+ $('.task-list-item input:checkbox').change('issue', updateTaskState)
$('.issue-details').waitForImages ->
$('.issuable-affix').affix offset:
@@ -22,3 +18,7 @@ class @Issue
@top = ($('.issuable-affix').offset().top - 70)
bottom: ->
@bottom = $('.footer').outerHeight(true)
+ $('.issuable-affix').on 'affix.bs.affix', ->
+ $(@).width($(@).outerWidth())
+ .on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
+ $(@).width('')
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 6127d2bb480..fc75f143836 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -26,6 +26,10 @@ class @MergeRequest
@top = ($('.issuable-affix').offset().top - 70)
bottom: ->
@bottom = $('.footer').outerHeight(true)
+ $('.issuable-affix').on 'affix.bs.affix', ->
+ $(@).width($(@).outerWidth())
+ .on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
+ $(@).width('')
# Local jQuery finder
$: (selector) ->
@@ -81,12 +85,8 @@ class @MergeRequest
this.$('.remove_source_branch_in_progress').hide()
this.$('.remove_source_branch_widget.failed').show()
- $(".task-list-item input:checkbox").on(
- "click"
- null
- "merge_request"
- updateTaskState
- )
+ $('.task-list-item input:checkbox').off('change')
+ $('.task-list-item input:checkbox').change('merge_request', updateTaskState)
activateTab: (action) ->
this.$('.merge-request-tabs li').removeClass 'active'
@@ -164,4 +164,3 @@ class @MergeRequest
else
setTimeout(merge_request.mergeInProgress, 3000)
dataType: 'json'
-
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index db393e08819..7c3021989a8 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -246,7 +246,7 @@ li.note {
.milestone {
&.milestone-closed {
- background: #eee;
+ background: #f9f9f9;
}
.progress {
margin-bottom: 0;
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 9a5685877f8..b5fda196bf0 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -38,6 +38,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:twitter_sharing_enabled,
:sign_in_text,
:home_page_url,
+ :max_attachment_size,
restricted_visibility_levels: []
)
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 2809f90c0d5..80e983b5314 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -203,6 +203,7 @@ class ApplicationController < ActionController::Base
gon.api_version = API::API.version
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
+ gon.max_file_size = current_application_settings.max_attachment_size;
if current_user
gon.current_user_id = current_user.id
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index c4d620d87b1..fbd9e67e6df 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -3,17 +3,35 @@ class HelpController < ApplicationController
end
def show
- @category = params[:category]
- @file = params[:file]
+ @filepath = params[:filepath]
+ @format = params[:format]
- if File.exists?(Rails.root.join('doc', @category, @file + '.md'))
- render 'show'
+ respond_to do |format|
+ format.md { render_doc }
+ format.all { send_file_data }
+ end
+ end
+
+ def shortcuts
+ end
+
+ private
+
+ def render_doc
+ if File.exists?(Rails.root.join('doc', @filepath + '.md'))
+ render 'show.html.haml'
else
not_found!
end
end
- def shortcuts
+ def send_file_data
+ path = Rails.root.join('doc', "#{@filepath}.#{@format}")
+ if File.exists?(path)
+ send_file(path, disposition: 'inline')
+ else
+ head :not_found
+ end
end
def ui
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index edb8bd4160b..93a7ace3530 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -8,7 +8,7 @@ class Import::BaseController < ApplicationController
namespace.add_owner(current_user)
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
namespace = Namespace.find_by_path_or_name(@target_namespace)
- unless namespace.owner == current_user
+ unless current_user.can?(:create_projects, namespace)
@already_been_taken = true
return false
end
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index 83ebc5fddca..bb8d7e0235c 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -36,8 +36,11 @@ class Import::BitbucketController < Import::BaseController
def create
@repo_id = params[:repo_id] || ""
repo = client.project(@repo_id.gsub("___", "/"))
- @target_namespace = params[:new_namespace].presence || repo["owner"]
@project_name = repo["slug"]
+
+ repo_owner = repo["owner"]
+ repo_owner = current_user.username if repo_owner == client.user["user"]["username"]
+ @target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 8650b6464dc..87b41454c77 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -31,8 +31,11 @@ class Import::GithubController < Import::BaseController
def create
@repo_id = params[:repo_id].to_i
repo = client.repo(@repo_id)
- @target_namespace = params[:new_namespace].presence || repo.owner.login
@project_name = repo.name
+
+ repo_owner = repo.owner.login
+ repo_owner = current_user.username if repo_owner == client.user.login
+ @target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index e979dad4b11..bddbfded812 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -28,8 +28,11 @@ class Import::GitlabController < Import::BaseController
def create
@repo_id = params[:repo_id].to_i
repo = client.project(@repo_id)
- @target_namespace = params[:new_namespace].presence || repo["namespace"]["path"]
@project_name = repo["name"]
+
+ repo_owner = repo["namespace"]["path"]
+ repo_owner = current_user.username if repo_owner == client.user["username"]
+ @target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
diff --git a/app/controllers/namespaces_controller.rb b/app/controllers/namespaces_controller.rb
index b7a9d8c1291..386d103ee5a 100644
--- a/app/controllers/namespaces_controller.rb
+++ b/app/controllers/namespaces_controller.rb
@@ -4,14 +4,22 @@ class NamespacesController < ApplicationController
def show
namespace = Namespace.find_by(path: params[:id])
- unless namespace
- return render_404
+ if namespace
+ if namespace.is_a?(Group)
+ group = namespace
+ else
+ user = namespace.owner
+ end
end
- if namespace.type == "Group"
- redirect_to group_path(namespace)
+ if user
+ redirect_to user_path(user)
+ elsif group && can?(current_user, :read_group, group)
+ redirect_to group_path(group)
+ elsif current_user.nil?
+ authenticate_user!
else
- redirect_to user_path(namespace.owner)
+ render_404
end
end
end
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index cbb888b25e8..96defb0c721 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,18 +11,18 @@ class Projects::RepositoriesController < Projects::ApplicationController
end
def archive
- unless can?(current_user, :download_code, @project)
- render_404 and return
+ begin
+ file_path = ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
+ rescue
+ return head :not_found
end
- file_path = ArchiveRepositoryService.new.execute(@project, params[:ref], params[:format])
-
if file_path
# Send file to user
response.headers["Content-Length"] = File.open(file_path).size.to_s
send_file file_path
else
- render_404
+ redirect_to request.fullpath
end
end
end
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 3386fac8657..9703c8d9e9c 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -29,6 +29,10 @@ module GitlabRoutingHelper
namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args)
end
+ def milestone_path(entity, *args)
+ namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args)
+ end
+
def project_url(project, *args)
namespace_project_url(project.namespace, project, *args)
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 187e21832f0..a9030729b48 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -40,7 +40,7 @@ module IconsHelper
def file_type_icon_class(type, mode, name)
if type == 'folder'
icon_class = 'folder'
- elsif mode == 0120000
+ elsif mode == '120000'
icon_class = 'share'
else
# Guess which icon to choose based on file extension.
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index a4bd4d30215..ad4a7612724 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -13,22 +13,34 @@ module IssuesHelper
OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
end
- def url_for_project_issues(project = @project)
+ def url_for_project_issues(project = @project, options = {})
return '' if project.nil?
- project.issues_tracker.project_url
+ if options[:only_path]
+ project.issues_tracker.project_path
+ else
+ project.issues_tracker.project_url
+ end
end
- def url_for_new_issue(project = @project)
+ def url_for_new_issue(project = @project, options = {})
return '' if project.nil?
- project.issues_tracker.new_issue_url
+ if options[:only_path]
+ project.issues_tracker.new_issue_path
+ else
+ project.issues_tracker.new_issue_url
+ end
end
- def url_for_issue(issue_iid, project = @project)
+ def url_for_issue(issue_iid, project = @project, options = {})
return '' if project.nil?
- project.issues_tracker.issue_url(issue_iid)
+ if options[:only_path]
+ project.issues_tracker.issue_path(issue_iid)
+ else
+ project.issues_tracker.issue_url(issue_iid)
+ end
end
def title_for_issue(issue_iid, project = @project)
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 8fcdd3bc853..0c186ab5866 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -19,7 +19,7 @@ class Notify < ActionMailer::Base
default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
default from: Proc.new { default_sender_address.format }
- default reply_to: "noreply@#{Gitlab.config.gitlab.host}"
+ default reply_to: Gitlab.config.gitlab.email_reply_to
# Just send email with 2 seconds delay
def self.delay
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 1c87db613ae..6e98c4c2f02 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -16,6 +16,7 @@
# default_branch_protection :integer default(2)
# twitter_sharing_enabled :boolean default(TRUE)
# restricted_visibility_levels :text
+# max_attachment_size :integer default(10)
#
class ApplicationSetting < ActiveRecord::Base
@@ -49,7 +50,8 @@ class ApplicationSetting < ActiveRecord::Base
twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
- restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels']
+ restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
+ max_attachment_size: Settings.gitlab['max_attachment_size']
)
end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 74900d4675d..d96e07034ec 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -52,7 +52,7 @@ module Mentionable
if identifier == "all"
users.push(*project.team.members.flatten)
elsif namespace = Namespace.find_by(path: identifier)
- if namespace.type == "Group"
+ if namespace.is_a?(Group)
users.push(*namespace.users)
else
users << namespace.owner
diff --git a/app/models/event.rb b/app/models/event.rb
index 57f6d5cd4e0..c9a88ffa8e0 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -183,7 +183,11 @@ class Event < ActiveRecord::Base
elsif commented?
"commented on"
elsif created_project?
- "created"
+ if project.import?
+ "imported"
+ else
+ "created"
+ end
else
"opened"
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 35280889a86..dd74165f887 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -24,8 +24,8 @@ class Namespace < ActiveRecord::Base
validates :name,
presence: true, uniqueness: true,
length: { within: 0..255 },
- format: { with: Gitlab::Regex.name_regex,
- message: Gitlab::Regex.name_regex_message }
+ format: { with: Gitlab::Regex.namespace_name_regex,
+ message: Gitlab::Regex.namespace_name_regex_message }
validates :description, length: { within: 0..255 }
validates :path,
@@ -33,8 +33,8 @@ class Namespace < ActiveRecord::Base
presence: true,
length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
- format: { with: Gitlab::Regex.path_regex,
- message: Gitlab::Regex.path_regex_message }
+ format: { with: Gitlab::Regex.namespace_regex,
+ message: Gitlab::Regex.namespace_regex_message }
delegate :name, to: :owner, allow_nil: true, prefix: true
@@ -44,21 +44,36 @@ class Namespace < ActiveRecord::Base
scope :root, -> { where('type IS NULL') }
- def self.by_path(path)
- where('lower(path) = :value', value: path.downcase).first
- end
+ class << self
+ def by_path(path)
+ where('lower(path) = :value', value: path.downcase).first
+ end
- # Case insensetive search for namespace by path or name
- def self.find_by_path_or_name(path)
- find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
- end
+ # Case insensetive search for namespace by path or name
+ def find_by_path_or_name(path)
+ find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
+ end
- def self.search(query)
- where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
- end
+ def search(query)
+ where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
+ end
+
+ def clean_path(path)
+ path.gsub!(/@.*\z/, "")
+ path.gsub!(/\.git\z/, "")
+ path.gsub!(/\A-/, "")
+ path.gsub!(/.\z/, "")
+ path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
+
+ counter = 0
+ base = path
+ while Namespace.by_path(path).present?
+ counter += 1
+ path = "#{base}#{counter}"
+ end
- def self.global_id
- 'GLN'
+ path
+ end
end
def to_param
diff --git a/app/models/note.rb b/app/models/note.rb
index e86160e7cd9..fdab4517df3 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -22,6 +22,7 @@ require 'file_size_validator'
class Note < ActiveRecord::Base
include Mentionable
+ include Gitlab::CurrentSettings
default_value_for :system, false
@@ -36,7 +37,8 @@ class Note < ActiveRecord::Base
validates :note, :project, presence: true
validates :line_code, format: { with: /\A[a-z0-9]+_\d+_\d+\Z/ }, allow_blank: true
- validates :attachment, file_size: { maximum: 10.megabytes.to_i }
+ # Attachments are deprecated and are handled by Markdown uploader
+ validates :attachment, file_size: { maximum: :max_attachment_size }
validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' }
validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' }
@@ -321,6 +323,10 @@ class Note < ActiveRecord::Base
end
end
+ def max_attachment_size
+ current_application_settings.max_attachment_size.megabytes.to_i
+ end
+
def commit_author
@commit_author ||=
project.team.users.find_by(email: noteable.author_email) ||
@@ -451,7 +457,7 @@ class Note < ActiveRecord::Base
prev_match_line = line
else
prev_lines << line
-
+
break if generate_line_code(line) == self.line_code
prev_lines.shift if prev_lines.length >= max_number_of_lines
diff --git a/app/models/project.rb b/app/models/project.rb
index c50b8a12621..79572f255db 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -124,12 +124,12 @@ class Project < ActiveRecord::Base
presence: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex,
- message: Gitlab::Regex.project_regex_message }
+ message: Gitlab::Regex.project_name_regex_message }
validates :path,
presence: true,
length: { within: 0..255 },
- format: { with: Gitlab::Regex.path_regex,
- message: Gitlab::Regex.path_regex_message }
+ format: { with: Gitlab::Regex.project_path_regex,
+ message: Gitlab::Regex.project_path_regex_message }
validates :issues_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 84346350a6c..5f0553f3b0b 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -20,8 +20,13 @@
class GitlabIssueTrackerService < IssueTrackerService
include Rails.application.routes.url_helpers
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ default_url_options[:host] = Gitlab.config.gitlab.host
+ default_url_options[:protocol] = Gitlab.config.gitlab.protocol
+ default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
+ default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
+
+ prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
def default?
true
@@ -32,20 +37,26 @@ class GitlabIssueTrackerService < IssueTrackerService
end
def project_url
- "#{gitlab_url}#{namespace_project_issues_path(project.namespace, project)}"
+ namespace_project_issues_url(project.namespace, project)
end
def new_issue_url
- "#{gitlab_url}#{new_namespace_project_issue_path(namespace_id: project.namespace, project_id: project)}"
+ new_namespace_project_issue_url(namespace_id: project.namespace, project_id: project)
end
def issue_url(iid)
- "#{gitlab_url}#{namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: iid)}"
+ namespace_project_issue_url(namespace_id: project.namespace, project_id: project, id: iid)
end
- private
+ def project_path
+ namespace_project_issues_path(project.namespace, project)
+ end
+
+ def new_issue_path
+ new_namespace_project_issue_path(namespace_id: project.namespace, project_id: project)
+ end
- def gitlab_url
- Gitlab.config.gitlab.relative_url_root.chomp("/") if Gitlab.config.gitlab.relative_url_root
+ def issue_path(iid)
+ namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: iid)
end
end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 8e90c44d103..c8ab9d63b74 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -34,6 +34,18 @@ class IssueTrackerService < Service
self.issues_url.gsub(':id', iid.to_s)
end
+ def project_path
+ project_url
+ end
+
+ def new_issue_path
+ new_issue_url
+ end
+
+ def issue_path(iid)
+ issue_url(iid)
+ end
+
def fields
[
{ type: 'text', name: 'description', placeholder: description },
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 77765cae1a0..72769498872 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -267,6 +267,9 @@ class Repository
# Remove archives older than 2 hours
def clean_old_archives
repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
+
+ return unless File.directory?(repository_downloads_path)
+
Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 3fb2ec1d66c..b35e72c4bdb 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -33,8 +33,8 @@ class Snippet < ActiveRecord::Base
validates :file_name,
presence: true,
length: { within: 0..255 },
- format: { with: Gitlab::Regex.path_regex,
- message: Gitlab::Regex.path_regex_message }
+ format: { with: Gitlab::Regex.file_name_regex,
+ message: Gitlab::Regex.file_name_regex_message }
validates :content, presence: true
validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
diff --git a/app/models/user.rb b/app/models/user.rb
index 979150b4d68..515f29ea0ba 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -129,8 +129,8 @@ class User < ActiveRecord::Base
presence: true,
uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
- format: { with: Gitlab::Regex.username_regex,
- message: Gitlab::Regex.username_regex_message }
+ format: { with: Gitlab::Regex.namespace_regex,
+ message: Gitlab::Regex.namespace_regex_message }
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
@@ -229,22 +229,6 @@ class User < ActiveRecord::Base
def build_user(attrs = {})
User.new(attrs)
end
-
- def clean_username(username)
- username.gsub!(/@.*\z/, "")
- username.gsub!(/\.git\z/, "")
- username.gsub!(/\A-/, "")
- username.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
-
- counter = 0
- base = username
- while User.by_login(username).present? || Namespace.by_path(username).present?
- counter += 1
- username = "#{base}#{counter}"
- end
-
- username
- end
end
#
diff --git a/app/services/archive_repository_service.rb b/app/services/archive_repository_service.rb
index 8823f6fdc67..e1b41527d8d 100644
--- a/app/services/archive_repository_service.rb
+++ b/app/services/archive_repository_service.rb
@@ -1,14 +1,62 @@
class ArchiveRepositoryService
- def execute(project, ref, format)
- storage_path = Gitlab.config.gitlab.repository_downloads_path
+ attr_reader :project, :ref, :format
- unless File.directory?(storage_path)
- FileUtils.mkdir_p(storage_path)
+ def initialize(project, ref, format)
+ format ||= 'tar.gz'
+ @project, @ref, @format = project, ref, format.downcase
+ end
+
+ def execute(options = {})
+ project.repository.clean_old_archives
+
+ raise "No archive file path" unless file_path
+
+ return file_path if archived?
+
+ unless archiving?
+ RepositoryArchiveWorker.perform_async(project.id, ref, format)
end
- format ||= 'tar.gz'
- repository = project.repository
- repository.clean_old_archives
- repository.archive_repo(ref, storage_path, format.downcase)
+ archived = wait_until_archived(options[:timeout] || 5.0)
+
+ file_path if archived
+ end
+
+ private
+
+ def storage_path
+ Gitlab.config.gitlab.repository_downloads_path
+ end
+
+ def file_path
+ @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
+ end
+
+ def pid_file_path
+ @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
+ end
+
+ def archived?
+ File.exist?(file_path)
+ end
+
+ def archiving?
+ File.exist?(pid_file_path)
+ end
+
+ def wait_until_archived(timeout = 5.0)
+ return archived? if timeout == 0.0
+
+ t1 = Time.now
+
+ begin
+ sleep 0.1
+
+ success = archived?
+
+ t2 = Time.now
+ end until success || t2 - t1 >= timeout
+
+ success
end
end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index eeafefc25af..23833aa78ec 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -12,10 +12,10 @@ module Files
file_name = File.basename(path)
file_path = path
- unless file_name =~ Gitlab::Regex.path_regex
+ unless file_name =~ Gitlab::Regex.file_name_regex
return error(
'Your changes could not be committed, because the file name ' +
- Gitlab::Regex.path_regex_message
+ Gitlab::Regex.file_name_regex_message
)
end
diff --git a/app/services/projects/upload_service.rb b/app/services/projects/upload_service.rb
index a186c97628f..992a7a7a1dc 100644
--- a/app/services/projects/upload_service.rb
+++ b/app/services/projects/upload_service.rb
@@ -5,7 +5,7 @@ module Projects
end
def execute
- return nil unless @file
+ return nil unless @file and @file.size <= max_attachment_size
uploader = FileUploader.new(@project)
uploader.store!(@file)
@@ -18,5 +18,11 @@ module Projects
'is_image' => uploader.image?
}
end
+
+ private
+
+ def max_attachment_size
+ current_application_settings.max_attachment_size.megabytes.to_i
+ end
end
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index edfcccfcf4c..4f3565c67eb 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -60,5 +60,10 @@
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
+ .form-group
+ = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.number_field :max_attachment_size, class: 'form-control'
+
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index 8db2b2a709c..4ef8e878a7f 100644
--- a/app/views/admin/background_jobs/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
@@ -41,4 +41,4 @@
.panel.panel-default
- %iframe{src: sidekiq_path, width: '100%', height: 900, style: "border: none"}
+ %iframe{src: sidekiq_path, width: '100%', height: 970, style: "border: none"}
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 05372f4124f..b0b23132560 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -42,11 +42,11 @@
%li
%span.light http:
%strong
- = link_to @project.http_url_to_repo
+ = link_to @project.http_url_to_repo, project_path(@project)
%li
%span.light ssh:
%strong
- = link_to @project.ssh_url_to_repo
+ = link_to @project.ssh_url_to_repo, project_path(@project)
- if @project.repository.exists?
%li
%span.light fs:
diff --git a/app/views/dashboard/milestones/_milestone.html.haml b/app/views/dashboard/milestones/_milestone.html.haml
new file mode 100644
index 00000000000..21e730bb7ff
--- /dev/null
+++ b/app/views/dashboard/milestones/_milestone.html.haml
@@ -0,0 +1,20 @@
+%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
+ %h4
+ = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
+ .row
+ .col-sm-6
+ = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.issue_count, 'Issue'
+ &nbsp;
+ = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.merge_requests_count, 'Merge Request'
+ &nbsp;
+ %span.light #{milestone.percent_complete}% complete
+
+ .col-sm-6
+ = milestone_progress_bar(milestone)
+ %div
+ - milestone.milestones.each do |milestone|
+ = link_to milestone_path(milestone) do
+ %span.label.label-gray
+ = milestone.project.name_with_namespace
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
index caf3b685864..9944c0df815 100644
--- a/app/views/dashboard/milestones/index.html.haml
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -16,23 +16,5 @@
.nothing-here-block No milestones to show
- else
- @dashboard_milestones.each do |milestone|
- %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
- %h4
- = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
- %div
- %div
- = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
- = pluralize milestone.issue_count, 'Issue'
- &nbsp;
- = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
- = pluralize milestone.merge_requests_count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
- = milestone_progress_bar(milestone)
- %div
- %br
- - milestone.milestones.each do |milestone|
- = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
- %span.label.label-default
- = milestone.project.name_with_namespace
+ = render 'milestone', milestone: milestone
= paginate @dashboard_milestones, theme: "gitlab"
diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml
index 3c7153d235f..552525f4a07 100644
--- a/app/views/events/event/_created_project.html.haml
+++ b/app/views/events/event/_created_project.html.haml
@@ -18,10 +18,10 @@
%a.twitter-share-button{ |
href: "https://twitter.com/share", |
"data-url" => event.project.web_url, |
- "data-text" => "I just created a new project in GitLab! GitLab is version control on your server.", |
+ "data-text" => "I just #{event.project.imported? ? "imported" : "created"} a new project in GitLab! GitLab is version control on your server.", |
"data-size" => "medium", |
"data-related" => "gitlab", |
"data-hashtags" => "gitlab", |
"data-count" => "none"}
Tweet
- %script{src: "//platform.twitter.com/widgets.js"} \ No newline at end of file
+ %script{src: "//platform.twitter.com/widgets.js"}
diff --git a/app/views/groups/milestones/_milestone.html.haml b/app/views/groups/milestones/_milestone.html.haml
new file mode 100644
index 00000000000..94fc43a581e
--- /dev/null
+++ b/app/views/groups/milestones/_milestone.html.haml
@@ -0,0 +1,25 @@
+%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
+ .pull-right
+ - if can?(current_user, :manage_group, @group)
+ - if milestone.closed?
+ = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
+ - else
+ = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
+ %h4
+ = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
+ .row
+ .col-sm-6
+ = link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.issue_count, 'Issue'
+ &nbsp;
+ = link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.merge_requests_count, 'Merge Request'
+ &nbsp;
+ %span.light #{milestone.percent_complete}% complete
+ .col-sm-6
+ = milestone_progress_bar(milestone)
+ %div
+ - milestone.milestones.each do |milestone|
+ = link_to milestone_path(milestone) do
+ %span.label.label-gray
+ = milestone.project.name
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 57dc235f5bb..008d5a6bd22 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -18,29 +18,5 @@
.nothing-here-block No milestones to show
- else
- @group_milestones.each do |milestone|
- %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
- .pull-right
- - if can?(current_user, :manage_group, @group)
- - if milestone.closed?
- = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
- - else
- = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
- %h4
- = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
- %div
- %div
- = link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
- = pluralize milestone.issue_count, 'Issue'
- &nbsp;
- = link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
- = pluralize milestone.merge_requests_count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
- = milestone_progress_bar(milestone)
- %div
- %br
- - milestone.milestones.each do |milestone|
- = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
- %span.label.label-default
- = milestone.project.name
+ = render 'milestone', milestone: milestone
= paginate @group_milestones, theme: "gitlab"
diff --git a/app/views/help/show.html.haml b/app/views/help/show.html.haml
index eca34dbff06..f22aa92caf7 100644
--- a/app/views/help/show.html.haml
+++ b/app/views/help/show.html.haml
@@ -1,2 +1,2 @@
.documentation.wiki
- = markdown File.read(Rails.root.join('doc', @category, @file + '.md')).gsub("$your_email", current_user.email)
+ = markdown File.read(Rails.root.join('doc', @filepath + '.md')).gsub("$your_email", current_user.email)
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 52681865d64..6c13f30f627 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -53,7 +53,7 @@
- if project_nav_tab? :issues
= nav_link(controller: :issues) do
- = link_to url_for_project_issues, title: 'Issues', class: 'shortcuts-issues' do
+ = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
%i.fa.fa-exclamation-circle
%span
Issues
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 778a78acf56..e796353cec4 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,2 @@
%div
- = replace_image_links_with_base64(markdown(@note.note), @note.project)
+ = replace_image_links_with_base64(markdown(@note.note, reference_only_path: false), @note.project)
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index 03cbee94608..d4d413b5b44 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,5 @@
-if @issue.description
- = replace_image_links_with_base64(markdown(@issue.description), @issue.project)
+ = replace_image_links_with_base64(markdown(@issue.description, reference_only_path: false), @issue.project)
- if @issue.assignee_id.present?
%p
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index 729a7bb505d..60e33227e01 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -6,4 +6,4 @@
Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
-if @merge_request.description
- = replace_image_links_with_base64(markdown(@merge_request.description), @merge_request.project)
+ = replace_image_links_with_base64(markdown(@merge_request.description, reference_only_path: false), @merge_request.project)
diff --git a/app/views/projects/_dropdown.html.haml b/app/views/projects/_dropdown.html.haml
index f4f4c2662cf..3adb3087289 100644
--- a/app/views/projects/_dropdown.html.haml
+++ b/app/views/projects/_dropdown.html.haml
@@ -5,7 +5,7 @@
%ul.dropdown-menu
- if @project.issues_enabled && can?(current_user, :write_issue, @project)
%li
- = link_to url_for_new_issue, title: "New Issue" do
+ = link_to url_for_new_issue(@project, only_path: true), title: "New Issue" do
New issue
- if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
%li
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index 7039c85bb2c..62360158ff9 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -11,16 +11,14 @@
%span.cred (Expired)
%small
= milestone.expires_at
- - if milestone.is_empty?
- %span.muted Empty
- - else
- %div
- %div
- = link_to namespace_project_issues_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
- = pluralize milestone.issues.count, 'Issue'
- &nbsp;
- = link_to namespace_project_merge_requests_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
- = pluralize milestone.merge_requests.count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
+ .row
+ .col-sm-6
+ = link_to namespace_project_issues_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
+ = pluralize milestone.issues.count, 'Issue'
+ &nbsp;
+ = link_to namespace_project_merge_requests_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
+ = pluralize milestone.merge_requests.count, 'Merge Request'
+ &nbsp;
+ %span.light #{milestone.percent_complete}% complete
+ .col-sm-6
= milestone_progress_bar(milestone)
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index be96c302143..2ada6cb6700 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -12,7 +12,7 @@
.comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
.pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
-
+ .error-alert
.note-form-actions
.buttons
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
index b7383d5594e..297fa537394 100644
--- a/app/views/users/_projects.html.haml
+++ b/app/views/users/_projects.html.haml
@@ -1,13 +1,13 @@
-- if @contributed_projects.present?
+- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present?
.panel.panel-default.contributed-projects
.panel-heading Projects contributed to
= render 'shared/projects_list',
- projects: @contributed_projects.sort_by(&:star_count).reverse,
+ projects: contributed_projects.sort_by(&:star_count).reverse,
projects_limit: 5, stars: true, avatar: false
-- if @projects.present?
+- if local_assigns.has_key?(:projects) && projects.present?
.panel.panel-default
.panel-heading Personal projects
= render 'shared/projects_list',
- projects: @projects.sort_by(&:star_count).reverse,
+ projects: projects.sort_by(&:star_count).reverse,
projects_limit: 10, stars: true, avatar: false
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 5e1d65e2ed8..9dd8cb0738c 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -44,7 +44,7 @@
= spinner
%aside.col-md-4
= render 'profile', user: @user
- = render 'projects'
+ = render 'projects', projects: @projects, contributed_projects: @contributed_projects
:coffeescript
$(".user-calendar").load("#{user_calendar_path}")
diff --git a/app/workers/repository_archive_worker.rb b/app/workers/repository_archive_worker.rb
new file mode 100644
index 00000000000..021c1139568
--- /dev/null
+++ b/app/workers/repository_archive_worker.rb
@@ -0,0 +1,43 @@
+class RepositoryArchiveWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: :archive_repo
+
+ attr_accessor :project, :ref, :format
+
+ def perform(project_id, ref, format)
+ @project = Project.find(project_id)
+ @ref, @format = ref, format.downcase
+
+ repository = project.repository
+
+ repository.clean_old_archives
+
+ return unless file_path
+ return if archived? || archiving?
+
+ repository.archive_repo(ref, storage_path, format)
+ end
+
+ private
+
+ def storage_path
+ Gitlab.config.gitlab.repository_downloads_path
+ end
+
+ def file_path
+ @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
+ end
+
+ def pid_file_path
+ @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
+ end
+
+ def archived?
+ File.exist?(file_path)
+ end
+
+ def archiving?
+ File.exist?(pid_file_path)
+ end
+end
diff --git a/bin/background_jobs b/bin/background_jobs
index 59a51c5c868..a041a4b0433 100755
--- a/bin/background_jobs
+++ b/bin/background_jobs
@@ -37,7 +37,7 @@ start_no_deamonize()
start_sidekiq()
{
- bundle exec sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
+ bundle exec sidekiq -q post_receive -q mailer -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
}
load_ok()
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 760a589d6e2..3d91b67e748 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -49,6 +49,7 @@ production: &base
# Email address used in the "From" field in mails sent by GitLab
email_from: example@example.com
email_display_name: GitLab
+ email_reply_to: noreply@example.com
# Email server smtp settings are in config/initializers/smtp_settings.rb.sample
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 15c1ae9466f..de79595d031 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -103,6 +103,7 @@ Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil?
Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}"
Settings.gitlab['email_display_name'] ||= "GitLab"
+Settings.gitlab['email_reply_to'] ||= "noreply@#{Settings.gitlab.host}"
Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url)
Settings.gitlab['user'] ||= 'git'
Settings.gitlab['user_home'] ||= begin
@@ -119,6 +120,7 @@ Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username
Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10
+Settings.gitlab['max_attachment_size'] ||= 10
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.gitlab.default_projects_features['merge_requests'].nil?
Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil?
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index 8f8bef42bef..6978ad93024 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -6,3 +6,4 @@
Mime::Type.register_alias "text/plain", :diff
Mime::Type.register_alias "text/plain", :patch
+Mime::Type.register_alias 'text/html', :md
diff --git a/config/routes.rb b/config/routes.rb
index 388858d2670..c1b85b025b5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -39,9 +39,9 @@ Gitlab::Application.routes.draw do
# Help
get 'help' => 'help#index'
- get 'help/:category/:file' => 'help#show', as: :help_page
get 'help/shortcuts'
get 'help/ui' => 'help#ui'
+ get 'help/:filepath' => 'help#show', as: :help_page, constraints: { filepath: /[^\.]+/ }
#
# Global snippets
diff --git a/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb b/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb
new file mode 100644
index 00000000000..7ce53c2a0d6
--- /dev/null
+++ b/db/migrate/20150324133047_remove_periods_at_ends_of_usernames.rb
@@ -0,0 +1,76 @@
+class RemovePeriodsAtEndsOfUsernames < ActiveRecord::Migration
+ include Gitlab::ShellAdapter
+
+ class Namespace < ActiveRecord::Base
+ class << self
+ def by_path(path)
+ where('lower(path) = :value', value: path.downcase).first
+ end
+
+ def clean_path(path)
+ path = path.dup
+ path.gsub!(/@.*\z/, "")
+ path.gsub!(/\.git\z/, "")
+ path.gsub!(/\A-/, "")
+ path.gsub!(/.\z/, "")
+ path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
+
+ counter = 0
+ base = path
+ while Namespace.by_path(path).present?
+ counter += 1
+ path = "#{base}#{counter}"
+ end
+
+ path
+ end
+ end
+ end
+
+ def up
+ changed_paths = {}
+
+ select_all("SELECT id, username FROM users WHERE username LIKE '%.'").each do |user|
+ username_was = user["username"]
+ username = Namespace.clean_path(username_was)
+ changed_paths[username_was] = username
+
+ username = quote_string(username)
+ execute "UPDATE users SET username = '#{username}' WHERE id = #{user["id"]}"
+ execute "UPDATE namespaces SET path = '#{username}', name = '#{username}' WHERE type IS NULL AND owner_id = #{user["id"]}"
+ end
+
+ select_all("SELECT id, path FROM namespaces WHERE type = 'Group' AND path LIKE '%.'").each do |group|
+ path_was = group["path"]
+ path = Namespace.clean_path(path_was)
+ changed_paths[path_was] = path
+
+ path = quote_string(path)
+ execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{group["id"]}"
+ end
+
+ changed_paths.each do |path_was, path|
+ if gitlab_shell.mv_namespace(path_was, path)
+ # If repositories moved successfully we need to remove old satellites
+ # and send update instructions to users.
+ # However we cannot allow rollback since we moved namespace dir
+ # So we basically we mute exceptions in next actions
+ begin
+ gitlab_shell.rm_satellites(path_was)
+ # We cannot send update instructions since models and mailers
+ # can't safely be used from migrations as they may be written for
+ # later versions of the database.
+ # send_update_instructions
+ rescue
+ # Returning false does not rollback after_* transaction but gives
+ # us information about failing some of tasks
+ false
+ end
+ else
+ # if we cannot move namespace directory we should rollback
+ # db changes in order to prevent out of sync between db and fs
+ raise Exception.new('namespace directory cannot be moved')
+ end
+ end
+ end
+end
diff --git a/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb b/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb
new file mode 100644
index 00000000000..1d161674a9a
--- /dev/null
+++ b/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb
@@ -0,0 +1,5 @@
+class AddMaxAttachmentSizeToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :max_attachment_size, :integer, default: 10, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4a445ae5832..14e32a7946e 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: 20150324155957) do
+ActiveRecord::Schema.define(version: 20150328132231) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -28,6 +28,7 @@ ActiveRecord::Schema.define(version: 20150324155957) do
t.integer "default_branch_protection", default: 2
t.boolean "twitter_sharing_enabled", default: true
t.text "restricted_visibility_levels"
+ t.integer "max_attachment_size", default: 10, null: false
end
create_table "broadcast_messages", force: true do |t|
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 7fe244477db..55d525fef66 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -44,6 +44,10 @@ Parameters:
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
+ "tag_list": [
+ "example",
+ "disapora client"
+ ],
"owner": {
"id": 3,
"name": "Diaspora",
@@ -80,6 +84,10 @@ Parameters:
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
+ "tag_list": [
+ "example",
+ "puppet"
+ ],
"owner": {
"id": 4,
"name": "Brightbox",
@@ -163,6 +171,10 @@ Parameters:
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
+ "tag_list": [
+ "example",
+ "disapora project"
+ ],
"owner": {
"id": 3,
"name": "Diaspora",
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 99cdfff0ac6..2e41fad89e7 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -17,6 +17,13 @@ sudo gitlab-rake gitlab:backup:create
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
+Also you can choose what should be backed up by adding environment variable SKIP. Available options: db,
+uploads (attachments), repositories. Use a comma to specify several options at the same time.
+
+```
+sudo gitlab-rake gitlab:backup:create SKIP=db,uploads
+```
+
Example output:
```
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index b9031f6f32b..af01c7058ea 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -42,6 +42,7 @@ Feature: Project Issues
Given I visit issue page "Release 0.4"
And I leave a comment like "XML attached"
Then I should see comment "XML attached"
+ And I should see an error alert section within the comment form
@javascript
Scenario: I search issue
diff --git a/features/steps/dashboard/help.rb b/features/steps/dashboard/help.rb
index ef433c57c6e..fa52e391f05 100644
--- a/features/steps/dashboard/help.rb
+++ b/features/steps/dashboard/help.rb
@@ -8,7 +8,7 @@ class Spinach::Features::DashboardHelp < Spinach::FeatureSteps
end
step 'I visit the "Rake Tasks" help page' do
- visit help_page_path("raketasks", "maintenance")
+ visit help_page_path('raketasks/maintenance', format: 'md')
end
step 'I should see "Rake Tasks" page markdown rendered' do
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index e8ca3f7c176..e2834d51a27 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -204,6 +204,12 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
end
+ step 'I should see an error alert section within the comment form' do
+ within(".js-main-target-form") do
+ find(".error-alert")
+ end
+ end
+
step 'The code block should be unchanged' do
page.should have_content("```\nCommand [1]: /usr/local/bin/git , see [text](doc/text)\n```")
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 557555aee58..caf6c73ee06 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -74,7 +74,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I fill the new file name with an illegal name' do
- fill_in :file_name, with: '.git'
+ fill_in :file_name, with: 'Spaces Not Allowed'
end
step 'I fill the commit message' do
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index edfdf842f85..592100a7045 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -1,5 +1,4 @@
require 'mime/types'
-require 'uri'
module API
# Projects API
@@ -101,10 +100,11 @@ module API
# branch (required) - The name of the branch
# Example Request:
# DELETE /projects/:id/repository/branches/:branch
- delete ":id/repository/branches/:branch" do
+ delete ":id/repository/branches/:branch",
+ requirements: { branch: /.*/ } do
authorize_push_project
result = DeleteBranchService.new(user_project, current_user).
- execute(URI.unescape(params[:branch]))
+ execute(params[:branch])
if result[:status] == :success
{
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 489be210784..51cb934616b 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -46,7 +46,7 @@ module API
end
class Project < Grape::Entity
- expose :id, :description, :default_branch
+ expose :id, :description, :default_branch, :tag_list
expose :public?, as: :public
expose :archived?, as: :archived
expose :visibility_level, :ssh_url_to_repo, :http_url_to_repo, :web_url
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index b259914a01c..1fbf3dca3c6 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -133,10 +133,11 @@ module API
authorize! :download_code, user_project
begin
- file_path = ArchiveRepositoryService.new.execute(
- user_project,
- params[:sha],
- params[:format])
+ file_path = ArchiveRepositoryService.new(
+ user_project,
+ params[:sha],
+ params[:format]
+ ).execute
rescue
not_found!('File')
end
@@ -149,7 +150,7 @@ module API
env['api.format'] = :binary
present data
else
- not_found!('File')
+ redirect request.fullpath
end
end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index afd05897509..b69aebf9fe1 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -1,7 +1,5 @@
module Backup
class Manager
- BACKUP_CONTENTS = %w{repositories/ db/ uploads/ backup_information.yml}
-
def pack
# saving additional informations
s = {}
@@ -9,6 +7,7 @@ module Backup
s[:backup_created_at] = Time.now
s[:gitlab_version] = Gitlab::VERSION
s[:tar_version] = tar_version
+ s[:skipped] = ENV["SKIP"]
tar_file = "#{s[:backup_created_at].to_i}_gitlab_backup.tar"
Dir.chdir(Gitlab.config.backup.path) do
@@ -17,12 +16,12 @@ module Backup
file << s.to_yaml.gsub(/^---\n/,'')
end
- FileUtils.chmod_R(0700, %w{db uploads repositories})
+ FileUtils.chmod(0700, folders_to_backup)
# create archive
$progress.print "Creating backup archive: #{tar_file} ... "
orig_umask = File.umask(0077)
- if Kernel.system('tar', '-cf', tar_file, *BACKUP_CONTENTS)
+ if Kernel.system('tar', '-cf', tar_file, *backup_contents)
$progress.puts "done".green
else
puts "creating archive #{tar_file} failed".red
@@ -46,6 +45,7 @@ module Backup
connection = ::Fog::Storage.new(connection_settings)
directory = connection.directories.get(remote_directory)
+
if directory.files.create(key: tar_file, body: File.open(tar_file), public: false)
$progress.puts "done".green
else
@@ -56,7 +56,10 @@ module Backup
def cleanup
$progress.print "Deleting tmp directories ... "
- BACKUP_CONTENTS.each do |dir|
+
+ backup_contents.each do |dir|
+ next unless File.exist?(File.join(Gitlab.config.backup.path, dir))
+
if FileUtils.rm_rf(File.join(Gitlab.config.backup.path, dir))
$progress.puts "done".green
else
@@ -73,6 +76,7 @@ module Backup
if keep_time > 0
removed = 0
+
Dir.chdir(Gitlab.config.backup.path) do
file_list = Dir.glob('*_gitlab_backup.tar')
file_list.map! { |f| $1.to_i if f =~ /(\d+)_gitlab_backup.tar/ }
@@ -84,6 +88,7 @@ module Backup
end
end
end
+
$progress.puts "done. (#{removed} removed)".green
else
$progress.puts "skipping".yellow
@@ -96,6 +101,7 @@ module Backup
# check for existing backups in the backup dir
file_list = Dir.glob("*_gitlab_backup.tar").each.map { |f| f.split(/_/).first.to_i }
puts "no backups found" if file_list.count == 0
+
if file_list.count > 1 && ENV["BACKUP"].nil?
puts "Found more than one backup, please specify which one you want to restore:"
puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup"
@@ -110,6 +116,7 @@ module Backup
end
$progress.print "Unpacking backup ... "
+
unless Kernel.system(*%W(tar -xf #{tar_file}))
puts "unpacking backup failed".red
exit 1
@@ -117,7 +124,6 @@ module Backup
$progress.puts "done".green
end
- settings = YAML.load_file("backup_information.yml")
ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0
# restoring mismatching backups can lead to unexpected problems
@@ -136,5 +142,29 @@ module Backup
tar_version, _ = Gitlab::Popen.popen(%W(tar --version))
tar_version.force_encoding('locale').split("\n").first
end
+
+ def skipped?(item)
+ settings[:skipped] && settings[:skipped].include?(item)
+ end
+
+ private
+
+ def backup_contents
+ folders_to_backup + ["backup_information.yml"]
+ end
+
+ def folders_to_backup
+ folders = %w{repositories db uploads}
+
+ if ENV["SKIP"]
+ return folders.reject{ |folder| ENV["SKIP"].include?(folder) }
+ end
+
+ folders
+ end
+
+ def settings
+ @settings ||= YAML.load_file("backup_information.yml")
+ end
end
end
diff --git a/lib/file_size_validator.rb b/lib/file_size_validator.rb
index 42970c1be59..2eae55e534b 100644
--- a/lib/file_size_validator.rb
+++ b/lib/file_size_validator.rb
@@ -25,8 +25,8 @@ class FileSizeValidator < ActiveModel::EachValidator
keys.each do |key|
value = options[key]
- unless value.is_a?(Integer) && value >= 0
- raise ArgumentError, ":#{key} must be a nonnegative Integer"
+ unless (value.is_a?(Integer) && value >= 0) || value.is_a?(Symbol)
+ raise ArgumentError, ":#{key} must be a nonnegative Integer or symbol"
end
end
end
@@ -39,6 +39,14 @@ class FileSizeValidator < ActiveModel::EachValidator
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
+ check_value =
+ case check_value
+ when Integer
+ check_value
+ when Symbol
+ record.send(check_value)
+ end
+
value ||= [] if key == :maximum
value_size = value.size
diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb
index db33af2c2da..54420e62c90 100644
--- a/lib/gitlab/bitbucket_import/project_creator.rb
+++ b/lib/gitlab/bitbucket_import/project_creator.rb
@@ -10,29 +10,16 @@ module Gitlab
end
def execute
- @project = Project.new(
+ ::Projects::CreateService.new(current_user,
name: repo["name"],
path: repo["slug"],
description: repo["description"],
- namespace: namespace,
- creator: current_user,
+ namespace_id: namespace.id,
visibility_level: repo["is_private"] ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
import_type: "bitbucket",
import_source: "#{repo["owner"]}/#{repo["slug"]}",
import_url: "ssh://git@bitbucket.org/#{repo["owner"]}/#{repo["slug"]}.git"
- )
-
- if @project.save!
- @project.reload
-
- if @project.import_failed?
- @project.import_retry
- else
- @project.import_start
- end
- end
-
- @project
+ ).execute
end
end
end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 0ebebfa09c4..d8f696d247b 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -20,7 +20,8 @@ module Gitlab
signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
- restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels']
+ restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
+ max_attachment_size: Settings.gitlab['max_attachment_size']
)
end
end
diff --git a/lib/gitlab/github_import/project_creator.rb b/lib/gitlab/github_import/project_creator.rb
index 9439ca6cbf4..2723eec933e 100644
--- a/lib/gitlab/github_import/project_creator.rb
+++ b/lib/gitlab/github_import/project_creator.rb
@@ -10,29 +10,16 @@ module Gitlab
end
def execute
- @project = Project.new(
+ ::Projects::CreateService.new(current_user,
name: repo.name,
path: repo.name,
description: repo.description,
- namespace: namespace,
- creator: current_user,
+ namespace_id: namespace.id,
visibility_level: repo.private ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
import_type: "github",
import_source: repo.full_name,
import_url: repo.clone_url.sub("https://", "https://#{current_user.github_access_token}@")
- )
-
- if @project.save!
- @project.reload
-
- if @project.import_failed?
- @project.import_retry
- else
- @project.import_start
- end
- end
-
- @project
+ ).execute
end
end
end
diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb
index f48ede9d067..9c00896c913 100644
--- a/lib/gitlab/gitlab_import/client.rb
+++ b/lib/gitlab/gitlab_import/client.rb
@@ -28,6 +28,10 @@ module Gitlab
client.auth_code.get_token(code, redirect_uri: redirect_uri).token
end
+ def user
+ api.get("/api/v3/user").parsed
+ end
+
def issues(project_identifier)
lazy_page_iterator(PER_PAGE) do |page|
api.get("/api/v3/projects/#{project_identifier}/issues?per_page=#{PER_PAGE}&page=#{page}").parsed
diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb
index 6424d56f8f1..f0d7141bf56 100644
--- a/lib/gitlab/gitlab_import/project_creator.rb
+++ b/lib/gitlab/gitlab_import/project_creator.rb
@@ -10,29 +10,16 @@ module Gitlab
end
def execute
- @project = Project.new(
+ ::Projects::CreateService.new(current_user,
name: repo["name"],
path: repo["path"],
description: repo["description"],
- namespace: namespace,
- creator: current_user,
+ namespace_id: namespace.id,
visibility_level: repo["visibility_level"],
import_type: "gitlab",
import_source: repo["path_with_namespace"],
import_url: repo["http_url_to_repo"].sub("://", "://oauth2:#{current_user.gitlab_access_token}@")
- )
-
- if @project.save!
- @project.reload
-
- if @project.import_failed?
- @project.import_retry
- else
- @project.import_start
- end
- end
-
- @project
+ ).execute
end
end
end
diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb
index 3cbebe53997..cc9a91c91f4 100644
--- a/lib/gitlab/gitorious_import/project_creator.rb
+++ b/lib/gitlab/gitorious_import/project_creator.rb
@@ -10,29 +10,16 @@ module Gitlab
end
def execute
- @project = Project.new(
+ ::Projects::CreateService.new(current_user,
name: repo.name,
path: repo.path,
description: repo.description,
- namespace: namespace,
- creator: current_user,
+ namespace_id: namespace.id,
visibility_level: Gitlab::VisibilityLevel::PUBLIC,
import_type: "gitorious",
import_source: repo.full_name,
import_url: repo.import_url
- )
-
- if @project.save!
- @project.reload
-
- if @project.import_failed?
- @project.import_retry
- else
- @project.import_start
- end
- end
-
- @project
+ ).execute
end
end
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 41bb8d08924..f1e2ae74a3a 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -32,12 +32,12 @@ module Gitlab
module Markdown
include IssuesHelper
- attr_reader :html_options
+ attr_reader :options, :html_options
# Public: Parse the provided text with GitLab-Flavored Markdown
#
# text - the source text
- # project - extra options for the reference links as given to link_to
+ # project - the project
# html_options - extra options for the reference links as given to link_to
def gfm(text, project = @project, html_options = {})
gfm_with_options(text, {}, project, html_options)
@@ -46,9 +46,10 @@ module Gitlab
# Public: Parse the provided text with GitLab-Flavored Markdown
#
# text - the source text
- # options - parse_tasks: true - render tasks
- # - xhtml: true - output XHTML instead of HTML
- # project - extra options for the reference links as given to link_to
+ # options - parse_tasks - render tasks
+ # - xhtml - output XHTML instead of HTML
+ # - reference_only_path - Use relative path for reference links
+ # project - the project
# html_options - extra options for the reference links as given to link_to
def gfm_with_options(text, options = {}, project = @project, html_options = {})
return text if text.nil?
@@ -58,6 +59,13 @@ module Gitlab
# for gsub calls to work as we need them to.
text = text.dup.to_str
+ options.reverse_merge!(
+ parse_tasks: false,
+ xhtml: false,
+ reference_only_path: true
+ )
+
+ @options = options
@html_options = html_options
# Extract pre blocks so they are not altered
@@ -113,12 +121,13 @@ module Gitlab
markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
result = markdown_pipeline.call(text, markdown_context)
- saveoptions = 0
+
+ save_options = 0
if options[:xhtml]
- saveoptions |= Nokogiri::XML::Node::SaveOptions::AS_XHTML
+ save_options |= Nokogiri::XML::Node::SaveOptions::AS_XHTML
end
- text = result[:output].to_html(save_with: saveoptions)
+ text = result[:output].to_html(save_with: save_options)
if options[:parse_tasks]
text = parse_tasks(text)
@@ -152,7 +161,7 @@ module Gitlab
text
end
- NAME_STR = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
+ NAME_STR = Gitlab::Regex::NAMESPACE_REGEX_STR
PROJ_STR = "(?<project>#{NAME_STR}/#{NAME_STR})"
REFERENCE_PATTERN = %r{
@@ -229,33 +238,37 @@ module Gitlab
end
def reference_user(identifier, project = @project, _ = nil)
- options = html_options.merge(
+ link_options = html_options.merge(
class: "gfm gfm-project_member #{html_options[:class]}"
)
if identifier == "all"
- link_to("@all", namespace_project_url(project.namespace, project), options)
+ link_to(
+ "@all",
+ namespace_project_url(project.namespace, project, only_path: options[:reference_only_path]),
+ link_options
+ )
elsif namespace = Namespace.find_by(path: identifier)
url =
- if namespace.type == "Group"
- group_url(identifier)
- else
- user_url(identifier)
+ if namespace.is_a?(Group)
+ group_url(identifier, only_path: options[:reference_only_path])
+ else
+ user_url(identifier, only_path: options[:reference_only_path])
end
-
- link_to("@#{identifier}", url, options)
+
+ link_to("@#{identifier}", url, link_options)
end
end
def reference_label(identifier, project = @project, _ = nil)
if label = project.labels.find_by(id: identifier)
- options = html_options.merge(
+ link_options = html_options.merge(
class: "gfm gfm-label #{html_options[:class]}"
)
link_to(
render_colored_label(label),
namespace_project_issues_path(project.namespace, project, label_name: label.name),
- options
+ link_options
)
end
end
@@ -263,14 +276,14 @@ module Gitlab
def reference_issue(identifier, project = @project, prefix_text = nil)
if project.default_issues_tracker?
if project.issue_exists? identifier
- url = url_for_issue(identifier, project)
+ url = url_for_issue(identifier, project, only_path: options[:reference_only_path])
title = title_for_issue(identifier, project)
- options = html_options.merge(
+ link_options = html_options.merge(
title: "Issue: #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
- link_to("#{prefix_text}##{identifier}", url, options)
+ link_to("#{prefix_text}##{identifier}", url, link_options)
end
else
if project.external_issue_tracker.present?
@@ -280,44 +293,46 @@ module Gitlab
end
end
- def reference_merge_request(identifier, project = @project,
- prefix_text = nil)
+ def reference_merge_request(identifier, project = @project, prefix_text = nil)
if merge_request = project.merge_requests.find_by(iid: identifier)
- options = html_options.merge(
+ link_options = html_options.merge(
title: "Merge Request: #{merge_request.title}",
class: "gfm gfm-merge_request #{html_options[:class]}"
)
url = namespace_project_merge_request_url(project.namespace, project,
- merge_request)
- link_to("#{prefix_text}!#{identifier}", url, options)
+ merge_request,
+ only_path: options[:reference_only_path])
+ link_to("#{prefix_text}!#{identifier}", url, link_options)
end
end
def reference_snippet(identifier, project = @project, _ = nil)
if snippet = project.snippets.find_by(id: identifier)
- options = html_options.merge(
+ link_options = html_options.merge(
title: "Snippet: #{snippet.title}",
class: "gfm gfm-snippet #{html_options[:class]}"
)
link_to(
"$#{identifier}",
- namespace_project_snippet_url(project.namespace, project, snippet),
- options
+ namespace_project_snippet_url(project.namespace, project, snippet,
+ only_path: options[:reference_only_path]),
+ link_options
)
end
end
def reference_commit(identifier, project = @project, prefix_text = nil)
if project.valid_repo? && commit = project.repository.commit(identifier)
- options = html_options.merge(
+ link_options = html_options.merge(
title: commit.link_title,
class: "gfm gfm-commit #{html_options[:class]}"
)
prefix_text = "#{prefix_text}@" if prefix_text
link_to(
"#{prefix_text}#{identifier}",
- namespace_project_commit_url(project.namespace, project, commit),
- options
+ namespace_project_commit_url( project.namespace, project, commit,
+ only_path: options[:reference_only_path]),
+ link_options
)
end
end
@@ -328,11 +343,11 @@ module Gitlab
inclusive = identifier !~ /\.{3}/
from_id << "^" if inclusive
- if project.valid_repo? &&
- from = project.repository.commit(from_id) &&
+ if project.valid_repo? &&
+ from = project.repository.commit(from_id) &&
to = project.repository.commit(to_id)
- options = html_options.merge(
+ link_options = html_options.merge(
title: "Commits #{from_id} through #{to_id}",
class: "gfm gfm-commit_range #{html_options[:class]}"
)
@@ -340,22 +355,23 @@ module Gitlab
link_to(
"#{prefix_text}#{identifier}",
- namespace_project_compare_url(project.namespace, project, from: from_id, to: to_id),
- options
+ namespace_project_compare_url(project.namespace, project,
+ from: from_id, to: to_id,
+ only_path: options[:reference_only_path]),
+ link_options
)
end
end
- def reference_external_issue(identifier, project = @project,
- prefix_text = nil)
- url = url_for_issue(identifier, project)
+ def reference_external_issue(identifier, project = @project, prefix_text = nil)
+ url = url_for_issue(identifier, project, only_path: options[:reference_only_path])
title = project.external_issue_tracker.title
- options = html_options.merge(
+ link_options = html_options.merge(
title: "Issue in #{title}",
class: "gfm gfm-issue #{html_options[:class]}"
)
- link_to("#{prefix_text}##{identifier}", url, options)
+ link_to("#{prefix_text}##{identifier}", url, link_options)
end
# Turn list items that start with "[ ]" into HTML checkbox inputs.
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index c023d275703..2f5c217d764 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -86,7 +86,7 @@ module Gitlab
def user_attributes
{
name: auth_hash.name,
- username: ::User.clean_username(auth_hash.username),
+ username: ::Namespace.clean_path(auth_hash.username),
email: auth_hash.email,
password: auth_hash.password,
password_confirmation: auth_hash.password,
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index cf6e260f257..0571574aa4f 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -2,49 +2,66 @@ module Gitlab
module Regex
extend self
- def username_regex
- default_regex
+ NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])'.freeze
+
+ def namespace_regex
+ @namespace_regex ||= /\A#{NAMESPACE_REGEX_STR}\z/.freeze
+ end
+
+ def namespace_regex_message
+ "can contain only letters, digits, '_', '-' and '.'. " \
+ "Cannot start with '-' or end in '.'." \
+ end
+
+
+ def namespace_name_regex
+ @namespace_name_regex ||= /\A[a-zA-Z0-9_\-\. ]*\z/.freeze
end
- def username_regex_message
- default_regex_message
+ def namespace_name_regex_message
+ "can contain only letters, digits, '_', '-', '.' and space."
end
+
def project_name_regex
- /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\. ]*\z/
+ @project_name_regex ||= /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\. ]*\z/.freeze
end
- def project_regex_message
- "can contain only letters, digits, '_', '-' and '.' and space. " \
+ def project_name_regex_message
+ "can contain only letters, digits, '_', '-', '.' and space. " \
"It must start with letter, digit or '_'."
end
- def name_regex
- /\A[a-zA-Z0-9_\-\. ]*\z/
+
+ def project_path_regex
+ @project_path_regex ||= /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\.]*(?<!\.git)\z/.freeze
end
- def name_regex_message
- "can contain only letters, digits, '_', '-' and '.' and space."
+ def project_path_regex_message
+ "can contain only letters, digits, '_', '-' and '.'. " \
+ "Cannot start with '-' or end in '.git'" \
end
- def path_regex
- default_regex
+
+ def file_name_regex
+ @file_name_regex ||= /\A[a-zA-Z0-9_\-\.]*\z/.freeze
end
- def path_regex_message
- default_regex_message
+ def file_name_regex_message
+ "can contain only letters, digits, '_', '-' and '.'. "
end
+
def archive_formats_regex
- #|zip|tar| tar.gz | tar.bz2 |
- /(zip|tar|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/
+ # |zip|tar| tar.gz | tar.bz2 |
+ @archive_formats_regex ||= /(zip|tar|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/.freeze
end
def git_reference_regex
# Valid git ref regex, see:
# https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
- %r{
+ @git_reference_regex ||= %r{
(?!
(?# doesn't begins with)
\/| (?# rule #6)
@@ -60,18 +77,7 @@ module Gitlab
(?# doesn't end with)
(?<!\.lock) (?# rule #1)
(?<![\/.]) (?# rule #6-7)
- }x
- end
-
- protected
-
- def default_regex_message
- "can contain only letters, digits, '_', '-' and '.'. " \
- "Cannot start with '-' or end in '.git'" \
- end
-
- def default_regex
- /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\.]*(?<!\.git)\z/
+ }x.freeze
end
end
end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 0230fbb010b..84445b3bf2f 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -27,9 +27,9 @@ namespace :gitlab do
backup = Backup::Manager.new
backup.unpack
- Rake::Task["gitlab:backup:db:restore"].invoke
- Rake::Task["gitlab:backup:repo:restore"].invoke
- Rake::Task["gitlab:backup:uploads:restore"].invoke
+ Rake::Task["gitlab:backup:db:restore"].invoke unless backup.skipped?("db")
+ Rake::Task["gitlab:backup:repo:restore"].invoke unless backup.skipped?("repositories")
+ Rake::Task["gitlab:backup:uploads:restore"].invoke unless backup.skipped?("uploads")
Rake::Task["gitlab:shell:setup"].invoke
backup.cleanup
@@ -38,8 +38,13 @@ namespace :gitlab do
namespace :repo do
task create: :environment do
$progress.puts "Dumping repositories ...".blue
- Backup::Repository.new.dump
- $progress.puts "done".green
+
+ if ENV["SKIP"] && ENV["SKIP"].include?("repositories")
+ $progress.puts "[SKIPPED]".cyan
+ else
+ Backup::Repository.new.dump
+ $progress.puts "done".green
+ end
end
task restore: :environment do
@@ -52,8 +57,13 @@ namespace :gitlab do
namespace :db do
task create: :environment do
$progress.puts "Dumping database ... ".blue
- Backup::Database.new.dump
- $progress.puts "done".green
+
+ if ENV["SKIP"] && ENV["SKIP"].include?("db")
+ $progress.puts "[SKIPPED]".cyan
+ else
+ Backup::Database.new.dump
+ $progress.puts "done".green
+ end
end
task restore: :environment do
@@ -66,8 +76,13 @@ namespace :gitlab do
namespace :uploads do
task create: :environment do
$progress.puts "Dumping uploads ... ".blue
- Backup::Uploads.new.dump
- $progress.puts "done".green
+
+ if ENV["SKIP"] && ENV["SKIP"].include?("uploads")
+ $progress.puts "[SKIPPED]".cyan
+ else
+ Backup::Uploads.new.dump
+ $progress.puts "done".green
+ end
end
task restore: :environment do
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index 5dd4124061c..c31563e6d77 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -55,24 +55,109 @@ describe Import::BitbucketController do
end
describe "POST create" do
- before do
- @repo = {
- slug: 'vim',
- owner: "john"
+ let(:bitbucket_username) { user.username }
+
+ let(:bitbucket_user) {
+ {
+ user: {
+ username: bitbucket_username
+ }
}.with_indifferent_access
- end
+ }
- it "takes already existing namespace" do
- namespace = create(:namespace, name: "john", owner: user)
- expect(Gitlab::BitbucketImport::KeyAdder).
- to receive(:new).with(@repo, user).
- and_return(double(execute: true))
- expect(Gitlab::BitbucketImport::ProjectCreator).
- to receive(:new).with(@repo, namespace, user).
+ let(:bitbucket_repo) {
+ {
+ slug: "vim",
+ owner: bitbucket_username
+ }.with_indifferent_access
+ }
+
+ before do
+ allow(Gitlab::BitbucketImport::KeyAdder).
+ to receive(:new).with(bitbucket_repo, user).
and_return(double(execute: true))
- controller.stub_chain(:client, :project).and_return(@repo)
- post :create, format: :js
+ controller.stub_chain(:client, :user).and_return(bitbucket_user)
+ controller.stub_chain(:client, :project).and_return(bitbucket_repo)
+ end
+
+ context "when the repository owner is the Bitbucket user" do
+ context "when the Bitbucket user and GitLab user's usernames match" do
+ it "takes the current user's namespace" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).with(bitbucket_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the Bitbucket user and GitLab user's usernames don't match" do
+ let(:bitbucket_username) { "someone_else" }
+
+ it "takes the current user's namespace" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).with(bitbucket_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+ end
+
+ context "when the repository owner is not the Bitbucket user" do
+ let(:other_username) { "someone_else" }
+
+ before do
+ bitbucket_repo["owner"] = other_username
+ end
+
+ context "when a namespace with the Bitbucket user's username already exists" do
+ let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) }
+
+ context "when the namespace is owned by the GitLab user" do
+ it "takes the existing namespace" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).with(bitbucket_repo, existing_namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the namespace is not owned by the GitLab user" do
+ before do
+ existing_namespace.owner = create(:user)
+ existing_namespace.save
+ end
+
+ it "doesn't create a project" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ not_to receive(:new)
+
+ post :create, format: :js
+ end
+ end
+ end
+
+ context "when a namespace with the Bitbucket user's username doesn't exist" do
+ it "creates the namespace" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).and_return(double(execute: true))
+
+ post :create, format: :js
+
+ expect(Namespace.where(name: other_username).first).not_to be_nil
+ end
+
+ it "takes the new namespace" do
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).with(bitbucket_repo, an_instance_of(Group), user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
end
end
end
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index 5b967bfcc0c..3d3846b2e3a 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -56,18 +56,98 @@ describe Import::GithubController do
end
describe "POST create" do
+ let(:github_username) { user.username }
+
+ let(:github_user) {
+ OpenStruct.new(login: github_username)
+ }
+
+ let(:github_repo) {
+ OpenStruct.new(name: 'vim', full_name: "#{github_username}/vim", owner: OpenStruct.new(login: github_username))
+ }
+
before do
- @repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim', owner: OpenStruct.new(login: "john"))
+ controller.stub_chain(:client, :user).and_return(github_user)
+ controller.stub_chain(:client, :repo).and_return(github_repo)
+ end
+
+ context "when the repository owner is the GitHub user" do
+ context "when the GitHub user and GitLab user's usernames match" do
+ it "takes the current user's namespace" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).with(github_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the GitHub user and GitLab user's usernames don't match" do
+ let(:github_username) { "someone_else" }
+
+ it "takes the current user's namespace" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).with(github_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
end
- it "takes already existing namespace" do
- namespace = create(:namespace, name: "john", owner: user)
- expect(Gitlab::GithubImport::ProjectCreator).
- to receive(:new).with(@repo, namespace, user).
- and_return(double(execute: true))
- controller.stub_chain(:client, :repo).and_return(@repo)
+ context "when the repository owner is not the GitHub user" do
+ let(:other_username) { "someone_else" }
+
+ before do
+ github_repo.owner = OpenStruct.new(login: other_username)
+ end
+
+ context "when a namespace with the GitHub user's username already exists" do
+ let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) }
+
+ context "when the namespace is owned by the GitLab user" do
+ it "takes the existing namespace" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).with(github_repo, existing_namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the namespace is not owned by the GitLab user" do
+ before do
+ existing_namespace.owner = create(:user)
+ existing_namespace.save
+ end
+
+ it "doesn't create a project" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ not_to receive(:new)
+
+ post :create, format: :js
+ end
+ end
+ end
+
+ context "when a namespace with the GitHub user's username doesn't exist" do
+ it "creates the namespace" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).and_return(double(execute: true))
+
+ post :create, format: :js
+
+ expect(Namespace.where(name: other_username).first).not_to be_nil
+ end
+
+ it "takes the new namespace" do
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).with(github_repo, an_instance_of(Group), user).
+ and_return(double(execute: true))
- post :create, format: :js
+ post :create, format: :js
+ end
+ end
end
end
end
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index b6b86b1bcee..112e51d431e 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -48,23 +48,105 @@ describe Import::GitlabController do
end
describe "POST create" do
- before do
- @repo = {
+ let(:gitlab_username) { user.username }
+
+ let(:gitlab_user) {
+ {
+ username: gitlab_username
+ }.with_indifferent_access
+ }
+
+ let(:gitlab_repo) {
+ {
path: 'vim',
- path_with_namespace: 'asd/vim',
- owner: {name: "john"},
- namespace: {path: "john"}
+ path_with_namespace: "#{gitlab_username}/vim",
+ owner: { name: gitlab_username },
+ namespace: { path: gitlab_username }
}.with_indifferent_access
+ }
+
+ before do
+ controller.stub_chain(:client, :user).and_return(gitlab_user)
+ controller.stub_chain(:client, :project).and_return(gitlab_repo)
+ end
+
+ context "when the repository owner is the GitLab.com user" do
+ context "when the GitLab.com user and GitLab server user's usernames match" do
+ it "takes the current user's namespace" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).with(gitlab_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the GitLab.com user and GitLab server user's usernames don't match" do
+ let(:gitlab_username) { "someone_else" }
+
+ it "takes the current user's namespace" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).with(gitlab_repo, user.namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
end
- it "takes already existing namespace" do
- namespace = create(:namespace, name: "john", owner: user)
- expect(Gitlab::GitlabImport::ProjectCreator).
- to receive(:new).with(@repo, namespace, user).
- and_return(double(execute: true))
- controller.stub_chain(:client, :project).and_return(@repo)
+ context "when the repository owner is not the GitLab.com user" do
+ let(:other_username) { "someone_else" }
+
+ before do
+ gitlab_repo["namespace"]["path"] = other_username
+ end
+
+ context "when a namespace with the GitLab.com user's username already exists" do
+ let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) }
+
+ context "when the namespace is owned by the GitLab server user" do
+ it "takes the existing namespace" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).with(gitlab_repo, existing_namespace, user).
+ and_return(double(execute: true))
+
+ post :create, format: :js
+ end
+ end
+
+ context "when the namespace is not owned by the GitLab server user" do
+ before do
+ existing_namespace.owner = create(:user)
+ existing_namespace.save
+ end
+
+ it "doesn't create a project" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ not_to receive(:new)
+
+ post :create, format: :js
+ end
+ end
+ end
+
+ context "when a namespace with the GitLab.com user's username doesn't exist" do
+ it "creates the namespace" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).and_return(double(execute: true))
+
+ post :create, format: :js
+
+ expect(Namespace.where(name: other_username).first).not_to be_nil
+ end
+
+ it "takes the new namespace" do
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).with(gitlab_repo, an_instance_of(Group), user).
+ and_return(double(execute: true))
- post :create, format: :js
+ post :create, format: :js
+ end
+ end
end
end
end
diff --git a/spec/controllers/namespaces_controller_spec.rb b/spec/controllers/namespaces_controller_spec.rb
new file mode 100644
index 00000000000..9c8619722cd
--- /dev/null
+++ b/spec/controllers/namespaces_controller_spec.rb
@@ -0,0 +1,121 @@
+require 'spec_helper'
+
+describe NamespacesController do
+ let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+
+ describe "GET show" do
+ context "when the namespace belongs to a user" do
+ let!(:other_user) { create(:user) }
+
+ it "redirects to the user's page" do
+ get :show, id: other_user.username
+
+ expect(response).to redirect_to(user_path(other_user))
+ end
+ end
+
+ context "when the namespace belongs to a group" do
+ let!(:group) { create(:group) }
+ let!(:project) { create(:project, namespace: group) }
+
+ context "when the group has public projects" do
+ before do
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ context "when not signed in" do
+ it "redirects to the group's page" do
+ get :show, id: group.path
+
+ expect(response).to redirect_to(group_path(group))
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "redirects to the group's page" do
+ get :show, id: group.path
+
+ expect(response).to redirect_to(group_path(group))
+ end
+ end
+ end
+
+ context "when the project doesn't have public projects" do
+ context "when not signed in" do
+ it "redirects to the sign in page" do
+ get :show, id: group.path
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ context "when the user has access to the project" do
+ before do
+ project.team << [user, :master]
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ project.team << [user, :master]
+ end
+
+ it "redirects to the sign in page" do
+ get :show, id: group.path
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "redirects to the group's page" do
+ get :show, id: group.path
+
+ expect(response).to redirect_to(group_path(group))
+ end
+ end
+ end
+
+ context "when the user doesn't have access to the project" do
+ it "responds with status 404" do
+ get :show, id: group.path
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
+ end
+
+ context "when the namespace doesn't exist" do
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "responds with status 404" do
+ get :show, id: "doesntexist"
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context "when not signed in" do
+ it "redirects to the sign in page" do
+ get :show, id: "doesntexist"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
new file mode 100644
index 00000000000..91856ed0cc0
--- /dev/null
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -0,0 +1,65 @@
+require "spec_helper"
+
+describe Projects::RepositoriesController do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ describe "GET archive" do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+
+ allow(ArchiveRepositoryService).to receive(:new).and_return(service)
+ end
+
+ let(:service) { ArchiveRepositoryService.new(project, "master", "zip") }
+
+ it "executes ArchiveRepositoryService" do
+ expect(ArchiveRepositoryService).to receive(:new).with(project, "master", "zip")
+ expect(service).to receive(:execute)
+
+ get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
+ end
+
+ context "when the service raises an error" do
+
+ before do
+ allow(service).to receive(:execute).and_raise("Archive failed")
+ end
+
+ it "renders Not Found" do
+ get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context "when the service doesn't return a path" do
+
+ before do
+ allow(service).to receive(:execute).and_return(nil)
+ end
+
+ it "reloads the page" do
+ get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
+
+ expect(response).to redirect_to(archive_namespace_project_repository_path(project.namespace, project, ref: "master", format: "zip"))
+ end
+ end
+
+ context "when the service returns a path" do
+
+ let(:path) { Rails.root.join("spec/fixtures/dk.png").to_s }
+
+ before do
+ allow(service).to receive(:execute).and_return(path)
+ end
+
+ it "sends the file" do
+ get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
+
+ expect(response.body).to eq(File.binread(path))
+ end
+ end
+ end
+end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 41088ce8271..28423eb8caa 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -6,7 +6,7 @@ describe 'Help Pages', feature: true do
login_as :user
end
it 'replace the variable $your_email with the email of the user' do
- visit help_page_path(category: 'ssh', file: 'README.md')
+ visit help_page_path(filepath: 'ssh/README', format: 'md')
expect(page).to have_content("ssh-keygen -t rsa -C \"#{@user.email}\"")
end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index c631acc591d..0d06c6ffb82 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -651,7 +651,7 @@ describe GitlabMarkdownHelper do
end
it "should leave ref-like href of 'manual' links untouched" do
- expect(markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})")).to eq("<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a class=\"gfm gfm-merge_request \" href=\"#{namespace_project_merge_request_url(project.namespace, project, merge_request)}\" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n")
+ expect(markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})")).to eq("<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a class=\"gfm gfm-merge_request \" href=\"#{namespace_project_merge_request_path(project.namespace, project, merge_request)}\" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n")
end
it "should leave ref-like src of images untouched" do
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 0b1cf07b7b0..c052981fe73 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -7,7 +7,7 @@ describe IconsHelper do
end
it 'returns share class' do
- expect(file_type_icon_class('file', 0120000, 'link')).to eq 'share'
+ expect(file_type_icon_class('file', '120000', 'link')).to eq 'share'
end
it 'returns file-pdf-o class with .pdf' do
diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb
new file mode 100644
index 00000000000..5c89c854714
--- /dev/null
+++ b/spec/lib/file_size_validator_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe 'Gitlab::FileSizeValidatorSpec' do
+ let(:validator) { FileSizeValidator.new(options) }
+ let(:attachment) { AttachmentUploader.new }
+ let(:note) { create(:note) }
+
+ describe 'options uses an integer' do
+ let(:options) { { maximum: 10, attributes: { attachment: attachment } } }
+
+ it 'attachment exceeds maximum limit' do
+ allow(attachment).to receive(:size) { 100 }
+ validator.validate_each(note, :attachment, attachment)
+ expect(note.errors).to have_key(:attachment)
+ end
+
+ it 'attachment under maximum limit' do
+ allow(attachment).to receive(:size) { 1 }
+ validator.validate_each(note, :attachment, attachment)
+ expect(note.errors).not_to have_key(:attachment)
+ end
+ end
+
+ describe 'options uses a symbol' do
+ let(:options) { { maximum: :test,
+ attributes: { attachment: attachment } } }
+ before do
+ allow(note).to receive(:test) { 10 }
+ end
+
+ it 'attachment exceeds maximum limit' do
+ allow(attachment).to receive(:size) { 100 }
+ validator.validate_each(note, :attachment, attachment)
+ expect(note.errors).to have_key(:attachment)
+ end
+
+ it 'attachment under maximum limit' do
+ allow(attachment).to receive(:size) { 1 }
+ validator.validate_each(note, :attachment, attachment)
+ expect(note.errors).not_to have_key(:attachment)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 1db9f15b790..727884c41c5 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
describe Gitlab::Regex do
- describe 'path regex' do
- it { expect('gitlab-ce').to match(Gitlab::Regex.path_regex) }
- it { expect('gitlab_git').to match(Gitlab::Regex.path_regex) }
- it { expect('_underscore.js').to match(Gitlab::Regex.path_regex) }
- it { expect('100px.com').to match(Gitlab::Regex.path_regex) }
- it { expect('?gitlab').not_to match(Gitlab::Regex.path_regex) }
- it { expect('git lab').not_to match(Gitlab::Regex.path_regex) }
- it { expect('gitlab.git').not_to match(Gitlab::Regex.path_regex) }
+ describe 'project path regex' do
+ it { expect('gitlab-ce').to match(Gitlab::Regex.project_path_regex) }
+ it { expect('gitlab_git').to match(Gitlab::Regex.project_path_regex) }
+ it { expect('_underscore.js').to match(Gitlab::Regex.project_path_regex) }
+ it { expect('100px.com').to match(Gitlab::Regex.project_path_regex) }
+ it { expect('?gitlab').not_to match(Gitlab::Regex.project_path_regex) }
+ it { expect('git lab').not_to match(Gitlab::Regex.project_path_regex) }
+ it { expect('gitlab.git').not_to match(Gitlab::Regex.project_path_regex) }
end
describe 'project name regex' do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index ba42f9e5c70..7c4235ab379 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -7,9 +7,12 @@ describe Notify do
let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name }
let(:gitlab_sender) { Gitlab.config.gitlab.email_from }
+ let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
let(:recipient) { create(:user, email: 'recipient@example.com') }
let(:project) { create(:project) }
+ around(:each) { ActionMailer::Base.deliveries.clear }
+
before(:each) do
email = recipient.emails.create(email: "notifications@example.com")
recipient.update_attribute(:notification_email, email.email)
@@ -27,6 +30,11 @@ describe Notify do
expect(sender.display_name).to eq(gitlab_sender_display_name)
expect(sender.address).to eq(gitlab_sender)
end
+
+ it 'has a Reply-To address' do
+ reply_to = subject.header[:reply_to].addresses
+ expect(reply_to).to eq([gitlab_sender_reply_to])
+ end
end
shared_examples 'an email starting a new thread' do |message_id_prefix|
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index ed6845c82cc..e87432fdf62 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -33,8 +33,6 @@ describe Namespace do
it { is_expected.to respond_to(:to_param) }
end
- it { expect(Namespace.global_id).to eq('GLN') }
-
describe :to_param do
it { expect(namespace.to_param).to eq(namespace.path) }
end
@@ -85,4 +83,14 @@ describe Namespace do
it { expect(Namespace.find_by_path_or_name('WOW')).to eq(@namespace) }
it { expect(Namespace.find_by_path_or_name('unknown')).to eq(nil) }
end
+
+ describe ".clean_path" do
+
+ let!(:user) { create(:user, username: "johngitlab-etc") }
+ let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") }
+
+ it "cleans the path and makes sure it's available" do
+ expect(Namespace.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
+ end
+ end
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 959044dc727..f94bef5c365 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -31,6 +31,7 @@ describe GitlabIssueTrackerService do
context 'with absolute urls' do
before do
+ GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root"
@service = project.create_gitlab_issue_tracker_service(active: true)
end
@@ -39,15 +40,15 @@ describe GitlabIssueTrackerService do
end
it 'should give the correct path' do
- expect(@service.project_url).to eq("/#{project.path_with_namespace}/issues")
- expect(@service.new_issue_url).to eq("/#{project.path_with_namespace}/issues/new")
- expect(@service.issue_url(432)).to eq("/#{project.path_with_namespace}/issues/432")
+ expect(@service.project_url).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(@service.new_issue_url).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues/new")
+ expect(@service.issue_url(432)).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues/432")
end
end
- context 'with enabled relative urls' do
+ context 'with relative urls' do
before do
- Settings.gitlab.stub(:relative_url_root).and_return("/gitlab/root")
+ GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root"
@service = project.create_gitlab_issue_tracker_service(active: true)
end
@@ -56,9 +57,9 @@ describe GitlabIssueTrackerService do
end
it 'should give the correct path' do
- expect(@service.project_url).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
- expect(@service.new_issue_url).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(@service.issue_url(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(@service.project_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
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 10e90cae143..24384e8bf22 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -307,16 +307,6 @@ describe User do
end
end
- describe ".clean_username" do
-
- let!(:user) { create(:user, username: "johngitlab-etc") }
- let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") }
-
- it "cleans a username and makes sure it's available" do
- expect(User.clean_username("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
- end
- end
-
describe 'all_ssh_keys' do
it { is_expected.to have_many(:keys).dependent(:destroy) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index f28dfea3ccf..cc387378d3a 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -57,7 +57,14 @@ describe API::API, api: true do
expect(json_response.first['name']).to eq(project.name)
expect(json_response.first['owner']['username']).to eq(user.username)
end
-
+
+ it 'should include the project labels as the tag_list' do
+ get api('/projects', user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first.keys.should include('tag_list')
+ end
+
context 'and using search' do
it 'should return searched project' do
get api('/projects', user), { search: project.name }
@@ -247,12 +254,12 @@ describe API::API, api: true do
expect(json_response['message']['name']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)',
- Gitlab::Regex.project_regex_message
+ Gitlab::Regex.project_name_regex_message
])
expect(json_response['message']['path']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)',
- Gitlab::Regex.send(:default_regex_message)
+ Gitlab::Regex.send(:project_path_regex_message)
])
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 081400cdedd..e6d5545f812 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -140,7 +140,7 @@ describe API::API, api: true do
expect(json_response['message']['projects_limit']).
to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username']).
- to eq([Gitlab::Regex.send(:default_regex_message)])
+ to eq([Gitlab::Regex.send(:namespace_regex_message)])
end
it "shouldn't available for non admin users" do
@@ -266,7 +266,7 @@ describe API::API, api: true do
expect(json_response['message']['projects_limit']).
to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username']).
- to eq([Gitlab::Regex.send(:default_regex_message)])
+ to eq([Gitlab::Regex.send(:namespace_regex_message)])
end
context "with existing user" do
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index d4915b51952..f5db548f97c 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -73,41 +73,41 @@ end
# help_markdown GET /help/markdown(.:format) help#markdown
# help_ssh GET /help/ssh(.:format) help#ssh
# help_raketasks GET /help/raketasks(.:format) help#raketasks
-describe HelpController, "routing" do
- it "to #index" do
- expect(get("/help")).to route_to('help#index')
+describe HelpController, 'routing' do
+ it 'to #index' do
+ expect(get('/help')).to route_to('help#index')
end
- it "to #permissions" do
- expect(get("/help/permissions/permissions")).to route_to('help#show', category: "permissions", file: "permissions")
+ it 'to #permissions' do
+ expect(get('/help/permissions/permissions')).to route_to('help#show', filepath: 'permissions/permissions')
end
- it "to #workflow" do
- expect(get("/help/workflow/README")).to route_to('help#show', category: "workflow", file: "README")
+ it 'to #workflow' do
+ expect(get('/help/workflow/README')).to route_to('help#show', filepath: 'workflow/README')
end
- it "to #api" do
- expect(get("/help/api/README")).to route_to('help#show', category: "api", file: "README")
+ it 'to #api' do
+ expect(get('/help/api/README')).to route_to('help#show', filepath: 'api/README')
end
- it "to #web_hooks" do
- expect(get("/help/web_hooks/web_hooks")).to route_to('help#show', category: "web_hooks", file: "web_hooks")
+ it 'to #web_hooks' do
+ expect(get('/help/web_hooks/web_hooks')).to route_to('help#show', filepath: 'web_hooks/web_hooks')
end
- it "to #system_hooks" do
- expect(get("/help/system_hooks/system_hooks")).to route_to('help#show', category: "system_hooks", file: "system_hooks")
+ it 'to #system_hooks' do
+ expect(get('/help/system_hooks/system_hooks')).to route_to('help#show', filepath: 'system_hooks/system_hooks')
end
- it "to #markdown" do
- expect(get("/help/markdown/markdown")).to route_to('help#show',category: "markdown", file: "markdown")
+ it 'to #markdown' do
+ expect(get('/help/markdown/markdown')).to route_to('help#show',filepath: 'markdown/markdown')
end
- it "to #ssh" do
- expect(get("/help/ssh/README")).to route_to('help#show', category: "ssh", file: "README")
+ it 'to #ssh' do
+ expect(get('/help/ssh/README')).to route_to('help#show', filepath: 'ssh/README')
end
- it "to #raketasks" do
- expect(get("/help/raketasks/README")).to route_to('help#show', category: "raketasks", file: "README")
+ it 'to #raketasks' do
+ expect(get('/help/raketasks/README')).to route_to('help#show', filepath: 'raketasks/README')
end
end
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
new file mode 100644
index 00000000000..f168a913976
--- /dev/null
+++ b/spec/services/archive_repository_service_spec.rb
@@ -0,0 +1,93 @@
+require 'spec_helper'
+
+describe ArchiveRepositoryService do
+ let(:project) { create(:project) }
+ subject { ArchiveRepositoryService.new(project, "master", "zip") }
+
+ describe "#execute" do
+ it "cleans old archives" do
+ expect(project.repository).to receive(:clean_old_archives)
+
+ subject.execute(timeout: 0.0)
+ end
+
+ context "when the repository doesn't have an archive file path" do
+ before do
+ allow(project.repository).to receive(:archive_file_path).and_return(nil)
+ end
+
+ it "raises an error" do
+ expect {
+ subject.execute(timeout: 0.0)
+ }.to raise_error
+ end
+ end
+
+ context "when the repository has an archive file path" do
+ let(:file_path) { "/archive.zip" }
+ let(:pid_file_path) { "/archive.zip.pid" }
+
+ before do
+ allow(project.repository).to receive(:archive_file_path).and_return(file_path)
+ allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
+ end
+
+ context "when the archive file already exists" do
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(true)
+ end
+
+ it "returns the file path" do
+ expect(subject.execute(timeout: 0.0)).to eq(file_path)
+ end
+ end
+
+ context "when the archive file doesn't exist yet" do
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(false)
+ allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
+ end
+
+ context "when the archive pid file doesn't exist yet" do
+ before do
+ allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
+ end
+
+ it "queues the RepositoryArchiveWorker" do
+ expect(RepositoryArchiveWorker).to receive(:perform_async)
+
+ subject.execute(timeout: 0.0)
+ end
+ end
+
+ context "when the archive pid file already exists" do
+ it "doesn't queue the RepositoryArchiveWorker" do
+ expect(RepositoryArchiveWorker).not_to receive(:perform_async)
+
+ subject.execute(timeout: 0.0)
+ end
+ end
+
+ context "when the archive file exists after a little while" do
+ before do
+ Thread.new do
+ sleep 0.1
+ allow(File).to receive(:exist?).with(file_path).and_return(true)
+ end
+ end
+
+ it "returns the file path" do
+ expect(subject.execute(timeout: 0.2)).to eq(file_path)
+ end
+ end
+
+ context "when the archive file doesn't exist after the timeout" do
+ it "returns nil" do
+ expect(subject.execute(timeout: 0.0)).to eq(nil)
+ end
+ end
+ end
+ end
+ end
+end
+
diff --git a/spec/services/projects/upload_service_spec.rb b/spec/services/projects/upload_service_spec.rb
index fc34b456482..e5c47015a03 100644
--- a/spec/services/projects/upload_service_spec.rb
+++ b/spec/services/projects/upload_service_spec.rb
@@ -67,6 +67,16 @@ describe Projects::UploadService do
it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file['url']).to match('doc_sample.txt') }
end
+
+ context 'for too large a file' do
+ before do
+ txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain')
+ allow(txt).to receive(:size) { 1000.megabytes.to_i }
+ @link_to_file = upload_file(@project.repository, txt)
+ end
+
+ it { expect(@link_to_file).to eq(nil) }
+ end
end
def upload_file(repository, file)
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 8a411b7720a..a59f74c2121 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -87,7 +87,7 @@ describe 'gitlab:app namespace rake task' do
expect(tar_contents).to match('db/')
expect(tar_contents).to match('uploads/')
expect(tar_contents).to match('repositories/')
- expect(tar_contents).not_to match(/^.{4,9}[rwx]/)
+ expect(tar_contents).not_to match(/^.{4,9}[rwx].* (db|uploads|repositories)\/$/)
end
it 'should delete temp directories' do
@@ -98,4 +98,55 @@ describe 'gitlab:app namespace rake task' do
expect(temp_dirs).to be_empty
end
end # backup_create task
+
+ describe "Skipping items" do
+ def tars_glob
+ Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar'))
+ end
+
+ before :all do
+ @origin_cd = Dir.pwd
+
+ Rake::Task["gitlab:backup:db:create"].reenable
+ Rake::Task["gitlab:backup:repo:create"].reenable
+ Rake::Task["gitlab:backup:uploads:create"].reenable
+
+ # Record the existing backup tars so we don't touch them
+ existing_tars = tars_glob
+
+ # Redirect STDOUT and run the rake task
+ orig_stdout = $stdout
+ $stdout = StringIO.new
+ ENV["SKIP"] = "repositories"
+ run_rake_task('gitlab:backup:create')
+ $stdout = orig_stdout
+
+ @backup_tar = (tars_glob - existing_tars).first
+ end
+
+ after :all do
+ FileUtils.rm(@backup_tar)
+ Dir.chdir @origin_cd
+ end
+
+ it "does not contain skipped item" do
+ tar_contents, exit_status = Gitlab::Popen.popen(
+ %W{tar -tvf #{@backup_tar} db uploads repositories}
+ )
+
+ expect(tar_contents).to match('db/')
+ expect(tar_contents).to match('uploads/')
+ expect(tar_contents).not_to match('repositories/')
+ end
+
+ it 'does not invoke repositories restore' do
+ Rake::Task["gitlab:shell:setup"].stub invoke: true
+ allow($stdout).to receive :write
+
+ expect(Rake::Task["gitlab:backup:db:restore"]).to receive :invoke
+ expect(Rake::Task["gitlab:backup:repo:restore"]).not_to receive :invoke
+ expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke
+ expect { run_rake_task('gitlab:backup:restore') }.to_not raise_error
+ end
+ end
end # gitlab:app namespace
diff --git a/spec/workers/repository_archive_worker_spec.rb b/spec/workers/repository_archive_worker_spec.rb
new file mode 100644
index 00000000000..c2362058cfd
--- /dev/null
+++ b/spec/workers/repository_archive_worker_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe RepositoryArchiveWorker do
+ let(:project) { create(:project) }
+ subject { RepositoryArchiveWorker.new }
+
+ before do
+ allow(Project).to receive(:find).and_return(project)
+ end
+
+ describe "#perform" do
+ it "cleans old archives" do
+ expect(project.repository).to receive(:clean_old_archives)
+
+ subject.perform(project.id, "master", "zip")
+ end
+
+ context "when the repository doesn't have an archive file path" do
+ before do
+ allow(project.repository).to receive(:archive_file_path).and_return(nil)
+ end
+
+ it "doesn't archive the repo" do
+ expect(project.repository).not_to receive(:archive_repo)
+
+ subject.perform(project.id, "master", "zip")
+ end
+ end
+
+ context "when the repository has an archive file path" do
+ let(:file_path) { "/archive.zip" }
+ let(:pid_file_path) { "/archive.zip.pid" }
+
+ before do
+ allow(project.repository).to receive(:archive_file_path).and_return(file_path)
+ allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
+ end
+
+ context "when the archive file already exists" do
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(true)
+ end
+
+ it "doesn't archive the repo" do
+ expect(project.repository).not_to receive(:archive_repo)
+
+ subject.perform(project.id, "master", "zip")
+ end
+ end
+
+ context "when the archive file doesn't exist yet" do
+ before do
+ allow(File).to receive(:exist?).with(file_path).and_return(false)
+ allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
+ end
+
+ context "when the archive pid file doesn't exist yet" do
+ before do
+ allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
+ end
+
+ it "archives the repo" do
+ expect(project.repository).to receive(:archive_repo)
+
+ subject.perform(project.id, "master", "zip")
+ end
+ end
+
+ context "when the archive pid file already exists" do
+ it "doesn't archive the repo" do
+ expect(project.repository).not_to receive(:archive_repo)
+
+ subject.perform(project.id, "master", "zip")
+ end
+ end
+ end
+ end
+ end
+end
+