summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--CHANGELOG24
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock22
-rw-r--r--PROCESS.md4
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/application.js.coffee2
-rw-r--r--app/assets/javascripts/behaviors/toggle_diff_line_wrap_behavior.coffee14
-rw-r--r--app/assets/javascripts/diff.js.coffee3
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/labels.js.coffee2
-rw-r--r--app/assets/javascripts/project.js.coffee2
-rw-r--r--app/assets/stylesheets/generic/common.scss2
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss4
-rw-r--r--app/assets/stylesheets/generic/timeline.scss77
-rw-r--r--app/assets/stylesheets/sections/dashboard.scss4
-rw-r--r--app/assets/stylesheets/sections/diff.scss11
-rw-r--r--app/assets/stylesheets/sections/login.scss21
-rw-r--r--app/assets/stylesheets/sections/nav.scss25
-rw-r--r--app/assets/stylesheets/sections/notes.scss27
-rw-r--r--app/assets/stylesheets/sections/projects.scss70
-rw-r--r--app/assets/stylesheets/sections/search.scss7
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb12
-rw-r--r--app/controllers/projects/raw_controller.rb6
-rw-r--r--app/controllers/projects/snippets_controller.rb2
-rw-r--r--app/controllers/search_controller.rb23
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/helpers/labels_helper.rb14
-rw-r--r--app/helpers/projects_helper.rb10
-rw-r--r--app/helpers/search_helper.rb17
-rw-r--r--app/models/concerns/issuable.rb8
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/models/label.rb18
-rw-r--r--app/models/label_link.rb12
-rw-r--r--app/models/merge_request.rb1
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/note.rb8
-rw-r--r--app/models/project.rb7
-rw-r--r--app/models/project_services/ci_service.rb19
-rw-r--r--app/models/project_wiki.rb5
-rw-r--r--app/models/users_star_project.rb10
-rw-r--r--app/services/projects/fork_service.rb7
-rw-r--r--app/services/search/global_service.rb20
-rw-r--r--app/services/search/project_service.rb36
-rw-r--r--app/views/admin/dashboard/index.html.haml2
-rwxr-xr-xapp/views/devise/confirmations/new.html.haml10
-rw-r--r--app/views/devise/passwords/edit.html.haml10
-rwxr-xr-xapp/views/devise/passwords/new.html.haml10
-rw-r--r--app/views/devise/registrations/new.html.haml10
-rw-r--r--app/views/devise/sessions/_new_base.html.haml6
-rw-r--r--app/views/devise/sessions/_oauth_providers.html.haml3
-rw-r--r--app/views/devise/sessions/new.html.haml10
-rw-r--r--app/views/explore/projects/_project.html.haml41
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/notify/project_was_moved_email.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml76
-rw-r--r--app/views/projects/blame/show.html.haml11
-rw-r--r--app/views/projects/commits/_diff_file.html.haml4
-rw-r--r--app/views/projects/commits/_diff_stats.html.haml2
-rw-r--r--app/views/projects/commits/_diffs.html.haml7
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/edit_tree/show.html.haml1
-rw-r--r--app/views/projects/import.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_commits.html.haml2
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply.html.haml2
-rw-r--r--app/views/projects/notes/_discussion.html.haml19
-rw-r--r--app/views/projects/notes/_note.html.haml117
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_active.html.haml1
-rw-r--r--app/views/projects/notes/discussions/_commit.html.haml1
-rw-r--r--app/views/projects/notes/discussions/_outdated.html.haml1
-rw-r--r--app/views/projects/show.html.haml37
-rw-r--r--app/views/projects/team_members/_form.html.haml2
-rw-r--r--app/views/projects/team_members/import.html.haml2
-rw-r--r--app/views/search/_filter.html.haml10
-rw-r--r--app/views/search/_global_filter.html.haml16
-rw-r--r--app/views/search/_global_results.html.haml5
-rw-r--r--app/views/search/_project_filter.html.haml25
-rw-r--r--app/views/search/_project_results.html.haml24
-rw-r--r--app/views/search/_results.html.haml22
-rw-r--r--app/views/search/results/_issue.html.haml21
-rw-r--r--app/views/search/results/_merge_request.html.haml30
-rw-r--r--app/views/search/results/_note.html.haml35
-rw-r--r--app/views/search/results/_project.html.haml9
-rw-r--r--app/views/search/show.html.haml2
-rw-r--r--app/views/shared/_clone_panel.html.haml5
-rw-r--r--config/application.rb19
-rw-r--r--config/environments/production.rb10
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/initializers/rack_attack.rb.example12
-rw-r--r--config/initializers/session_store.rb3
-rw-r--r--db/migrate/20140729152420_migrate_taggable_labels.rb12
-rw-r--r--doc/api/README.md8
-rw-r--r--doc/api/branches.md10
-rw-r--r--doc/api/groups.md37
-rw-r--r--doc/api/labels.md11
-rw-r--r--doc/api/merge_requests.md4
-rw-r--r--doc/api/notes.md54
-rw-r--r--doc/api/project_snippets.md2
-rw-r--r--doc/api/projects.md159
-rw-r--r--doc/api/repositories.md42
-rw-r--r--doc/api/repository_files.md6
-rw-r--r--doc/api/session.md8
-rw-r--r--doc/api/system_hooks.md2
-rw-r--r--doc/api/users.md6
-rw-r--r--doc/install/installation.md54
-rw-r--r--doc/install/requirements.md14
-rw-r--r--doc/integration/google.md14
-rw-r--r--doc/raketasks/web_hooks.md12
-rw-r--r--doc/release/monthly.md42
-rw-r--r--doc/update/5.1-to-5.2.md2
-rw-r--r--doc/update/5.1-to-5.4.md2
-rw-r--r--doc/update/5.1-to-6.0.md5
-rw-r--r--doc/update/5.2-to-5.3.md2
-rw-r--r--doc/update/5.3-to-5.4.md2
-rw-r--r--doc/update/6.0-to-6.1.md2
-rw-r--r--doc/update/6.0-to-7.2.md (renamed from doc/update/6.0-to-7.1.md)91
-rw-r--r--doc/update/6.1-to-6.2.md2
-rw-r--r--doc/update/6.2-to-6.3.md2
-rw-r--r--doc/update/6.3-to-6.4.md2
-rw-r--r--doc/update/6.4-to-6.5.md2
-rw-r--r--doc/update/6.5-to-6.6.md2
-rw-r--r--doc/update/6.6-to-6.7.md2
-rw-r--r--doc/update/6.7-to-6.8.md2
-rw-r--r--doc/update/6.8-to-6.9.md2
-rw-r--r--doc/update/6.9-to-7.0.md2
-rw-r--r--doc/update/7.0-to-7.1.md2
-rw-r--r--doc/update/7.1-to-7.2.md134
-rw-r--r--doc/update/mysql_to_postgresql.md5
-rw-r--r--doc/update/upgrader.md2
-rw-r--r--doc/web_hooks/web_hooks.md4
-rw-r--r--doc/workflow/README.md1
-rw-r--r--doc/workflow/labels.md16
-rw-r--r--doc/workflow/labels/label1.pngbin0 -> 5846 bytes
-rw-r--r--doc/workflow/labels/label2.pngbin0 -> 16931 bytes
-rw-r--r--doc/workflow/labels/label3.pngbin0 -> 19360 bytes
-rw-r--r--features/dashboard/search.feature10
-rw-r--r--features/search.feature46
-rw-r--r--features/steps/dashboard/search.rb19
-rw-r--r--features/steps/explore/projects.rb4
-rw-r--r--features/steps/group/group.rb4
-rw-r--r--features/steps/project/active_tab.rb2
-rw-r--r--features/steps/project/redirects.rb6
-rw-r--r--features/steps/project/search_code.rb3
-rw-r--r--features/steps/search.rb73
-rw-r--r--lib/api/helpers.rb8
-rw-r--r--lib/api/issues.rb11
-rw-r--r--lib/api/labels.rb4
-rw-r--r--lib/api/merge_requests.rb11
-rw-r--r--lib/gitlab/blacklist.rb25
-rw-r--r--lib/gitlab/project_search_results.rb52
-rw-r--r--lib/gitlab/satellite/satellite.rb1
-rw-r--r--lib/gitlab/search_results.rb69
-rw-r--r--lib/gitlab/visibility_level.rb16
-rw-r--r--lib/support/nginx/gitlab94
-rw-r--r--lib/support/nginx/gitlab-ssl23
-rw-r--r--lib/tasks/gitlab/shell.rake2
-rw-r--r--lib/tasks/gitlab/sidekiq.rake47
-rw-r--r--spec/factories/label_links.rb12
-rw-r--r--spec/factories/labels.rb12
-rw-r--r--spec/factories/merge_requests.rb22
-rw-r--r--spec/factories/notes.rb19
-rw-r--r--spec/factories/projects.rb28
-rw-r--r--spec/models/label_link_spec.rb12
-rw-r--r--spec/models/label_spec.rb35
-rw-r--r--spec/models/merge_request_spec.rb1
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/requests/api/issues_spec.rb56
-rw-r--r--spec/requests/api/labels_spec.rb32
-rw-r--r--spec/requests/api/merge_requests_spec.rb13
-rw-r--r--spec/services/projects/fork_service_spec.rb (renamed from spec/services/fork_service_spec.rb)23
-rw-r--r--spec/services/projects/update_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb8
-rwxr-xr-xvendor/assets/javascripts/jquery.sticky.js170
180 files changed, 2059 insertions, 932 deletions
diff --git a/.travis.yml b/.travis.yml
index 9b7b2cb3c09..dc30c490995 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,7 @@
language: ruby
+cache:
+ directories:
+ - vendor/bundle
env:
global:
- TRAVIS=true
diff --git a/CHANGELOG b/CHANGELOG
index c19826bc5c1..bff2bf993f9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,17 +1,29 @@
+v 7.3.0
+ - Always set the 'origin' remote in satellite actions
+ - Write authorized_keys in tmp/ during tests
+ - Expire Rack sessions after 1 week
+ - Cleaner signin/signup pages
+ - Improved comments UI
+ - Better search with filtering, pagination etc
+ - Added a checkbox to toggle line wrapping in diff (Yuriy Glukhov)
+ - Prevent project stars duplication when fork project
+ - Support Unix domain sockets for Redis
+ - Store session Redis keys in 'session:gitlab:' namespace
+
v 7.2.0
- Explore page
- Add project stars (Ciro Santilli)
- Log Sidekiq arguments
- - Fix cpu usage issue in Firefox
- Better labels: colors, ability to rename and remove
- Improve the way merge request collects diffs
- - Improve compare page for large diffs
+ - Improve compare page for large diffs
- Expose the full commit message via API
- Fix 500 error on repository rename
- Fix bug when MR download patch return invalid diff
- Test gitlab-shell integration
- Repository import timeout increased from 2 to 4 minutes allowing larger repos to be imported
- API for labels (Robert Schilling)
+ - API: ability to set an import url when creating project for specific user
v 7.1.1
- Fix cpu usage issue in Firefox
@@ -73,7 +85,7 @@ v 7.0.0
- Show notice if your profile is public
- UI improvements for mobile devices
- Improve diff rendering performance
- - Drag-n-drop for issues and merge requests between states at milestone page
+ - Drag-n-drop for issues and merge requests between states at milestone page
- Fix '0 commits' message for huge repositories on project home page
- Prevent 500 error page when visit commit page from large repo
- Add notice about huge push over http to unicorn config
@@ -83,7 +95,7 @@ v 7.0.0
- Be more selective when killing stray Sidekiqs
- Check LDAP user filter during sign-in
- Remove wall feature (no data loss - you can take it from database)
- - Dont expose user emails via API unless you are admin
+ - Dont expose user emails via API unless you are admin
- Detect issues closed by Merge Request description
- Better email subject lines from email on push service (Alex Elman)
- Enable identicon for gravatar be default
@@ -158,7 +170,7 @@ v 6.7.0
- Blob and tree gfm links to anchors work
- Piwik Integration (Sebastian Winkler)
- Show contribution guide link for new issue form (Jeroen van Baarsen)
- - Fix CI status for merge requests from fork
+ - Fix CI status for merge requests from fork
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
- New page load indicator that includes a spinner that scrolls with the page
- Converted all the help sections into markdown
@@ -349,7 +361,7 @@ v 6.2.0
- Store the sessions in Redis instead of the cookie store
- Fixed relative links in markdown
- User must confirm their email if signup enabled
- - User must confirm changed email
+ - User must confirm changed email
v 6.1.0
- Project specific IDs for issues, mr, milestones
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 7bc1c40470f..fee0a2788b2 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-1.9.6
+1.9.7
diff --git a/Gemfile b/Gemfile
index d6ce9c6719f..61a9c6cdf66 100644
--- a/Gemfile
+++ b/Gemfile
@@ -85,7 +85,7 @@ gem "github-markup"
gem 'redcarpet', '~> 2.2.2'
gem 'RedCloth'
gem 'rdoc', '~>3.6'
-gem 'org-ruby', '= 0.9.1'
+gem 'org-ruby'
gem 'creole', '~>0.3.6'
gem 'wikicloth', '=0.8.1'
gem 'asciidoctor', '= 0.1.4'
diff --git a/Gemfile.lock b/Gemfile.lock
index 6cd6bb7a308..edd30fda37a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -129,7 +129,7 @@ GEM
factory_girl_rails (4.3.0)
factory_girl (~> 4.3.0)
railties (>= 3.0.0)
- faraday (0.8.8)
+ faraday (0.8.9)
multipart-post (~> 1.2.0)
faraday_middleware (0.9.0)
faraday (>= 0.7.4, < 0.9)
@@ -158,7 +158,7 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.4)
- gemnasium-gitlab-service (0.2.1)
+ gemnasium-gitlab-service (0.2.2)
rugged (~> 0.19)
gherkin-ruby (0.3.1)
racc
@@ -234,7 +234,7 @@ GEM
activesupport (>= 4.0.1)
haml (>= 3.1, < 5.0)
railties (>= 4.0.1)
- hashie (2.0.5)
+ hashie (2.1.2)
hike (1.2.3)
hipchat (0.14.0)
httparty
@@ -243,7 +243,7 @@ GEM
httparty (0.13.0)
json (~> 1.8)
multi_xml (>= 0.5.2)
- httpauth (0.2.0)
+ httpauth (0.2.1)
i18n (0.6.11)
ice_nine (0.10.0)
jasmine (2.0.2)
@@ -264,7 +264,7 @@ GEM
jquery-ui-rails (4.2.1)
railties (>= 3.2.16)
json (1.8.1)
- jwt (0.1.8)
+ jwt (0.1.13)
multi_json (>= 1.5)
kaminari (0.15.1)
actionpack (>= 3.0.0)
@@ -311,9 +311,9 @@ GEM
omniauth-github (1.1.1)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
- omniauth-google-oauth2 (0.2.1)
- omniauth (~> 1.0)
- omniauth-oauth2
+ omniauth-google-oauth2 (0.2.5)
+ omniauth (> 1.0)
+ omniauth-oauth2 (~> 1.1)
omniauth-oauth (1.0.1)
oauth
omniauth (~> 1.0)
@@ -323,8 +323,8 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
- org-ruby (0.9.1)
- rubypants (>= 0.2.0)
+ org-ruby (0.9.8)
+ rubypants (~> 0.2)
orm_adapter (0.5.0)
pg (0.15.1)
phantomjs (1.9.2.0)
@@ -642,7 +642,7 @@ DEPENDENCIES
omniauth-github
omniauth-google-oauth2
omniauth-twitter
- org-ruby (= 0.9.1)
+ org-ruby
pg
poltergeist (~> 1.5.1)
pry
diff --git a/PROCESS.md b/PROCESS.md
index a6ff62a9a69..c986013e2f2 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -34,7 +34,7 @@ The most important thing is making sure valid issues receive feedback from the d
## Workflow labels
-Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to reevaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
+Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
- *Awaiting feedback*: Feedback pending from the reporter
- *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
@@ -61,7 +61,7 @@ If an issue is complex and needs the attention of a specific person, assignment
## Be kind
-Be kind to people trying to contribute. Be aware that people can be a non-native or a native English speaker, they might not understand thing or they might be very sensitive to how your word things. Use emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
+Be kind to people trying to contribute. Be aware that people may be a non-native English speaker, they might not understand things or they might be very sensitive as to how you word things. Use Emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
## Copy & paste responses
diff --git a/VERSION b/VERSION
index d2e57d3064d..ab8884ed9bc 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.2.0.pre
+7.3.0.pre
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 1960479321c..6bc24cf7590 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -15,6 +15,7 @@
#= require jquery.atwho
#= require jquery.scrollTo
#= require jquery.blockUI
+#= require jquery.sticky
#= require turbolinks
#= require jquery.turbolinks
#= require bootstrap
@@ -25,6 +26,7 @@
#= require branch-graph
#= require highlight.pack
#= require ace/ace
+#= require ace/ext-searchbox
#= require d3
#= require underscore
#= require nprogress
diff --git a/app/assets/javascripts/behaviors/toggle_diff_line_wrap_behavior.coffee b/app/assets/javascripts/behaviors/toggle_diff_line_wrap_behavior.coffee
new file mode 100644
index 00000000000..691ed4f98ae
--- /dev/null
+++ b/app/assets/javascripts/behaviors/toggle_diff_line_wrap_behavior.coffee
@@ -0,0 +1,14 @@
+$ ->
+ # Toggle line wrapping in diff.
+ #
+ # %div.diff-file
+ # %input.js-toggle-diff-line-wrap
+ # %td.line_content
+ #
+ $("body").on "click", ".js-toggle-diff-line-wrap", (e) ->
+ diffFile = $(@).closest(".diff-file")
+ if $(@).is(":checked")
+ diffFile.addClass("diff-wrap-lines")
+ else
+ diffFile.removeClass("diff-wrap-lines")
+
diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee
index dbe00c487dc..78bb385b5bb 100644
--- a/app/assets/javascripts/diff.js.coffee
+++ b/app/assets/javascripts/diff.js.coffee
@@ -34,7 +34,8 @@ class Diff
$.get(link, params, (response) =>
target.parent().replaceWith(response)
)
- )
+ ).ready =>
+ $(".diff-header").sticky {responsiveWidth:true, getWidthFrom: ".diff-file"}
lineNumbers: (line) ->
return ([0, 0]) unless line.children().length
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index a463a2eb194..e5e62c87e40 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -50,7 +50,7 @@ class Dispatcher
new TreeView()
when 'projects:blob:show'
new BlobView()
- when 'projects:labels:new'
+ when 'projects:labels:new', 'projects:labels:edit'
new Labels()
switch path.first()
diff --git a/app/assets/javascripts/labels.js.coffee b/app/assets/javascripts/labels.js.coffee
index 8e53d6929df..d306ad64f5b 100644
--- a/app/assets/javascripts/labels.js.coffee
+++ b/app/assets/javascripts/labels.js.coffee
@@ -4,7 +4,7 @@ class Labels
@setupLabelForm(form)
@cleanBinding()
@addBinding()
- @updateColorPreview
+ @updateColorPreview()
addBinding: ->
$(document).on 'click', '.suggest-colors a', @setSuggestedColor
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index f7c64b4b816..d81cc087df9 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -47,7 +47,7 @@ $ ->
$(@).parents('.no-ssh-key-message').hide()
e.preventDefault()
- $('.project-side .star').on 'ajax:success', (e, data, status, xhr) ->
+ $('.project-home-panel .star').on 'ajax:success', (e, data, status, xhr) ->
$(@).toggleClass('on').find('.count').html(data.star_count)
.on 'ajax:error', (e, xhr, status, error) ->
new Flash('Star toggle failed. Try again later.', 'alert')
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 9d3c9f372a9..803219a2e86 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -128,7 +128,7 @@ p.time {
}
.highlight_word {
- border-bottom: 2px solid #F90;
+ background: #fafe3d;
}
.thin_area{
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index c468980f64d..0679690c05f 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -88,6 +88,10 @@
.description {
padding: 0 15px 10px 15px;
+
+ code {
+ white-space: pre-wrap;
+ }
}
.title, .context, .description {
diff --git a/app/assets/stylesheets/generic/timeline.scss b/app/assets/stylesheets/generic/timeline.scss
new file mode 100644
index 00000000000..f29cf25fa4c
--- /dev/null
+++ b/app/assets/stylesheets/generic/timeline.scss
@@ -0,0 +1,77 @@
+.timeline {
+ list-style: none;
+ padding: 20px 0 20px;
+ position: relative;
+
+ &:before {
+ top: 0;
+ bottom: 0;
+ position: absolute;
+ content: " ";
+ width: 3px;
+ background-color: #eeeeee;
+ margin-left: 29px;
+ }
+
+ .timeline-entry {
+ position: relative;
+ margin-top: 5px;
+ margin-left: 30px;
+ margin-bottom: 10px;
+ clear: both;
+
+
+ &:target {
+ .timeline-entry-inner .timeline-content {
+ -webkit-animation:target-note 2s linear;
+ background: $hover;
+ }
+ }
+
+ .timeline-entry-inner {
+ position: relative;
+ margin-left: -20px;
+
+ &:before, &:after {
+ content: " ";
+ display: table;
+ }
+
+ .timeline-icon {
+ margin-top: 2px;
+ background: #fff;
+ color: #737881;
+ float: left;
+ @include border-radius(40px);
+ @include box-shadow(0 0 0 3px #EEE);
+ overflow: hidden;
+
+ .avatar {
+ margin: 0;
+ padding: 0;
+ }
+ }
+
+ .timeline-content {
+ position: relative;
+ background: #f5f5f6;
+ padding: 10px 15px;
+ margin-left: 60px;
+
+ &:after {
+ content: '';
+ display: block;
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 9px 9px 9px 0;
+ border-color: transparent #f5f5f6 transparent transparent;
+ left: 0;
+ top: 10px;
+ margin-left: -9px;
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
index 6487e0acd91..2be24e9b131 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -89,6 +89,10 @@
}
}
+.project-description {
+ overflow: hidden;
+}
+
.project-access-icon {
margin-left: 10px;
float: left;
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/sections/diff.scss
index 488d06919b0..758f15c8013 100644
--- a/app/assets/stylesheets/sections/diff.scss
+++ b/app/assets/stylesheets/sections/diff.scss
@@ -125,8 +125,6 @@
}
.line_content {
display: block;
- white-space: pre;
- height: 18px;
margin: 0px;
padding: 0px 0.5em;
border: none;
@@ -341,3 +339,12 @@
margin: 0;
border: none;
}
+
+.diff-file .line_content {
+ white-space: pre;
+}
+
+.diff-wrap-lines .line_content {
+ white-space: pre-wrap;
+}
+
diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss
index 77ebef690c3..1bcb1f6d68e 100644
--- a/app/assets/stylesheets/sections/login.scss
+++ b/app/assets/stylesheets/sections/login.scss
@@ -6,6 +6,21 @@
}
.login-box{
+ padding: 0 15px;
+
+ .login-heading h3 {
+ font-weight: 300;
+ line-height: 2;
+ }
+
+ .login-footer {
+ margin-top: 10px;
+ }
+
+ .btn {
+ padding: 12px !important;
+ @extend .btn-block;
+ }
}
.brand-image {
@@ -19,7 +34,7 @@
}
}
- .login-logo{
+ .login-logo {
margin: 10px 0 30px 0;
display: block;
}
@@ -64,4 +79,8 @@
color: #a00;
}
}
+
+ .brand-holder {
+ border-right: 1px solid #EEE;
+ }
}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index f5d09c2df10..778953984d6 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -35,39 +35,31 @@
width: 1%;
&.active {
a {
- color: #333;
+ color: $link_color;
font-weight: bold;
&:after {
content: '';
display: block;
position: relative;
- bottom: 8px;
- left: 50%;
- width: 0;
- height: 0;
- border-color: transparent transparent #333 transparent;
+ bottom: -1px;
+ border-color: $link_color;
border-style: solid;
- border-width: 6px;
- margin-left: -6px;
+ border-width: 2px;
}
}
}
&:hover {
a {
- color: $link_color;
+ color: $link_hover_color;
&:after {
content: '';
display: block;
position: relative;
- bottom: 8px;
- left: 50%;
- width: 0;
- height: 0;
- border-color: transparent transparent $link_color transparent;
+ bottom: -1px;
+ border-color: $link_hover_color;
border-style: solid;
- border-width: 6px;
- margin-left: -6px;
+ border-width: 2px;
}
}
}
@@ -90,7 +82,6 @@
line-height: 34px;
color: #777;
text-shadow: 0 1px 1px white;
- padding: 0 10px;
text-decoration: none;
padding-top: 2px;
}
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 18db7abc64e..4e13e30bac8 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -17,7 +17,6 @@ ul.notes {
.discussion-header,
.note-header {
@extend .cgray;
- padding-top: 5px;
padding-bottom: 15px;
.avatar {
@@ -43,34 +42,19 @@ ul.notes {
}
.discussion {
- padding: 10px 0;
overflow: hidden;
display: block;
position:relative;
- border-bottom: 1px solid #EEE;
-
- .discussion-body {
- margin-left: 50px;
- }
}
.note {
- padding: 8px 0;
- overflow: hidden;
display: block;
position:relative;
- border-bottom: 1px solid #eee;
- p { color: $style_color; }
-
- .avatar {
- margin-top: 3px;
- }
.attachment {
font-size: 14px;
}
.note-body {
@include md-typography;
- margin-left: 43px;
}
.note-header {
padding-bottom: 3px;
@@ -80,11 +64,6 @@ ul.notes {
border-bottom: none;
}
}
-
- .note:target {
- -webkit-animation:target-note 2s linear;
- background: #fffff0;
- }
}
.diff-file .notes_holder {
@@ -99,7 +78,7 @@ ul.notes {
&.notes_line {
text-align: center;
padding: 10px 0;
- background: #eee;
+ background: #FFF;
}
&.notes_line2 {
text-align: center;
@@ -362,3 +341,7 @@ ul.notes {
border-top: 1px solid #DDD;
}
}
+
+.discussion-notes-count {
+ font-size: 16px;
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 6757cbd30f6..918ac554ea3 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -15,62 +15,64 @@
}
.project-home-panel {
- border-bottom: 1px solid #DDD;
- padding-bottom: 15px;
- margin-bottom: 30px;
+ margin-bottom: 15px;
&.empty-project {
- border-bottom: 0px;
- padding-bottom: 15px;
- margin-bottom: 0px;
+ border-bottom: 0px;
+ padding-bottom: 15px;
+ margin-bottom: 0px;
}
- .project-home-title {
- font-size: 18px;
- color: #444;
- margin: 0;
- line-height: 32px;
- }
.project-home-dropdown {
margin-left: 10px;
float: right;
}
- .project-home-extra {
- margin-top: 15px;
+
+ .project-home-row {
+ @extend .clearfix;
+ margin-bottom: 15px;
.project-home-desc {
float: left;
- color: #777;
- margin-bottom: 10px;
+ color: #666;
+ font-size: 16px;
}
- .project-home-links {
+ .star-fork-buttons {
float: right;
- a {
- margin-left: 10px;
- font-weight: 500;
+ width: 200px;
+ font-size: 14px;
+ font-weight: bold;
+
+ .star-buttons, .fork-buttons {
+ float: right;
+ margin-left: 20px;
+
+ .count {
+ margin-left: 5px;
+ }
}
}
}
.visibility-level-label {
- font-size: 17px;
- background: #f1f1f1;
- border-radius: 4px;
- color: #444;
- position: absolute;
- margin-left: -55px;
- text-shadow: 0 1px 1px #FFF;
- width: 40px;
- text-align: center;
- padding: 6px;
-
+ color: #555;
+ font-weight: bold;
i {
color: inherit;
}
}
}
+.project-home-links {
+ padding: 10px 0px;
+ float: right;
+ a {
+ margin-left: 10px;
+ font-weight: 500;
+ }
+}
+
.git-clone-holder {
.project-home-dropdown + & {
margin-right: 45px;
@@ -159,6 +161,7 @@ ul.nav.nav-projects-tabs {
li {
.project-info {
margin-bottom: 10px;
+ overflow: hidden;
}
.access-icon {
@@ -192,10 +195,11 @@ ul.nav.nav-projects-tabs {
background-image: none;
.btn, &.btn {
+ white-space: normal;
text-align: left;
padding: 10px 15px;
- background-color: #F1f1f1;
- border-color: #EEE;
+ background-color: #F9F9F9;
+ border-color: #DDD;
&:hover {
background-color: #eee;
diff --git a/app/assets/stylesheets/sections/search.scss b/app/assets/stylesheets/sections/search.scss
new file mode 100644
index 00000000000..bdaa17ac339
--- /dev/null
+++ b/app/assets/stylesheets/sections/search.scss
@@ -0,0 +1,7 @@
+.search-results {
+ .search-result-row {
+ border-bottom: 1px solid #EEE;
+ padding-bottom: 10px;
+ margin-bottom: 10px;
+ }
+}
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index bde90466ea1..0b49803cfec 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -20,7 +20,7 @@ class Projects::IssuesController < Projects::ApplicationController
terms = params['issue_search']
@issues = issues_filtered
- @issues = @issues.where("title LIKE ? OR description LIKE ?", "%#{terms}%", "%#{terms}%") if terms.present?
+ @issues = @issues.full_search(terms) if terms.present?
@issues = @issues.page(params[:page]).per(20)
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 2154b6ed2eb..7b08b79d236 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -30,8 +30,10 @@ class Projects::NotesController < Projects::ApplicationController
end
def update
- note.update_attributes(note_params)
- note.reset_events_cache
+ if note.editable?
+ note.update_attributes(note_params)
+ note.reset_events_cache
+ end
respond_to do |format|
format.json { render_note_json(note) }
@@ -40,8 +42,10 @@ class Projects::NotesController < Projects::ApplicationController
end
def destroy
- note.destroy
- note.reset_events_cache
+ if note.editable?
+ note.destroy
+ note.reset_events_cache
+ end
respond_to do |format|
format.js { render nothing: true }
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index a6b7ae3f127..5ec9c576a66 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -29,12 +29,10 @@ class Projects::RawController < Projects::ApplicationController
private
def get_blob_type
- if @blob.mime_type =~ /html|javascript/
+ if @blob.text?
'text/plain; charset=utf-8'
- elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/
- 'application/octet-stream'
else
- @blob.mime_type
+ 'application/octet-stream'
end
end
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 25026973118..cba058fe214 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -63,7 +63,7 @@ class Projects::SnippetsController < Projects::ApplicationController
def raw
send_data(
@snippet.content,
- type: "text/plain",
+ type: 'text/plain; charset=utf-8',
disposition: 'inline',
filename: @snippet.file_name
)
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 8df84e9884a..a58b24de643 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -4,14 +4,25 @@ class SearchController < ApplicationController
def show
@project = Project.find_by(id: params[:project_id]) if params[:project_id].present?
@group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
+ @scope = params[:scope]
- if @project
- return access_denied! unless can?(current_user, :download_code, @project)
+ @search_results = if @project
+ return access_denied! unless can?(current_user, :download_code, @project)
- @search_results = Search::ProjectService.new(@project, current_user, params).execute
- else
- @search_results = Search::GlobalService.new(current_user, params).execute
- end
+ unless %w(blobs notes issues merge_requests).include?(@scope)
+ @scope = 'blobs'
+ end
+
+ Search::ProjectService.new(@project, current_user, params).execute
+ else
+ unless %w(projects issues merge_requests).include?(@scope)
+ @scope = 'projects'
+ end
+
+ Search::GlobalService.new(current_user, params).execute
+ end
+
+ @objects = @search_results.objects(@scope, params[:page])
end
def autocomplete
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index e75db61e680..3927584235e 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -86,7 +86,7 @@ class SnippetsController < ApplicationController
def raw
send_data(
@snippet.content,
- type: "text/plain",
+ type: 'text/plain; charset=utf-8',
disposition: 'inline',
filename: @snippet.file_name
)
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 5bfba4f14f2..19d688c4bb8 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -14,13 +14,13 @@ module LabelsHelper
def suggested_colors
[
- '#d9534f',
- '#f0ad4e',
- '#428bca',
- '#5cb85c',
- '#34495e',
- '#7f8c8d',
- '#8e44ad',
+ '#D9534F',
+ '#F0AD4E',
+ '#428BCA',
+ '#5CB85C',
+ '#34495E',
+ '#7F8C8D',
+ '#8E44AD',
'#FFECDB'
]
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 8350f5dc072..d22526947dd 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -123,7 +123,7 @@ module ProjectsHelper
end
def link_to_toggle_star(title, starred, signed_in)
- cls = 'btn btn-block'
+ cls = 'star-btn'
cls += ' disabled' unless signed_in
toggle_html = content_tag('span', class: 'toggle') do
@@ -151,7 +151,7 @@ module ProjectsHelper
content_tag 'span', class: starred ? 'turn-on' : 'turn-off' do
link_to toggle_star_project_path(@project), link_opts do
- toggle_html + count_html
+ toggle_html + ' ' + count_html
end
end
end
@@ -261,4 +261,10 @@ module ProjectsHelper
project_blob_path(project, tree_join(project.default_branch, project.repository.contribution_guide.name))
end
end
+
+ def hidden_pass_url(original_url)
+ result = URI(original_url)
+ result.password = '*****' if result.password.present?
+ result
+ end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index ecd8d3994d0..94e15c0f81c 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -91,4 +91,21 @@ module SearchHelper
def search_result_sanitize(str)
Sanitize.clean(str)
end
+
+ def search_filter_path(options={})
+ exist_opts = {
+ search: params[:search],
+ project_id: params[:project_id],
+ group_id: params[:group_id],
+ scope: params[:scope]
+ }
+
+ options = exist_opts.merge(options)
+ search_path(options)
+ end
+
+ # Sanitize html generated after parsing markdown from issue description or comment
+ def search_md_sanitize(html)
+ sanitize(html, tags: %w(a p ol ul li pre code))
+ end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 0a5fe24b5af..698b5b8c30a 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -49,6 +49,10 @@ module Issuable
where("LOWER(title) like :query", query: "%#{query.downcase}%")
end
+ def full_search(query)
+ where("LOWER(title) like :query OR LOWER(description) like :query", query: "%#{query.downcase}%")
+ end
+
def sort(method)
case method.to_s
when 'newest' then reorder("#{table_name}.created_at DESC")
@@ -138,6 +142,10 @@ module Issuable
labels.order('title ASC').pluck(:title)
end
+ def remove_labels
+ labels.delete_all
+ end
+
def add_labels_by_names(label_names)
label_names.each do |label_name|
label = project.labels.create_with(
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 92a8ff9b677..45a8e43b03d 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -15,7 +15,6 @@
# milestone_id :integer
# state :string(255)
# iid :integer
-# attachment :string(255)
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/label.rb b/app/models/label.rb
index 819d6cefa41..2b2b02e0645 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -1,19 +1,31 @@
+# == Schema Information
+#
+# Table name: labels
+#
+# id :integer not null, primary key
+# title :string(255)
+# color :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+#
+
class Label < ActiveRecord::Base
- DEFAULT_COLOR = '#428bca'
+ DEFAULT_COLOR = '#428BCA'
belongs_to :project
has_many :label_links, dependent: :destroy
has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
validates :color,
- format: { with: /\A\#[0-9A-Fa-f]{6}+\Z/ },
+ format: { with: /\A#[0-9A-Fa-f]{6}\Z/ },
allow_blank: false
validates :project, presence: true
# Don't allow '?', '&', and ',' for label titles
validates :title,
presence: true,
- format: { with: /\A[^&\?,&]*\z/ },
+ format: { with: /\A[^&\?,&]+\z/ },
uniqueness: { scope: :project_id }
scope :order_by_name, -> { reorder("labels.title ASC") }
diff --git a/app/models/label_link.rb b/app/models/label_link.rb
index 47bd6eaf35f..b94c9c777af 100644
--- a/app/models/label_link.rb
+++ b/app/models/label_link.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: label_links
+#
+# id :integer not null, primary key
+# label_id :integer
+# target_id :integer
+# target_type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
class LabelLink < ActiveRecord::Base
belongs_to :target, polymorphic: true
belongs_to :label
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index b5705ef151d..10bd76b1c35 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -17,6 +17,7 @@
# target_project_id :integer not null
# iid :integer
# description :text
+# position :integer default(0)
#
require Rails.root.join("app/models/commit")
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 248fa18353e..409e82ed1ef 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -3,7 +3,7 @@
# Table name: merge_request_diffs
#
# id :integer not null, primary key
-# state :string(255) default("collected"), not null
+# state :string(255)
# st_commits :text
# st_diffs :text
# merge_request_id :integer not null
diff --git a/app/models/note.rb b/app/models/note.rb
index 7ff6444cc9b..0fa1a7ab615 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -146,6 +146,10 @@ class Note < ActiveRecord::Base
def cross_reference_exists?(noteable, mentioner)
where(noteable_id: noteable.id, system: true, note: "_mentioned in #{mentioner.gfm_reference}_").any?
end
+
+ def search(query)
+ where("note like :query", query: "%#{query}%")
+ end
end
def commit_author
@@ -333,4 +337,8 @@ class Note < ActiveRecord::Base
def set_references
notice_added_references(project, author)
end
+
+ def editable?
+ !system
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 7f6aa6d4249..5cc35f20cad 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -22,7 +22,8 @@
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# import_status :string(255)
-# star_count :integer
+# repository_size :float default(0.0)
+# star_count :integer default(0), not null
#
class Project < ActiveRecord::Base
@@ -176,11 +177,11 @@ class Project < ActiveRecord::Base
joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
end
- def search query
+ def search(query)
joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
end
- def search_by_title query
+ def search_by_title(query)
where("projects.archived = ?", false).where("LOWER(projects.name) LIKE :query", query: "%#{query.downcase}%")
end
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index fd34a2a35ea..1a107f92c93 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -1,3 +1,22 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# token :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# project_url :string(255)
+# subdomain :string(255)
+# room :string(255)
+# recipients :text
+# api_key :string(255)
+#
+
# Base class for CI services
# List methods you need to implement to get your CI service
# working with GitLab Merge Requests
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index a8ba5efcc7c..a82a300a672 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -2,8 +2,9 @@ class ProjectWiki
include Gitlab::ShellAdapter
MARKUPS = {
- "Markdown" => :markdown,
- "RDoc" => :rdoc
+ 'Markdown' => :markdown,
+ 'RDoc' => :rdoc,
+ 'AsciiDoc' => :asciidoc
}
class CouldNotCreateWikiError < StandardError; end
diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb
index 80e756bd00c..3d49cb05949 100644
--- a/app/models/users_star_project.rb
+++ b/app/models/users_star_project.rb
@@ -2,11 +2,11 @@
#
# Table name: users_star_projects
#
-# id :integer not null, primary key
-# starrer_id :integer not null
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
+# id :integer not null, primary key
+# project_id :integer not null
+# user_id :integer not null
+# created_at :datetime
+# updated_at :datetime
#
class UsersStarProject < ActiveRecord::Base
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 2f1c7b18aa0..66f0a02f0af 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -7,7 +7,12 @@ module Projects
end
def execute
- project = @from_project.dup
+ project_params = {
+ visibility_level: @from_project.visibility_level,
+ description: @from_project.description,
+ }
+
+ project = Project.new(project_params)
project.name = @from_project.name
project.path = @from_project.path
project.namespace = current_user.namespace
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index d213e1375e0..0bcc50c81a7 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -7,30 +7,12 @@ module Search
end
def execute
- query = params[:search]
- query = Shellwords.shellescape(query) if query.present?
- return result unless query.present?
-
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
projects = ProjectsFinder.new.execute(current_user)
projects = projects.where(namespace_id: group.id) if group
project_ids = projects.pluck(:id)
- result[:projects] = projects.search(query).limit(20)
- result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20)
- result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20)
- result[:total_results] = %w(projects issues merge_requests).sum { |items| result[items.to_sym].size }
- result
- end
-
- def result
- @result ||= {
- projects: [],
- merge_requests: [],
- issues: [],
- notes: [],
- total_results: 0,
- }
+ Gitlab::SearchResults.new(project_ids, params[:search])
end
end
end
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index 8aac18840e4..f630c0a3790 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -7,39 +7,9 @@ module Search
end
def execute
- query = params[:search]
- query = Shellwords.shellescape(query) if query.present?
- return result unless query.present?
-
- if params[:search_code].present?
- if !@project.empty_repo?
- blobs = project.repository.search_files(query,
- params[:repository_ref])
- else
- blobs = Array.new
- end
-
- blobs = Kaminari.paginate_array(blobs).page(params[:page]).per(20)
- result[:blobs] = blobs
- result[:total_results] = blobs.total_count
- else
- result[:merge_requests] = project.merge_requests.search(query).order('updated_at DESC').limit(20)
- result[:issues] = project.issues.where("title like :query OR description like :query ", query: "%#{query}%").order('updated_at DESC').limit(20)
- result[:notes] = Note.where(noteable_type: 'issue').where(project_id: project.id).where("note like :query", query: "%#{query}%").order('updated_at DESC').limit(20)
- result[:total_results] = %w(issues merge_requests notes).sum { |items| result[items.to_sym].size }
- end
-
- result
- end
-
- def result
- @result ||= {
- merge_requests: [],
- issues: [],
- blobs: [],
- notes: [],
- total_results: 0,
- }
+ Gitlab::ProjectSearchResults.new(project.id,
+ params[:search],
+ params[:repository_ref])
end
end
end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 41760f8b1e3..7427cea7e8b 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -94,7 +94,7 @@
%span.light.pull-right
= Milestone.count
%p
- Monthly active users
+ Active users last 30 days
%span.light.pull-right
= User.where("current_sign_in_at > ?", 30.days.ago).count
.col-md-4
diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml
index 08e17490865..8d17f39eba2 100755
--- a/app/views/devise/confirmations/new.html.haml
+++ b/app/views/devise/confirmations/new.html.haml
@@ -1,7 +1,7 @@
-.login-box.panel.panel-default
- .panel-heading
- %h3.panel-title Resend confirmation instructions
- .panel-body
+.login-box
+ .login-heading
+ %h3 Resend confirmation instructions
+ .login-body
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
.devise-errors
= devise_error_messages!
@@ -9,5 +9,5 @@
= f.email_field :email, placeholder: 'Email', class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Resend confirmation instructions", class: 'btn btn-success'
- .panel-footer
+ .login-footer
= render 'devise/shared/sign_in_link'
diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml
index efcd0296176..1326cc0aac9 100644
--- a/app/views/devise/passwords/edit.html.haml
+++ b/app/views/devise/passwords/edit.html.haml
@@ -1,7 +1,7 @@
-.login-box.panel.panel-default
- .panel-heading
- %h3.panel-title Change your password
- .panel-body
+.login-box
+ .login-heading
+ %h3 Change your password
+ .login-body
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
.devise-errors
= devise_error_messages!
@@ -12,7 +12,7 @@
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.clearfix.append-bottom-10
= f.submit "Change my password", class: "btn btn-primary"
- .panel-footer
+ .login-footer
%p
= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
= render 'devise/shared/sign_in_link'
diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml
index bf44dee5ad7..b8af1b8693a 100755
--- a/app/views/devise/passwords/new.html.haml
+++ b/app/views/devise/passwords/new.html.haml
@@ -1,7 +1,7 @@
-.login-box.panel.panel-default
- .panel-heading
- %h3.panel-title Reset password
- .panel-body
+.login-box
+ .login-heading
+ %h3 Reset password
+ .login-body
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
.devise-errors
= devise_error_messages!
@@ -9,5 +9,5 @@
= f.email_field :email, placeholder: "Email", class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Reset password", class: "btn-primary btn"
- .panel-footer
+ .login-footer
= render 'devise/shared/sign_in_link'
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index 52d484949b6..d6a952f3dc5 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -1,7 +1,7 @@
-.login-box.panel.panel-success
- .panel-heading
- %h3.panel-title Sign up
- .panel-body
+.login-box
+ .login-heading
+ %h3 Sign up
+ .login-body
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
.devise-errors
= devise_error_messages!
@@ -17,7 +17,7 @@
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm password", required: true
%div
= f.submit "Sign up", class: "btn-create btn"
- .panel-footer
+ .login-footer
%p
%span.light
Have an account?
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index 4e196044892..e819847e5ea 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -6,7 +6,7 @@
%label.checkbox.remember_me{for: "user_remember_me"}
= f.check_box :remember_me
%span Remember me
+ .pull-right
+ = link_to "Forgot your password?", new_password_path(resource_name)
%div
- = f.submit "Sign in", class: "btn-save btn"
- .pull-right
- = link_to "Forgot your password?", new_password_path(resource_name), class: "btn"
+ = f.submit "Sign in", class: "btn btn-save"
diff --git a/app/views/devise/sessions/_oauth_providers.html.haml b/app/views/devise/sessions/_oauth_providers.html.haml
index 935bc6af505..15048a78063 100644
--- a/app/views/devise/sessions/_oauth_providers.html.haml
+++ b/app/views/devise/sessions/_oauth_providers.html.haml
@@ -1,7 +1,6 @@
- providers = (enabled_oauth_providers - [:ldap])
- if providers.present?
- %hr
- %div{:'data-no-turbolink' => 'data-no-turbolink'}
+ .bs-callout.bs-callout-info{:'data-no-turbolink' => 'data-no-turbolink'}
%span Sign in with: &nbsp;
- providers.each do |provider|
%span
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index f53d6f09daf..b70b0d66172 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,7 +1,7 @@
-.login-box.panel.panel-primary
- .panel-heading
- %h3.panel-title Sign in
- .panel-body
+.login-box
+ .login-heading
+ %h3 Sign in
+ .login-body
- if ldap_enabled? && gitlab_config.signin_enabled
%ul.nav.nav-tabs
%li.active
@@ -24,7 +24,7 @@
= render 'devise/sessions/oauth_providers' if Gitlab.config.omniauth.enabled && devise_mapping.omniauthable?
- .panel-footer
+ .login-footer
- if gitlab_config.signup_enabled
%p
%span.light
diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml
index a9498416c8a..0b4be2ef5cd 100644
--- a/app/views/explore/projects/_project.html.haml
+++ b/app/views/explore/projects/_project.html.haml
@@ -1,25 +1,26 @@
%li
- %h4.project-title
- .project-access-icon
- = visibility_level_icon(project.visibility_level)
- = link_to project.name_with_namespace, project
+ .project-access-icon
+ = visibility_level_icon(project.visibility_level)
- - if current_page?(starred_explore_projects_path)
- %strong.pull-right
- = pluralize project.star_count, 'star'
+ .project-description
+ %h4.project-title
+ = link_to project.name_with_namespace, project
- - if project.description.present?
- %p.project-description.str-truncated
- = project.description
+ - if current_page?(starred_explore_projects_path)
+ %strong.pull-right
+ = pluralize project.star_count, 'star'
- .repo-info
- - unless project.empty_repo?
- = link_to pluralize(project.repository.round_commit_count, 'commit'), project_commits_path(project, project.default_branch)
- &middot;
- = link_to pluralize(project.repository.branch_names.count, 'branch'), project_branches_path(project)
- &middot;
- = link_to pluralize(project.repository.tag_names.count, 'tag'), project_tags_path(project)
- - else
- %i.icon-warning-sign
- Empty repository
+ - if project.description.present?
+ %p.project-description.str-truncated
+ = project.description
+ .repo-info
+ - unless project.empty_repo?
+ = link_to pluralize(project.repository.round_commit_count, 'commit'), project_commits_path(project, project.default_branch)
+ &middot;
+ = link_to pluralize(project.repository.branch_names.count, 'branch'), project_branches_path(project)
+ &middot;
+ = link_to pluralize(project.repository.tag_names.count, 'tag'), project_tags_path(project)
+ - else
+ %i.icon-warning-sign
+ Empty repository
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index dd70836cdc9..ffa48a68b42 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -11,7 +11,7 @@
.container
.content
.row
- .col-md-7
+ .col-md-7.brand-holder
- if brand_item
.brand-image
= brand_image
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 69491c2529e..92ef7923714 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,7 +1,7 @@
%ul
= nav_link(path: 'projects#show', html_options: {class: "home"}) do
= link_to project_path(@project), title: "Project" do
- Activity
+ Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml
index 1667c59bc07..fe248584e55 100644
--- a/app/views/notify/project_was_moved_email.html.haml
+++ b/app/views/notify/project_was_moved_email.html.haml
@@ -1,5 +1,5 @@
%p
- = "Project was moved to another location"
+ Project was moved to another location
%p
The project is now located under
= link_to project_url(@project) do
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 62348f26f0a..1627a61d236 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -1,36 +1,48 @@
- empty_repo = @project.empty_repo?
.project-home-panel{:class => ("empty-project" if empty_repo)}
- .visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(@project.visibility_level)} project" }
- = visibility_level_icon(@project.visibility_level)
- .row
- .col-sm-6
- %h4.project-home-title
- = @project.name_with_namespace
+ .project-home-row
+ .project-home-desc
+ - if @project.description.present?
+ = auto_link ERB::Util.html_escape(@project.description), link: :urls
+ - if can?(current_user, :admin_project, @project)
+ &ndash;
+ = link_to 'Edit', edit_project_path
+ - elsif !@project.empty_repo? && @repository.readme
+ - readme = @repository.readme
+ &ndash;
+ = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do
+ = readme.name
+ .star-fork-buttons
+ - unless @project.empty_repo?
+ .fork-buttons
+ - if current_user && can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
+ - if current_user.already_forked?(@project)
+ = link_to project_path(current_user.fork_of(@project)), title: 'Got to my fork' do
+ %i.icon-code-fork
+ Fork
+ %span.count
+ = @project.forks_count
+ - else
+ = link_to fork_project_path(@project), title: "Fork project", method: "POST" do
+ %i.icon-code-fork
+ Fork
+ %span.count
+ = @project.forks_count
- .col-sm-6
- - if current_user && !empty_repo
- .project-home-dropdown
- = render "dropdown"
- = render "shared/clone_panel"
+ .star-buttons
+ %span.star.js-toggler-container{class: @show_star ? 'on' : ''}
+ - if current_user
+ = link_to_toggle_star('Star this project.', false, true)
+ = link_to_toggle_star('Unstar this project.', true, true)
+ - else
+ = link_to_toggle_star('You must sign in to star a project.', false, false)
- .project-home-extra.row
- .col-md-7
- .project-home-desc
- - if @project.description.present?
- = auto_link ERB::Util.html_escape(@project.description), link: :urls
- - if can?(current_user, :admin_project, @project)
- &ndash;
- %strong= link_to 'Edit', edit_project_path
- - elsif !@project.empty_repo? && @repository.readme
- - readme = @repository.readme
- &ndash;
- = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do
- = readme.name
-
- .col-md-5
- .project-home-links
- - unless empty_repo
- = link_to pluralize(number_with_delimiter(@repository.commit_count), 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
- = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), project_branches_path(@project)
- = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), project_tags_path(@project)
- %span.light.prepend-left-20= repository_size
+ .project-home-row
+ - if current_user && !empty_repo
+ .project-home-dropdown
+ = render "dropdown"
+ - unless @project.empty_repo?
+ - if can? current_user, :download_code, @project
+ .pull-right.prepend-left-10
+ = render 'projects/repositories/download_archive', split_button: true
+ = render "shared/clone_panel"
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index cdca8b2e634..64bbd495102 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -8,7 +8,7 @@
= @path
%small= number_to_human_size @blob.size
%span.options= render "projects/blob/actions"
- .file-content.blame
+ .file-content.blame.highlight
%table
- current_line = 1
- @blame.each do |commit, lines|
@@ -33,7 +33,8 @@
- current_line += 1
%td.lines
%pre
- :erb
- <% lines.each do |line| %>
- <%= line %>
- <% end %>
+ %code{ class: highlightjs_class(@blob.name) }
+ :erb
+ <% lines.each do |line| %>
+ <%= line %>
+ <% end %>
diff --git a/app/views/projects/commits/_diff_file.html.haml b/app/views/projects/commits/_diff_file.html.haml
index 6e6107c8849..31208a227ce 100644
--- a/app/views/projects/commits/_diff_file.html.haml
+++ b/app/views/projects/commits/_diff_file.html.haml
@@ -16,6 +16,10 @@
%span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
.diff-btn-group
+ %label
+ = check_box_tag nil, 1, false, class: "js-toggle-diff-line-wrap"
+ Wrap text
+ &nbsp;
= link_to "#", class: "js-toggle-diff-comments btn btn-small" do
%i.icon-chevron-down
Diff comments
diff --git a/app/views/projects/commits/_diff_stats.html.haml b/app/views/projects/commits/_diff_stats.html.haml
index 846a1ee10e6..8ef7cc6e086 100644
--- a/app/views/projects/commits/_diff_stats.html.haml
+++ b/app/views/projects/commits/_diff_stats.html.haml
@@ -26,7 +26,7 @@
%a{href: "#diff-#{i}"}
%i.icon-minus
= diff.old_path
- = "->"
+ \->
= diff.new_path
- elsif diff.new_file
%span.new-file
diff --git a/app/views/projects/commits/_diffs.html.haml b/app/views/projects/commits/_diffs.html.haml
index 64d6a2f09cf..17efa8debe1 100644
--- a/app/views/projects/commits/_diffs.html.haml
+++ b/app/views/projects/commits/_diffs.html.haml
@@ -4,9 +4,12 @@
.col-md-4
%ul.nav.nav-tabs
%li.pull-right{class: params[:view] == 'parallel' ? 'active' : ''}
- = link_to "Side-by-side Diff", url_for(view: 'parallel'), {id: "commit-diff-viewtype"}
+ - params_copy = params.dup
+ - params_copy[:view] = 'parallel'
+ = link_to "Side-by-side Diff", url_for(params_copy), {id: "commit-diff-viewtype"}
%li.pull-right{class: params[:view] != 'parallel' ? 'active' : ''}
- = link_to "Inline Diff", url_for(view: 'inline'), {id: "commit-diff-viewtype"}
+ - params_copy[:view] = 'inline'
+ = link_to "Inline Diff", url_for(params_copy), {id: "commit-diff-viewtype"}
- if show_diff_size_warninig?(diffs)
= render 'projects/commits/diff_warning', diffs: diffs
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 99b6d8ad288..d9acb685517 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -114,7 +114,7 @@
%br
%strong Once active this project shows up in the search and on the dashboard.
= link_to 'Unarchive', unarchive_project_path(@project),
- data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be comitted to again." },
+ data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
method: :post, class: "btn btn-remove"
- else
%p
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 05050e7df7c..62798b51d82 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -41,6 +41,7 @@
:javascript
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
+ ace.config.loadModule("ace/ext/searchbox");
var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
editor.setValue("#{escape_javascript(@blob.data)}");
diff --git a/app/views/projects/import.html.haml b/app/views/projects/import.html.haml
index 9efb1658c25..649dd56a8d9 100644
--- a/app/views/projects/import.html.haml
+++ b/app/views/projects/import.html.haml
@@ -4,7 +4,7 @@
%h2
%i.icon-spinner.icon-spin
Import in progress.
- %p.monospace git clone --bare #{@project.import_url}
+ %p.monospace git clone --bare #{hidden_pass_url(@project.import_url)}
%p Please wait while we import the repository for you. Refresh at will.
:javascript
new ProjectImport();
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index db28b831182..e257f317b95 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -9,7 +9,7 @@
= link_to_gfm issue.title, project_issue_path(issue.project, issue), class: "row_title"
- if issue.closed?
%small.pull-right
- = "CLOSED"
+ CLOSED
.issue-info
- if issue.assignee
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 7f5de232dcf..06cf390fbde 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -5,7 +5,7 @@
- if merge_request.merged?
%small.pull-right
%i.icon-ok
- = "MERGED"
+ MERGED
- else
%span.pull-right
- if merge_request.for_fork?
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 7c43d355987..dc3f9d592f6 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -16,7 +16,7 @@
.form-group
.light
= f.label :title do
- = "Title *"
+ Title *
= f.text_field :title, class: "form-control input-lg js-gfm-input", maxlength: 255, rows: 5, required: true
.form-group
.light
diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml
index 92a7bb927e4..ede709ea1df 100644
--- a/app/views/projects/merge_requests/show/_commits.html.haml
+++ b/app/views/projects/merge_requests/show/_commits.html.haml
@@ -17,7 +17,7 @@
- @commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE).each do |commit|
= render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project
%li
- other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden top prevent performance issues.
+ other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden to prevent performance issues.
- else
%ul.all-commits.hide.well-list
- @commits.each do |commit|
diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml
index 79a66eff129..a01056b7166 100644
--- a/app/views/projects/notes/_diff_notes_with_reply.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply.html.haml
@@ -3,7 +3,7 @@
- if !defined?(line) || line == note.diff_line
%tr.notes_holder
%td.notes_line{ colspan: 2 }
- %span.btn.disabled
+ %span.discussion-notes-count
%i.icon-comment
= notes.count
%td.notes_content
diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml
index 8c7964cbf3e..f4c6fad2fed 100644
--- a/app/views/projects/notes/_discussion.html.haml
+++ b/app/views/projects/notes/_discussion.html.haml
@@ -1,8 +1,13 @@
- note = discussion_notes.first
-- if note.for_merge_request?
- - if note.outdated?
- = render "projects/notes/discussions/outdated", discussion_notes: discussion_notes
- - else
- = render "projects/notes/discussions/active", discussion_notes: discussion_notes
-- else
- = render "projects/notes/discussions/commit", discussion_notes: discussion_notes
+.timeline-entry
+ .timeline-entry-inner
+ .timeline-icon
+ = image_tag avatar_icon(note.author_email), class: "avatar s40"
+ .timeline-content
+ - if note.for_merge_request?
+ - if note.outdated?
+ = render "projects/notes/discussions/outdated", discussion_notes: discussion_notes
+ - else
+ = render "projects/notes/discussions/active", discussion_notes: discussion_notes
+ - else
+ = render "projects/notes/discussions/commit", discussion_notes: discussion_notes
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 5e84aed0cc4..394fa88e045 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,66 +1,69 @@
-%li{ id: dom_id(note), class: dom_class(note), data: { discussion: note.discussion_id } }
- .note-header
- .note-actions
- = link_to "##{dom_id(note)}", name: dom_id(note) do
- %i.icon-link
- Link here
- &nbsp;
- - if(note.author_id == current_user.try(:id)) || can?(current_user, :admin_note, @project)
- = link_to "#", title: "Edit comment", class: "js-note-edit" do
- %i.icon-edit
- Edit
- &nbsp;
- = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: "danger js-note-delete" do
- %i.icon-trash.cred
- Remove
- = image_tag avatar_icon(note.author_email), class: "avatar s32"
- = link_to_member(@project, note.author, avatar: false)
- %span.note-last-update
- = note_timestamp(note)
+%li.timeline-entry{ id: dom_id(note), class: dom_class(note), data: { discussion: note.discussion_id } }
+ .timeline-entry-inner
+ .timeline-icon
+ = image_tag avatar_icon(note.author_email), class: "avatar s40"
+ .timeline-content
+ .note-header
+ .note-actions
+ = link_to "##{dom_id(note)}", name: dom_id(note) do
+ %i.icon-link
+ Link here
+ &nbsp;
+ - if can?(current_user, :admin_note, note) && note.editable?
+ = link_to "#", title: "Edit comment", class: "js-note-edit" do
+ %i.icon-edit
+ Edit
+ &nbsp;
+ = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: "danger js-note-delete" do
+ %i.icon-trash.cred
+ Remove
+ = link_to_member(@project, note.author, avatar: false)
+ %span.note-last-update
+ = note_timestamp(note)
- - if note.upvote?
- %span.vote.upvote.label.label-success
- %i.icon-thumbs-up
- \+1
- - if note.downvote?
- %span.vote.downvote.label.label-danger
- %i.icon-thumbs-down
- \-1
+ - if note.upvote?
+ %span.vote.upvote.label.label-success
+ %i.icon-thumbs-up
+ \+1
+ - if note.downvote?
+ %span.vote.downvote.label.label-danger
+ %i.icon-thumbs-down
+ \-1
- .note-body
- .note-text
- = preserve do
- = markdown(note.note, {no_header_anchors: true})
+ .note-body
+ .note-text
+ = preserve do
+ = markdown(note.note, {no_header_anchors: true})
- .note-edit-form
- = form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
- = f.text_area :note, class: 'note_text js-note-text js-gfm-input turn-on'
+ .note-edit-form
+ = form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
+ = f.text_area :note, class: 'note_text js-note-text js-gfm-input turn-on'
- .form-actions.clearfix
- = f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button"
+ .form-actions.clearfix
+ = f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button"
- .note-form-option
- %a.choose-btn.btn.js-choose-note-attachment-button
- %i.icon-paper-clip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-attachment-filename File name...
- = f.file_field :attachment, class: "js-note-attachment-input hidden"
+ .note-form-option
+ %a.choose-btn.btn.js-choose-note-attachment-button
+ %i.icon-paper-clip
+ %span Choose File ...
+ &nbsp;
+ %span.file_name.js-attachment-filename File name...
+ = f.file_field :attachment, class: "js-note-attachment-input hidden"
- = link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel"
+ = link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel"
- - if note.attachment.url
- .note-attachment
- - if note.attachment.image?
- = link_to note.attachment.secure_url, target: '_blank' do
- = image_tag note.attachment.secure_url, class: 'note-image-attach'
- .attachment.pull-right
- = link_to note.attachment.secure_url, target: "_blank" do
- %i.icon-paper-clip
- = note.attachment_identifier
- = link_to delete_attachment_project_note_path(@project, note),
- title: "Delete this attachment", method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove the attachment?' }, class: "danger js-note-attachment-delete" do
- %i.icon-trash.cred
- .clear
+ - if note.attachment.url
+ .note-attachment
+ - if note.attachment.image?
+ = link_to note.attachment.secure_url, target: '_blank' do
+ = image_tag note.attachment.secure_url, class: 'note-image-attach'
+ .attachment.pull-right
+ = link_to note.attachment.secure_url, target: "_blank" do
+ %i.icon-paper-clip
+ = note.attachment_identifier
+ = link_to delete_attachment_project_note_path(@project, note),
+ title: "Delete this attachment", method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove the attachment?' }, class: "danger js-note-attachment-delete" do
+ %i.icon-trash.cred
+ .clear
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index 052661962e4..04ee17a40a0 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -1,4 +1,4 @@
-%ul#notes-list.notes.main-notes-list
+%ul#notes-list.notes.main-notes-list.timeline
= render "projects/notes/notes"
.js-notes-busy
diff --git a/app/views/projects/notes/discussions/_active.html.haml b/app/views/projects/notes/discussions/_active.html.haml
index ef296b35dd5..eb416c5b5f0 100644
--- a/app/views/projects/notes/discussions/_active.html.haml
+++ b/app/views/projects/notes/discussions/_active.html.haml
@@ -5,7 +5,6 @@
= link_to "#", class: "js-toggle-button" do
%i.icon-chevron-up
Show/hide discussion
- = image_tag avatar_icon(note.author_email), class: "avatar s32"
%div
= link_to_member(@project, note.author, avatar: false)
started a discussion
diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml
index 78460974a9b..a928029a5e5 100644
--- a/app/views/projects/notes/discussions/_commit.html.haml
+++ b/app/views/projects/notes/discussions/_commit.html.haml
@@ -5,7 +5,6 @@
= link_to "#", class: "js-toggle-button" do
%i.icon-chevron-up
Show/hide discussion
- = image_tag avatar_icon(note.author_email), class: "avatar s32"
%div
= link_to_member(@project, note.author, avatar: false)
started a discussion on commit
diff --git a/app/views/projects/notes/discussions/_outdated.html.haml b/app/views/projects/notes/discussions/_outdated.html.haml
index 67c29be8ac1..4ae914c107b 100644
--- a/app/views/projects/notes/discussions/_outdated.html.haml
+++ b/app/views/projects/notes/discussions/_outdated.html.haml
@@ -5,7 +5,6 @@
= link_to "#", class: "js-toggle-button" do
%i.icon-chevron-down
Show/hide discussion
- = image_tag avatar_icon(note.author_email), class: "avatar s32"
%div
= link_to_member(@project, note.author, avatar: false)
started a discussion on the
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 0fd290b5398..7902f51f72f 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,5 +1,16 @@
= render "home_panel"
+%ul.nav.nav-tabs
+ %li.active
+ = link_to project_path(@project) do
+ Activity
+ .project-home-links
+ - unless @project.empty_repo?
+ = link_to pluralize(number_with_delimiter(@repository.commit_count), 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
+ = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), project_branches_path(@project)
+ = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), project_tags_path(@project)
+ %span.light.prepend-left-20= repository_size
+
.row
%section.col-md-9
= render "events/event_last_push", event: @last_push
@@ -22,33 +33,7 @@
%br
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
- .star-buttons
- %span.star.js-toggler-container{class: @show_star ? 'on' : ''}
- - if current_user
- = link_to_toggle_star('Star this project.', false, true)
- = link_to_toggle_star('Unstar this project.', true, true)
- - else
- = link_to_toggle_star('You must sign in to star a project.', false, false)
-
- unless @project.empty_repo?
- .fork-buttons
- - if current_user && can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
- - if current_user.already_forked?(@project)
- = link_to project_path(current_user.fork_of(@project)), class: 'btn btn-block' do
- %i.icon-compass
- Go to fork
- %span.count
- = @project.forks_count
- - else
- = link_to fork_project_path(@project), title: "Fork", class: "btn btn-block", method: "POST" do
- %i.icon-code-fork
- Fork repository
- %span.count
- = @project.forks_count
- - unless @project.empty_repo?
- - if can? current_user, :download_code, @project
- = render 'projects/repositories/download_archive', btn_class: 'btn-block btn-group-justified', split_button: true
-
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: @ref || @repository.root_ref), class: 'btn btn-block' do
Compare code
diff --git a/app/views/projects/team_members/_form.html.haml b/app/views/projects/team_members/_form.html.haml
index dd059fb99d3..5998e4c6b42 100644
--- a/app/views/projects/team_members/_form.html.haml
+++ b/app/views/projects/team_members/_form.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- = "New project member(s)"
+ New project member(s)
= form_for @user_project_relation, as: :team_member, url: project_team_members_path(@project), html: { class: "form-horizontal users-project-form" } do |f|
-if @user_project_relation.errors.any?
diff --git a/app/views/projects/team_members/import.html.haml b/app/views/projects/team_members/import.html.haml
index d3e4a762018..510b579fe2f 100644
--- a/app/views/projects/team_members/import.html.haml
+++ b/app/views/projects/team_members/import.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- = "Import members from another project"
+ Import members from another project
%p.light
Only project members will be imported. Group members will be skipped.
%hr
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index 979b18e3856..049aff0bc9b 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -9,14 +9,14 @@
%b.caret
%ul.dropdown-menu
%li
- = link_to search_path(group_id: nil, search: params[:search]) do
+ = link_to search_filter_path(group_id: nil) do
Any
- current_user.authorized_groups.sort_by(&:name).each do |group|
%li
- = link_to search_path(group_id: group.id, search: params[:search]) do
+ = link_to search_filter_path(group_id: group.id, project_id: nil) do
= group.name
-.dropdown.inline.prepend-left-10
+.dropdown.inline.prepend-left-10.project-filter
%a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
%i.icon-tags
%span.light Project:
@@ -27,9 +27,9 @@
%b.caret
%ul.dropdown-menu
%li
- = link_to search_path(project_id: nil, search: params[:search]) do
+ = link_to search_filter_path(project_id: nil) do
Any
- current_user.authorized_projects.sort_by(&:name_with_namespace).each do |project|
%li
- = link_to search_path(project_id: project.id, search: params[:search]) do
+ = link_to search_filter_path(project_id: project.id, group_id: nil) do
= project.name_with_namespace
diff --git a/app/views/search/_global_filter.html.haml b/app/views/search/_global_filter.html.haml
new file mode 100644
index 00000000000..442bd84f930
--- /dev/null
+++ b/app/views/search/_global_filter.html.haml
@@ -0,0 +1,16 @@
+%ul.nav.nav-pills.nav-stacked.search-filter
+ %li{class: ("active" if @scope == 'projects')}
+ = link_to search_filter_path(scope: 'projects') do
+ Projects
+ .pull-right
+ = @search_results.projects_count
+ %li{class: ("active" if @scope == 'issues')}
+ = link_to search_filter_path(scope: 'issues') do
+ Issues
+ .pull-right
+ = @search_results.issues_count
+ %li{class: ("active" if @scope == 'merge_requests')}
+ = link_to search_filter_path(scope: 'merge_requests') do
+ Merge requests
+ .pull-right
+ = @search_results.merge_requests_count
diff --git a/app/views/search/_global_results.html.haml b/app/views/search/_global_results.html.haml
deleted file mode 100644
index 7f4f0e5e000..00000000000
--- a/app/views/search/_global_results.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-.search_results
- %ul.bordered-list
- = render partial: "search/results/project", collection: @search_results[:projects]
- = render partial: "search/results/merge_request", collection: @search_results[:merge_requests]
- = render partial: "search/results/issue", collection: @search_results[:issues]
diff --git a/app/views/search/_project_filter.html.haml b/app/views/search/_project_filter.html.haml
new file mode 100644
index 00000000000..36947675d18
--- /dev/null
+++ b/app/views/search/_project_filter.html.haml
@@ -0,0 +1,25 @@
+%ul.nav.nav-pills.nav-stacked.search-filter
+ %li{class: ("active" if @scope == 'blobs')}
+ = link_to search_filter_path(scope: 'blobs') do
+ %i.icon-code
+ Code
+ .pull-right
+ = @search_results.blobs_count
+ %li{class: ("active" if @scope == 'issues')}
+ = link_to search_filter_path(scope: 'issues') do
+ %i.icon-exclamation-sign
+ Issues
+ .pull-right
+ = @search_results.issues_count
+ %li{class: ("active" if @scope == 'merge_requests')}
+ = link_to search_filter_path(scope: 'merge_requests') do
+ %i.icon-code-fork
+ Merge requests
+ .pull-right
+ = @search_results.merge_requests_count
+ %li{class: ("active" if @scope == 'notes')}
+ = link_to search_filter_path(scope: 'notes') do
+ %i.icon-comments
+ Comments
+ .pull-right
+ = @search_results.notes_count
diff --git a/app/views/search/_project_results.html.haml b/app/views/search/_project_results.html.haml
deleted file mode 100644
index 5e8346a8262..00000000000
--- a/app/views/search/_project_results.html.haml
+++ /dev/null
@@ -1,24 +0,0 @@
-%ul.nav.nav-tabs
- %li{class: ("active" if params[:search_code].present?)}
- = link_to search_path(params.merge(search_code: true)) do
- Repository Code
- %li{class: ("active" if params[:search_code].blank?)}
- = link_to search_path(params.merge(search_code: nil)) do
- Issues and Merge requests
-
-.search_results
- - if params[:search_code].present?
- .blob-results
- - if !@search_results[:blobs].empty?
- = render partial: "search/results/blob", collection: @search_results[:blobs]
- = paginate @search_results[:blobs], theme: 'gitlab'
- - else
- = render partial: "search/results/empty", :locals => { message: "We couldn't find any matching code" }
- - else
- - if @search_results[:merge_requests].present? || @search_results[:issues].present? || @search_results[:notes].present?
- %ul.bordered-list
- = render partial: "search/results/merge_request", collection: @search_results[:merge_requests]
- = render partial: "search/results/issue", collection: @search_results[:issues]
- = render partial: "search/results/note", collection: @search_results[:notes]
- - else
- = render partial: "search/results/empty", locals: { message: "We couldn't find any issues, merge requests or notes" }
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 2336d0f71d5..f9c0a6d61ff 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,5 +1,5 @@
%h4
- #{@search_results[:total_results]} results found
+ #{@search_results.total_count} results found
- if @project
for #{link_to @project.name_with_namespace, @project}
- elsif @group
@@ -7,11 +7,19 @@
%hr
-- if @project
- = render "project_results"
-- else
- = render "global_results"
+.row
+ .col-sm-3
+ - if @project
+ = render "project_filter"
+ - else
+ = render "global_filter"
+ .col-sm-9
+ .search-results
+ - if @search_results.empty?
+ = render partial: "search/results/empty", locals: { message: "We couldn't find any matching results" }
+ - else
+ = render partial: "search/results/#{@scope.singularize}", collection: @objects
+ = paginate @objects, theme: 'gitlab'
:javascript
- $(".search_results .term").highlight("#{escape_javascript(params[:search])}");
-
+ $(".search-results .term").highlight("#{escape_javascript(params[:search])}");
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index 8147cf272fb..7868f958261 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -1,9 +1,14 @@
-%li
- issue:
- = link_to [issue.project, issue] do
- %span ##{issue.iid}
- %strong.term
- = truncate issue.title, length: 50
- %span.light (#{issue.project.name_with_namespace})
+.search-result-row
+ %h4
+ = link_to [issue.project, issue] do
+ %span.term.str-truncated= issue.title
+ .pull-right ##{issue.iid}
+ - if issue.description.present?
+ .description.term
+ = preserve do
+ = search_md_sanitize(markdown(issue.description))
+ %span.light
+ #{issue.project.name_with_namespace}
- if issue.closed?
- %span.label.label-danger Closed
+ .pull-right
+ %span.label.label-danger Closed
diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml
index de2a79970c1..56b185283bd 100644
--- a/app/views/search/results/_merge_request.html.haml
+++ b/app/views/search/results/_merge_request.html.haml
@@ -1,14 +1,16 @@
-%li
- merge request:
- = link_to [merge_request.target_project, merge_request] do
- %span ##{merge_request.iid}
- %strong.term
- = truncate merge_request.title, length: 50
- - if merge_request.for_fork?
- %span.light (#{merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} &rarr; #{merge_request.target_project.name_with_namespace}:#{merge_request.target_branch})
- - else
- %span.light (#{merge_request.source_branch} &rarr; #{merge_request.target_branch})
- - if merge_request.merged?
- %span.label.label-primary Merged
- - elsif merge_request.closed?
- %span.label.label-danger Closed
+.search-result-row
+ %h4
+ = link_to [merge_request.target_project, merge_request] do
+ %span.term.str-truncated= merge_request.title
+ .pull-right ##{merge_request.iid}
+ - if merge_request.description.present?
+ .description.term
+ = preserve do
+ = search_md_sanitize(markdown(merge_request.description))
+ %span.light
+ #{merge_request.project.name_with_namespace}
+ .pull-right
+ - if merge_request.merged?
+ %span.label.label-primary Merged
+ - elsif merge_request.closed?
+ %span.label.label-danger Closed
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index 97e892bdd4d..6a446538574 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -1,9 +1,26 @@
-%li
- note on issue:
- = link_to [note.project, note.noteable] do
- %span ##{note.noteable.iid}
- %strong.term
- = truncate note.noteable.title, length: 50
- %span.light (#{note.project.name_with_namespace})
- - if note.noteable.closed?
- %span.label Closed
+- project = note.project
+.search-result-row
+ %h5.note-search-caption.str-truncated
+ %i.icon-comment
+ = link_to_member(project, note.author, avatar: false)
+ commented on
+
+ - if note.for_commit?
+ = link_to project do
+ = project.name_with_namespace
+ &middot;
+ = link_to project_commit_path(project, note.commit_id, anchor: dom_id(note)) do
+ Commit #{note.commit_id[0..8]}
+ - else
+ = link_to project do
+ = project.name_with_namespace
+ &middot;
+ %span #{note.noteable_type.titleize} ##{note.noteable.iid}
+ &middot;
+ = link_to [project, note.noteable, anchor: dom_id(note)] do
+ = note.noteable.title
+
+ .note-search-result
+ .term
+ = preserve do
+ = search_md_sanitize(markdown(note.note, {no_header_anchors: true}))
diff --git a/app/views/search/results/_project.html.haml b/app/views/search/results/_project.html.haml
index abc86c72bef..301b65eca29 100644
--- a/app/views/search/results/_project.html.haml
+++ b/app/views/search/results/_project.html.haml
@@ -1,7 +1,6 @@
-%li
- project:
- = link_to project do
- %strong.term= project.name_with_namespace
+.search-result-row
+ %h4
+ = link_to project do
+ %span.term= project.name_with_namespace
- if project.description.present?
- &ndash;
%span.light.term= project.description
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 3b6f10d4d9c..8d1614bfbd4 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -13,7 +13,7 @@
= render 'filter', f: f
= hidden_field_tag :project_id, params[:project_id]
= hidden_field_tag :group_id, params[:group_id]
- = hidden_field_tag :search_code, params[:search_code]
+ = hidden_field_tag :scope, params[:scope]
.results.prepend-top-10
- if params[:search].present?
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 8cd426c71e6..1cc6043f56b 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -4,3 +4,8 @@
%button{class: "btn #{ 'active' if default_clone_protocol == 'ssh' }", :"data-clone" => project.ssh_url_to_repo} SSH
%button{class: "btn #{ 'active' if default_clone_protocol == 'http' }", :"data-clone" => project.http_url_to_repo}= gitlab_config.protocol.upcase
= text_field_tag :project_clone, default_url_to_repo(project), class: "one_click_select form-control", readonly: true
+ - if project.kind_of?(Project)
+ .input-group-addon
+ .visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(project.visibility_level)} project" }
+ = visibility_level_icon(project.visibility_level)
+ = visibility_level_label(project.visibility_level).downcase
diff --git a/config/application.rb b/config/application.rb
index 58a5949c653..68dce05fc59 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -73,5 +73,24 @@ module Gitlab
resource '/api/*', headers: :any, methods: [:get, :post, :options, :put, :delete]
end
end
+
+ # Use Redis caching across all environments
+ redis_config_file = Rails.root.join('config', 'resque.yml')
+
+ redis_url_string = if File.exists?(redis_config_file)
+ YAML.load_file(redis_config_file)[Rails.env]
+ else
+ "redis://localhost:6379"
+ end
+
+ # Redis::Store does not handle Unix sockets well, so let's do it for them
+ redis_config_hash = Redis::Store::Factory.extract_host_options_from_uri(redis_url_string)
+ redis_uri = URI.parse(redis_url_string)
+ if redis_uri.scheme == 'unix'
+ redis_config_hash[:path] = redis_uri.path
+ end
+
+ redis_config_hash[:namespace] = 'cache:gitlab'
+ config.cache_store = :redis_store, redis_config_hash
end
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 2450d5719eb..78bf543402b 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -45,16 +45,6 @@ Gitlab::Application.configure do
# Use a different logger for distributed setups
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
- # Use a different cache store in production
- config_file = Rails.root.join('config', 'resque.yml')
-
- resque_url = if File.exists?(config_file)
- YAML.load_file(config_file)[Rails.env]
- else
- "redis://localhost:6379"
- end
- config.cache_store = :redis_store, resque_url, {namespace: 'cache:gitlab'}
-
# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index d897eb4c02d..47865ff4b44 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -61,7 +61,7 @@ production: &base
# Restrict setting visibility levels for non-admin users.
# The default is to allow all levels.
- #restricted_visibility_levels: [ "public" ]
+ # restricted_visibility_levels: [ "public" ]
## Automatic issue closing
# If a commit message matches this regular expression, all issues referenced from the matched text will be closed.
diff --git a/config/initializers/rack_attack.rb.example b/config/initializers/rack_attack.rb.example
index bc3234bf0b6..332865d2881 100644
--- a/config/initializers/rack_attack.rb.example
+++ b/config/initializers/rack_attack.rb.example
@@ -8,11 +8,19 @@ paths_to_be_protected = [
"#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session.json",
"#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session",
"#{Rails.application.config.relative_url_root}/users",
- "#{Rails.application.config.relative_url_root}/users/confirmation"
+ "#{Rails.application.config.relative_url_root}/users/confirmation",
+ "#{Rails.application.config.relative_url_root}/unsubscribes/"
+
]
+# Create one big regular expression that matches strings starting with any of
+# the paths_to_be_protected.
+paths_regex = Regexp.union(paths_to_be_protected.map { |path| /\A#{Regexp.escape(path)}/ })
+
unless Rails.env.test?
Rack::Attack.throttle('protected paths', limit: 10, period: 60.seconds) do |req|
- req.ip if paths_to_be_protected.include?(req.path) && req.post?
+ if req.post? && req.path =~ paths_regex
+ req.ip
+ end
end
end
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 5fe5270236b..b2d59f1c4b7 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -2,9 +2,10 @@
Gitlab::Application.config.session_store(
:redis_store, # Using the cookie_store would enable session replay attacks.
- servers: Gitlab::Application.config.cache_store[1], # re-use the Redis config from the Rails cache store
+ servers: Gitlab::Application.config.cache_store[1].merge(namespace: 'session:gitlab'), # re-use the Redis config from the Rails cache store
key: '_gitlab_session',
secure: Gitlab.config.gitlab.https,
httponly: true,
+ expire_after: 1.week,
path: (Rails.application.config.relative_url_root.nil?) ? '/' : Rails.application.config.relative_url_root
)
diff --git a/db/migrate/20140729152420_migrate_taggable_labels.rb b/db/migrate/20140729152420_migrate_taggable_labels.rb
index 0b844720ba1..dc28d727d9a 100644
--- a/db/migrate/20140729152420_migrate_taggable_labels.rb
+++ b/db/migrate/20140729152420_migrate_taggable_labels.rb
@@ -2,6 +2,12 @@ class MigrateTaggableLabels < ActiveRecord::Migration
def up
taggings = ActsAsTaggableOn::Tagging.where(taggable_type: ['Issue', 'MergeRequest'], context: 'labels')
taggings.find_each(batch_size: 500) do |tagging|
+ # Clean up orphaned taggings while we are here
+ if tagging.taggable.blank? || tagging.tag.nil?
+ tagging.destroy
+ print 'D'
+ next
+ end
create_label_from_tagging(tagging)
end
end
@@ -16,9 +22,11 @@ class MigrateTaggableLabels < ActiveRecord::Migration
def create_label_from_tagging(tagging)
target = tagging.taggable
label_name = tagging.tag.name
- label = target.project.labels.find_or_create_by(title: label_name)
+ # '?', '&' and ',' are no longer allowed in label names so we remove them
+ label_name.tr!('?&,', '')
+ label = target.project.labels.find_or_create_by(title: label_name, color: Label::DEFAULT_COLOR)
- if LabelLink.create(label: label, target: target)
+ if label.valid? && LabelLink.create(label: label, target: target)
print '.'
else
print 'F'
diff --git a/doc/api/README.md b/doc/api/README.md
index 44e95ed8258..ababb7b6999 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -31,7 +31,7 @@
## Introduction
-All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile.
+All API requests require authentication. You need to pass a `private_token` parameter by URL or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile.
If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401:
@@ -65,14 +65,14 @@ API request types:
- `GET` requests access one or more resources and return the result as JSON
- `POST` requests return `201 Created` if the resource is successfully created and return the newly created resource as JSON
-- `GET`, `PUT` and `DELETE` return `200 Ok` if the resource is accessed, modified or deleted successfully, the (modified) result is returned as JSON
-- `DELETE` requests are designed to be idempotent, meaning a request a resource still returns `200 Ok` even it was deleted before or is not available. The reasoning behind it is the user is not really interested if the resource existed before or not.
+- `GET`, `PUT` and `DELETE` return `200 OK` if the resource is accessed, modified or deleted successfully, the (modified) result is returned as JSON
+- `DELETE` requests are designed to be idempotent, meaning a request a resource still returns `200 OK` even it was deleted before or is not available. The reasoning behind it is the user is not really interested if the resource existed before or not.
The following list shows the possible return codes for API requests.
Return values:
-- `200 Ok` - The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON
+- `200 OK` - The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON
- `201 Created` - The `POST` request was successful and the resource is returned as JSON
- `400 Bad Request` - A required attribute of the API request is missing, e.g. the title of an issue is not given
- `401 Unauthorized` - The user is not authenticated, a valid user token is necessary, see above
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 090287133ce..31469b6fe97 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -41,7 +41,6 @@ Parameters:
]
```
-
## Get single repository branch
Get a single project repository branch.
@@ -85,7 +84,7 @@ Parameters:
## Protect repository branch
Protects a single project repository branch. This is an idempotent function, protecting an already
-protected repository branch still returns a `200 Ok` status code.
+protected repository branch still returns a `200 OK` status code.
```
PUT /projects/:id/repository/branches/:branch/protect
@@ -126,7 +125,7 @@ Parameters:
## Unprotect repository branch
Unprotects a single project repository branch. This is an idempotent function, unprotecting an already
-unprotected repository branch still returns a `200 Ok` status code.
+unprotected repository branch still returns a `200 OK` status code.
```
PUT /projects/:id/repository/branches/:branch/unprotect
@@ -199,14 +198,13 @@ Parameters:
## Delete repository branch
-
```
DELETE /projects/:id/repository/branches/:branch
```
Parameters:
-+ `id` (required) - The ID of a project
-+ `branch` (required) - The name of the branch
+- `id` (required) - The ID of a project
+- `branch` (required) - The name of the branch
It return 200 if succeed or 405 if failed with error message explaining reason.
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 1dbb93f9082..6b379b02d28 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -19,7 +19,6 @@ GET /groups
]
```
-
## Details of a group
Get all details of a group.
@@ -30,8 +29,7 @@ GET /groups/:id
Parameters:
-+ `id` (required) - The ID of a group
-
+- `id` (required) - The ID of a group
## New group
@@ -43,8 +41,8 @@ POST /groups
Parameters:
-+ `name` (required) - The name of the group
-+ `path` (required) - The path of the group
+- `name` (required) - The name of the group
+- `path` (required) - The path of the group
## Transfer project to group
@@ -55,9 +53,9 @@ POST /groups/:id/projects/:project_id
```
Parameters:
-+ `id` (required) - The ID of a group
-+ `project_id` (required) - The ID of a project
+- `id` (required) - The ID of a group
+- `project_id` (required) - The ID of a project
## Remove group
@@ -69,22 +67,20 @@ DELETE /groups/:id
Parameters:
-+ `id` (required) - The ID of a user group
-
+- `id` (required) - The ID of a user group
## Group members
-
**Group access levels**
The group access levels are defined in the `Gitlab::Access` module. Currently, these levels are recognized:
```
- GUEST = 10
- REPORTER = 20
- DEVELOPER = 30
- MASTER = 40
- OWNER = 50
+GUEST = 10
+REPORTER = 20
+DEVELOPER = 30
+MASTER = 40
+OWNER = 50
```
### List group members
@@ -128,10 +124,9 @@ POST /groups/:id/members
Parameters:
-+ `id` (required) - The ID of a group
-+ `user_id` (required) - The ID of a user to add
-+ `access_level` (required) - Project access level
-
+- `id` (required) - The ID of a group
+- `user_id` (required) - The ID of a user to add
+- `access_level` (required) - Project access level
### Remove user team member
@@ -143,5 +138,5 @@ DELETE /groups/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID of a user group
-+ `user_id` (required) - The ID of a group member
+- `id` (required) - The ID of a user group
+- `user_id` (required) - The ID of a group member
diff --git a/doc/api/labels.md b/doc/api/labels.md
index 95fd4e84119..de41f35d284 100644
--- a/doc/api/labels.md
+++ b/doc/api/labels.md
@@ -45,7 +45,7 @@ Parameters:
It returns 200 and the newly created label, if the operation succeeds.
If the label already exists, 409 and an error message is returned.
-If label parameters are invalid, 405 and an explaining error message is returned.
+If label parameters are invalid, 400 and an explaining error message is returned.
## Delete a label
@@ -58,8 +58,8 @@ DELETE /projects/:id/labels
- `id` (required) - The ID of a project
- `name` (required) - The name of the label to be deleted
-It returns 200 if the label successfully was deleted, 404 for wrong parameters
-and 400 if the label does not exist.
+It returns 200 if the label successfully was deleted, 400 for wrong parameters
+and 404 if the label does not exist.
In case of an error, additionally an error message is returned.
## Edit an existing label
@@ -79,7 +79,6 @@ Parameters:
- `color` (optional) - New color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB)
On success, this method returns 200 with the updated label.
-If required parameters are missing, 400 is returned.
+If required parameters are missing or parameters are invalid, 400 is returned.
If the label to be updated is missing, 404 is returned.
-If parameters are invalid, 405 is returned. In case of an error,
-additionally an error message is returned.
+In case of an error, additionally an error message is returned.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 230f572fc3b..3616e29ef7c 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -196,13 +196,13 @@ If an error occurs, an error number and a message explaining the reason is retur
Merge changes submitted with MR using this API.
-If merge success you get 200 OK.
+If merge success you get `200 OK`.
If it has some conflicts and can not be merged - you get 405 and error message 'Branch cannot be merged'
If merge request is already merged or closed - you get 405 and error message 'Method Not Allowed'
-If you dont have permissions to accept this merge request - you get 401
+If you don't have permissions to accept this merge request - you'll get a 401
```
PUT /projects/:id/merge_request/:merge_request_id/merge
diff --git a/doc/api/notes.md b/doc/api/notes.md
index e7f19965a30..b5256ac803e 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -14,8 +14,8 @@ GET /projects/:id/issues/:issue_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `issue_id` (required) - The ID of an issue
+- `id` (required) - The ID of a project
+- `issue_id` (required) - The ID of an issue
```json
[
@@ -60,10 +60,9 @@ GET /projects/:id/issues/:issue_id/notes/:note_id
Parameters:
-+ `id` (required) - The ID of a project
-+ `issue_id` (required) - The ID of a project issue
-+ `note_id` (required) - The ID of an issue note
-
+- `id` (required) - The ID of a project
+- `issue_id` (required) - The ID of a project issue
+- `note_id` (required) - The ID of an issue note
### Create new issue note
@@ -75,10 +74,9 @@ POST /projects/:id/issues/:issue_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `issue_id` (required) - The ID of an issue
-+ `body` (required) - The content of a note
-
+- `id` (required) - The ID of a project
+- `issue_id` (required) - The ID of an issue
+- `body` (required) - The content of a note
## Snippets
@@ -92,9 +90,8 @@ GET /projects/:id/snippets/:snippet_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of a project snippet
-
+- `id` (required) - The ID of a project
+- `snippet_id` (required) - The ID of a project snippet
### Get single snippet note
@@ -106,9 +103,9 @@ GET /projects/:id/snippets/:snippet_id/notes/:note_id
Parameters:
-+ `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of a project snippet
-+ `note_id` (required) - The ID of an snippet note
+- `id` (required) - The ID of a project
+- `snippet_id` (required) - The ID of a project snippet
+- `note_id` (required) - The ID of an snippet note
```json
{
@@ -139,10 +136,9 @@ POST /projects/:id/snippets/:snippet_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of an snippet
-+ `body` (required) - The content of a note
-
+- `id` (required) - The ID of a project
+- `snippet_id` (required) - The ID of an snippet
+- `body` (required) - The content of a note
## Merge Requests
@@ -156,9 +152,8 @@ GET /projects/:id/merge_requests/:merge_request_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `merge_request_id` (required) - The ID of a project merge request
-
+- `id` (required) - The ID of a project
+- `merge_request_id` (required) - The ID of a project merge request
### Get single merge request note
@@ -170,9 +165,9 @@ GET /projects/:id/merge_requests/:merge_request_id/notes/:note_id
Parameters:
-+ `id` (required) - The ID of a project
-+ `merge_request_id` (required) - The ID of a project merge request
-+ `note_id` (required) - The ID of a merge request note
+- `id` (required) - The ID of a project
+- `merge_request_id` (required) - The ID of a project merge request
+- `note_id` (required) - The ID of a merge request note
```json
{
@@ -201,7 +196,6 @@ POST /projects/:id/merge_requests/:merge_request_id/notes
Parameters:
-+ `id` (required) - The ID of a project
-+ `merge_request_id` (required) - The ID of a merge request
-+ `body` (required) - The content of a note
-
+- `id` (required) - The ID of a project
+- `merge_request_id` (required) - The ID of a merge request
+- `body` (required) - The content of a note
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index 47c81b6446c..50e134847c0 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -78,7 +78,7 @@ Parameters:
## Delete snippet
Deletes an existing project snippet. This is an idempotent function and deleting a non-existent
-snippet still returns a `200 Ok` status code.
+snippet still returns a `200 OK` status code.
```
DELETE /projects/:id/snippets/:snippet_id
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 894c2fd76a4..8995551b9ea 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,6 +1,6 @@
# Projects
-### List projects
+## List projects
Get a list of projects accessible by the authenticated user.
@@ -10,7 +10,7 @@ GET /projects
Parameters:
-+ `archived` (optional) - if passed, limit by archived status
+- `archived` (optional) - if passed, limit by archived status
```json
[
@@ -87,8 +87,7 @@ Parameters:
]
```
-
-#### List owned projects
+### List owned projects
Get a list of projects which are owned by the authenticated user.
@@ -96,7 +95,7 @@ Get a list of projects which are owned by the authenticated user.
GET /projects/owned
```
-#### List ALL projects
+### List ALL projects
Get a list of all GitLab projects (admin only).
@@ -115,7 +114,7 @@ GET /projects/:id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
{
@@ -176,7 +175,7 @@ GET /projects/:id/events
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
[
@@ -238,7 +237,6 @@ Parameters:
]
```
-
### Create project
Creates a new project owned by the authenticated user.
@@ -249,17 +247,16 @@ POST /projects
Parameters:
-+ `name` (required) - new project name
-+ `namespace_id` (optional) - namespace for the new project (defaults to user)
-+ `description` (optional) - short project description
-+ `issues_enabled` (optional)
-+ `merge_requests_enabled` (optional)
-+ `wiki_enabled` (optional)
-+ `snippets_enabled` (optional)
-+ `public` (optional) - if `true` same as setting visibility_level = 20
-+ `visibility_level` (optional)
-* `import_url` (optional)
-
+- `name` (required) - new project name
+- `namespace_id` (optional) - namespace for the new project (defaults to user)
+- `description` (optional) - short project description
+- `issues_enabled` (optional)
+- `merge_requests_enabled` (optional)
+- `wiki_enabled` (optional)
+- `snippets_enabled` (optional)
+- `public` (optional) - if `true` same as setting visibility_level = 20
+- `visibility_level` (optional)
+- `import_url` (optional)
### Create project for user
@@ -271,20 +268,19 @@ POST /projects/user/:user_id
Parameters:
-+ `user_id` (required) - user_id of owner
-+ `name` (required) - new project name
-+ `description` (optional) - short project description
-+ `default_branch` (optional) - 'master' by default
-+ `issues_enabled` (optional)
-+ `merge_requests_enabled` (optional)
-+ `wiki_enabled` (optional)
-+ `snippets_enabled` (optional)
-+ `public` (optional) - if `true` same as setting visibility_level = 20
-+ `visibility_level` (optional)
-* `import_url` (optional)
+- `user_id` (required) - user_id of owner
+- `name` (required) - new project name
+- `description` (optional) - short project description
+- `default_branch` (optional) - 'master' by default
+- `issues_enabled` (optional)
+- `merge_requests_enabled` (optional)
+- `wiki_enabled` (optional)
+- `snippets_enabled` (optional)
+- `public` (optional) - if `true` same as setting visibility_level = 20
+- `visibility_level` (optional)
+- `import_url` (optional)
-
-## Remove project
+### Remove project
Removes a project including all associated resources (issues, merge requests etc.)
@@ -294,8 +290,7 @@ DELETE /projects/:id
Parameters:
-+ `id` (required) - The ID of a project
-
+- `id` (required) - The ID of a project
## Team members
@@ -309,9 +304,8 @@ GET /projects/:id/members
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `query` (optional) - Query string to search for members
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `query` (optional) - Query string to search for members
### Get project team member
@@ -323,8 +317,8 @@ GET /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `user_id` (required) - The ID of a user
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `user_id` (required) - The ID of a user
```json
{
@@ -338,7 +332,6 @@ Parameters:
}
```
-
### Add project team member
Adds a user to a project team. This is an idempotent method and can be called multiple times
@@ -351,10 +344,9 @@ POST /projects/:id/members
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `user_id` (required) - The ID of a user to add
-+ `access_level` (required) - Project access level
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `user_id` (required) - The ID of a user to add
+- `access_level` (required) - Project access level
### Edit project team member
@@ -366,10 +358,9 @@ PUT /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `user_id` (required) - The ID of a team member
-+ `access_level` (required) - Project access level
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `user_id` (required) - The ID of a team member
+- `access_level` (required) - Project access level
### Remove project team member
@@ -381,15 +372,14 @@ DELETE /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `user_id` (required) - The ID of a team member
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `user_id` (required) - The ID of a team member
This method is idempotent and can be called multiple times with the same parameters.
Revoking team membership for a user who is not currently a team member is considered success.
Please note that the returned JSON currently differs slightly. Thus you should not
rely on the returned JSON structure.
-
## Hooks
### List project hooks
@@ -402,8 +392,7 @@ GET /projects/:id/hooks
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
### Get project hook
@@ -415,8 +404,8 @@ GET /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `hook_id` (required) - The ID of a project hook
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `hook_id` (required) - The ID of a project hook
```json
{
@@ -430,7 +419,6 @@ Parameters:
}
```
-
### Add project hook
Adds a hook to a specified project.
@@ -441,12 +429,11 @@ POST /projects/:id/hooks
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `url` (required) - The hook URL
-+ `push_events` - Trigger hook on push events
-+ `issues_events` - Trigger hook on issues events
-+ `merge_requests_events` - Trigger hook on merge_requests events
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `url` (required) - The hook URL
+- `push_events` - Trigger hook on push events
+- `issues_events` - Trigger hook on issues events
+- `merge_requests_events` - Trigger hook on merge_requests events
### Edit project hook
@@ -458,13 +445,12 @@ PUT /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `hook_id` (required) - The ID of a project hook
-+ `url` (required) - The hook URL
-+ `push_events` - Trigger hook on push events
-+ `issues_events` - Trigger hook on issues events
-+ `merge_requests_events` - Trigger hook on merge_requests events
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `hook_id` (required) - The ID of a project hook
+- `url` (required) - The hook URL
+- `push_events` - Trigger hook on push events
+- `issues_events` - Trigger hook on issues events
+- `merge_requests_events` - Trigger hook on merge_requests events
### Delete project hook
@@ -477,13 +463,12 @@ DELETE /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `hook_id` (required) - The ID of hook to delete
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `hook_id` (required) - The ID of hook to delete
Note the JSON response differs if the hook is available or not. If the project hook
is available before it is returned in the JSON response or an empty response is returned.
-
## Branches
### List branches
@@ -496,7 +481,7 @@ GET /projects/:id/repository/branches
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
[
@@ -561,9 +546,8 @@ GET /projects/:id/repository/branches/:branch
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `branch` (required) - The name of the branch.
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `branch` (required) - The name of the branch.
### Protect single branch
@@ -575,9 +559,8 @@ PUT /projects/:id/repository/branches/:branch/protect
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `branch` (required) - The name of the branch.
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `branch` (required) - The name of the branch.
### Unprotect single branch
@@ -589,9 +572,8 @@ PUT /projects/:id/repository/branches/:branch/unprotect
Parameters:
-+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
-+ `branch` (required) - The name of the branch.
-
+- `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+- `branch` (required) - The name of the branch.
## Admin fork relation
@@ -605,8 +587,8 @@ POST /projects/:id/fork/:forked_from_id
Parameters:
-+ `id` (required) - The ID of the project
-+ `forked_from_id:` (required) - The ID of the project that was forked from
+- `id` (required) - The ID of the project
+- `forked_from_id:` (required) - The ID of the project that was forked from
### Delete an existing forked from relationship
@@ -616,8 +598,7 @@ DELETE /projects/:id/fork
Parameter:
-+ `id` (required) - The ID of the project
-
+- `id` (required) - The ID of the project
## Search for projects by name
@@ -629,6 +610,6 @@ GET /projects/search/:query
Parameters:
-+ query (required) - A string contained in the project name
-+ per_page (optional) - number of projects to return per page
-+ page (optional) - the page to retrieve
+- query (required) - A string contained in the project name
+- per_page (optional) - number of projects to return per page
+- page (optional) - the page to retrieve
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 7d6164a0819..1074b78fd73 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -10,7 +10,7 @@ GET /projects/:id/repository/tags
Parameters:
-+ `id` (required) - The ID of a project
+- `id` (required) - The ID of a project
```json
[
@@ -47,9 +47,9 @@ POST /projects/:id/repository/tags
Parameters:
-+ `id` (required) - The ID of a project
-+ `tag_name` (required) - The name of a tag
-+ `ref` (required) - Create tag using commit SHA, another tag name, or branch name.
+- `id` (required) - The ID of a project
+- `tag_name` (required) - The name of a tag
+- `ref` (required) - Create tag using commit SHA, another tag name, or branch name.
```json
[
@@ -81,9 +81,9 @@ GET /projects/:id/repository/tree
Parameters:
-+ `id` (required) - The ID of a project
-+ `path` (optional) - The path inside repository. Used to get contend of subdirectories
-+ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
+- `id` (required) - The ID of a project
+- `path` (optional) - The path inside repository. Used to get contend of subdirectories
+- `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
```json
[
@@ -126,7 +126,6 @@ Parameters:
]
```
-
## Raw file content
Get the raw file contents for a file by commit SHA and path.
@@ -137,10 +136,9 @@ GET /projects/:id/repository/blobs/:sha
Parameters:
-+ `id` (required) - The ID of a project
-+ `sha` (required) - The commit or branch name
-+ `filepath` (required) - The path the file
-
+- `id` (required) - The ID of a project
+- `sha` (required) - The commit or branch name
+- `filepath` (required) - The path the file
## Raw blob content
@@ -152,22 +150,21 @@ GET /projects/:id/repository/raw_blobs/:sha
Parameters:
-+ `id` (required) - The ID of a project
-+ `sha` (required) - The blob SHA
-
+- `id` (required) - The ID of a project
+- `sha` (required) - The blob SHA
## Get file archive
-Get a an archive of the repository
+Get an archive of the repository
```
GET /projects/:id/repository/archive
```
Parameters:
-+ `id` (required) - The ID of a project
-+ `sha` (optional) - The commit SHA to download defaults to the tip of the default branch
+- `id` (required) - The ID of a project
+- `sha` (optional) - The commit SHA to download defaults to the tip of the default branch
## Compare branches, tags or commits
@@ -176,10 +173,10 @@ GET /projects/:id/repository/compare
```
Parameters:
-+ `id` (required) - The ID of a project
-+ `from` (required) - the commit SHA or branch name
-+ `to` (required) - the commit SHA or branch name
+- `id` (required) - The ID of a project
+- `from` (required) - the commit SHA or branch name
+- `to` (required) - the commit SHA or branch name
```
GET /projects/:id/repository/compare?from=master&to=feature
@@ -230,7 +227,8 @@ GET /projects/:id/repository/contributors
```
Parameters:
-+ `id` (required) - The ID of a project
+
+- `id` (required) - The ID of a project
Response:
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index b53d60bceec..25311b07107 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -1,10 +1,8 @@
# Repository files
-## CRUD for repository files
+**CRUD for repository files**
-## Create, read, update and delete repository files using this API
-
----
+**Create, read, update and delete repository files using this API**
## Get file from repository
diff --git a/doc/api/session.md b/doc/api/session.md
index 2e717a2ea77..47c1c8a7a49 100644
--- a/doc/api/session.md
+++ b/doc/api/session.md
@@ -8,12 +8,12 @@ POST /session
Parameters:
-+ `login` (required) - The login of user
-+ `email` (required if login missing) - The email of user
-+ `password` (required) - Valid password
+- `login` (required) - The login of user
+- `email` (required if login missing) - The email of user
+- `password` (required) - Valid password
+**You can login with both GitLab and LDAP credentials now**
-__You can login with both GitLab and LDAP credentials now__
```json
{
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 6483a73c7ec..f9637d8a6c4 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -59,7 +59,7 @@ Parameters:
## Delete system hook
-Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook is not available. If the hook is deleted it is also returned as JSON.
+Deletes a system hook. This is an idempotent API function and returns `200 OK` even if the hook is not available. If the hook is deleted it is also returned as JSON.
```
DELETE /hooks/:id
diff --git a/doc/api/users.md b/doc/api/users.md
index 57078353fd0..3fdd3a75e88 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -202,7 +202,7 @@ e.g. when renaming the email address to some existing one.
Deletes a user. Available only for administrators.
This is an idempotent function, calling this function for a non-existent user id
-still returns a status code `200 Ok`.
+still returns a status code `200 OK`.
The JSON response differs if the user was actually deleted or not.
In the former the user is returned and in the latter not.
@@ -336,7 +336,7 @@ Will return created key with status `201 Created` on success, or `404 Not found`
Deletes key owned by currently authenticated user.
This is an idempotent function and calling it on a key that is already deleted
-or not available results in `200 Ok`.
+or not available results in `200 OK`.
```
DELETE /user/keys/:id
@@ -359,4 +359,4 @@ Parameters:
- `uid` (required) - id of specified user
- `id` (required) - SSH key ID
-Will return `200 Ok` on success, or `404 Not found` if either user or key cannot be found.
+Will return `200 OK` on success, or `404 Not found` if either user or key cannot be found.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 44742984ca9..423a5f0cb19 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -4,11 +4,11 @@
Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install. In most cases this should be the highest numbered stable branch (example shown below).
-![capture](http://i.imgur.com/d2AlIVj.png)
+![Select latest branch](https://i.imgur.com/Lrdxk1k.png)
If the highest number stable branch is unclear please check the [GitLab Blog](https://www.gitlab.com/blog/) for installation guide links by version.
-## Important notes
+## Important Notes
This guide is long because it covers many cases and includes all commands you need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
@@ -49,7 +49,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake
Make sure you have the right version of Git installed
@@ -116,7 +116,7 @@ Create a `git` user for GitLab:
We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](database_mysql.md). *Note*: because we need to make use of extensions you need at least pgsql 9.1.
# Install the database packages
- sudo apt-get install -y postgresql-9.1 postgresql-client libpq-dev
+ sudo apt-get install -y postgresql postgresql-client libpq-dev
# Login to PostgreSQL
sudo -u postgres psql -d template1
@@ -141,15 +141,13 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-1-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-2-stable gitlab
- # Go to gitlab dir
- cd /home/git/gitlab
-
-**Note:** You can change `7-1-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `7-2-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
-### Configure it
+### Configure It
+ # Go to GitLab installation folder
cd /home/git/gitlab
# Copy the example GitLab config
@@ -198,7 +196,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
**Important Note:** Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
-### Configure GitLab DB settings
+### Configure GitLab DB Settings
# PostgreSQL only:
sudo -u git cp config/database.yml.postgresql config/database.yml
@@ -222,23 +220,18 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
**Note:** As of bundler 1.5.2, you can invoke `bundle install -jN` (where `N` the number of your processor cores) and enjoy the parallel gems installation with measurable difference in completion time (~60% faster). Check the number of your cores with `nproc`. For more information check this [post](http://robots.thoughtbot.com/parallel-gem-installing-using-bundler). First make sure you have bundler >= 1.5.2 (run `bundle -v`) as it addresses some [issues](https://devcenter.heroku.com/changelog-items/411) that were [fixed](https://github.com/bundler/bundler/pull/2817) in 1.5.2.
- cd /home/git/gitlab
-
# For PostgreSQL (note, the option says "without ... mysql")
sudo -u git -H bundle install --deployment --without development test mysql aws
# Or if you use MySQL (note, the option says "without ... postgres")
sudo -u git -H bundle install --deployment --without development test postgres aws
-### Install GitLab shell
+### Install GitLab Shell
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
- # Go to the GitLab installation folder:
- cd /home/git/gitlab
-
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
- sudo -u git -H bundle exec rake gitlab:shell:install[v1.9.6] REDIS_URL=redis://localhost:6379 RAILS_ENV=production
+ sudo -u git -H bundle exec rake gitlab:shell:install[v1.9.7] REDIS_URL=redis://localhost:6379 RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main gitlab config.
#
@@ -261,7 +254,7 @@ GitLab Shell is an SSH access and repository management software developed speci
### Install Init Script
-Download the init script (will be /etc/init.d/gitlab):
+Download the init script (will be `/etc/init.d/gitlab`):
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
@@ -269,13 +262,13 @@ And if you are installing with a non-default folder or user copy and edit the de
sudo cp lib/support/init.d/gitlab.default.example /etc/default/gitlab
-If you installed GitLab in another directory or as a user other than the default you should change these settings in `/etc/default/gitlab`. Do not edit `/etc/init.d/gitlab as it will be changed on upgrade.
+If you installed GitLab in another directory or as a user other than the default you should change these settings in `/etc/default/gitlab`. Do not edit `/etc/init.d/gitlab` as it will be changed on upgrade.
Make GitLab start on boot:
sudo update-rc.d gitlab defaults 21
-### Set up logrotate
+### Setup Logrotate
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
@@ -285,7 +278,7 @@ Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
-### Compile assets
+### Compile Assets
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
@@ -300,6 +293,7 @@ Check if GitLab and its environment are configured correctly:
**Note:** Nginx is the officially supported web server for GitLab. If you cannot or do not want to use Nginx as your web server, have a look at the [GitLab recipes](https://gitlab.com/gitlab-org/gitlab-recipes/).
### Installation
+
sudo apt-get install -y nginx
### Site Configuration
@@ -315,7 +309,15 @@ Make sure to edit the config file to match your setup:
# domain name of your host serving GitLab.
sudo editor /etc/nginx/sites-available/gitlab
-**Note:** If you want to use https, replace the `gitlab` nginx config with `gitlab-ssl`. See [Using HTTPS](#using-https) for all necessary details.
+**Note:** If you want to use HTTPS, replace the `gitlab` Nginx config with `gitlab-ssl`. See [Using HTTPS](#using-https) for all necessary details.
+
+### Test Configuration
+
+Validate your `gitlab` or `gitlab-ssl` Nginx config file with the following command:
+
+ sudo nginx -t
+
+You should receive `syntax is okay` and `test is successful` messages. If you receive errors check your `gitlab` or `gitlab-ssl` Nginx config file for typos, etc. as indiciated in the error message given.
### Restart
@@ -354,7 +356,7 @@ To recapitulate what is needed to use GitLab with HTTPS:
1. In the `config.yml` of gitlab-shell set the relevant options (see the [install GitLab Shell section](#install-gitlab-shell) of this document).
1. Use the `gitlab-ssl` nginx example config instead of the `gitlab` config.
-### Additional markup styles
+### Additional Markup Styles
Apart from the always supported markdown style there are other rich text files that GitLab can display. But you might have to install a dependency to do so. Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
@@ -382,7 +384,7 @@ If you are running SSH on a non-standard port, you must change the GitLab user's
You also need to change the corresponding options (e.g. `ssh_user`, `ssh_host`, `admin_uri`) in the `config\gitlab.yml` file.
-### LDAP authentication
+### LDAP Authentication
You can configure LDAP authentication in `config/gitlab.yml`. Please restart GitLab after editing this file.
@@ -414,7 +416,7 @@ These steps are fairly general and you will need to figure out the exact details
- Start GitLab:
- `sudo service gitlab start`
+ sudo service gitlab start
#### Examples
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 938e48ddd74..53f6ccc8c34 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -55,13 +55,13 @@ You will either need to configure 512MB or 1.5GB of swap space.
With 512MB of swap space you must configure only one unicorn worker.
With one unicorn worker only git over ssh access will work because the git over http access requires two running workers (one worker to receive the user request and one worker for the authorization check).
If you use SSD storage and configure 1.5GB of swap space you can use two Unicorn workers, this will allow http access but it will still be slow.
-- 1GB supports up to 100 users (we highly recommend adding al least 1GB of swap space, this is a must if you have individual repositories under 250MB)
-- **2GB** is the **recommended** memory size and supports up to 500 users
-- 4GB supports up to 2,000 users
-- 8GB supports up to 5,000 users
-- 16GB supports up to 10,000 users
-- 32GB supports up to 20,000 users
-- 64GB supports up to 40,000 users
+- 1GB RAM + 1GB swap supports up to 100 users
+- **2GB RAM** is the **recommended** memory size and supports up to 500 users
+- 4GB RAM supports up to 2,000 users
+- 8GB RAM supports up to 5,000 users
+- 16GB RAM supports up to 10,000 users
+- 32GB RAM supports up to 20,000 users
+- 64GB RAM supports up to 40,000 users
Notice: The 25 workers of Sidekiq will show up as separate processes in your process overview (such as top or htop) but they share the same RAM allocation since Sidekiq is a multithreaded application.
diff --git a/doc/integration/google.md b/doc/integration/google.md
index 3cf546bd77e..7a78aff8ea4 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -2,17 +2,21 @@
To enable the Google OAuth2 OmniAuth provider you must register your application with Google. Google will generate a client ID and secret key for you to use.
-1. Sign in to the [Google Developers Console](https://console.developers.google.com/) with the Google account you want to use to register GitLab.
+1. Sign in to the [Google Developers Console](https://console.developers.google.com/) with the Google account you want to use to register GitLab.
1. Select "Create Project".
1. Provide the project information
- - Project name: 'GitLab' works just fine here.
+ - Project name: 'GitLab' works just fine here.
- Project ID: Must be unique to all Google Developer registered applications. Google provides a randomly generated Project ID by default. You can use the randomly generated ID or choose a new one.
1. Refresh the page. You should now see your new project in the list. Click on the project.
1. Select "APIs & auth" in the left menu.
+1. Select "APIs" in the submenu.
+ - Enable `Contacts API`
+ - Enable `Google+ API`
+
1. Select "Credentials" in the submenu.
1. Select "Create New Client ID".
@@ -41,7 +45,7 @@ To enable the Google OAuth2 OmniAuth provider you must register your application
args: { access_type: 'offline', approval_prompt: '' } }
```
-1. Change 'YOUR APP ID' to the client ID from the GitHub application page from step 7.
+1. Change 'YOUR APP ID' to the client ID from the GitHub application page from step 7.
1. Change 'YOUR APP SECRET' to the client secret from the GitHub application page from step 7.
@@ -51,12 +55,12 @@ To enable the Google OAuth2 OmniAuth provider you must register your application
On the sign in page there should now be a Google icon below the regular sign in form. Click the icon to begin the authentication process. Google will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
-## Further Configuration
+## Further Configuration
This further configuration is not required for Google authentication to function but it is strongly recommended. Taking these steps will increase usability for users by providing a little more recognition and branding.
At this point, when users first try to authenticate to your GitLab installation with Google they will see a generic application name on the prompt screen. The prompt informs the user that "Project Default Service Account" would like to access their account. "Project Default Service Account" isn't very recognizable and may confuse or cause users to be concerned. This is easily changeable.
1. Select 'Consent screen' in the left menu. (See steps 1, 4 and 5 above for instructions on how to get here if you closed your window).
-1. Scroll down until you find "Product Name". Change the product name to something more descriptive.
+1. Scroll down until you find "Product Name". Change the product name to something more descriptive.
1. Add any additional information as you wish - homepage, logo, privacy policy, etc. None of this is required, but it may help your users.
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index ac32c01289d..e1a58835d88 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -5,41 +5,41 @@
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook"
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:add URL="http://example.com/hook"
+ bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" RAILS_ENV=production
## Add a web hook for projects in a given **NAMESPACE**:
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
+ bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
## Remove a web hook from **ALL** projects using:
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook"
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook"
+ bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" RAILS_ENV=production
## Remove a web hook from projects in a given **NAMESPACE**:
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
+ bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
## List **ALL** web hooks:
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:list
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:list
+ bundle exec rake gitlab:web_hook:list RAILS_ENV=production
## List the web hooks from projects in a given **NAMESPACE**:
# omnibus-gitlab
sudo gitlab-rake gitlab:web_hook:list NAMESPACE=/
# source installations or cookbook
- RAILS_ENV=production bundle exec rake gitlab:web_hook:list NAMESPACE=/
+ bundle exec rake gitlab:web_hook:list NAMESPACE=/ RAILS_ENV=production
> Note: `/` is the global namespace.
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 09bdde81dcc..2e19fc50890 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -153,6 +153,7 @@ git tag -a vx.x.0.rc1 -m 'Version x.x.0.rc1'
Merge the RC1 EE code into GitLab.com.
Once the build is green, create a package.
+If there are big database migrations consider testing them with the production db on a VM.
Try to deploy in the morning.
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
@@ -210,9 +211,16 @@ For GitLab EE, append `-ee` to the branches and tags.
`v.x.x.0-ee`
-Merge CE into EE if needed.
+Note: Merge CE into EE if needed.
-### **1. Create x-x-stable branch and push to the repositories**
+### **1. Set VERSION to x.x.x and push**
+
+- Change the GITLAB_SHELL_VERSION file in `master` of the CE repository if the version changed.
+- Change the GITLAB_SHELL_VERSION file in `master` of the EE repository if the version changed.
+- Change the VERSION file in `master` branch of the CE repository and commit and push.
+- Change the VERSION file in `master` branch of the EE repository and commit and push.
+
+### **2. Create x-x-stable branch and push to the repositories**
```
git checkout master
@@ -221,22 +229,7 @@ git checkout -b x-x-stable
git push <remote> x-x-stable
```
-### **2. Build the Omnibus packages**
-
-Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
-This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
-
-### **3. Set VERSION to x.x.x and push**
-
-Change the GITLAB_SHELL_VERSION file in `master` of the CE repository if the version changed.
-
-Change the GITLAB_SHELL_VERSION file in `master` of the EE repository if the version changed.
-
-Change the VERSION file in `master` branch of the CE repository and commit. Cherry-pick into the `x-x-stable` branch of CE.
-
-Change the VERSION file in `master` branch of the EE repository and commit. Cherry-pick into the `x-x-stable-ee` branch of EE.
-
-### **4. Create annotated tag vx.x.x**
+### **3. Create annotated tag vx.x.x**
In `x-x-stable` branch check for the SHA-1 of the commit with VERSION file changed. Tag that commit,
@@ -246,12 +239,17 @@ git tag -a vx.x.0 -m 'Version x.x.0' xxxxx
where `xxxxx` is SHA-1.
-### **5. Push the tag**
+### **4. Push the tag**
```
git push origin vx.x.0
```
+### **5. Build the Omnibus packages**
+
+Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
+This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
+
### **6. Push to remotes**
For GitLab CE, push to dev, GitLab.com and GitHub.
@@ -260,8 +258,6 @@ For GitLab EE, push to the subscribers repo.
Make sure the branch is marked 'protected' on each of the remotes you pushed to.
-NOTE: You might not have the rights to push to master on dev. Ask Dmitriy.
-
### **7. Publish blog for new release**
Merge the [blog merge request](#1-prepare-the-blog-post) in `www-gitlab-com` repository.
@@ -282,6 +278,10 @@ Include a link to the blog post and keep it short.
Proposed email text:
"We have released a new version of GitLab. See our blog post(<link>) for more information."
+### **10. Update installation.md**
+
+Update [installation.md](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) to the newest version in master and cherry-pick that commit into the stable branch.
+
# **23rd - Optional Patch Release**
# **24th - Update GitLab.com**
diff --git a/doc/update/5.1-to-5.2.md b/doc/update/5.1-to-5.2.md
index c37f20ce55e..6ef559ac9f9 100644
--- a/doc/update/5.1-to-5.2.md
+++ b/doc/update/5.1-to-5.2.md
@@ -93,7 +93,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.0 to 5.1`](5.0-to-5.1.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.0 to 5.1](5.0-to-5.1.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup
diff --git a/doc/update/5.1-to-5.4.md b/doc/update/5.1-to-5.4.md
index 53dbfd00ad4..8ec56b266ca 100644
--- a/doc/update/5.1-to-5.4.md
+++ b/doc/update/5.1-to-5.4.md
@@ -89,7 +89,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.2 to 5.3`](5.2-to-5.3.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.2 to 5.3](5.2-to-5.3.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/5.1-to-6.0.md b/doc/update/5.1-to-6.0.md
index 123b3326ead..8870f5bc859 100644
--- a/doc/update/5.1-to-6.0.md
+++ b/doc/update/5.1-to-6.0.md
@@ -89,6 +89,9 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
# Clear and precompile assets
sudo -u git -H bundle exec rake assets:clean RAILS_ENV=production
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+
+#Add dealing with newlines for editor
+sudo -u git -H git config --global core.autocrlf input
```
## 6. Update config files
@@ -136,7 +139,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.0 to 5.1`](5.0-to-5.1.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.0 to 5.1](5.0-to-5.1.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/5.2-to-5.3.md b/doc/update/5.2-to-5.3.md
index 9851f7b2730..61ddf135641 100644
--- a/doc/update/5.2-to-5.3.md
+++ b/doc/update/5.2-to-5.3.md
@@ -75,7 +75,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.1 to 5.2`](5.1-to-5.2.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.1 to 5.2](5.1-to-5.2.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/5.3-to-5.4.md b/doc/update/5.3-to-5.4.md
index b130f4c65bb..8a0d43e3e64 100644
--- a/doc/update/5.3-to-5.4.md
+++ b/doc/update/5.3-to-5.4.md
@@ -79,7 +79,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.2 to 5.3`](5.2-to-5.3.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.2 to 5.3](5.2-to-5.3.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/6.0-to-6.1.md b/doc/update/6.0-to-6.1.md
index 36c7f04f635..b8df16bfd97 100644
--- a/doc/update/6.0-to-6.1.md
+++ b/doc/update/6.0-to-6.1.md
@@ -98,7 +98,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.4 to 6.0`](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.4 to 6.0](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/6.0-to-7.1.md b/doc/update/6.0-to-7.2.md
index e328114a673..51e260b9e62 100644
--- a/doc/update/6.0-to-7.1.md
+++ b/doc/update/6.0-to-7.2.md
@@ -1,13 +1,16 @@
-# From 6.0 to 7.1
-
-## Deprecations
-
-The 'Wall' feature has been removed in GitLab 7.1. Existing wall comments will remain stored in the database after the upgrade.
+# From 6.0 to 7.2
## Global issue numbers
As of 6.1 issue numbers are project specific. This means all issues are renumbered and get a new number in their URL. If you use an old issue number URL and the issue number does not exist yet you are redirected to the new one. This conversion does not trigger if the old number already exists for this project, this is unlikely but will happen with old issues and large projects.
+## Editable labels
+
+In GitLab 7.2 we replace Issue and Merge Request tags with labels, making it
+possible to edit the label text and color. The characters '?', '&' and ',' are
+no longer allowed however so those will be removed from your tags during the
+database migrations for GitLab 7.2.
+
## 0. Backup
It's useful to make a backup just in case things go south:
@@ -22,7 +25,39 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
sudo service gitlab stop
-## 2. Get latest code
+## 2. Update Ruby
+
+If you are still using Ruby 1.9.3 or below, you will need to update Ruby.
+You can check which version you are running with `ruby -v`.
+
+If you are you running Ruby 2.0.x, you do not need to upgrade ruby, but can consider doing so for performance reasons.
+
+If you are running Ruby 2.1.1 consider upgrading to 2.1.2, because of the high memory usage of Ruby 2.1.1.
+
+Install, update dependencies:
+
+```bash
+sudo apt-get install build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl
+```
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.gz | tar xz
+cd ruby-2.1.2
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+## 3. Get latest code
```bash
cd /home/git/gitlab
@@ -32,7 +67,7 @@ sudo -u git -H git fetch --all
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout 7-1-stable
+sudo -u git -H git checkout 7-2-stable
```
OR
@@ -40,26 +75,29 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout 7-1-stable-ee
+sudo -u git -H git checkout 7-2-stable-ee
```
-## 3. Install additional packages
+## 4. Install additional packages
```bash
# Add support for lograte for better log file handling
sudo apt-get install logrotate
+
+# Install pkg-config and cmake, which is needed for the latest versions of rugged
+sudo apt-get install pkg-config cmake
```
-## 4. Update gitlab-shell
+## 5. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.9.6 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.9.7
```
-## 5. Install libs, migrations, etc.
+## 6. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
@@ -84,17 +122,18 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS
sudo chmod u+rwx,g+rx,o-rwx /home/git/gitlab-satellites
```
-## 6. Update config files
+## 7. Update config files
-TIP: to see what changed in gitlab.yml.example in this release use next command:
+TIP: to see what changed in gitlab.yml.example in this release use next command:
```
-git diff 6-0-stable:config/gitlab.yml.example 7-1-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 7-2-stable:config/gitlab.yml.example
```
-* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-1-stable/config/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-1-stable/config/unicorn.rb.example but with your settings.
-* Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-1-stable/lib/support/nginx/gitlab but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/config/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v1.9.7/config.yml.example but with your settings.
+* Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-2-stable/lib/support/nginx/gitlab but with your settings.
* Copy rack attack middleware config
```bash
@@ -107,18 +146,18 @@ sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
```
-## 7. Update Init script
+## 8. Update Init script
```bash
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
```
-## 8. Start application
+## 9. Start application
sudo service gitlab start
sudo service nginx restart
-## 9. Check application status
+## 10. Check application status
Check if GitLab and its environment are configured correctly:
@@ -131,11 +170,17 @@ To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations upgrade complete!
+## 11. Update OmniAuth configuration
+
+When using Google omniauth login, changes of the Google account required.
+Ensure that `Contacts API` and the `Google+ API` are enabled in the [Google Developers Console](https://console.developers.google.com/).
+More details can be found at the [integration documentation](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/google.md).
+
## Things went south? Revert to previous version (6.0)
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 5.4 to 6.0`](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 5.4 to 6.0](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
@@ -146,4 +191,4 @@ sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
## Login issues after upgrade?
-If running in HTTPS mode, be sure to read [Can't Verify CSRF token authenticity](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide#cant-verify-csrf-token-authenticitycant-get-past-login-pageredirected-to-login-page)
+If running in HTTPS mode, be sure to read [Can't Verify CSRF token authenticity](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide#cant-verify-csrf-token-authenticitycant-get-past-login-pageredirected-to-login-page)
diff --git a/doc/update/6.1-to-6.2.md b/doc/update/6.1-to-6.2.md
index 9ab53aae24b..f189899f57b 100644
--- a/doc/update/6.1-to-6.2.md
+++ b/doc/update/6.1-to-6.2.md
@@ -112,7 +112,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.0 to 6.1`](6.0-to-6.1.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.0 to 6.1](6.0-to-6.1.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/6.2-to-6.3.md b/doc/update/6.2-to-6.3.md
index 345480c4d32..aa6ef56990b 100644
--- a/doc/update/6.2-to-6.3.md
+++ b/doc/update/6.2-to-6.3.md
@@ -98,7 +98,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.1 to 6.2`](6.1-to-6.2.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.1 to 6.2](6.1-to-6.2.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md
index 18dce9b5f93..96c2895981d 100644
--- a/doc/update/6.3-to-6.4.md
+++ b/doc/update/6.3-to-6.4.md
@@ -79,7 +79,7 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.2 to 6.3`](6.2-to-6.3.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.2 to 6.3](6.2-to-6.3.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md
index 1a95a98b6f2..1624296fc3f 100644
--- a/doc/update/6.4-to-6.5.md
+++ b/doc/update/6.4-to-6.5.md
@@ -83,7 +83,7 @@ If all items are green, then congratulations upgrade is complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.3 to 6.4`](6.3-to-6.4.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.3 to 6.4](6.3-to-6.4.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup
diff --git a/doc/update/6.5-to-6.6.md b/doc/update/6.5-to-6.6.md
index ee6a5a9bdf2..544eee17fec 100644
--- a/doc/update/6.5-to-6.6.md
+++ b/doc/update/6.5-to-6.6.md
@@ -83,7 +83,7 @@ If all items are green, then congratulations upgrade is complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.4 to 6.5`](6.4-to-6.5.md), except for the database migration
+Follow the [upgrade guide from 6.4 to 6.5](6.4-to-6.5.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
diff --git a/doc/update/6.6-to-6.7.md b/doc/update/6.6-to-6.7.md
index c3a749b9a92..77ac4d0bfa6 100644
--- a/doc/update/6.6-to-6.7.md
+++ b/doc/update/6.6-to-6.7.md
@@ -93,7 +93,7 @@ If all items are green, then congratulations upgrade is complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.5 to 6.6`](6.5-to-6.6.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.5 to 6.6](6.5-to-6.6.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup
diff --git a/doc/update/6.7-to-6.8.md b/doc/update/6.7-to-6.8.md
index 3c98896a9b2..b5b47f8930e 100644
--- a/doc/update/6.7-to-6.8.md
+++ b/doc/update/6.7-to-6.8.md
@@ -111,7 +111,7 @@ If all items are green, then congratulations upgrade is complete!
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.6 to 6.7`](6.6-to-6.7.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.6 to 6.7](6.6-to-6.7.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup
diff --git a/doc/update/6.8-to-6.9.md b/doc/update/6.8-to-6.9.md
index b7305d082a5..9efb384ff59 100644
--- a/doc/update/6.8-to-6.9.md
+++ b/doc/update/6.8-to-6.9.md
@@ -90,7 +90,7 @@ If all items are green, then congratulations upgrade is complete!
## Things went south? Revert to previous version (6.8)
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.7 to 6.8`](6.7-to-6.8.md), except for the database migration
+Follow the [upgrade guide from 6.7 to 6.8](6.7-to-6.8.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
diff --git a/doc/update/6.9-to-7.0.md b/doc/update/6.9-to-7.0.md
index 99ec441e275..f1d3d9c7b2d 100644
--- a/doc/update/6.9-to-7.0.md
+++ b/doc/update/6.9-to-7.0.md
@@ -126,7 +126,7 @@ If all items are green, then congratulations upgrade is complete!
## Things went south? Revert to previous version (6.9)
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.8 to 6.9`](6.8-to-6.9.md), except for the database migration
+Follow the [upgrade guide from 6.8 to 6.9](6.8-to-6.9.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
diff --git a/doc/update/7.0-to-7.1.md b/doc/update/7.0-to-7.1.md
index 569f9160eb3..166ff0ea136 100644
--- a/doc/update/7.0-to-7.1.md
+++ b/doc/update/7.0-to-7.1.md
@@ -126,7 +126,7 @@ If all items are green, then congratulations upgrade is complete!
## Things went south? Revert to previous version (7.0)
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.9 to 7.0`](6.9-to-7.0.md), except for the database migration
+Follow the [upgrade guide from 6.9 to 7.0](6.9-to-7.0.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
diff --git a/doc/update/7.1-to-7.2.md b/doc/update/7.1-to-7.2.md
new file mode 100644
index 00000000000..04b9ce76a14
--- /dev/null
+++ b/doc/update/7.1-to-7.2.md
@@ -0,0 +1,134 @@
+# From 7.1 to 7.2
+
+## Editable labels
+
+In GitLab 7.2 we replace Issue and Merge Request tags with labels, making it
+possible to edit the label text and color. The characters '?', '&' and ',' are
+no longer allowed however so those will be removed from your tags during the
+database migrations for GitLab 7.2.
+
+### 0. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Get latest code
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H git fetch --all
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 7-2-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 7-2-stable-ee
+```
+
+### 3. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v1.9.7
+```
+
+### 4. Install new system dependencies
+
+The latest version of the 'rugged' gem requires `pkg-config` and `cmake` to
+build its native extensions.
+
+```bash
+sudo apt-get install pkg-config cmake
+```
+
+### 5. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+sudo chmod +x /etc/init.d/gitlab
+```
+
+### 6. Update config files
+
+#### New configuration options for gitlab.yml
+
+There are new configuration options available for gitlab.yml. View them with the command below and apply them to your current gitlab.yml.
+
+```
+git diff 7-1-stable:config/gitlab.yml.example 7-2-stable:config/gitlab.yml.example
+```
+
+Update rack attack middleware config
+
+```
+sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb
+```
+
+### 7. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 8. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
+
+### 9. Update OmniAuth configuration
+
+When using Google omniauth login, changes of the Google account required.
+Ensure that `Contacts API` and the `Google+ API` are enabled in the [Google Developers Console](https://console.developers.google.com/).
+More details can be found at the [integration documentation](../integration/google.md).
+
+## Things went south? Revert to previous version (7.1)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.0 to 7.1](7.0-to-7.1.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index 91689890640..ed72e156efe 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -15,7 +15,9 @@ git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
cd mysql-postgresql-converter
mysqldump --compatible=postgresql --default-character-set=utf8 -r databasename.mysql -u root gitlabhq_production
python db_converter.py databasename.mysql databasename.psql
-psql -f databasename.psql -d gitlabhq_production
+
+# Import the database dump as the application database user
+sudo -u git psql -f databasename.psql -d gitlabhq_production
# Rebuild indexes (see below)
@@ -68,6 +70,7 @@ test -e /opt/gitlab/embedded/service/gitlab-rails/db/schema.rb.bundled || sudo /
```
## Converting a GitLab backup file from MySQL to Postgres
+**Note:** Please make sure to have Python 2.7.x (or higher) installed.
GitLab backup files (<timestamp>_gitlab_backup.tar) contain a SQL dump. Using the lanyrd database converter we can replace a MySQL database dump inside the tar file with a Postgres database dump. This can be useful if you are moving to another server.
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 00dc87e2f99..e8379fcc318 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -21,6 +21,8 @@ If you have local changes to your GitLab repository the script will stash them a
## 2. Run GitLab upgrade tool
+Note: GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
+
# Starting with GitLab version 7.0 upgrader script has been moved to bin directory
cd /home/git/gitlab
if [ -f bin/upgrade.rb ]; then sudo -u git -H ruby bin/upgrade.rb; else sudo -u git -H ruby script/upgrade.rb; fi
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index ada21d23ac3..13c4de4301e 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -76,7 +76,9 @@ Triggered when a new issue is created or an existing issue was updated/closed/re
"description": "Create new API for manipulations with repository",
"milestone_id": null,
"state": "opened",
- "iid": 23
+ "iid": 23,
+ "url": "http://example.com/diaspora/issues/23",
+ "action": "open"
}
}
```
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 00d4bed1cc7..b18f62a1fa6 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -2,3 +2,4 @@
- [Project Features](project_features.md)
- [Authorization for merge requests](authorization_for_merge_requests.md)
- [Groups](groups.md)
+- [Labels](labels.md)
diff --git a/doc/workflow/labels.md b/doc/workflow/labels.md
new file mode 100644
index 00000000000..085b7baf5ce
--- /dev/null
+++ b/doc/workflow/labels.md
@@ -0,0 +1,16 @@
+# Labels
+
+In GitLab, you can easily tag issues and merge requests. If you have permission level `Developer` or higher, you can manage labels. To create, edit or delete a label, go to a project and then to `Issues` and then `Labels`.
+
+Here you can create a new label.
+
+![new label](labels/label1.png)
+
+You can choose to set a color.
+
+![label color](labels/label2.png)
+
+If you want to change an existing label, press edit next to the listed label.
+You will be presented with the same form as when creating a new label.
+
+![edit label](labels/label3.png)
diff --git a/doc/workflow/labels/label1.png b/doc/workflow/labels/label1.png
new file mode 100644
index 00000000000..cac661a34c8
--- /dev/null
+++ b/doc/workflow/labels/label1.png
Binary files differ
diff --git a/doc/workflow/labels/label2.png b/doc/workflow/labels/label2.png
new file mode 100644
index 00000000000..44d9fef86d4
--- /dev/null
+++ b/doc/workflow/labels/label2.png
Binary files differ
diff --git a/doc/workflow/labels/label3.png b/doc/workflow/labels/label3.png
new file mode 100644
index 00000000000..e2fce11b7a4
--- /dev/null
+++ b/doc/workflow/labels/label3.png
Binary files differ
diff --git a/features/dashboard/search.feature b/features/dashboard/search.feature
deleted file mode 100644
index 24c45028697..00000000000
--- a/features/dashboard/search.feature
+++ /dev/null
@@ -1,10 +0,0 @@
-@dashboard
-Feature: Dashboard Search
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And I visit dashboard search page
-
- Scenario: I should see project I am looking for
- Given I search for "Sho"
- Then I should see "Shop" project link
diff --git a/features/search.feature b/features/search.feature
new file mode 100644
index 00000000000..54708c17575
--- /dev/null
+++ b/features/search.feature
@@ -0,0 +1,46 @@
+@dashboard
+Feature: Search
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And I visit dashboard search page
+
+ Scenario: I should see project I am looking for
+ Given I search for "Sho"
+ Then I should see "Shop" project link
+
+ Scenario: I should see issues I am looking for
+ And project has issues
+ When I search for "Foo"
+ And I click "Issues" link
+ Then I should see "Foo" link
+ And I should not see "Bar" link
+
+ Scenario: I should see merge requests I am looking for
+ And project has merge requests
+ When I search for "Foo"
+ When I click "Merge requests" link
+ Then I should see "Foo" link
+ And I should not see "Bar" link
+
+ Scenario: I should see project code I am looking for
+ When I click project "Shop" link
+ And I search for "rspec"
+ Then I should see code results for project "Shop"
+
+ Scenario: I should see project issues
+ And project has issues
+ When I click project "Shop" link
+ And I search for "Foo"
+ And I click "Issues" link
+ Then I should see "Foo" link
+ And I should not see "Bar" link
+
+ Scenario: I should see project merge requests
+ And project has merge requests
+ When I click project "Shop" link
+ And I search for "Foo"
+ And I click "Merge requests" link
+ Then I should see "Foo" link
+ And I should not see "Bar" link
+
diff --git a/features/steps/dashboard/search.rb b/features/steps/dashboard/search.rb
deleted file mode 100644
index 32966a8617a..00000000000
--- a/features/steps/dashboard/search.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class DashboardSearch < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedProject
-
- Given 'I search for "Sho"' do
- fill_in "dashboard_search", with: "Sho"
- click_button "Search"
- end
-
- Then 'I should see "Shop" project link' do
- page.should have_link "Shop"
- end
-
- Given 'I search for "Contibuting"' do
- fill_in "dashboard_search", with: "Contibuting"
- click_button "Search"
- end
-end
diff --git a/features/steps/explore/projects.rb b/features/steps/explore/projects.rb
index dfd51060738..f31d32a4a2d 100644
--- a/features/steps/explore/projects.rb
+++ b/features/steps/explore/projects.rb
@@ -35,13 +35,13 @@ class Spinach::Features::ExploreProjectsFeature < Spinach::FeatureSteps
end
step 'I should see project "Community" home page' do
- within '.project-home-title' do
+ within '.navbar-gitlab .title' do
page.should have_content 'Community'
end
end
step 'I should see project "Internal" home page' do
- within '.project-home-title' do
+ within '.navbar-gitlab .title' do
page.should have_content 'Internal'
end
end
diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb
index 288524f92b2..c3ee42f1127 100644
--- a/features/steps/group/group.rb
+++ b/features/steps/group/group.rb
@@ -189,7 +189,7 @@ class Groups < Spinach::FeatureSteps
step 'I should see group milestone with descriptions and expiry date' do
page.should have_content('Lorem Ipsum is simply dummy text of the printing and typesetting industry')
- page.should have_content('expires at Aug 20, 2014')
+ page.should have_content('expires at Aug 20, 2114')
end
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
@@ -238,7 +238,7 @@ class Groups < Spinach::FeatureSteps
milestone2_project3 = create :milestone,
title: "GL-113",
project: @project3,
- due_date: '2014-08-20',
+ due_date: '2114-08-20',
description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry'
@issue1 = create :issue,
project: @project1,
diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb
index dfafbc6fc0e..e39c0b65b91 100644
--- a/features/steps/project/active_tab.rb
+++ b/features/steps/project/active_tab.rb
@@ -7,7 +7,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
# Main Tabs
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Activity')
+ ensure_active_main_tab('Project')
end
Then 'the active main tab should be Settings' do
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index 7e01735af95..39d39c8aeca 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -18,7 +18,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I should see project "Community" home page' do
Gitlab.config.gitlab.stub(:host).and_return("www.example.com")
- within '.project-home-title' do
+ within '.navbar-gitlab .title' do
page.should have_content 'Community'
end
end
@@ -34,9 +34,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
end
step 'I click on "Sign In"' do
- within '.pull-right' do
- click_link "Sign in"
- end
+ first(:link, "Sign in").click
end
step 'Authenticate' do
diff --git a/features/steps/project/search_code.rb b/features/steps/project/search_code.rb
index affa7d3b43b..55218b6e745 100644
--- a/features/steps/project/search_code.rb
+++ b/features/steps/project/search_code.rb
@@ -6,7 +6,6 @@ class ProjectSearchCode < Spinach::FeatureSteps
step 'I search for term "coffee"' do
fill_in "search", with: "coffee"
click_button "Go"
- click_link 'Repository Code'
end
step 'I should see files from repository containing "coffee"' do
@@ -15,6 +14,6 @@ class ProjectSearchCode < Spinach::FeatureSteps
end
step 'I should see empty result' do
- page.should have_content "We couldn't find any matching code"
+ page.should have_content "We couldn't find any matching"
end
end
diff --git a/features/steps/search.rb b/features/steps/search.rb
new file mode 100644
index 00000000000..b1058989d0b
--- /dev/null
+++ b/features/steps/search.rb
@@ -0,0 +1,73 @@
+class Spinach::Features::Search < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedProject
+
+ step 'I search for "Sho"' do
+ fill_in "dashboard_search", with: "Sho"
+ click_button "Search"
+ end
+
+ step 'I search for "Foo"' do
+ fill_in "dashboard_search", with: "Foo"
+ click_button "Search"
+ end
+
+ step 'I search for "rspec"' do
+ fill_in "dashboard_search", with: "rspec"
+ click_button "Search"
+ end
+
+ step 'I click "Issues" link' do
+ within '.search-filter' do
+ click_link 'Issues'
+ end
+ end
+
+ step 'I click project "Shop" link' do
+ within '.project-filter' do
+ click_link project.name_with_namespace
+ end
+ end
+
+ step 'I click "Merge requests" link' do
+ within '.search-filter' do
+ click_link 'Merge requests'
+ end
+ end
+
+ step 'I should see "Shop" project link' do
+ page.should have_link "Shop"
+ end
+
+ step 'I should see code results for project "Shop"' do
+ page.should have_content 'Update capybara, rspec-rails, poltergeist to recent versions'
+ end
+
+ step 'I search for "Contibuting"' do
+ fill_in "dashboard_search", with: "Contibuting"
+ click_button "Search"
+ end
+
+ step 'project has issues' do
+ create(:issue, title: "Foo", project: project)
+ create(:issue, title: "Bar", project: project)
+ end
+
+ step 'project has merge requests' do
+ create(:merge_request, title: "Foo", source_project: project, target_project: project)
+ create(:merge_request, :simple, title: "Bar", source_project: project, target_project: project)
+ end
+
+ step 'I should see "Foo" link' do
+ page.should have_link "Foo"
+ end
+
+ step 'I should not see "Bar" link' do
+ page.should_not have_link "Bar"
+ end
+
+ def project
+ @project ||= Project.find_by(name: "Shop")
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index d36b29a00b1..6af0f6d1b25 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -114,17 +114,21 @@ module API
# Helper method for validating all labels against its names
def validate_label_params(params)
+ errors = {}
+
if params[:labels].present?
params[:labels].split(',').each do |label_name|
label = user_project.labels.create_with(
color: Label::DEFAULT_COLOR).find_or_initialize_by(
title: label_name.strip)
+
if label.invalid?
- return true
+ errors[label.title] = label.errors
end
end
end
- false
+
+ errors
end
# error helpers
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 055529ccbd8..eb6a74cd2bc 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -52,8 +52,8 @@ module API
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
issue = ::Issues::CreateService.new(user_project, current_user, attrs).execute
@@ -90,8 +90,8 @@ module API
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
issue = ::Issues::UpdateService.new(user_project, current_user, attrs).execute(issue)
@@ -99,7 +99,8 @@ module API
if issue.valid?
# Find or create labels and attach to issue. Labels are valid because
# we already checked its name, so there can't be an error here
- if params[:labels].present?
+ unless params[:labels].nil?
+ issue.remove_labels
# Create and add labels to the new created issue
issue.add_labels_by_names(params[:labels].split(','))
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index d1684b2293c..2fdf53ffec2 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -39,7 +39,7 @@ module API
if label.valid?
present label, with: Entities::Label
else
- render_api_error!(label.errors.full_messages.join(', '), 405)
+ render_api_error!(label.errors.full_messages.join(', '), 400)
end
end
@@ -95,7 +95,7 @@ module API
if label.update(attrs)
present label, with: Entities::Label
else
- render_api_error!(label.errors.full_messages.join(', '), 405)
+ render_api_error!(label.errors.full_messages.join(', '), 400)
end
end
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 0d765f9280e..8726379bf3c 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -78,8 +78,8 @@ module API
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute
@@ -117,15 +117,16 @@ module API
authorize! :modify_merge_request, merge_request
# Validate label names in advance
- if validate_label_params(params)
- return render_api_error!('Label names invalid', 405)
+ if (errors = validate_label_params(params)).any?
+ render_api_error!({ labels: errors }, 400)
end
merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request)
if merge_request.valid?
# Find or create labels and attach to issue
- if params[:labels].present?
+ unless params[:labels].nil?
+ merge_request.remove_labels
merge_request.add_labels_by_names(params[:labels].split(","))
end
diff --git a/lib/gitlab/blacklist.rb b/lib/gitlab/blacklist.rb
index 6bc2c3b487c..a47d120dd21 100644
--- a/lib/gitlab/blacklist.rb
+++ b/lib/gitlab/blacklist.rb
@@ -3,7 +3,30 @@ module Gitlab
extend self
def path
- %w(admin dashboard files groups help profile projects search public assets u s teams merge_requests issues users snippets services repository hooks notes)
+ %w(
+ admin
+ dashboard
+ files
+ groups
+ help
+ profile
+ projects
+ search
+ public
+ assets
+ u
+ s
+ teams
+ merge_requests
+ issues
+ users
+ snippets
+ services
+ repository
+ hooks
+ notes
+ unsubscribes
+ )
end
end
end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
new file mode 100644
index 00000000000..90511662b20
--- /dev/null
+++ b/lib/gitlab/project_search_results.rb
@@ -0,0 +1,52 @@
+module Gitlab
+ class ProjectSearchResults < SearchResults
+ attr_reader :project, :repository_ref
+
+ def initialize(project_id, query, repository_ref = nil)
+ @project = Project.find(project_id)
+ @repository_ref = repository_ref
+ @query = Shellwords.shellescape(query) if query.present?
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'notes'
+ notes.page(page).per(per_page)
+ when 'blobs'
+ Kaminari.paginate_array(blobs).page(page).per(per_page)
+ else
+ super
+ end
+ end
+
+ def total_count
+ @total_count ||= issues_count + merge_requests_count + blobs_count + notes_count
+ end
+
+ def blobs_count
+ @blobs_count ||= blobs.count
+ end
+
+ def notes_count
+ @notes_count ||= notes.count
+ end
+
+ private
+
+ def blobs
+ if project.empty_repo?
+ []
+ else
+ project.repository.search_files(query, repository_ref)
+ end
+ end
+
+ def notes
+ Note.where(project_id: limit_project_ids).search(query).order('updated_at DESC')
+ end
+
+ def limit_project_ids
+ [project.id]
+ end
+ end
+end
diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb
index 7c058b58c4c..f34d661c9fc 100644
--- a/lib/gitlab/satellite/satellite.rb
+++ b/lib/gitlab/satellite/satellite.rb
@@ -121,6 +121,7 @@ module Gitlab
#
# Note: this will only update remote branches (i.e. origin/*)
def update_from_source!
+ repo.git.remote(default_options, 'set-url', :origin, project.repository.path_to_repo)
repo.git.fetch(default_options, :origin)
end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
new file mode 100644
index 00000000000..75a3dfe37c3
--- /dev/null
+++ b/lib/gitlab/search_results.rb
@@ -0,0 +1,69 @@
+module Gitlab
+ class SearchResults
+ attr_reader :query
+
+ # Limit search results by passed project ids
+ # It allows us to search only for projects user has access to
+ attr_reader :limit_project_ids
+
+ def initialize(limit_project_ids, query)
+ @limit_project_ids = limit_project_ids || Project.all
+ @query = Shellwords.shellescape(query) if query.present?
+ end
+
+ def objects(scope, page = nil)
+ case scope
+ when 'projects'
+ projects.page(page).per(per_page)
+ when 'issues'
+ issues.page(page).per(per_page)
+ when 'merge_requests'
+ merge_requests.page(page).per(per_page)
+ else
+ Kaminari.paginate_array([]).page(page).per(per_page)
+ end
+ end
+
+ def total_count
+ @total_count ||= projects_count + issues_count + merge_requests_count
+ end
+
+ def projects_count
+ @projects_count ||= projects.count
+ end
+
+ def issues_count
+ @issues_count ||= issues.count
+ end
+
+ def merge_requests_count
+ @merge_requests_count ||= merge_requests.count
+ end
+
+ def empty?
+ total_count.zero?
+ end
+
+ private
+
+ def projects
+ Project.where(id: limit_project_ids).search(query)
+ end
+
+ def issues
+ Issue.where(project_id: limit_project_ids).full_search(query).order('updated_at DESC')
+ end
+
+ def merge_requests
+ MergeRequest.in_projects(limit_project_ids).full_search(query).order('updated_at DESC')
+ end
+
+ def default_scope
+ 'projects'
+ end
+
+ def per_page
+ 20
+ end
+ end
+end
diff --git a/lib/gitlab/visibility_level.rb b/lib/gitlab/visibility_level.rb
index ea1319268f8..d0b6cde3c7e 100644
--- a/lib/gitlab/visibility_level.rb
+++ b/lib/gitlab/visibility_level.rb
@@ -23,7 +23,21 @@ module Gitlab
end
def allowed_for?(user, level)
- user.is_admin? || !Gitlab.config.gitlab.restricted_visibility_levels.include?(level)
+ user.is_admin? || allowed_level?(level)
+ end
+
+ # Level can be a string `"public"` or a value `20`, first check if valid,
+ # then check if the corresponding string appears in the config
+ def allowed_level?(level)
+ if options.has_key?(level.to_s)
+ non_restricted_level?(level)
+ elsif options.has_value?(level.to_i)
+ non_restricted_level?(options.key(level.to_i).downcase)
+ end
+ end
+
+ def non_restricted_level?(level)
+ ! Gitlab.config.gitlab.restricted_visibility_levels.include?(level)
end
end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 49306fb63da..16b06fe006e 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -1,69 +1,85 @@
-# GITLAB
-# Maintainer: @randx
-
-# CHUNKED TRANSFER
-# It is a known issue that Git-over-HTTP requires chunked transfer encoding [0] which is not
-# supported by Nginx < 1.3.9 [1]. As a result, pushing a large object with Git (i.e. a single large file)
-# can lead to a 411 error. In theory you can get around this by tweaking this configuration file and either
-# - installing an old version of Nginx with the chunkin module [2] compiled in, or
-# - using a newer version of Nginx.
-#
-# At the time of writing we do not know if either of these theoretical solutions works. As a workaround
-# users can use Git over SSH to push large files.
-#
-# [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
-# [1] https://github.com/agentzh/chunkin-nginx-module#status
-# [2] https://github.com/agentzh/chunkin-nginx-module
+## GitLab
+## Maintainer: @randx
+##
+## Lines starting with two hashes (##) are comments with information.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
+##
+##################################
+## CHUNKED TRANSFER ##
+##################################
+##
+## It is a known issue that Git-over-HTTP requires chunked transfer encoding [0]
+## which is not supported by Nginx < 1.3.9 [1]. As a result, pushing a large object
+## with Git (i.e. a single large file) can lead to a 411 error. In theory you can get
+## around this by tweaking this configuration file and either:
+## - installing an old version of Nginx with the chunkin module [2] compiled in, or
+## - using a newer version of Nginx.
+##
+## At the time of writing we do not know if either of these theoretical solutions works.
+## As a workaround users can use Git over SSH to push large files.
+##
+## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
+## [1] https://github.com/agentzh/chunkin-nginx-module#status
+## [2] https://github.com/agentzh/chunkin-nginx-module
+##
+###################################
+## configuration ##
+###################################
+##
upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
}
+## Normal HTTP host
server {
listen *:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
root /home/git/gitlab/public;
-
- # Increase this if you want to upload large attachments
- # Or if you want to accept large git objects over http
+
+ ## Increase this if you want to upload large attachments
+ ## Or if you want to accept large git objects over http
client_max_body_size 20m;
- # individual nginx logs for this gitlab vhost
+ ## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
location / {
- # serve static files from defined root folder;.
- # @gitlab is a named location for the upstream fallback, see below
+ ## Serve static files from defined root folder.
+ ## @gitlab is a named location for the upstream fallback, see below.
try_files $uri $uri/index.html $uri.html @gitlab;
}
- # if a file, which is not found in the root folder is requested,
- # then the proxy pass the request to the upsteam (gitlab unicorn)
+ ## If a file, which is not found in the root folder is requested,
+ ## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
- # If you use https make sure you disable gzip compression
- # to be safe against BREACH attack
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
# gzip off;
- proxy_read_timeout 300; # Some requests take more than 30 seconds.
- proxy_connect_timeout 300; # Some requests take more than 30 seconds.
- proxy_redirect off;
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Frame-Options SAMEORIGIN;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://gitlab;
}
- # Enable gzip compression as per rails guide: http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- # WARNING: If you are using relative urls do remove the block below
- # See config/application.rb under "Relative url support" for the list of
- # other files that need to be changed for relative url support
- location ~ ^/(assets)/ {
+ ## Enable gzip compression as per rails guide:
+ ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
+ ## WARNING: If you are using relative urls remove the block below
+ ## See config/application.rb under "Relative url support" for the list of
+ ## other files that need to be changed for relative url support
+ location ~ ^/(assets)/ {
root /home/git/gitlab/public;
gzip_static on; # to serve pre-gzipped version
expires max;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 54a4a080a9f..9ab228b46d7 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -6,8 +6,7 @@
## Modified from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
##
## Lines starting with two hashes (##) are comments with information.
-## Lines starting with one hash (#) are configuration parameters.
-## The last category can be commented/uncommented to your liking.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
##
##################################
## CHUNKED TRANSFER ##
@@ -20,8 +19,8 @@
## - installing an old version of Nginx with the chunkin module [2] compiled in, or
## - using a newer version of Nginx.
##
-## At the time of writing we do not know if either of these theoretical solutions works. As a workaround
-## users can use Git over SSH to push large files.
+## At the time of writing we do not know if either of these theoretical solutions works.
+## As a workaround users can use Git over SSH to push large files.
##
## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99
## [1] https://github.com/agentzh/chunkin-nginx-module#status
@@ -49,15 +48,18 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;
}
-## This is a normal HTTP host which redirects all traffic to the HTTPS host.
+## Normal HTTP host
server {
listen *:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
+
+ ## Redirects all traffic to the HTTPS host
root /nowhere; ## root doesn't have to be a valid path since we are redirecting
- rewrite ^ https://$server_name$request_uri permanent;
+ rewrite ^ https://$server_name$request_uri? permanent;
}
+## HTTPS host
server {
listen 443 ssl;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
@@ -82,7 +84,7 @@ server {
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security max-age=63072000;
- add_header X-Frame-Options DENY;
+ add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
## Individual nginx logs for this GitLab vhost
@@ -96,10 +98,9 @@ server {
}
## If a file, which is not found in the root folder is requested,
- ## then the proxy pass the request to the upsteam (gitlab unicorn).
+ ## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
-
- ## If you use https make sure you disable gzip compression
+ ## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
@@ -121,7 +122,7 @@ server {
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
- ## WARNING: If you are using relative urls do remove the block below
+ ## WARNING: If you are using relative urls remove the block below
## See config/application.rb under "Relative url support" for the list of
## other files that need to be changed for relative url support
location ~ ^/(assets)/ {
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index ff27e6a3066..ece3ad58385 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -8,7 +8,7 @@ namespace :gitlab do
args.with_defaults(tag: 'v' + default_version, repo: "https://gitlab.com/gitlab-org/gitlab-shell.git")
user = Settings.gitlab.user
- home_dir = Settings.gitlab.user_home
+ home_dir = Rails.env.test? ? Rails.root.join('tmp/tests') : Settings.gitlab.user_home
gitlab_url = Settings.gitlab.url
# gitlab-shell requires a / at the end of the url
gitlab_url += "/" unless gitlab_url.match(/\/$/)
diff --git a/lib/tasks/gitlab/sidekiq.rake b/lib/tasks/gitlab/sidekiq.rake
new file mode 100644
index 00000000000..7e2a6668e59
--- /dev/null
+++ b/lib/tasks/gitlab/sidekiq.rake
@@ -0,0 +1,47 @@
+namespace :gitlab do
+ namespace :sidekiq do
+ QUEUE = 'queue:post_receive'
+
+ desc 'Drop all Sidekiq PostReceive jobs for a given project'
+ task :drop_post_receive , [:project] => :environment do |t, args|
+ unless args.project.present?
+ abort "Please specify the project you want to drop PostReceive jobs for:\n rake gitlab:sidekiq:drop_post_receive[group/project]"
+ end
+ project_path = Project.find_with_namespace(args.project).repository.path_to_repo
+
+ Sidekiq.redis do |redis|
+ unless redis.exists(QUEUE)
+ abort "Queue #{QUEUE} is empty"
+ end
+
+ temp_queue = "#{QUEUE}_#{Time.now.to_i}"
+ redis.rename(QUEUE, temp_queue)
+
+ # At this point, then post_receive queue is empty. It may be receiving
+ # new jobs already. We will repopulate it with the old jobs, skipping the
+ # ones we want to drop.
+ dropped = 0
+ while (job = redis.lpop(temp_queue)) do
+ if repo_path(job) == project_path
+ dropped += 1
+ else
+ redis.rpush(QUEUE, job)
+ end
+ end
+ # The temp_queue will delete itself after we have popped all elements
+ # from it
+
+ puts "Dropped #{dropped} jobs containing #{project_path} from #{QUEUE}"
+ end
+ end
+
+ def repo_path(job)
+ job_args = JSON.parse(job)['args']
+ if job_args
+ job_args.first
+ else
+ nil
+ end
+ end
+ end
+end
diff --git a/spec/factories/label_links.rb b/spec/factories/label_links.rb
index d6b6f8581f6..bd304b5db6b 100644
--- a/spec/factories/label_links.rb
+++ b/spec/factories/label_links.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: label_links
+#
+# id :integer not null, primary key
+# label_id :integer
+# target_id :integer
+# target_type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/labels.rb b/spec/factories/labels.rb
index af9f3efa641..6829387c660 100644
--- a/spec/factories/labels.rb
+++ b/spec/factories/labels.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: labels
+#
+# id :integer not null, primary key
+# title :string(255)
+# color :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 3319262c015..0ae8ea5f878 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -1,3 +1,25 @@
+# == Schema Information
+#
+# Table name: merge_requests
+#
+# id :integer not null, primary key
+# target_branch :string(255) not null
+# source_branch :string(255) not null
+# source_project_id :integer not null
+# author_id :integer
+# assignee_id :integer
+# title :string(255)
+# created_at :datetime
+# updated_at :datetime
+# milestone_id :integer
+# state :string(255)
+# merge_status :string(255)
+# target_project_id :integer not null
+# iid :integer
+# description :text
+# position :integer default(0)
+#
+
FactoryGirl.define do
factory :merge_request do
title
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index a55ccf289dd..83d0cc62dbf 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -1,3 +1,22 @@
+# == Schema Information
+#
+# Table name: notes
+#
+# id :integer not null, primary key
+# note :text
+# noteable_type :string(255)
+# author_id :integer
+# created_at :datetime
+# updated_at :datetime
+# project_id :integer
+# attachment :string(255)
+# line_code :string(255)
+# commit_id :string(255)
+# noteable_id :integer
+# system :boolean default(FALSE), not null
+# st_diff :text
+#
+
require_relative '../support/repo_helpers'
FactoryGirl.define do
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 353d9d645ef..5324654c48c 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -1,3 +1,31 @@
+# == Schema Information
+#
+# Table name: projects
+#
+# id :integer not null, primary key
+# name :string(255)
+# path :string(255)
+# description :text
+# created_at :datetime
+# updated_at :datetime
+# creator_id :integer
+# issues_enabled :boolean default(TRUE), not null
+# wall_enabled :boolean default(TRUE), not null
+# merge_requests_enabled :boolean default(TRUE), not null
+# wiki_enabled :boolean default(TRUE), not null
+# namespace_id :integer
+# issues_tracker :string(255) default("gitlab"), not null
+# issues_tracker_id :string(255)
+# snippets_enabled :boolean default(TRUE), not null
+# last_activity_at :datetime
+# import_url :string(255)
+# visibility_level :integer default(0), not null
+# archived :boolean default(FALSE), not null
+# import_status :string(255)
+# repository_size :float default(0.0)
+# star_count :integer default(0), not null
+#
+
FactoryGirl.define do
factory :empty_project, class: 'Project' do
sequence(:name) { |n| "project#{n}" }
diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb
index 078e61a7d62..0db60432ad3 100644
--- a/spec/models/label_link_spec.rb
+++ b/spec/models/label_link_spec.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: label_links
+#
+# id :integer not null, primary key
+# label_id :integer
+# target_id :integer
+# target_type :string(255)
+# created_at :datetime
+# updated_at :datetime
+#
+
require 'spec_helper'
describe LabelLink do
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 5098af84cc3..31634648f04 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: labels
+#
+# id :integer not null, primary key
+# title :string(255)
+# color :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+#
+
require 'spec_helper'
describe Label do
@@ -5,4 +17,27 @@ describe Label do
it { label.should be_valid }
it { should belong_to(:project) }
+
+ describe 'Validation' do
+ it 'should validate color code' do
+ build(:label, color: 'G-ITLAB').should_not be_valid
+ build(:label, color: 'AABBCC').should_not be_valid
+ build(:label, color: '#AABBCCEE').should_not be_valid
+ build(:label, color: '#GGHHII').should_not be_valid
+ build(:label, color: '#').should_not be_valid
+ build(:label, color: '').should_not be_valid
+
+ build(:label, color: '#AABBCC').should be_valid
+ end
+
+ it 'should validate title' do
+ build(:label, title: 'G,ITLAB').should_not be_valid
+ build(:label, title: 'G?ITLAB').should_not be_valid
+ build(:label, title: 'G&ITLAB').should_not be_valid
+ build(:label, title: '').should_not be_valid
+
+ build(:label, title: 'GITLAB').should be_valid
+ build(:label, title: 'gitlab').should be_valid
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index ec6d29de82b..c40f75290ed 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -17,6 +17,7 @@
# target_project_id :integer not null
# iid :integer
# description :text
+# position :integer default(0)
#
require 'spec_helper'
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 82ab97cdd7a..1c11ac39567 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -22,6 +22,8 @@
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# import_status :string(255)
+# repository_size :float default(0.0)
+# star_count :integer default(0), not null
#
require 'spec_helper'
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index d8e8e4f5035..08dc94ebdf3 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -73,12 +73,12 @@ describe API::API, api: true do
response.status.should == 400
end
- it 'should return 405 on invalid label names' do
+ it 'should return 400 on invalid label names' do
post api("/projects/#{project.id}/issues", user),
title: 'new issue',
labels: 'label, ?'
- response.status.should == 405
- json_response['message'].should == 'Label names invalid'
+ response.status.should == 400
+ json_response['message']['labels']['?']['title'].should == ['is invalid']
end
end
@@ -97,12 +97,56 @@ describe API::API, api: true do
response.status.should == 404
end
- it 'should return 405 on invalid label names' do
+ it 'should return 400 on invalid label names' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
title: 'updated title',
labels: 'label, ?'
- response.status.should == 405
- json_response['message'].should == 'Label names invalid'
+ response.status.should == 400
+ json_response['message']['labels']['?']['title'].should == ['is invalid']
+ end
+ end
+
+ describe 'PUT /projects/:id/issues/:issue_id to update labels' do
+ let!(:label) { create(:label, title: 'dummy', project: project) }
+ let!(:label_link) { create(:label_link, label: label, target: issue) }
+
+ it 'should not update labels if not present' do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ title: 'updated title'
+ response.status.should == 200
+ json_response['labels'].should == [label.title]
+ end
+
+ it 'should remove all labels' do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: ''
+ response.status.should == 200
+ json_response['labels'].should == []
+ end
+
+ it 'should update labels' do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: 'foo,bar'
+ response.status.should == 200
+ json_response['labels'].should include 'foo'
+ json_response['labels'].should include 'bar'
+ end
+
+ it 'should return 400 on invalid label names' do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: 'label, ?'
+ response.status.should == 400
+ json_response['message']['labels']['?']['title'].should == ['is invalid']
+ end
+
+ it 'should allow special label names' do
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: 'label:foo, label-bar,label_bar,label/bar'
+ response.status.should == 200
+ json_response['labels'].should include 'label:foo'
+ json_response['labels'].should include 'label-bar'
+ json_response['labels'].should include 'label_bar'
+ json_response['labels'].should include 'label/bar'
end
end
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index b06b353333d..ee9088933a1 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -42,19 +42,27 @@ describe API::API, api: true do
response.status.should == 400
end
- it 'should return 405 for invalid color' do
+ it 'should return 400 for invalid color' do
post api("/projects/#{project.id}/labels", user),
name: 'Foo',
color: '#FFAA'
- response.status.should == 405
+ response.status.should == 400
+ json_response['message'].should == 'Color is invalid'
+ end
+
+ it 'should return 400 for too long color code' do
+ post api("/projects/#{project.id}/labels", user),
+ name: 'Foo',
+ color: '#FFAAFFFF'
+ response.status.should == 400
json_response['message'].should == 'Color is invalid'
end
- it 'should return 405 for invalid name' do
+ it 'should return 400 for invalid name' do
post api("/projects/#{project.id}/labels", user),
name: '?',
color: '#FFAABB'
- response.status.should == 405
+ response.status.should == 400
json_response['message'].should == 'Title is invalid'
end
@@ -131,20 +139,28 @@ describe API::API, api: true do
response.status.should == 400
end
- it 'should return 405 for invalid name' do
+ it 'should return 400 for invalid name' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
new_name: '?',
color: '#FFFFFF'
- response.status.should == 405
+ response.status.should == 400
json_response['message'].should == 'Title is invalid'
end
- it 'should return 405 for invalid name' do
+ it 'should return 400 for invalid name' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
color: '#FF'
- response.status.should == 405
+ response.status.should == 400
+ json_response['message'].should == 'Color is invalid'
+ end
+
+ it 'should return 400 for too long color code' do
+ post api("/projects/#{project.id}/labels", user),
+ name: 'Foo',
+ color: '#FFAAFFFF'
+ response.status.should == 400
json_response['message'].should == 'Color is invalid'
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 58cf7f139dc..06a25c5e3a5 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -112,15 +112,16 @@ describe API::API, api: true do
response.status.should == 400
end
- it 'should return 405 on invalid label names' do
+ it 'should return 400 on invalid label names' do
post api("/projects/#{project.id}/merge_requests", user),
title: 'Test merge_request',
source_branch: 'stable',
target_branch: 'master',
author: user,
labels: 'label, ?'
- response.status.should == 405
- json_response['message'].should == 'Label names invalid'
+ response.status.should == 400
+ json_response['message']['labels']['?']['title'].should ==
+ ['is invalid']
end
end
@@ -252,13 +253,13 @@ describe API::API, api: true do
json_response['target_branch'].should == 'wiki'
end
- it 'should return 405 on invalid label names' do
+ it 'should return 400 on invalid label names' do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}",
user),
title: 'new issue',
labels: 'label, ?'
- response.status.should == 405
- json_response['message'].should == 'Label names invalid'
+ response.status.should == 400
+ json_response['message']['labels']['?']['title'].should == ['is invalid']
end
end
diff --git a/spec/services/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index b6573095dbd..0edc3a8e807 100644
--- a/spec/services/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -5,44 +5,40 @@ describe Projects::ForkService do
before do
@from_namespace = create(:namespace)
@from_user = create(:user, namespace: @from_namespace )
- @from_project = create(:project, creator_id: @from_user.id, namespace: @from_namespace)
+ @from_project = create(:project, creator_id: @from_user.id,
+ namespace: @from_namespace, star_count: 107,
+ description: 'wow such project')
@to_namespace = create(:namespace)
@to_user = create(:user, namespace: @to_namespace)
end
context 'fork project' do
+ describe "successfully creates project in the user namespace" do
+ let(:to_project) { fork_project(@from_project, @to_user) }
- it "successfully creates project in the user namespace" do
- @to_project = fork_project(@from_project, @to_user)
-
- @to_project.owner.should == @to_user
- @to_project.namespace.should == @to_user.namespace
+ it { to_project.owner.should == @to_user }
+ it { to_project.namespace.should == @to_user.namespace }
+ it { to_project.star_count.should be_zero }
+ it { to_project.description.should == @from_project.description }
end
end
context 'fork project failure' do
-
it "fails due to transaction failure" do
- # make the mock gitlab-shell fail
@to_project = fork_project(@from_project, @to_user, false)
-
@to_project.errors.should_not be_empty
@to_project.errors[:base].should include("Fork transaction failed.")
end
-
end
context 'project already exists' do
-
it "should fail due to validation, not transaction failure" do
@existing_project = create(:project, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace)
@to_project = fork_project(@from_project, @to_user)
-
@existing_project.persisted?.should be_true
@to_project.errors[:base].should include("Invalid fork destination")
@to_project.errors[:base].should_not include("Fork transaction failed.")
end
-
end
end
@@ -53,5 +49,4 @@ describe Projects::ForkService do
context.stub(gitlab_shell: shell)
context.execute
end
-
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 62357787521..5a10174eb36 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -48,7 +48,7 @@ describe Projects::UpdateService do
context 'respect configured visibility restrictions setting' do
before(:each) do
@restrictions = double("restrictions")
- @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] }
+ @restrictions.stub(:restricted_visibility_levels) { [ "public" ] }
Settings.stub_chain(:gitlab).and_return(@restrictions)
end
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index daffe98a8ed..3217c571e67 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -19,7 +19,7 @@ describe 'Search::GlobalService' do
it 'should return public projects only' do
context = Search::GlobalService.new(nil, search: "searchable")
results = context.execute
- results[:projects].should match_array [public_project]
+ results.objects('projects').should match_array [public_project]
end
end
@@ -27,19 +27,19 @@ describe 'Search::GlobalService' do
it 'should return public, internal and private projects' do
context = Search::GlobalService.new(user, search: "searchable")
results = context.execute
- results[:projects].should match_array [public_project, found_project, internal_project]
+ results.objects('projects').should match_array [public_project, found_project, internal_project]
end
it 'should return only public & internal projects' do
context = Search::GlobalService.new(internal_user, search: "searchable")
results = context.execute
- results[:projects].should match_array [internal_project, public_project]
+ results.objects('projects').should match_array [internal_project, public_project]
end
it 'namespace name should be searchable' do
context = Search::GlobalService.new(user, search: found_project.namespace.path)
results = context.execute
- results[:projects].should match_array [found_project]
+ results.objects('projects').should match_array [found_project]
end
end
end
diff --git a/vendor/assets/javascripts/jquery.sticky.js b/vendor/assets/javascripts/jquery.sticky.js
new file mode 100755
index 00000000000..f7c9cd46ae9
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.sticky.js
@@ -0,0 +1,170 @@
+// Sticky Plugin v1.0.0 for jQuery
+// =============
+// Author: Anthony Garand
+// Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)
+// Improvements by Leonardo C. Daronco (daronco)
+// Created: 2/14/2011
+// Date: 2/12/2012
+// Website: http://labs.anthonygarand.com/sticky
+// Description: Makes an element on the page stick on the screen as you scroll
+// It will only set the 'top' and 'position' of your element, you
+// might need to adjust the width in some cases.
+
+(function($) {
+ var defaults = {
+ topSpacing: 0,
+ bottomSpacing: 0,
+ className: 'is-sticky',
+ wrapperClassName: 'sticky-wrapper',
+ center: false,
+ getWidthFrom: '',
+ responsiveWidth: false
+ },
+ $window = $(window),
+ $document = $(document),
+ sticked = [],
+ windowHeight = $window.height(),
+ scroller = function() {
+ var scrollTop = $window.scrollTop(),
+ documentHeight = $document.height(),
+ dwh = documentHeight - windowHeight,
+ extra = (scrollTop > dwh) ? dwh - scrollTop : 0;
+
+ for (var i = 0; i < sticked.length; i++) {
+ var s = sticked[i],
+ elementTop = s.stickyWrapper.offset().top,
+ etse = elementTop - s.topSpacing - extra;
+
+ if (scrollTop <= etse) {
+ if (s.currentTop !== null) {
+ s.stickyElement
+ .css('position', '')
+ .css('top', '');
+ s.stickyElement.trigger('sticky-end', [s]).parent().removeClass(s.className);
+ s.currentTop = null;
+ }
+ }
+ else {
+ var newTop = documentHeight - s.stickyElement.outerHeight()
+ - s.topSpacing - s.bottomSpacing - scrollTop - extra;
+ if (newTop < 0) {
+ newTop = newTop + s.topSpacing;
+ } else {
+ newTop = s.topSpacing;
+ }
+ if (s.currentTop != newTop) {
+ s.stickyElement
+ .css('position', 'fixed')
+ .css('top', newTop);
+
+ if (typeof s.getWidthFrom !== 'undefined') {
+ s.stickyElement.css('width', $(s.getWidthFrom).width());
+ }
+
+ s.stickyElement.trigger('sticky-start', [s]).parent().addClass(s.className);
+ s.currentTop = newTop;
+ }
+ }
+ }
+ },
+ resizer = function() {
+ windowHeight = $window.height();
+
+ for (var i = 0; i < sticked.length; i++) {
+ var s = sticked[i];
+ if (typeof s.getWidthFrom !== 'undefined' && s.responsiveWidth === true) {
+ s.stickyElement.css('width', $(s.getWidthFrom).width());
+ }
+ }
+ },
+ methods = {
+ init: function(options) {
+ var o = $.extend({}, defaults, options);
+ return this.each(function() {
+ var stickyElement = $(this);
+
+ var stickyId = stickyElement.attr('id');
+ var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName
+ var wrapper = $('<div></div>')
+ .attr('id', stickyId + '-sticky-wrapper')
+ .addClass(o.wrapperClassName);
+ stickyElement.wrapAll(wrapper);
+
+ if (o.center) {
+ stickyElement.parent().css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"});
+ }
+
+ if (stickyElement.css("float") == "right") {
+ stickyElement.css({"float":"none"}).parent().css({"float":"right"});
+ }
+
+ var stickyWrapper = stickyElement.parent();
+ stickyWrapper.css('height', stickyElement.outerHeight());
+ sticked.push({
+ topSpacing: o.topSpacing,
+ bottomSpacing: o.bottomSpacing,
+ stickyElement: stickyElement,
+ currentTop: null,
+ stickyWrapper: stickyWrapper,
+ className: o.className,
+ getWidthFrom: o.getWidthFrom,
+ responsiveWidth: o.responsiveWidth
+ });
+ });
+ },
+ update: scroller,
+ unstick: function(options) {
+ return this.each(function() {
+ var unstickyElement = $(this);
+
+ var removeIdx = -1;
+ for (var i = 0; i < sticked.length; i++)
+ {
+ if (sticked[i].stickyElement.get(0) == unstickyElement.get(0))
+ {
+ removeIdx = i;
+ }
+ }
+ if(removeIdx != -1)
+ {
+ sticked.splice(removeIdx,1);
+ unstickyElement.unwrap();
+ unstickyElement.removeAttr('style');
+ }
+ });
+ }
+ };
+
+ // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):
+ if (window.addEventListener) {
+ window.addEventListener('scroll', scroller, false);
+ window.addEventListener('resize', resizer, false);
+ } else if (window.attachEvent) {
+ window.attachEvent('onscroll', scroller);
+ window.attachEvent('onresize', resizer);
+ }
+
+ $.fn.sticky = function(method) {
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.sticky');
+ }
+ };
+
+ $.fn.unstick = function(method) {
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method ) {
+ return methods.unstick.apply( this, arguments );
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.sticky');
+ }
+
+ };
+ $(function() {
+ setTimeout(scroller, 0);
+ });
+})(jQuery);