summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG19
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock32
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/admin.js.coffee5
-rw-r--r--app/assets/javascripts/merge_requests.js8
-rw-r--r--app/assets/javascripts/projects.js.coffee4
-rw-r--r--app/assets/javascripts/tree.js.coffee2
-rw-r--r--app/assets/stylesheets/common.scss304
-rw-r--r--app/assets/stylesheets/fonts.scss7
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/blocks.scss88
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/buttons.scss66
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/common.scss59
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/files.scss76
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/lists.scss16
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/tables.scss22
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap/typography.scss34
-rw-r--r--app/assets/stylesheets/highlight/dark.scss60
-rw-r--r--app/assets/stylesheets/highlight/white.scss64
-rw-r--r--app/assets/stylesheets/main.scss113
-rw-r--r--app/assets/stylesheets/mixins.scss60
-rw-r--r--app/assets/stylesheets/ref_select.scss26
-rw-r--r--app/assets/stylesheets/sections/commits.scss122
-rw-r--r--app/assets/stylesheets/sections/editor.scss2
-rw-r--r--app/assets/stylesheets/sections/events.scss56
-rw-r--r--app/assets/stylesheets/sections/graph.scss4
-rw-r--r--app/assets/stylesheets/sections/header.scss94
-rw-r--r--app/assets/stylesheets/sections/issues.scss60
-rw-r--r--app/assets/stylesheets/sections/login.scss22
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss59
-rw-r--r--app/assets/stylesheets/sections/nav.scss78
-rw-r--r--app/assets/stylesheets/sections/notes.scss113
-rw-r--r--app/assets/stylesheets/sections/profile.scss18
-rw-r--r--app/assets/stylesheets/sections/projects.scss61
-rw-r--r--app/assets/stylesheets/sections/themes.scss24
-rw-r--r--app/assets/stylesheets/sections/tree.scss26
-rw-r--r--app/assets/stylesheets/themes/ui_basic.scss4
-rw-r--r--app/assets/stylesheets/themes/ui_mars.scss6
-rw-r--r--app/assets/stylesheets/variables.scss5
-rw-r--r--app/contexts/notes/load_context.rb2
-rw-r--r--app/contexts/project_update_context.rb21
-rw-r--r--app/controllers/admin/groups_controller.rb11
-rw-r--r--app/controllers/admin/projects_controller.rb53
-rw-r--r--app/controllers/application_controller.rb15
-rw-r--r--app/controllers/commit_controller.rb3
-rw-r--r--app/controllers/dashboard_controller.rb50
-rw-r--r--app/controllers/groups_controller.rb21
-rw-r--r--app/controllers/merge_requests_controller.rb12
-rw-r--r--app/controllers/project_resource_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb5
-rw-r--r--app/controllers/team_members_controller.rb6
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/helpers/dashboard_helper.rb32
-rw-r--r--app/helpers/namespaces_helper.rb26
-rw-r--r--app/helpers/tab_helper.rb13
-rw-r--r--app/mailers/notify.rb10
-rw-r--r--app/models/ability.rb78
-rw-r--r--app/models/commit.rb15
-rw-r--r--app/models/group.rb32
-rw-r--r--app/models/merge_request.rb26
-rw-r--r--app/models/namespace.rb70
-rw-r--r--app/models/project.rb140
-rw-r--r--app/models/user.rb31
-rw-r--r--app/observers/issue_observer.rb6
-rw-r--r--app/observers/project_observer.rb5
-rw-r--r--app/observers/user_observer.rb10
-rw-r--r--app/roles/account.rb37
-rw-r--r--app/roles/push_observer.rb2
-rw-r--r--app/roles/repository.rb16
-rw-r--r--app/views/admin/dashboard/index.html.haml47
-rw-r--r--app/views/admin/groups/_form.html.haml7
-rw-r--r--app/views/admin/groups/index.html.haml5
-rw-r--r--app/views/admin/groups/new.html.haml22
-rw-r--r--app/views/admin/groups/show.html.haml21
-rw-r--r--app/views/admin/logs/show.html.haml10
-rw-r--r--app/views/admin/projects/_form.html.haml25
-rw-r--r--app/views/admin/projects/_new_form.html.haml29
-rw-r--r--app/views/admin/projects/edit.html.haml4
-rw-r--r--app/views/admin/projects/index.html.haml14
-rw-r--r--app/views/admin/projects/new.html.haml12
-rw-r--r--app/views/admin/projects/show.html.haml30
-rw-r--r--app/views/admin/shared/_projects_head.html.haml5
-rw-r--r--app/views/admin/users/_form.html.haml107
-rw-r--r--app/views/admin/users/edit.html.haml5
-rw-r--r--app/views/admin/users/index.html.haml9
-rw-r--r--app/views/admin/users/new.html.haml6
-rw-r--r--app/views/admin/users/show.html.haml6
-rw-r--r--app/views/commit/show.patch.erb1
-rw-r--r--app/views/commits/_commit_box.html.haml11
-rw-r--r--app/views/dashboard/_filter.html.haml33
-rw-r--r--app/views/dashboard/_groups.html.haml4
-rw-r--r--app/views/dashboard/_projects.html.haml14
-rw-r--r--app/views/dashboard/index.html.haml1
-rw-r--r--app/views/dashboard/issues.atom.builder8
-rw-r--r--app/views/dashboard/issues.html.haml32
-rw-r--r--app/views/dashboard/merge_requests.html.haml28
-rw-r--r--app/views/errors/access_denied.html.haml5
-rw-r--r--app/views/errors/encoding.html.haml3
-rw-r--r--app/views/errors/git_not_found.html.haml4
-rw-r--r--app/views/errors/gitolite.html.haml4
-rw-r--r--app/views/errors/not_found.html.haml4
-rw-r--r--app/views/events/_event.html.haml2
-rw-r--r--app/views/groups/_new_member.html.haml18
-rw-r--r--app/views/groups/_people_filter.html.haml14
-rw-r--r--app/views/groups/_projects.html.haml7
-rw-r--r--app/views/groups/people.html.haml30
-rw-r--r--app/views/groups/show.html.haml3
-rw-r--r--app/views/help/api.html.haml11
-rw-r--r--app/views/layouts/_head.html.haml2
-rw-r--r--app/views/layouts/_head_panel.html.haml2
-rw-r--r--app/views/layouts/_init_auto_complete.html.haml2
-rw-r--r--app/views/layouts/admin.html.haml6
-rw-r--r--app/views/layouts/application.html.haml2
-rw-r--r--app/views/layouts/errors.html.haml2
-rw-r--r--app/views/layouts/group.html.haml2
-rw-r--r--app/views/layouts/notify.html.haml6
-rw-r--r--app/views/layouts/profile.html.haml2
-rw-r--r--app/views/layouts/project_resource.html.haml6
-rw-r--r--app/views/merge_requests/show/_diffs.html.haml6
-rw-r--r--app/views/merge_requests/show/_mr_title.html.haml11
-rw-r--r--app/views/notify/note_wiki_email.html.haml23
-rw-r--r--app/views/profile/account.html.haml23
-rw-r--r--app/views/projects/_clone_panel.html.haml6
-rw-r--r--app/views/projects/_form.html.haml59
-rw-r--r--app/views/projects/_new_form.html.haml23
-rw-r--r--app/views/projects/empty.html.haml48
-rw-r--r--app/views/projects/update.js.haml2
-rw-r--r--app/views/search/show.html.haml2
-rw-r--r--app/views/services/_gitlab_ci.html.haml2
-rw-r--r--app/views/shared/_clone_panel.html.haml2
-rw-r--r--app/views/shared/_no_ssh.html.haml4
-rw-r--r--app/views/snippets/_blob.html.haml12
-rw-r--r--app/views/snippets/_form.html.haml40
-rw-r--r--app/views/snippets/show.html.haml16
-rw-r--r--app/views/team_members/_show.html.haml46
-rw-r--r--app/views/team_members/_team.html.haml12
-rw-r--r--app/views/team_members/index.html.haml14
-rw-r--r--app/views/tree/_head.html.haml2
-rw-r--r--app/views/tree/blob/_text.html.haml7
-rw-r--r--app/views/wikis/show.html.haml3
-rw-r--r--app/workers/post_receive.rb4
-rw-r--r--config/database.yml.sqlite31
-rw-r--r--config/initializers/mime_types.rb3
-rw-r--r--config/routes.rb9
-rw-r--r--db/fixtures/development/001_admin.rb32
-rw-r--r--db/fixtures/development/002_project.rb6
-rw-r--r--db/fixtures/development/003_users.rb16
-rw-r--r--db/fixtures/development/009_source_code.rb7
-rw-r--r--db/fixtures/development/010_groups.rb11
-rw-r--r--db/fixtures/production/001_admin.rb9
-rw-r--r--db/migrate/20121122145155_convert_group_to_namespace.rb13
-rw-r--r--db/migrate/20121122150932_add_namespace_id_to_project.rb5
-rw-r--r--db/migrate/20121123104937_add_username_to_user.rb5
-rw-r--r--db/migrate/20121123164910_rename_code_to_path.rb11
-rw-r--r--db/schema.rb23
-rw-r--r--doc/api/notes.md136
-rw-r--r--doc/install/databases.md17
-rw-r--r--doc/install/installation.md4
-rw-r--r--features/admin/active_tab.feature5
-rw-r--r--features/dashboard/dashboard.feature6
-rw-r--r--features/project/issues/issues.feature15
-rw-r--r--features/project/wiki.feature6
-rw-r--r--features/steps/admin/admin_active_tab.rb4
-rw-r--r--features/steps/admin/admin_groups.rb3
-rw-r--r--features/steps/dashboard/dashboard.rb10
-rw-r--r--features/steps/dashboard/dashboard_issues.rb1
-rw-r--r--features/steps/project/create_project.rb2
-rw-r--r--features/steps/project/project_issues.rb1
-rw-r--r--features/support/env.rb5
-rw-r--r--lib/api.rb1
-rw-r--r--lib/api/entities.rb7
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/api/merge_requests.rb30
-rw-r--r--lib/api/notes.rb94
-rw-r--r--lib/api/projects.rb6
-rw-r--r--lib/api/users.rb2
-rw-r--r--lib/gitlab/auth.rb1
-rw-r--r--lib/gitlab/backend/gitolite.rb15
-rw-r--r--lib/gitlab/backend/gitolite_config.rb16
-rw-r--r--lib/gitlab/backend/grack_auth.rb12
-rw-r--r--lib/gitlab/logger.rb2
-rw-r--r--lib/gitlab/project_mover.rb44
-rw-r--r--lib/gitlab/regex.rb19
-rw-r--r--lib/gitlab/satellite/satellite.rb4
-rw-r--r--lib/redcarpet/render/gitlab_html.rb10
-rw-r--r--lib/tasks/gitlab/activate_namespaces.rake67
-rw-r--r--lib/tasks/gitlab/backup.rake2
-rw-r--r--lib/tasks/resque.rake13
-rw-r--r--public/404.html7
-rw-r--r--public/500.html9
-rw-r--r--public/githost_error.html36
-rw-r--r--public/static.css76
-rw-r--r--spec/controllers/commit_controller_spec.rb74
-rw-r--r--spec/controllers/commits_controller_spec.rb2
-rw-r--r--spec/controllers/merge_requests_controller_spec.rb85
-rw-r--r--spec/factories.rb26
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb6
-rw-r--r--spec/lib/project_mover_spec.rb65
-rw-r--r--spec/mailers/notify_spec.rb4
-rw-r--r--spec/models/group_spec.rb17
-rw-r--r--spec/models/namespace_spec.rb78
-rw-r--r--spec/models/project_spec.rb12
-rw-r--r--spec/models/user_spec.rb4
-rw-r--r--spec/observers/user_observer_spec.rb7
-rw-r--r--spec/observers/users_project_observer_spec.rb4
-rw-r--r--spec/requests/admin/admin_hooks_spec.rb4
-rw-r--r--spec/requests/admin/admin_projects_spec.rb50
-rw-r--r--spec/requests/admin/admin_users_spec.rb1
-rw-r--r--spec/requests/api/issues_spec.rb10
-rw-r--r--spec/requests/api/merge_requests_spec.rb12
-rw-r--r--spec/requests/api/milestones_spec.rb8
-rw-r--r--spec/requests/api/notes_spec.rb98
-rw-r--r--spec/requests/api/projects_spec.rb56
-rw-r--r--spec/requests/gitlab_flavored_markdown_spec.rb12
-rw-r--r--spec/requests/projects_spec.rb11
-rw-r--r--spec/routing/admin_routing_spec.rb8
-rw-r--r--spec/routing/project_routing_spec.rb11
-rw-r--r--spec/spec_helper.rb5
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb46
220 files changed, 3265 insertions, 1907 deletions
diff --git a/.gitignore b/.gitignore
index d22760e7780..94a210b9461 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ db/data.yml
.idea
.DS_Store
.chef
+vendor/bundle/*
diff --git a/CHANGELOG b/CHANGELOG
index 2eca1f14c4f..2c6152e77dd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,20 @@
+v 4.0.0
+ - [API] list, create issue notes
+ - [API] list, create snippet notes
+ - [API] list, create wall notes
+ - Remove project code - use path instead
+ - added username field to user
+ - rake task to fill usernames based on emails create namespaces for users
+ - STI Group < Namespace
+ - Project has namespace_id
+ - Projects with namespaces also namespaced in gitolite and stored in subdir
+ - Moving project to group will move it under group namespace
+ - Ability to move project from namespaces to another
+ - Fixes commit patches getting escaped (see #2036)
+ - Support diff and patch generation for commits and merge request
+ - MergeReqest doesn't generate a temporary file for the patch any more
+ - Update the UI to allow downloading Patch or Diff
+
v 3.1.0
- Updated gems
- Services: Gitlab CI integration
@@ -34,7 +51,7 @@ v 3.0.0
- Fixed bug with gitolite keys
- UI improved
- Increased perfomance of application
- - Show user avatar in last commit when browsing Files
+ - Show user avatar in last commit when browsing Files
- Refactored Gitlab::Merge
- Use Font Awsome for icons
- Separate observing of Note and MergeRequestsa
diff --git a/Gemfile b/Gemfile
index f723f587fbc..40f8bfe9095 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,7 +11,6 @@ end
gem "rails", "3.2.9"
# Supported DBs
-gem "sqlite3", group: :sqlite
gem "mysql2", group: :mysql
gem "pg", group: :postgres
@@ -27,7 +26,7 @@ gem "grit", git: "https://github.com/gitlabhq/grit.git", ref:
gem "omniauth-ldap", git: "https://github.com/gitlabhq/omniauth-ldap.git", ref: 'f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e'
gem 'yaml_db', git: "https://github.com/gitlabhq/yaml_db.git", ref: '98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd'
gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
-gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '212fd40bea61f3c6a167223768e7295dc32bbc10'
+gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e'
# Gitolite client (for work with gitolite-admin repo)
gem "gitolite", '1.1.0'
@@ -105,7 +104,7 @@ group :assets do
gem "jquery-rails", "2.1.3"
gem "jquery-ui-rails", "2.0.2"
gem "modernizr", "2.6.2"
- gem "raphael-rails", "2.1.0"
+ gem "raphael-rails", "1.5.2"
gem 'bootstrap-sass', "2.2.1.1"
gem "font-awesome-sass-rails", "~> 2.0.0"
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
@@ -139,7 +138,7 @@ group :development, :test do
gem 'rb-inotify', require: linux_only('rb-inotify')
# PhantomJS driver for Capybara
- gem 'poltergeist'
+ gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca'
end
group :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index 0e3a9810dbe..0c9563e4ab2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -26,10 +26,10 @@ GIT
GIT
remote: https://github.com/gitlabhq/grit_ext.git
- revision: 212fd40bea61f3c6a167223768e7295dc32bbc10
- ref: 212fd40bea61f3c6a167223768e7295dc32bbc10
+ revision: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
+ ref: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
specs:
- grit_ext (0.6.0)
+ grit_ext (0.6.1)
charlock_holmes (~> 0.6.9)
GIT
@@ -59,6 +59,18 @@ GIT
specs:
yaml_db (0.2.2)
+GIT
+ remote: https://github.com/jonleighton/poltergeist.git
+ revision: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
+ ref: 5c2e092001074a8cf09f332d3714e9ba150bc8ca
+ specs:
+ poltergeist (1.0.2)
+ capybara (~> 1.1)
+ childprocess (~> 0.3)
+ faye-websocket (~> 0.4, >= 0.4.4)
+ http_parser.rb (~> 0.5.3)
+ multi_json (~> 1.0)
+
GEM
remote: http://rubygems.org/
specs:
@@ -279,12 +291,6 @@ GEM
omniauth-oauth (~> 1.0)
orm_adapter (0.4.0)
pg (0.14.1)
- poltergeist (1.0.2)
- capybara (~> 1.1)
- childprocess (~> 0.3)
- faye-websocket (~> 0.4, >= 0.4.4)
- http_parser.rb (~> 0.5.3)
- multi_json (~> 1.0)
polyglot (0.3.3)
posix-spawn (0.3.6)
pry (0.9.10)
@@ -329,7 +335,7 @@ GEM
thor (>= 0.14.6, < 2.0)
raindrops (0.10.0)
rake (10.0.1)
- raphael-rails (2.1.0)
+ raphael-rails (1.5.2)
rb-fsevent (0.9.2)
rb-inotify (0.8.8)
ffi (>= 0.5.0)
@@ -404,7 +410,6 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
- sqlite3 (1.3.6)
stamp (0.3.0)
test_after_commit (0.0.1)
therubyracer (0.10.2)
@@ -490,14 +495,14 @@ DEPENDENCIES
omniauth-ldap!
omniauth-twitter
pg
- poltergeist
+ poltergeist!
pry
pygments.rb!
quiet_assets (~> 1.0.1)
rack-mini-profiler
rails (= 3.2.9)
rails-dev-tweaks
- raphael-rails (= 2.1.0)
+ raphael-rails (= 1.5.2)
rb-fsevent
rb-inotify
redcarpet (~> 2.2.2)
@@ -512,7 +517,6 @@ DEPENDENCIES
simplecov
six
spinach-rails
- sqlite3
stamp
test_after_commit
therubyracer
diff --git a/VERSION b/VERSION
index fd2a01863fd..0c042a83799 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.1.0
+4.0.0pre
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index 76454c29269..1dafdf4bd8b 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -10,3 +10,8 @@ $ ->
$('.log-tabs a').click (e) ->
e.preventDefault()
$(this).tab('show')
+
+ $('.log-bottom').click (e) ->
+ e.preventDefault()
+ visible_log = $(".file_content:visible")
+ visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast")
diff --git a/app/assets/javascripts/merge_requests.js b/app/assets/javascripts/merge_requests.js
index cc6b0771af5..170a0479de7 100644
--- a/app/assets/javascripts/merge_requests.js
+++ b/app/assets/javascripts/merge_requests.js
@@ -14,14 +14,6 @@ var MergeRequest = {
$(".mr_show_all_commits").bind("click", function() {
self.showAllCommits();
});
-
- $(".line_note_link, .line_note_reply_link").live("click", function(e) {
- var form = $(".per_line_form");
- $(this).parent().parent().after(form);
- form.find("#note_line_code").val($(this).attr("line_code"));
- form.show();
- return false;
- });
},
initMergeWidget:
diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee
index 3059723dfa0..1808f0578f6 100644
--- a/app/assets/javascripts/projects.js.coffee
+++ b/app/assets/javascripts/projects.js.coffee
@@ -1,8 +1,4 @@
window.Projects = ->
- $('#project_name').on 'change', ->
- slug = slugify $(@).val()
- $('#project_code, #project_path').val slug
-
$('.new_project, .edit_project').on 'ajax:before', ->
$('.project_new_holder, .project_edit_holder').hide()
$('.save-project-loader').show()
diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee
index 3f8ed6c2552..5003f9b00c7 100644
--- a/app/assets/javascripts/tree.js.coffee
+++ b/app/assets/javascripts/tree.js.coffee
@@ -28,7 +28,7 @@ $ ->
return false
$('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
- History.pushState(null, null, $(@).attr('href'))
+ History.pushState(null, null, decodeURIComponent($(@).attr('href')))
return false
History.Adapter.bind window, 'statechange', ->
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index e45cb876e7d..c82ddc185b3 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -1,23 +1,23 @@
/** LAYOUT **/
body {
- margin-bottom:20px;
+ margin-bottom: 20px;
}
.container {
- padding-top:0;
- z-index:5;
+ padding-top: 0;
+ z-index: 5;
}
.container .content {
- margin:0 0;
+ margin: 0 0;
}
.container .sidebar {
width: 200px;
- height:100%;
- min-height:450px;
- float:right;
+ height: 100%;
+ min-height: 450px;
+ float: right;
}
@@ -29,25 +29,25 @@ body {
.help li { color:#111 }
.back_link {
- text-decoration:underline;
- font-size:14px;
- font-weight:bold;
- padding:10px 0;
- padding-bottom:0;
+ text-decoration: underline;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 10px 0;
+ padding-bottom: 0;
}
.info_link {
- margin-right:5px;
- float:left;
+ margin-right: 5px;
+ float: left;
img {
- width:20px;
+ width: 20px;
}
}
.download_repo_link {
background: url("images.png") no-repeat 0 -48px;
- padding-left:20px;
+ padding-left: 20px;
}
table a code {
@@ -61,32 +61,32 @@ table a code {
}
.loading {
- margin:20px auto;
+ margin: 20px auto;
background: url(ajax_loader.gif) no-repeat center center;
- width:40px;
- height:40px;
+ width: 40px;
+ height: 40px;
}
/** FLASH message **/
#flash_container {
- height:50px;
- position:fixed;
- z-index:10001;
- top:0px;
- width:100%;
- margin-bottom:15px;
- overflow:hidden;
- background:white;
- cursor:pointer;
- border-bottom:1px solid #ccc;
+ height: 50px;
+ position: fixed;
+ z-index: 10001;
+ top: 0px;
+ width: 100%;
+ margin-bottom: 15px;
+ overflow: hidden;
+ background: white;
+ cursor: pointer;
+ border-bottom: 1px solid #ccc;
h4 {
- color:#666;
- font-size:18px;
- line-height:38px;
- padding-top:5px;
- margin:2px;
- font-weight:normal;
+ color: #666;
+ font-size: 18px;
+ line-height: 38px;
+ padding-top: 5px;
+ margin: 2px;
+ font-weight: normal;
}
}
@@ -95,39 +95,39 @@ table a code {
}
.handle:hover {
- cursor:move;
+ cursor: move;
}
span.update-author {
- display:block;
+ display: block;
}
span.update-author {
- color:#999;
- font-weight:normal;
- font-style:italic;
+ color: #999;
+ font-weight: normal;
+ font-style: italic;
}
span.update-author strong {
- font-weight:bold;
+ font-weight: bold;
font-style: normal;
}
/** UPDATE ITEM **/
span.update-author {
- display:block;
+ display: block;
}
/** END UPDATE ITEM **/
.dashboard-loader {
- float:left;
- margin:10px;
- display:none;
+ float: left;
+ margin: 10px;
+ display: none;
}
.user-mention {
- color:#2FA0BB;
- font-weight:bold;
+ color: #2FA0BB;
+ font-weight: bold;
}
.neib {
- margin-right:10px;
+ margin-right: 10px;
}
.label {
@@ -136,9 +136,9 @@ span.update-author {
&.label-tag {
background: none;
border: none;
- padding:4px 6px;
- color:#444;
- text-shadow:0 0 1px #fff;
+ padding: 4px 6px;
+ color: #444;
+ text-shadow: 0 0 1px #fff;
&.grouped {
float: left;
@@ -149,9 +149,9 @@ span.update-author {
&.label-issue {
background-color: #eee;
border: 1px solid #ccc;
- padding:4px 6px;
- color:#444;
- text-shadow:0 0 1px #fff;
+ padding: 4px 6px;
+ color: #444;
+ text-shadow: 0 0 1px #fff;
&.grouped {
float: left;
@@ -201,21 +201,21 @@ form {
.field_with_errors {
- display:inline;
+ display: inline;
}
ul.breadcrumb {
- background:white;
- border:none;
+ background: white;
+ border: none;
li {
display: inline;
text-shadow: 0 1px 0 white
}
a {
- color:#474D57;
- font-weight:bold;
- font-size:14px;
+ color: #474D57;
+ font-weight: bold;
+ font-size: 14px;
}
.arrow {
@@ -225,31 +225,31 @@ ul.breadcrumb {
float: left;
position: relative;
left: -10px;
- padding:0;
- margin:0;
+ padding: 0;
+ margin: 0;
}
}
input[type=text] {
&.large_text {
- padding:6px;
- font-size:16px;
+ padding: 6px;
+ font-size: 16px;
}
}
input.git_clone_url {
- width:325px;
+ width: 325px;
}
.merge-request-form-holder {
select {
- width:300px;
+ width: 300px;
}
}
/** Issues **/
#issue_assignee_id {
- width:300px;
+ width: 300px;
}
#new_issue_dialog textarea{
@@ -257,21 +257,21 @@ input.git_clone_url {
}
.project_list_url {
- width:250px;
+ width: 250px;
background:#fff !important;
}
/** bordered list **/
ul.bordered-list {
- margin:5px 0px;
- padding:0px;
+ margin: 5px 0px;
+ padding: 0px;
li {
padding: 5px 0;
border-bottom: 1px solid #EEE;
overflow: hidden;
display: block;
- margin:0px;
+ margin: 0px;
}
}
@@ -287,10 +287,10 @@ ul.bordered-list li:last-child { border:none }
li.commit {
.avatar {
- width:24px;
+ width: 24px;
top:-5px;
- margin-right:10px;
- margin-left:10px;
+ margin-right: 10px;
+ margin-left: 10px;
}
code {
@@ -310,7 +310,7 @@ p.time {
.styled_image {
- border:2px solid #ddd;
+ border: 2px solid #ddd;
}
@@ -337,29 +337,29 @@ p.time {
.leftbar {
h5, .title {
- padding:5px 10px;
+ padding: 5px 10px;
}
h4 {
- font-size:14px;
- padding:2px 10px;
- color:#666;
- border-bottom:1px solid #f1f1f1;
+ font-size: 14px;
+ padding: 2px 10px;
+ color: #666;
+ border-bottom: 1px solid #f1f1f1;
}
- a:last-child h4 { border:none; }
+ a:last-child h4 { border: none; }
a:hover {
h4 {
- color:#111;
- background:$hover;
- border-color:#CCC;
+ color: #111;
+ background: $hover;
+ border-color: #CCC;
.ico.project {
background-position:-209px -21px;
}
}
}
.bottom {
- padding:10px;
+ padding: 10px;
}
}
@@ -374,12 +374,12 @@ p.time {
height: 100%;
}
.bar-success {
+ @include linear-gradient(#62C462, #51A351);
background-color: #468847;
- @include bg-gradient(#62C462, #51A351);
}
.bar-danger {
+ @include linear-gradient(#EE5F5B, #BD362F);
background-color: #B94A48;
- @include bg-gradient(#EE5F5B, #BD362F);
}
}
.upvotes {
@@ -420,17 +420,17 @@ p.time {
.highlight_word {
- background:#EEDC94;
+ background: #EEDC94;
}
.status_info {
- font-size:14px;
- padding:5px 15px;
- line-height:24px;
- width:60px;
- text-align:center;
- float:left;
- margin-right:20px;
+ font-size: 14px;
+ padding: 5px 15px;
+ line-height: 24px;
+ width: 60px;
+ text-align: center;
+ float: left;
+ margin-right: 20px;
&.success {
background: #5BB75B;
@@ -449,12 +449,12 @@ p.time {
.arrow{
background: #E3E5EA;
padding: 5px;
- margin-top:5px;
- border-radius: 5px;
+ margin-top: 5px;
+ @include border-radius(5px);
text-shadow: none;
color: #999;
line-height: 16px;
- font-weight:bold;
+ font-weight: bold;
}
.thin_area{
@@ -462,19 +462,19 @@ p.time {
}
.gitlab_pagination {
- span a { color:$link_color; }
+ span a { color: $link_color; }
.prev, .next, .current, .page a {
- padding:10px;
+ padding: 10px;
}
.current {
- border-bottom:2px solid $style_color;
+ border-bottom: 2px solid $style_color;
}
}
// Fixes alignment on notes.
.new_note {
label {
- text-align:left;
+ text-align: left;
}
}
@@ -486,7 +486,7 @@ li.note {
border-bottom:none !important;
}
.file {
- padding-left:20px;
+ padding-left: 20px;
background:url("icon-attachment.png") no-repeat left center;
}
}
@@ -494,7 +494,7 @@ li.note {
.markdown {
img {
- max-width:100%;
+ max-width: 100%;
}
}
@@ -504,19 +504,19 @@ li.note {
.team_member_show {
td:first-child {
- color:#aaa;
+ color: #aaa;
}
}
.remember_me {
- text-align:left;
+ text-align: left;
input {
- margin:0;
+ margin: 0;
}
span {
- padding-left:5px;
+ padding-left: 5px;
}
}
@@ -530,10 +530,10 @@ li.note {
.data {
a {
h1 {
- line-height:48px;
- font-size:48px;
- padding:20px;
- text-align:center;
+ line-height: 48px;
+ font-size: 48px;
+ padding: 20px;
+ text-align: center;
}
}
}
@@ -541,12 +541,12 @@ li.note {
.rss-icon {
img {
- width:24px;
- vertical-align:top;
+ width: 24px;
+ vertical-align: top;
}
strong {
- line-height:24px;
+ line-height: 24px;
}
}
@@ -554,43 +554,43 @@ li.note {
/* CHZN reset few styles */
.chzn-container-single .chzn-single {
- background:#FFF;
+ background: #FFF;
border: 1px solid #bbb;
- box-shadow:none;
+ box-shadow: none;
}
.chzn-container-active .chzn-single {
- background:#fff;
+ background: #fff;
}
.supp_diff_link,
.mr_show_all_commits {
- cursor:pointer;
+ cursor: pointer;
}
.merge_request,
.issue {
&.today{
background: #EFE;
- border-color:#CEC;
+ border-color: #CEC;
}
&.closed {
background: #F5f5f5;
- border-color:#E5E5E5;
+ border-color: #E5E5E5;
}
&.merged {
background: #F5f5f5;
- border-color:#E5E5E5;
+ border-color: #E5E5E5;
}
}
.git_error_tips {
@extend .span6;
- text-align:left;
- margin-top:40px;
+ text-align: left;
+ margin-top: 40px;
pre {
- background:white;
- border:none;
+ background: white;
+ border: none;
font-size: 12px;
}
}
@@ -602,18 +602,22 @@ li.note {
margin-bottom: 10px;
background: #FEE;
padding-left: 20px;
+
+ &.centered {
+ text-align: center;
+ }
}
.oauth_select_holder {
- padding:20px;
+ padding: 20px;
img {
- padding:5px;
- margin-right:10px;
+ padding: 5px;
+ margin-right: 10px;
}
.active {
img {
- border:1px solid #ccc;
- background:$hover;
+ border: 1px solid #ccc;
+ background: $hover;
@include border-radius(5px);
}
}
@@ -627,29 +631,49 @@ li.note {
.gitlab-promo {
a {
- color:#aaa;
+ color: #aaa;
margin-right: 30px;
}
}
pre {
&.clean {
- background:none;
- border:none;
- margin:0;
- padding:0;
+ background: none;
+ border: none;
+ margin: 0;
+ padding: 0;
}
}
.milestone .progress {
margin-bottom: 0;
- margin-top:4px;
+ margin-top: 4px;
}
.float-link {
- float:left;
- margin-right:15px;
+ float: left;
+ margin-right: 15px;
.s16 {
- margin-right:5px;
+ margin-right: 5px;
}
}
+
+.dashboard-search-filter {
+ padding:5px;
+
+ .search-text-input {
+ float:left;
+ @extend .span2;
+ }
+ .btn {
+ margin-left: 5px;
+ float:left;
+ }
+}
+
+h1.http_status_code {
+ font-size: 56px;
+ line-height: 100px;
+ font-weight: normal;
+ color: #456;
+}
diff --git a/app/assets/stylesheets/fonts.scss b/app/assets/stylesheets/fonts.scss
new file mode 100644
index 00000000000..88c966d18f7
--- /dev/null
+++ b/app/assets/stylesheets/fonts.scss
@@ -0,0 +1,7 @@
+@font-face{
+ font-family: Korolev;
+ src: font-url('korolev-medium-compressed.otf');
+}
+
+/** Typo **/
+$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; \ No newline at end of file
diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
index ae66bd201f8..ecd6cf7e4e8 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss
@@ -15,8 +15,8 @@
@extend .borders;
@extend .prepend-top-20;
@extend .append-bottom-20;
- border-width:1px;
- @include solid_shade;
+ border-width: 1px;
+ @include solid-shade;
img { max-width: 100%; }
@@ -30,27 +30,27 @@
.top_box_content,
.middle_box_content,
.bottom_box_content {
- padding:15px;
+ padding: 15px;
pre {
background: none !important;
- margin:0;
- border:none;
- padding:0;
+ margin: 0;
+ border: none;
+ padding: 0;
}
}
.middle_box_content {
- border-radius:0;
- border:none;
- font-size:12px;
- background-color:#f5f5f5;
- border:none;
- border-top:1px solid #eee;
+ @include border-radius(0);
+ border: none;
+ font-size: 12px;
+ background-color: #f5f5f5;
+ border: none;
+ border-top: 1px solid #eee;
}
.bottom_box_content {
- border-top:1px solid #eee;
+ border-top: 1px solid #eee;
}
}
@@ -59,44 +59,48 @@
*
*/
.ui-box {
- background:#F9F9F9;
+ background: #F9F9F9;
margin-bottom: 25px;
- @include round-borders-all(4px);
+
+ border: 1px solid #eaeaea;
+ @include border-radius(4px);
+
border-color: #CCC;
- @include solid_shade;
+ @include solid-shade;
&.white {
- background:#fff;
+ background: #fff;
}
ul {
- margin:0;
+ margin: 0;
}
h5, .title {
padding: 0 10px;
- @include round-borders-top(4px);
+ @include border-radius(4px 4px 0 0);
@include bg-gray-gradient;
+ border-top: 1px solid #eaeaea;
border-bottom: 1px solid #bbb;
&.small {
line-height: 28px;
font-size: 14px;
- line-height:28px;
+ line-height: 28px;
text-shadow: 0 1px 1px white;
}
form {
- padding:9px 0;
- margin:0px;
+ padding: 9px 0;
+ margin: 0px;
}
.nav-pills {
li {
- padding:3px 0;
- &.active a { background-color:$style_color; }
+ padding: 3px 0;
+ &.active a { background-color: $style_color; }
a {
- border-radius:7px;
+ @include border-radius(7px);
}
}
}
@@ -104,8 +108,8 @@
.bottom {
@include bg-gray-gradient;
- @include round-borders-bottom(4px);
- border-bottom:none;
+ @include border-radius(0 0 4px 4px);
+ border-bottom: none;
border-top: 1px solid #bbb;
}
@@ -116,38 +120,38 @@
padding: 5px 20px;
}
.middle_title {
- background:#f5f5f5;
+ background: #f5f5f5;
margin:20px -20px;
padding: 0 20px;
- border-top:1px solid #eee;
- border-bottom:1px solid #eee;
- font-size:14px;
- color:#777;
+ border-top: 1px solid #eee;
+ border-bottom: 1px solid #eee;
+ font-size: 14px;
+ color: #777;
}
}
.row_title {
- font-weight:bold;
- color:#444;
+ font-weight: bold;
+ color: #444;
&:hover {
- color:#444;
- text-decoration:underline;
+ color: #444;
+ text-decoration: underline;
}
}
li, .wll {
- padding:10px;
+ padding: 10px;
&:first-child {
- @include round-borders-top(4px);
- border-top:none;
+ @include border-radius(4px 4px 0 0);
+ border-top: none;
}
&:last-child {
- @include round-borders-bottom(4px);
- border:none;
+ @include border-radius(0 0 4px 4px);
+ border: none;
}
}
.ui-box-body {
- padding:10px;
+ padding: 10px;
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
index f9249e871b7..883a8773962 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss
@@ -1,42 +1,42 @@
.btn {
- @include bg-gradient(#f7f7f7, #d5d5d5);
- border-color:#aaa;
+ @include linear-gradient(#f7f7f7, #d5d5d5);
+ border-color: #aaa;
&:hover {
@include bg-gray-gradient;
- border-color:#bbb;
- color:#333;
+ border-color: #bbb;
+ color: #333;
}
&.primary {
- background:#2a79A3;
- @include bg-gradient(#47A7b7, #2585b5);
+ background: #2a79A3;
+ @include linear-gradient(#47A7b7, #2585b5);
border-color: #2A79A3;
- color:#fff;
+ color: #fff;
text-shadow: 0 1px 1px #268;
&:hover {
- background:$blue_link;
- color:#fff;
+ background: $primary_color;
+ color: #fff;
}
&.disabled {
- color:#fff;
- background:#29B;
+ color: #fff;
+ background: #29B;
}
}
&.btn-info {
- background:#5aB9C3;
- border-color: $blue_link;
- color:#fff;
+ background: #5aB9C3;
+ border-color: $primary_color;
+ color: #fff;
text-shadow: 0 1px 1px #268;
&:hover {
- background:$blue_link;
- color:#fff;
+ background: $primary_color;
+ color: #fff;
}
&.disabled {
- color:#fff;
- background:#29B;
+ color: #fff;
+ background: #29B;
}
}
@@ -49,8 +49,8 @@
}
&.disabled {
- color:#fff;
- background:#2b2;
+ color: #fff;
+ background: #2b2;
}
}
@@ -60,12 +60,12 @@
}
&.cancel-btn {
- float:right;
+ float: right;
}
&.wide {
- padding-left:30px;
- padding-right:30px;
+ padding-left: 30px;
+ padding-right: 30px;
}
&.danger {
@@ -73,7 +73,7 @@
border-color: #BD362F;
&:hover {
- color:#fff;
+ color: #fff;
background: #EE4E49;
}
}
@@ -87,24 +87,24 @@
}
&.active {
- border-color:#aaa;
- background-color:#ccc;
+ border-color: #aaa;
+ background-color: #ccc;
}
&.very_small {
- font-size:11px;
- padding:2px 6px;
+ font-size: 11px;
+ padding: 2px 6px;
line-height: 16px;
- margin:2px;
+ margin: 2px;
}
&.grouped {
- margin-right:7px;
- float:left;
+ margin-right: 7px;
+ float: left;
}
&.padded {
- margin-right:3px;
- padding:4px 10px 4px;
+ margin-right: 3px;
+ padding: 4px 10px 4px;
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss
index c1b2880140d..9a4f2e80f87 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/common.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -24,7 +24,7 @@
.lborder { border-left:1px solid #eee }
.no-padding { padding:0 !important; }
.underlined { border-bottom: 1px solid #CCC; }
-.no-borders { border:none; }
+.no-borders { border: none; }
.vlink { color: $link_color !important; }
.underlined_link { text-decoration: underline; }
.borders { border: 1px solid #ccc; @include shade; }
@@ -32,32 +32,33 @@
.light { color: #888 }
/** PILLS & TABS**/
-.nav-pills a:hover { background-color:#888; }
+.nav-pills a:hover { background-color: #888; }
.nav-pills .active a { background-color: $style_color; }
-.nav-tabs > li > a, .nav-pills > li > a { color:$style_color; }
+.nav-pills > .active > a > i[class^="icon-"] { background: inherit; }
+.nav-tabs > li > a, .nav-pills > li > a { color: $style_color; }
.nav.nav-tabs {
li {
> a {
- padding:8px 20px;
+ padding: 8px 20px;
margin-right: 7px;
line-height: 19px;
border-color: #EEE;
- color:#888;
+ color: #888;
border-bottom: 1px solid #ddd;
.badge {
background-color: #eee;
- color:#888;
- text-shadow:0 1px 1px #fff;
+ color: #888;
+ text-shadow: 0 1px 1px #fff;
}
i[class^="icon-"] {
- line-height:14px;
+ line-height: 14px;
}
}
&.active {
> a {
border-color: #CCC;
border-bottom: 1px solid #fff;
- color:#333;
+ color: #333;
}
}
}
@@ -69,25 +70,47 @@
.alert-message.error { @extend .alert-error; }
/** AVATARS **/
-img.avatar { float:left; margin-right:12px; width:40px; border:1px solid #ddd; padding:1px; }
-img.avatar.s16 { width:16px; height:16px; margin-right:6px; }
-img.avatar.s24 { width:24px; height:24px; margin-right:8px; }
-img.avatar.s32 { width:32px; height:32px; margin-right:10px; }
-img.lil_av { padding-left: 4px; padding-right:3px; }
+img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #ddd; padding: 1px; }
+img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; }
+img.avatar.s24 { width: 24px; height: 24px; margin-right: 8px; }
+img.avatar.s32 { width: 32px; height: 32px; margin-right: 10px; }
+img.lil_av { padding-left: 4px; padding-right: 3px; }
img.small { width: 80px; }
/** HELPERS **/
-.nothing_here_message { text-align:center; padding:20px; color:#777; }
-p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
+.nothing_here_message {
+ text-align: center;
+ padding: 20px;
+ color: #666;
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 36px;
+}
+
+p.slead { color: #456; font-size: 16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
/** FORMS **/
input[type='search'].search-text-input {
background-image: url("icon-search.png");
background-repeat: no-repeat;
background-position: 10px;
- padding-left:25px;
+ padding-left: 25px;
@include border-radius(4px);
- border:1px solid #ccc;
+ border: 1px solid #ccc;
}
fieldset legend { font-size: 17px; }
+
+ul.nav.nav-projects-tabs {
+ @extend .nav-tabs;
+
+ padding-left: 8px;
+
+ li {
+ a {
+ padding: 4px 20px;
+ margin-top: 2px;
+ border-color: #DDD;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss
index 4887d1c9402..e4924a49456 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/files.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss
@@ -3,9 +3,9 @@
*
*/
.file_holder {
- border:1px solid #BBB;
- margin-bottom:1em;
- @include solid_shade;
+ border: 1px solid #BBB;
+ margin-bottom: 1em;
+ @include solid-shade;
.file_title {
border-bottom: 1px solid #bbb;
@@ -16,33 +16,33 @@
text-align: left;
color: #666;
padding: 9px 10px;
- height:18px;
+ height: 18px;
.options {
- float:right;
+ float: right;
margin-top: -5px;
}
.file_name {
- color:$style_color;
- font-size:14px;
+ color: $style_color;
+ font-size: 14px;
text-shadow: 0 1px 1px #fff;
small {
- color:#999;
- font-size:13px;
+ color: #999;
+ font-size: 13px;
}
}
}
.file_content {
- background:#fff;
+ background: #fff;
font-size: 11px;
&.wiki {
font-size: 13px;
code {
- padding:0 4px;
+ padding: 0 4px;
}
- padding:20px;
+ padding: 20px;
h1, h2 {
line-height: 46px;
}
@@ -52,11 +52,11 @@
}
&.image_file {
- background:#eee;
- text-align:center;
+ background: #eee;
+ text-align: center;
img {
- padding:100px;
- max-width:300px;
+ padding: 100px;
+ max-width: 300px;
}
}
@@ -69,60 +69,60 @@
*/
&.blame {
table {
- border:none;
- box-shadow:none;
- margin:0;
+ border: none;
+ box-shadow: none;
+ margin: 0;
}
tr {
border-bottom: 1px solid #eee;
}
td {
&:first-child {
- border-left:none;
+ border-left: none;
}
&:last-child {
- border-right:none;
+ border-right: none;
}
- background:#fff;
- padding:5px;
+ background: #fff;
+ padding: 5px;
}
.author,
.blame_commit {
- background:#f5f5f5;
- vertical-align:top;
+ background: #f5f5f5;
+ vertical-align: top;
}
.lines {
pre {
- padding:0;
- margin:0;
- background:none;
- border:none;
+ padding: 0;
+ margin: 0;
+ background: none;
+ border: none;
}
}
}
&.logs {
- background:#eee;
+ background: #eee;
max-height: 700px;
overflow-y: auto;
ol {
- margin-left:40px;
+ margin-left: 40px;
padding: 10px 0;
border-left: 1px solid #CCC;
- margin-bottom:0;
+ margin-bottom: 0;
background: white;
li {
- color:#888;
+ color: #888;
p {
- margin:0;
- color:#333;
- line-height:24px;
+ margin: 0;
+ color: #333;
+ line-height: 24px;
padding-left: 10px;
}
&:hover {
- background:$hover;
+ background: $hover;
}
}
}
@@ -142,8 +142,8 @@
table-layout: fixed;
pre {
- background: none;
border: none;
+ border-radius: 0;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
font-size: 12px !important;
line-height: 16px !important;
diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
index 4fe45ecc277..5bd087b080e 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss
@@ -12,21 +12,21 @@ ul {
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- &.smoke { background-color:#f5f5f5; }
+ &.smoke { background-color: #f5f5f5; }
&:hover {
- background:$hover;
- border-bottom:1px solid #ADF;
+ background: $hover;
+ border-bottom: 1px solid #ADF;
}
&:last-child { border:none }
.author { color: #999; }
p {
padding-top: 1px;
- margin:0;
- color:#222;
+ margin: 0;
+ color: #222;
img {
- position:relative;
- top:3px;
+ position: relative;
+ top: 3px;
}
}
}
@@ -35,7 +35,7 @@ ul {
ol, ul {
&.styled {
li {
- padding:2px;
+ padding: 2px;
}
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/tables.scss b/app/assets/stylesheets/gitlab_bootstrap/tables.scss
index 549cdfee5a6..5905efd3aae 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/tables.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/tables.scss
@@ -1,13 +1,13 @@
table {
@extend .table;
@extend .table-striped;
- @include solid_shade;
- border:1px solid #bbb;
- width:100%;
+ @include solid-shade;
+ border: 1px solid #bbb;
+ width: 100%;
&.low {
td {
- line-height:18px;
+ line-height: 18px;
}
}
@@ -31,8 +31,8 @@ table {
}
td {
- border-color:#f1f1f1;
- line-height:28px;
+ border-color: #f1f1f1;
+ line-height: 28px;
.s16 {
margin-top: 5px;
@@ -40,11 +40,11 @@ table {
}
&:first-child {
- border-left:1px solid #bbb;
+ border-left: 1px solid #bbb;
}
&:last-child {
- border-right:1px solid #bbb;
+ border-right: 1px solid #bbb;
}
}
@@ -53,10 +53,10 @@ table {
}
&.lite {
- border:none;
- box-shadow:none;
+ border: none;
+ box-shadow: none;
tr, td {
- border:none;
+ border: none;
background:none !important;
}
}
diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
index fe3bd68b608..81fb79a43f2 100644
--- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss
@@ -5,11 +5,11 @@
h1, h2, h3, h4, h5, h6 { margin: 0; }
h3, h4, h5, h6 { line-height: 36px; }
-h5 { font-size:14px; }
+h5 { font-size: 14px; }
h3.page_title {
- color:#456;
- font-size:20px;
+ color: #456;
+ font-size: 20px;
font-weight: normal;
line-height: 28px;
}
@@ -25,7 +25,7 @@ pre {
&.dark {
background: #333;
- color:#f5f5f5;
+ color: #f5f5f5;
}
}
@@ -37,8 +37,8 @@ a {
outline: none;
color: $link_color;
&:hover {
- text-decoration:none;
- color: $blue_link;
+ text-decoration: none;
+ color: $primary_color;
}
&.btn {
@@ -53,27 +53,31 @@ a {
}
&.lined {
- text-decoration:underline;
- &:hover { text-decoration:underline; }
+ text-decoration: underline;
+ &:hover { text-decoration: underline; }
}
&.gray {
- color:gray;
+ color: gray;
}
&.supp_diff_link {
- text-align:center;
- padding:20px 0;
- background:#f1f1f1;
- width:100%;
- float:left;
+ text-align: center;
+ padding: 20px 0;
+ background: #f1f1f1;
+ width: 100%;
+ float: left;
}
&.neib {
- margin-right:15px;
+ margin-right: 15px;
}
}
a:focus {
outline: none;
}
+
+.monospace {
+ font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
+}
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 0996cc772f4..4196ea7ad29 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,6 +1,8 @@
-.black .lines .highlight {
- background: #333;
- pre { color: #eee; }
+.black .highlight {
+ pre {
+ background-color: #333;
+ color: #eee;
+ }
.hll { display: block; background-color: darken($hover, 65%) }
.c { color: #888888; font-style: italic } /* Comment */
@@ -21,43 +23,43 @@
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #606060 } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */
- .kc{font-weight:bold;} /* Keyword.Constant */
- .kd{font-weight:bold;} /* Keyword.Declaration */
- .kn{font-weight:bold;} /* Keyword.Namespace */
- .kp{font-weight:bold;} /* Keyword.Pseudo */
- .kr{font-weight:bold;} /* Keyword.Reserved */
- .kt{color:#458;font-weight:bold;} /* Keyword.Type */
+ .kc{font-weight: bold;} /* Keyword.Constant */
+ .kd{font-weight: bold;} /* Keyword.Declaration */
+ .kn{font-weight: bold;} /* Keyword.Namespace */
+ .kp{font-weight: bold;} /* Keyword.Pseudo */
+ .kr{font-weight: bold;} /* Keyword.Reserved */
+ .kt{color: #458;font-weight: bold;} /* Keyword.Type */
.m { color: #0000DD; font-weight: bold } /* Literal.Number */
.p { color: #eee; }
.s { color: #0AD; background-color: transparent } /* Literal.String */
- .na{color:#008080;} /* Name.Attribute */
- .nb{color:#0086B3;} /* Name.Builtin */
- .nc{color:#ccc;font-weight:bold;} /* Name.Class */
- .no{color:turquoise;} /* Name.Constant */
- .ni{color:#800080;}
- .ne{color:#900;font-weight:bold;} /* Name.Exception */
- .nf{color:#ccc;font-weight:bold;} /* Name.Function */
- .nn{color:#79C3E0;font-weight:bold;} /* Name.Namespace */
- .nt{color:#fc5;} /* Name.Tag */
- .nv{color:#FA4;} /* Name.Variable */
+ .na{color: #008080;} /* Name.Attribute */
+ .nb{color: #0086B3;} /* Name.Builtin */
+ .nc{color: #ccc;font-weight: bold;} /* Name.Class */
+ .no{color: turquoise;} /* Name.Constant */
+ .ni{color: #800080;}
+ .ne{color: #900;font-weight: bold;} /* Name.Exception */
+ .nf{color: #ccc;font-weight: bold;} /* Name.Function */
+ .nn{color: #79C3E0;font-weight: bold;} /* Name.Namespace */
+ .nt{color: #fc5;} /* Name.Tag */
+ .nv{color: #FA4;} /* Name.Variable */
.py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */
.mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */
- .mi {color:#099;} /* Literal.Number.Integer */
+ .mi {color: #099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */
- .sc{color:#d14;} /* Literal.String.Char */
+ .sc{color: #d14;} /* Literal.String.Char */
.sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */
- .s2{color:orange;} /* Literal.String.Double */
- .se{color:orange;} /* Literal.String.Escape */
- .sh{color:orange;} /* Literal.String.Heredoc */
- .si{color:orange;} /* Literal.String.Interpol */
- .sx{color:orange;} /* Literal.String.Other */
- .sr{color:orange;} /* Literal.String.Regex */
- .s1{color:orange;} /* Literal.String.Single */
- .ss{color:orange;} /* Literal.String.Symbol */
+ .s2{color: orange;} /* Literal.String.Double */
+ .se{color: orange;} /* Literal.String.Escape */
+ .sh{color: orange;} /* Literal.String.Heredoc */
+ .si{color: orange;} /* Literal.String.Interpol */
+ .sx{color: orange;} /* Literal.String.Other */
+ .sr{color: orange;} /* Literal.String.Regex */
+ .s1{color: orange;} /* Literal.String.Single */
+ .ss{color: orange;} /* Literal.String.Symbol */
.bp { color: #D58 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */
.vg { color: #dd7700 } /* Name.Variable.Global */
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index d6792b37e9c..f200e1d7b60 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,6 +1,8 @@
-.white .lines .highlight {
- background: white;
- pre { color: #333; }
+.white .highlight {
+ pre {
+ background-color: #fff;
+ color: #333;
+ }
.hll { display: block; background-color: $hover }
.c { color: #888888; font-style: italic } /* Comment */
@@ -20,42 +22,42 @@
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #606060 } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */
- .kc{font-weight:bold;} /* Keyword.Constant */
- .kd{font-weight:bold;} /* Keyword.Declaration */
- .kn{font-weight:bold;} /* Keyword.Namespace */
- .kp{font-weight:bold;} /* Keyword.Pseudo */
- .kr{font-weight:bold;} /* Keyword.Reserved */
- .kt{color:#458;font-weight:bold;} /* Keyword.Type */
+ .kc{font-weight: bold;} /* Keyword.Constant */
+ .kd{font-weight: bold;} /* Keyword.Declaration */
+ .kn{font-weight: bold;} /* Keyword.Namespace */
+ .kp{font-weight: bold;} /* Keyword.Pseudo */
+ .kr{font-weight: bold;} /* Keyword.Reserved */
+ .kt{color: #458;font-weight: bold;} /* Keyword.Type */
.m { color: #0000DD; font-weight: bold } /* Literal.Number */
.s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
- .na{color:#008080;} /* Name.Attribute */
- .nb{color:#0086B3;} /* Name.Builtin */
- .nc{color:#458;font-weight:bold;} /* Name.Class */
- .no{color:#008080;} /* Name.Constant */
- .ni{color:#800080;}
- .ne{color:#900;font-weight:bold;} /* Name.Exception */
- .nf{color:#900;font-weight:bold;} /* Name.Function */
- .nn{color:#005;font-weight:bold;} /* Name.Namespace */
- .nt{color:#000080;} /* Name.Tag */
- .nv{color:#008080;} /* Name.Variable */
+ .na{color: #008080;} /* Name.Attribute */
+ .nb{color: #0086B3;} /* Name.Builtin */
+ .nc{color: #458;font-weight: bold;} /* Name.Class */
+ .no{color: #008080;} /* Name.Constant */
+ .ni{color: #800080;}
+ .ne{color: #900;font-weight: bold;} /* Name.Exception */
+ .nf{color: #900;font-weight: bold;} /* Name.Function */
+ .nn{color: #005;font-weight: bold;} /* Name.Namespace */
+ .nt{color: #000080;} /* Name.Tag */
+ .nv{color: #008080;} /* Name.Variable */
.py { color: #336699; font-weight: bold } /* Name.Property */
.ow { color: #008800 } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
- .mi {color:#099;} /* Literal.Number.Integer */
+ .mi {color: #099;} /* Literal.Number.Integer */
.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
- .sc{color:#d14;} /* Literal.String.Char */
+ .sc{color: #d14;} /* Literal.String.Char */
.sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
- .s2{color:#d14;} /* Literal.String.Double */
- .se{color:#d14;} /* Literal.String.Escape */
- .sh{color:#d14;} /* Literal.String.Heredoc */
- .si{color:#d14;} /* Literal.String.Interpol */
- .sx{color:#d14;} /* Literal.String.Other */
- .sr{color:#d14;} /* Literal.String.Regex */
- .s1{color:#d14;} /* Literal.String.Single */
- .ss{color:#d14;} /* Literal.String.Symbol */
+ .s2{color: #d14;} /* Literal.String.Double */
+ .se{color: #d14;} /* Literal.String.Escape */
+ .sh{color: #d14;} /* Literal.String.Heredoc */
+ .si{color: #d14;} /* Literal.String.Interpol */
+ .sx{color: #d14;} /* Literal.String.Other */
+ .sr{color: #d14;} /* Literal.String.Regex */
+ .s1{color: #d14;} /* Literal.String.Single */
+ .ss{color: #d14;} /* Literal.String.Symbol */
.bp { color: #003388 } /* Name.Builtin.Pseudo */
.vc { color: #336699 } /* Name.Variable.Class */
.vg { color: #dd7700 } /* Name.Variable.Global */
@@ -63,7 +65,5 @@
}
.shadow {
- -webkit-box-shadow:0 5px 15px #000;
- -moz-box-shadow:0 5px 15px #000;
- box-shadow:0 5px 15px #000;
+ @include box-shadow(0 5px 15px #000);
}
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index 7ae32b3a7d9..bc7a74406ef 100644
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -2,96 +2,31 @@
$baseFontSize: 13px !default;
$baseLineHeight: 18px !default;
+// BOOTSTRAP
@import "bootstrap";
-@import "bootstrap-responsive";
-@import 'font-awesome';
-
-/** GitLab colors **/
-$link_color: #3A89A3;
-$blue_link: #2FA0BB;
-$style_color: #474D57;
-$hover: #D9EDF7;
-$hover_border: #ADF;
-
-/** GitLab Fonts **/
-@font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); }
-$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
-
-/** MIXINS **/
-@mixin shade {
- -moz-box-shadow: 0 0 3px #ddd;
- -webkit-box-shadow: 0 0 3px #ddd;
- box-shadow: 0 0 3px #ddd;
-}
-
-@mixin solid_shade {
- -moz-box-shadow: 0 0 0 3px #f1f1f1;
- -webkit-box-shadow: 0 0 0 3px #f1f1f1;
- box-shadow: 0 0 0 3px #f1f1f1;
-}
-
-@mixin border-radius($radius) {
- -moz-border-radius: $radius;
- -webkit-border-radius: $radius;
- border-radius: $radius;
-}
-
-@mixin round-borders-bottom($radius) {
- border-top: 1px solid #eaeaea;
- -moz-border-radius-bottomright: $radius;
- -moz-border-radius-bottomleft: $radius;
- border-bottom-right-radius: $radius;
- border-bottom-left-radius: $radius;
- -webkit-border-bottom-left-radius: $radius;
- -webkit-border-bottom-right-radius: $radius;
-}
-
-@mixin round-borders-top($radius) {
- border-top: 1px solid #eaeaea;
- -moz-border-radius-topright: $radius;
- -moz-border-radius-topleft: $radius;
- border-top-right-radius: $radius;
- border-top-left-radius: $radius;
- -webkit-border-top-left-radius: $radius;
- -webkit-border-top-right-radius: $radius;
-}
-
-@mixin round-borders-all($radius) {
- border: 1px solid #eaeaea;
- -moz-border-radius: $radius;
- -webkit-border-radius: $radius;
- border-radius: $radius;
-}
-
-@mixin bg-gradient($from, $to) {
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to));
- background-image: -webkit-linear-gradient($from, $to);
- background-image: -moz-linear-gradient($from, $to);
- background-image: -o-linear-gradient($from, $to);
-}
-
-@mixin bg-light-gray-gradient {
- background:#f1f1f1;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1));
- background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
- background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
- background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
-}
-
-@mixin bg-gray-gradient {
- background:#eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
-}
-
-@mixin bg-dark-gray-gradient {
- background:#eee;
- background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
- background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
- background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
-}
+@import "bootstrap/responsive-utilities";
+@import "bootstrap/responsive-1200px-min";
+
+// FONT AWESOME
+@import "font-awesome";
+
+/**
+ * Variables
+ * Contains colors
+ */
+@import "variables.scss";
+
+/**
+ * Custom fonts
+ * Contains @font-face font Korolev and default $monotype
+ */
+@import "fonts.scss";
+
+/**
+ * General mixins.
+ * Contains rounded borders, gradients and shades
+ */
+@import "mixins.scss";
/**
* Header of application.
diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss
new file mode 100644
index 00000000000..441a85f3410
--- /dev/null
+++ b/app/assets/stylesheets/mixins.scss
@@ -0,0 +1,60 @@
+/**
+ * Generic mixins
+ */
+ @mixin box-shadow($shadow) {
+ -webkit-box-shadow: $shadow;
+ -moz-box-shadow: $shadow;
+ -ms-box-shadow: $shadow;
+ -o-box-shadow: $shadow;
+ box-shadow: $shadow;
+}
+
+@mixin border-radius($radius) {
+ -webkit-border-radius: $radius;
+ -moz-border-radius: $radius;
+ -ms-border-radius: $radius;
+ -o-border-radius: $radius;
+ border-radius: $radius;
+}
+
+@mixin linear-gradient($from, $to) {
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to));
+ background-image: -webkit-linear-gradient($from, $to);
+ background-image: -moz-linear-gradient($from, $to);
+ background-image: -o-linear-gradient($from, $to);
+}
+
+/**
+ * Prefilled mixins
+ * Mixins with fixed values
+ */
+@mixin bg-light-gray-gradient {
+ background: #f1f1f1;
+ background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1));
+ background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
+ background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
+ background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
+}
+
+@mixin bg-gray-gradient {
+ background: #eee;
+ background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
+ background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
+}
+
+@mixin bg-dark-gray-gradient {
+ background: #eee;
+ background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
+ background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
+ background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
+}
+
+@mixin shade {
+ @include box-shadow(0 0 3px #ddd);
+}
+
+@mixin solid-shade {
+ @include box-shadow(0 0 0 3px #f1f1f1);
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/ref_select.scss
index 377d008605e..284d1c324e5 100644
--- a/app/assets/stylesheets/ref_select.scss
+++ b/app/assets/stylesheets/ref_select.scss
@@ -1,6 +1,6 @@
/** Branch/tag selector **/
.project-refs-form {
- margin:0;
+ margin: 0;
span {
background:none !important;
position:static !important;
@@ -9,7 +9,7 @@
}
}
.project-refs-select {
- width:120px;
+ width: 120px;
}
.project-refs-form .chzn-container {
@@ -21,10 +21,10 @@
.chzn-drop {
min-width: 400px;
.chzn-results {
- max-height:300px;
+ max-height: 300px;
}
.chzn-search input {
- min-width:365px;
+ min-width: 365px;
}
}
}
@@ -33,21 +33,19 @@
.chzn-container {
.chzn-search {
input:focus {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
+ @include box-shadow(none);
}
}
.chzn-drop {
- margin:7px 0;
+ margin: 7px 0;
min-width: 200px;
border: 1px solid #bbb;
- border-radius:0;
+ @include border-radius(0);
.chzn-results {
margin-top: 5px;
- max-height:300px;
+ max-height: 300px;
.group-result {
color: $style_color;
@@ -55,7 +53,7 @@
padding: 8px;
}
.active-result {
- border-radius: 0;
+ @include border-radius(0);
&.highlighted {
background: $hover;
@@ -71,7 +69,7 @@
.chzn-search {
@include bg-gray-gradient;
input {
- min-width:165px;
+ min-width: 165px;
border-color: #CCC;
}
}
@@ -81,8 +79,8 @@
@include bg-light-gray-gradient;
div {
- background:transparent;
- border-left:none;
+ background: transparent;
+ border-left: none;
}
span {
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index 9cce5bd0389..bf405bfcd51 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -6,14 +6,14 @@
.commit-title {
line-height: 26px;
- margin:0;
+ margin: 0;
}
.commit-description {
font-size: 14px;
border: none;
background-color: white;
- padding-top:10px;
+ padding-top: 10px;
}
.browse-button {
@@ -28,9 +28,9 @@
@extend .clearfix;
.sha-block {
- text-align:right;
+ text-align: right;
&:first-child {
- padding-bottom:6px;
+ padding-bottom: 6px;
}
a {
@@ -49,10 +49,10 @@
.author a,
.committer a {
- font-size:14px;
- line-height:22px;
- text-shadow:0 1px 1px #fff;
- color:#777;
+ font-size: 14px;
+ line-height: 22px;
+ text-shadow: 0 1px 1px #fff;
+ color: #777;
&:hover {
color: #999;
}
@@ -70,15 +70,16 @@
*
*/
.diff_file {
- border:1px solid #CCC;
- margin-bottom:1em;
+ border: 1px solid #CCC;
+ margin-bottom: 1em;
.diff_file_header {
@extend .clearfix;
padding: 5px 5px 5px 10px;
color: #555;
- border-bottom:1px solid #CCC;
+ border-bottom: 1px solid #CCC;
background: #eee;
+ // TODO Replace with linear-gradient mixin
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
@@ -86,7 +87,7 @@
> span {
font-family: $monospace;
- font-size:14px;
+ font-size: 14px;
line-height: 30px;
}
@@ -104,36 +105,36 @@
}
}
.diff_file_content {
- overflow:auto;
- overflow-y:hidden;
- background:#fff;
- color:#333;
+ overflow: auto;
+ overflow-y: hidden;
+ background: #fff;
+ color: #333;
font-size: 12px;
font-family: $monospace;
.old{
span.idiff{
- background-color:#FAA;
+ background-color: #FAA;
}
}
.new{
span.idiff{
- background-color:#AFA;
+ background-color: #AFA;
}
}
table {
td {
- line-height:18px;
+ line-height: 18px;
}
}
}
.diff_file_content_image {
- background:#eee;
- text-align:center;
+ background: #eee;
+ text-align: center;
.image {
display: inline-block;
- margin:50px;
- max-width:400px;
+ margin: 50px;
+ max-width: 400px;
img{
background: url('trans_bg.gif');
@@ -158,7 +159,7 @@
&.img_compared {
.image {
- max-width:300px;
+ max-width: 300px;
}
}
}
@@ -166,46 +167,46 @@
.diff_file_content{
table {
- border:none;
- margin:0px;
- padding:0px;
+ border: none;
+ margin: 0px;
+ padding: 0px;
tr {
td {
- font-size:12px;
+ font-size: 12px;
}
}
}
.old_line, .new_line {
- margin:0px;
- padding:0px;
- border:none;
- background:#EEE;
- color:#666;
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ background: #EEE;
+ color: #666;
padding: 0px 5px;
border-right: 1px solid #ccc;
- text-align:right;
- min-width:35px;
- max-width:35px;
- width:35px;
+ text-align: right;
+ min-width: 35px;
+ max-width: 35px;
+ width: 35px;
moz-user-select: none;
-khtml-user-select: none;
user-select: none;
a {
- float:left;
- width:35px;
- font-weight:normal;
- color:#666;
+ float: left;
+ width: 35px;
+ font-weight: normal;
+ color: #666;
&:hover {
- text-decoration:underline;
+ text-decoration: underline;
}
}
}
.line_content {
- white-space:pre;
- height:14px;
- margin:0px;
- padding:0px;
- border:none;
+ white-space: pre;
+ height: 14px;
+ margin: 0px;
+ padding: 0px;
+ border: none;
&.new {
background: #CFD;
}
@@ -213,8 +214,8 @@
background: #FDD;
}
&.matched {
- color:#ccc;
- background:#fafafa;
+ color: #ccc;
+ background: #fafafa;
}
}
}
@@ -232,28 +233,28 @@
.browse_code_link_holder {
@extend .span2;
- float:right;
+ float: right;
}
.committed_ago {
- float:right;
+ float: right;
@extend .cgray;
}
.notes_count {
- float:right;
+ float: right;
margin: -6px 8px 6px;
}
code {
- background:#FCEEC1;
- color:$style_color;
+ background: #FCEEC1;
+ color: $style_color;
}
.commit_short_id {
- float:left;
+ float: left;
@extend .lined;
- min-width:65px;
+ min-width: 65px;
font-family: $monospace;
}
@@ -294,11 +295,10 @@
}
.label_commit {
- @include round-borders-all(4px);
- padding:2px 4px;
- border:none;
- font-size:13px;
+ @include border-radius(4px);
+ padding: 2px 4px;
+ font-size: 13px;
background: #474D57;
- color:#fff;
+ color: #fff;
font-family: $monospace;
}
diff --git a/app/assets/stylesheets/sections/editor.scss b/app/assets/stylesheets/sections/editor.scss
index 711dc0d8e43..a71e5438936 100644
--- a/app/assets/stylesheets/sections/editor.scss
+++ b/app/assets/stylesheets/sections/editor.scss
@@ -1,7 +1,7 @@
.file-editor {
#editor{
border: none;
- border-radius: 0;
+ @include border-radius(0);
height: 500px;
margin: 0;
padding: 0;
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index 369ebc81e31..28551d9a6ee 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -4,25 +4,25 @@
*/
.event_label {
&.pushed {
- padding:0 2px;
+ padding: 0 2px;
}
&.opened {
- padding:0 2px;
+ padding: 0 2px;
}
&.closed {
- padding:0 2px;
+ padding: 0 2px;
}
&.merged {
- padding:0 2px;
+ padding: 0 2px;
}
&.left,
&.joined {
- padding:0 2px;
- float:none;
+ padding: 0 2px;
+ float: none;
}
}
@@ -31,26 +31,26 @@
*
*/
.event-item {
- min-height:40px;
- border-bottom:1px solid #eee;
+ min-height: 40px;
+ border-bottom: 1px solid #eee;
.event-title {
- color:#333;
+ color: #333;
font-weight: bold;
.author_name {
- color:#333;
+ color: #333;
}
}
.event-body {
p {
- color:#555;
+ color: #555;
padding-top: 5px;
}
.event-info {
- color:#666;
+ color: #666;
}
}
.avatar {
- width:32px;
+ width: 32px;
}
.event_icon {
float: right;
@@ -59,15 +59,15 @@
@include border-radius(5px);
background: #F9F9F9;
img {
- width:20px;
+ width: 20px;
}
}
ul {
- margin-left:50px;
- margin-bottom:5px;
+ margin-left: 50px;
+ margin-bottom: 5px;
.avatar {
- width:18px;
- margin-top:3px;
+ width: 18px;
+ margin-top: 3px;
}
}
@@ -81,9 +81,9 @@
li {
&.commit {
background: transparent;
- padding:3px;
- border:none;
- font-size:12px;
+ padding: 3px;
+ border: none;
+ font-size: 12px;
}
&.commits-stat {
display: block;
@@ -98,15 +98,15 @@
*
*/
.event_lp {
- color:#777;
- padding:10px;
- min-height:22px;
+ color: #777;
+ padding: 10px;
+ min-height: 22px;
border-left: 5px solid #5AB9C3;
- margin-bottom:20px;
- background:#f9f9f9;
+ margin-bottom: 20px;
+ background: #f9f9f9;
.avatar {
- width:24px;
+ width: 24px;
}
.btn-new-mr {
@@ -133,7 +133,7 @@
background: #f9f9f9;
margin-bottom: 10px;
img {
- width:20px;
+ width: 20px;
}
&.inactive {
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss
index 2aa4463e45e..5800098ade4 100644
--- a/app/assets/stylesheets/sections/graph.scss
+++ b/app/assets/stylesheets/sections/graph.scss
@@ -1,10 +1,10 @@
.graph_holder {
border: 1px solid #aaa;
- padding:1px;
+ padding: 1px;
h4 {
- padding:0 10px;
+ padding: 0 10px;
border-bottom: 1px solid #bbb;
@include bg-gray-gradient;
}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index 0db40ec9ac7..4171c00ab8b 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -5,7 +5,7 @@
header {
&.navbar-gitlab {
.navbar-inner {
- height:45px;
+ height: 45px;
padding: 5px;
background: #F1F1F1;
@@ -24,8 +24,8 @@ header {
}
}
- z-index:10;
- /*height:60px;*/
+ z-index: 10;
+ /*height: 60px;*/
/**
*
@@ -33,24 +33,24 @@ header {
*
*/
.app_logo {
- width:170px;
- float:left;
+ width: 170px;
+ float: left;
a {
- float:left;
+ float: left;
padding: 0px;
h1 {
- width:90px;
+ width: 90px;
background: url('logo_dark.png') no-repeat 0px 2px;
- float:left;
- margin-left:2px;
- font-size:30px;
- line-height:48px;
- font-weight:normal;
- color:$style_color;
+ float: left;
+ margin-left: 2px;
+ font-size: 30px;
+ line-height: 48px;
+ font-weight: normal;
+ color: $style_color;
text-shadow: 0 1px 1px #FFF;
- padding-left:45px;
- height:40px;
+ padding-left: 45px;
+ height: 40px;
font-family: 'Korolev', sans-serif;
}
}
@@ -62,14 +62,14 @@ header {
*
*/
.project_name {
- position:relative;
- float:left;
- margin:0;
- margin-right:30px;
- font-size:30px;
- line-height:48px;
- font-weight:normal;
- color:$style_color;
+ position: relative;
+ float: left;
+ margin: 0;
+ margin-right: 30px;
+ font-size: 30px;
+ line-height: 48px;
+ font-weight: normal;
+ color: $style_color;
text-shadow: 0 1px 1px #FFF;
font-family: 'Korolev', sans-serif;
}
@@ -81,7 +81,7 @@ header {
*/
.search {
margin-right: 45px;
- margin-left:10px;
+ margin-left: 10px;
margin-top: 2px;
.search-input {
@@ -89,11 +89,11 @@ header {
background-image: url("icon-search.png");
background-repeat: no-repeat;
background-position: 10px;
- padding-left:25px;
+ padding-left: 25px;
font-size: 13px;
@include border-radius(3px);
- border:1px solid #c6c6c6;
- box-shadow:none;
+ border: 1px solid #c6c6c6;
+ box-shadow: none;
&:focus {
@extend .span3;
}
@@ -122,7 +122,7 @@ header {
width: 28px;
height: 28px;
display: block;
- top:1px;
+ top: 1px;
&:after {
content: " ";
display: block;
@@ -132,12 +132,15 @@ header {
left: 0;
bottom: 0;
float: right;
- border-radius: 5px;
+ @include border-radius(5px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: 0;
- background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.15)), to(rgba(0, 0, 0, 0.25))), -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(255, 255, 255, 0)), color-stop(0.5, rgba(255, 255, 255, 0.1)), color-stop(0.501, rgba(255, 255, 255, 0)), color-stop(1, rgba(255, 255, 255, 0)));
- background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)), -moz-linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0));
- background: linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)), linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0));
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.15)), to(rgba(0, 0, 0, 0.25))),
+ -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(255, 255, 255, 0)), color-stop(0.5, rgba(255, 255, 255, 0.1)), color-stop(0.501, rgba(255, 255, 255, 0)), color-stop(1, rgba(255, 255, 255, 0)));
+ background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)),
+ -moz-linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0));
+ background: linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)),
+ linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0));
-webkit-background-origin: border-box;
-moz-background-origin: border;
background-origin: border-box; } } }
@@ -149,7 +152,7 @@ header {
display: block; } }
.account-links {
- border-radius: 5px;
+ @include border-radius(5px);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
position: relative;
&:before {
@@ -184,7 +187,7 @@ header {
border-bottom: 1px solid #666;
font-size: 12px;
&:hover {
- color:#fff;
+ color: #fff;
background: #333;
}
}
@@ -197,20 +200,13 @@ header {
.account-links a {
&:first-child {
- -webkit-border-top-left-radius: 5px;
- -webkit-border-top-right-radius: 5px;
- -moz-border-radius-topleft: 5px;
- -moz-border-radius-topright: 5px;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px; }
+ @include border-radius(5px 5px 0 0);
+ }
&:last-child {
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
- -moz-border-radius-bottomright: 5px;
- -moz-border-radius-bottomleft: 5px;
- border-bottom-right-radius: 5px;
- border-bottom-left-radius: 5px;
- border-bottom: 0; } }
+ @include border-radius(0 0 5px 5px);
+ border-bottom: 0;
+ }
+ }
@@ -248,13 +244,13 @@ header {
a {
h1 {
background: url('logo_white.png') no-repeat 0px 2px;
- color:#fff;
+ color: #fff;
text-shadow: 0 1px 1px #111;
}
}
}
.project_name {
- color:#fff;
+ color: #fff;
text-shadow: 0 1px 1px #111;
}
}
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index 93622d6149a..ca1aab44916 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -3,7 +3,7 @@
.issue_title {
@extend .top_box_content;
.clearfix {
- margin-bottom:0px;
+ margin-bottom: 0px;
input {
@extend .span8;
}
@@ -11,14 +11,14 @@
}
.issue_middle_block {
@extend .middle_box_content;
- height:30px;
+ height: 30px;
.issue_assignee {
@extend .span6;
- float:left;
+ float: left;
}
.issue_milestone {
@extend .span4;
- float:left;
+ float: left;
}
}
.issue_description {
@@ -28,31 +28,31 @@
.issues_table {
.issue {
- padding:7px 10px;
+ padding: 7px 10px;
.issue_check {
- float:left;
+ float: left;
padding: 8px 0;
padding-right: 8px;
min-width: 15px;
}
p {
- padding-top:0;
- padding-bottom:2px;
+ padding-top: 0;
+ padding-bottom: 2px;
}
img.avatar {
- width:32px;
- margin-top:1px;
+ width: 32px;
+ margin-top: 1px;
}
}
}
input.check_all_issues {
- float:left;
+ float: left;
padding: 0;
- margin:0;
+ margin: 0;
margin-right: 10px;
position: relative;
top: 8px;
@@ -82,16 +82,16 @@ input.check_all_issues {
}
}
-@media (min-width: 800px) { .issues_filters select { width:160px; } }
-@media (min-width: 1000px) { .issues_filters select { width:200px; } }
-@media (min-width: 1200px) { .issues_filters select { width:220px; } }
+@media (min-width: 800px) { .issues_filters select { width: 160px; } }
+@media (min-width: 1000px) { .issues_filters select { width: 200px; } }
+@media (min-width: 1200px) { .issues_filters select { width: 220px; } }
#issues-table-holder {
.issues_filters {
form {
- padding:0;
- margin:0;
+ padding: 0;
+ margin: 0;
margin-top:7px
}
}
@@ -99,27 +99,27 @@ input.check_all_issues {
.issues_bulk_update {
margin: 0;
form {
- padding:0;
- margin:0;
+ padding: 0;
+ margin: 0;
margin-top:7px
}
.update_selected_issues {
- position:relative;
+ position: relative;
top:-2px;
- margin-left:4px;
- float:left;
+ margin-left: 4px;
+ float: left;
}
.update_issues_text {
- padding:3px;
+ padding: 3px;
line-height: 18px;
- float:left;
+ float: left;
}
}
}
#update_status {
- width:100px;
+ width: 100px;
}
@@ -136,11 +136,11 @@ input.check_all_issues {
*/
.ui-datepicker {
- border:none;
- box-shadow:none;
+ border: none;
+ box-shadow: none;
.ui-datepicker-header {
- @include solid_shade;
- margin-bottom:10px;
- border:1px solid #bbb;
+ @include solid-shade;
+ margin-bottom: 10px;
+ border: 1px solid #bbb;
}
}
diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss
index 5b8763cfec0..8c21de70013 100644
--- a/app/assets/stylesheets/sections/login.scss
+++ b/app/assets/stylesheets/sections/login.scss
@@ -1,13 +1,13 @@
/* Login Page */
body.login-page{
padding-top: 10%;
- background:#f1f1f1;
+ background: #f1f1f1;
}
.login-box{
width: 304px;
position: relative;
- border-radius: 5px;
+ @include border-radius(5px);
margin: auto;
padding: 20px;
background: white;
@@ -18,25 +18,15 @@ body.login-page{
display: block;
}
-.login-box input.text{background-color: #f1f1f1; font-size: 16px; border-radius: 0; padding: 14px 10px; width: 280px}
+.login-box input.text{background-color: #f1f1f1; font-size: 16px; @include border-radius(0); padding: 14px 10px; width: 280px}
.login-box input.text.top{
- -webkit-border-top-left-radius: 5px;
- -webkit-border-top-right-radius: 5px;
- -moz-border-radius-topleft: 5px;
- -moz-border-radius-topright: 5px;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- margin-bottom:0px;
+ @include border-radius(5px 5px 0 0);
+ margin-bottom: 0px;
}
.login-box input.text.bottom{
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
- -moz-border-radius-bottomright: 5px;
- -moz-border-radius-bottomleft: 5px;
- border-bottom-right-radius: 5px;
- border-bottom-left-radius: 5px;
+ @include border-radius(0 0 5px 5px);
border-top: 0;
margin-bottom: 20px;
}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 9087e7c2f59..a5ec1756e5f 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -5,10 +5,10 @@
.mr_branch_box {
@extend .ui-box;
- margin-bottom:20px;
+ margin-bottom: 20px;
.body {
- background:#f1f1f1;
+ background: #f1f1f1;
}
}
@@ -23,31 +23,30 @@
}
form {
- margin-bottom:0;
+ margin-bottom: 0;
.clearfix {
- margin-bottom:0;
+ margin-bottom: 0;
}
}
.accept_group {
- float:left;
+ float: left;
border: 1px solid #ADA;
padding: 2px;
@include border-radius(5px);
- border-radius: 5px;
background: #CEB;
.accept_merge_request {
- font-size:13px;
- float:left;
+ font-size: 13px;
+ float: left;
}
.remove_branch_holder {
- margin-left:20px;
- margin-right:10px;
- float:left;
+ margin-left: 20px;
+ margin-right: 10px;
+ float: left;
}
label {
- color:#444;
+ color: #444;
}
}
@@ -60,15 +59,15 @@
.mr_nav_tabs {
li {
a {
- font-weight:bold;
- padding:8px 20px;
- text-align:center;
+ font-weight: bold;
+ padding: 8px 20px;
+ text-align: center;
}
}
}
li.merge_request {
- padding:7px 10px;
+ padding: 7px 10px;
img.avatar {
width: 32px;
margin-top: 1px;
@@ -85,35 +84,35 @@ li.merge_request {
}
.label_branch {
- @include round-borders-all(4px);
- padding:2px 4px;
- border:none;
- font-size:14px;
+ @include border-radius(4px);
+ padding: 2px 4px;
+ border: none;
+ font-size: 14px;
background: #474D57;
- color:#fff;
+ color: #fff;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
}
.mr_source_commit,
.mr_target_commit {
.commit {
- margin:0;
- padding:0;
+ margin: 0;
+ padding: 0;
padding: 5px;
margin-bottom: 5px;
.avatar { position:relative }
.row_title {
- color:#444;
+ color: #444;
}
.commit-author-name,
.dash,
.committed_ago,
.browse_code_link_holder {
- display:none;
+ display: none;
}
- list-style:none;
+ list-style: none;
&:hover {
- background:none;
+ background: none;
}
}
}
@@ -126,14 +125,14 @@ li.merge_request {
@extend .main_box;
.merge_requests_middle_box {
@extend .middle_box_content;
- height:30px;
+ height: 30px;
.merge_requests_assignee {
@extend .span6;
- float:left;
+ float: left;
}
.merge_requests_milestone {
@extend .span4;
- float:left;
+ float: left;
}
}
}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 5707216922c..595568fc059 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -3,36 +3,35 @@
*
*/
ul.main_menu {
- border-radius: 4px;
+ @include border-radius(4px);
margin: auto;
- margin:30px 0;
- border:1px solid #BBB;
- height:37px;
+ margin: 30px 0;
+ border: 1px solid #BBB;
+ height: 37px;
@include bg-gray-gradient;
- position:relative;
- overflow:hidden;
+ position: relative;
+ overflow: hidden;
@include shade;
.count {
position: relative;
- top: -1px;
- display: inline-block;
- height: 15px;
- margin: 0 0 0 5px;
- padding: 0 8px 1px 8px;
- height: auto;
- font-size: 0.82em;
- line-height: 14px;
- text-align: center;
- color: #777;
- background: #f2f2f2;
- border-top: 1px solid #CCC;
- border-radius: 8px;
- -moz-border-radius: 8px;
+ top: -1px;
+ display: inline-block;
+ height: 15px;
+ margin: 0 0 0 5px;
+ padding: 0 8px 1px 8px;
+ height: auto;
+ font-size: 0.82em;
+ line-height: 14px;
+ text-align: center;
+ color: #777;
+ background: #f2f2f2;
+ border-top: 1px solid #CCC;
+ @include border-radius(8px);
}
.label {
- background:$hover;
- text-shadow:none;
- color:$style_color;
+ background: $hover;
+ text-shadow: none;
+ color: $style_color;
}
li {
list-style-type: none;
@@ -41,26 +40,21 @@ ul.main_menu {
width: 1%;
border-right: 1px solid #DDD;
border-left: 1px solid #EEE;
- border-bottom:2px solid #CFCFCF;
+ border-bottom: 2px solid #CFCFCF;
&:first-child{
- -webkit-border-top-left-radius: 4px;
- -webkit-border-bottom-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- -moz-border-radius-bottomleft: 4px;
- border-top-left-radius: 4px;
- border-bottom-left-radius: 4px;
+ @include border-radius(5px 0 0 5px);
border-left: 0;
}
&.active {
- background-color:#D5D5D5;
+ background-color: #D5D5D5;
border-right: 1px solid #BBB;
border-left: 1px solid #BBB;
- border-radius: 0 0 1px 1px;
+ @include border-radius(0 0 1px 1px);
&:first-child{
- border-bottom:none;
- border-left:none;
+ border-bottom: none;
+ border-left: none;
}
}
@@ -68,10 +62,10 @@ ul.main_menu {
a {
background: url(home_icon.PNG) no-repeat center center;
text-indent:-9999px;
- min-width:20px;
+ min-width: 20px;
img {
- position:relative;
- top:4px;
+ position: relative;
+ top: 4px;
}
}
}
@@ -79,12 +73,12 @@ ul.main_menu {
a {
display: block;
text-align: center;
- font-weight:bold;
- height:35px;
- line-height:36px;
+ font-weight: bold;
+ height: 35px;
+ line-height: 36px;
color: $style_color;
- text-shadow:0 1px 1px white;
- padding:0 10px;
+ text-shadow: 0 1px 1px white;
+ padding: 0 10px;
}
}
/*
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index d24d070df1e..0c2a56d62f5 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -4,30 +4,30 @@
*/
#notes-list,
#new-notes-list {
- display:block;
- list-style:none;
- margin:0px;
- padding:0px;
+ display: block;
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
}
.issue_notes,
.wiki_notes {
.note_content {
- float:left;
- width:400px;
+ float: left;
+ width: 400px;
}
}
/* Note textare */
#note_note {
- height:80px;
- width:99%;
- font-size:14px;
+ height: 80px;
+ width: 99%;
+ font-size: 14px;
}
#new_note {
.attach_holder {
- display:none;
+ display: none;
}
}
@@ -36,34 +36,34 @@
border: 1px solid #ddd;
padding: 10px;
min-height: 60px;
- background:#f5f5f5;
+ background: #f5f5f5;
}
.note {
padding: 8px 0;
overflow: hidden;
display: block;
- position:relative;
+ position: relative;
img {float: left; margin-right: 10px;}
- img.emoji {float:none;margin:0;}
+ img.emoji {float: none;margin: 0;}
.note-author cite{font-style: italic;}
- p { color:$style_color; }
+ p { color: $style_color; }
.note-author { color: $style_color;}
- .note-title { margin-left:45px; padding-top: 5px;}
+ .note-title { margin-left: 45px; padding-top: 5px;}
.avatar {
- margin-top:3px;
+ margin-top: 3px;
}
.delete-note {
- display:none;
- position:absolute;
- right:0;
- top:0;
+ display: none;
+ position: absolute;
+ right: 0;
+ top: 0;
}
&:hover {
- .delete-note { display:block; }
+ .delete-note { display: block; }
}
}
#notes-list:not(.reversed) .note,
@@ -94,30 +94,31 @@ p.notify_controls span{
}
tr.line_notes_row {
- border-bottom:1px solid #DDD;
+ border-bottom: 1px solid #DDD;
border-left: 7px solid #2A79A3;
&.reply {
- background:#eee;
+ background: #eee;
border-left: 7px solid #2A79A3;
- border-top:1px solid #ddd;
+ border-top: 1px solid #ddd;
td {
- padding:7px 10px;
+ padding: 7px 10px;
}
a.line_note_reply_link {
- @include round-borders-all(4px);
+ border: 1px solid #eaeaea;
+ @include border-radius(4px);
padding: 3px 10px;
- margin-left:5px;
+ margin-left: 5px;
color: white;
background: #2A79A3;
border-color: #2A79A3;
}
}
ul {
- margin:0;
+ margin: 0;
li {
- padding:0;
- border:none;
+ padding: 0;
+ border: none;
}
}
}
@@ -125,28 +126,28 @@ tr.line_notes_row {
.line_notes_row, .per_line_form { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
.per_line_form {
- background:#f5f5f5;
- border-top:1px solid #eee;
+ background: #f5f5f5;
+ border-top: 1px solid #eee;
form { margin: 0; }
td {
- border-bottom:1px solid #ddd;
+ border-bottom: 1px solid #ddd;
}
.note_actions {
- margin:0;
+ margin: 0;
padding-top: 10px;
.buttons {
- float:left;
- width:300px;
+ float: left;
+ width: 300px;
}
.options {
.labels {
- float:left;
- padding-left:10px;
+ float: left;
+ padding-left: 10px;
label {
padding: 6px 0;
margin: 0;
- width:120px;
+ width: 120px;
}
}
}
@@ -154,13 +155,13 @@ tr.line_notes_row {
}
td .line_note_link {
- position:absolute;
+ position: absolute;
margin-left:-70px;
margin-top:-10px;
- z-index:10;
+ z-index: 10;
background: url("comment_add.png") no-repeat left 0;
- width:32px;
- height:32px;
+ width: 32px;
+ height: 32px;
opacity: 0.0;
filter: alpha(opacity=0);
@@ -180,13 +181,13 @@ td .line_note_link {
.new_note {
.input-file {
font: 500px monospace;
- opacity:0;
+ opacity: 0;
filter: alpha(opacity=0);
position: absolute;
z-index: 1;
- top:0;
- right:0;
- padding:0;
+ top: 0;
+ right: 0;
+ padding: 0;
margin: 0;
}
@@ -198,24 +199,24 @@ td .line_note_link {
}
.attachments {
- position:relative;
+ position: relative;
width: 350px;
height: 50px;
- overflow:hidden;
+ overflow: hidden;
margin:0 0 5px !important;
.input_file {
.file_upload {
position: absolute;
- right:14px;
- top:7px;
+ right: 14px;
+ top: 7px;
}
.file_name {
- line-height:30px;
- width:240px;
- height:28px;
- overflow:hidden;
+ line-height: 30px;
+ width: 240px;
+ height: 28px;
+ overflow: hidden;
}
.input-file {
width: 260px;
@@ -228,5 +229,5 @@ td .line_note_link {
.note-text {
border: 1px solid #aaa;
- box-shadow:none;
+ box-shadow: none;
}
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index e945ca00918..607daf7a97e 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -1,21 +1,21 @@
.profile_history {
.event_feed {
- min-height:20px;
+ min-height: 20px;
.avatar {
- width:20px;
+ width: 20px;
}
}
}
.profile_avatar_holder {
- float:left;
- width:60px;
- height:60px;
- margin-right:20px;
+ float: left;
+ width: 60px;
+ height: 60px;
+ margin-right: 20px;
img {
- width:60px;
- height:60px;
- background:#fff;
+ width: 60px;
+ height: 60px;
+ background: #fff;
padding: 1px;
border: 1px solid #ddd;
}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index c9d386ab5bb..452fbc2bdfb 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -10,38 +10,38 @@
.groups_box,
.projects_box {
h5 {
- color:$style_color;
- font-size:16px;
+ color: $style_color;
+ font-size: 16px;
text-shadow: 0 1px 1px #fff;
padding: 2px 10px;
- line-height:32px;
- font-size:14px;
+ line-height: 32px;
+ font-size: 14px;
}
ul {
li {
- padding:0;
+ padding: 0;
a {
- display:block;
+ display: block;
.group_name {
- font-size:14px;
- line-height:18px;
+ font-size: 14px;
+ line-height: 18px;
}
.project_name {
- color:#4fa2bd;
- font-size:14px;
- line-height:18px;
+ color: #4fa2bd;
+ font-size: 14px;
+ line-height: 18px;
}
.arrow {
- float:right;
- padding:10px;
- margin:0;
+ float: right;
+ padding: 10px;
+ margin: 0;
}
.last_activity {
- padding-top:5px;
- display:block;
+ padding-top: 5px;
+ display: block;
span, strong {
- font-size:12px;
- color:#666;
+ font-size: 12px;
+ color: #666;
}
}
}
@@ -58,21 +58,21 @@
.project_name_holder {
input,
label {
- font-size:16px;
- line-height:20px;
- padding:8px;
+ font-size: 16px;
+ line-height: 20px;
+ padding: 8px;
}
label {
- color:#888;
+ color: #888;
}
.btn {
- padding:6px 10px;
- margin-left:10px;
- margin-bottom:8px;
+ padding: 6px 10px;
+ margin-left: 10px;
+ margin-bottom: 8px;
}
}
.adv_settings {
- h6 { margin-left:40px; }
+ h6 { margin-left: 40px; }
}
}
@@ -81,19 +81,20 @@
@include bg-gray-gradient;
padding: 4px 7px;
border: 1px solid #CCC;
- margin-bottom:20px;
+ margin-bottom: 20px;
}
.project_clone_holder {
input[type="text"],
.btn {
- font-size:12px;
+ font-size: 12px;
line-height: 18px;
margin: 0;
padding: 3px 10px;
}
input[type="text"] {
+ @extend .monospace;
border: 1px solid #BBB;
box-shadow: none;
margin-left: -1px;
@@ -102,8 +103,8 @@
.save-project-loader {
img {
- margin-top:50px;
- margin-bottom:50px;
+ margin-top: 50px;
+ margin-bottom: 50px;
}
h3 {
@extend .page_title;
diff --git a/app/assets/stylesheets/sections/themes.scss b/app/assets/stylesheets/sections/themes.scss
index 2d121519b02..4e5eaf575ae 100644
--- a/app/assets/stylesheets/sections/themes.scss
+++ b/app/assets/stylesheets/sections/themes.scss
@@ -6,17 +6,17 @@
}
.themes_opts {
- padding-left:20px;
+ padding-left: 20px;
label {
- width:175px;
- margin-right:40px;
+ width: 175px;
+ margin-right: 40px;
.prev {
@extend .thumbnail;
- height:30px;
- width:175px;
- margin-bottom:10px;
+ height: 30px;
+ width: 175px;
+ margin-bottom: 10px;
&.classic {
background: #31363e;
@@ -42,17 +42,17 @@
}
.code_highlight_opts {
- padding-left:20px;
+ padding-left: 20px;
label {
- width:220px;
- margin-right:40px;
+ width: 220px;
+ margin-right: 40px;
.prev {
@extend .thumbnail;
- height:151px;
- width:220px;
- margin-bottom:10px;
+ height: 151px;
+ width: 220px;
+ margin-bottom: 10px;
}
}
}
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index f6bdb0f3dba..b0d795f4d5a 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -1,14 +1,14 @@
.tree-holder {
.tree-content-holder {
- float:left;
- width:100%;
+ float: left;
+ width: 100%;
}
.tree_progress {
- display:none;
- margin:20px;
+ display: none;
+ margin: 20px;
&.loading {
- display:block;
+ display: block;
}
}
@@ -18,20 +18,20 @@
&:hover {
td {
background: $hover;
- border-top:1px solid #ADF;
- border-bottom:1px solid #ADF;
+ border-top: 1px solid #ADF;
+ border-bottom: 1px solid #ADF;
}
- cursor:pointer;
+ cursor: pointer;
}
}
}
.tree-item {
.tree-item-file-name {
- vertical-align:middle;
+ vertical-align: middle;
a {
&:hover {
- color:$blue_link;
+ color: $primary_color;
}
}
@@ -48,8 +48,8 @@
padding: 2px 10px;
}
td {
- line-height:20px;
- background:#fafafa;
+ line-height: 20px;
+ background: #fafafa;
}
}
@@ -86,7 +86,7 @@
.tree-btn-group {
.btn {
margin-right:-3px;
- padding:2px 10px;
+ padding: 2px 10px;
}
}
diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss
index 1f3d3d3d389..fee179899ce 100644
--- a/app/assets/stylesheets/themes/ui_basic.scss
+++ b/app/assets/stylesheets/themes/ui_basic.scss
@@ -11,8 +11,8 @@
a {
color: $link_color;
&:hover {
- text-decoration:none;
- color: $blue_link;
+ text-decoration: none;
+ color: $primary_color;
}
}
diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss
index a9d2124130d..9e6433c5f9e 100644
--- a/app/assets/stylesheets/themes/ui_mars.scss
+++ b/app/assets/stylesheets/themes/ui_mars.scss
@@ -47,17 +47,17 @@
a {
h1 {
background: url('logo_white.png') no-repeat 0px 2px;
- color:#eee;
+ color: #eee;
text-shadow: 0 1px 1px #111;
}
}
.separator {
- display:none;
+ display: none;
}
}
.project_name {
- color:#eee;
+ color: #eee;
text-shadow: 0 1px 1px #111;
}
}
diff --git a/app/assets/stylesheets/variables.scss b/app/assets/stylesheets/variables.scss
new file mode 100644
index 00000000000..ba78c8351f4
--- /dev/null
+++ b/app/assets/stylesheets/variables.scss
@@ -0,0 +1,5 @@
+/** Colors **/
+$primary_color: #2FA0BB;
+$link_color: #3A89A3;
+$style_color: #474D57;
+$hover: #D9EDF7; \ No newline at end of file
diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb
index f3949149a06..9f8299f52f7 100644
--- a/app/contexts/notes/load_context.rb
+++ b/app/contexts/notes/load_context.rb
@@ -19,8 +19,6 @@ module Notes
when "wall"
# this is the only case, where the order is DESC
project.common_notes.order("created_at DESC, id DESC").limit(50)
- when "wiki"
- project.wiki_notes.limit(20)
end
@notes = if after_id
diff --git a/app/contexts/project_update_context.rb b/app/contexts/project_update_context.rb
new file mode 100644
index 00000000000..e28d43d0e81
--- /dev/null
+++ b/app/contexts/project_update_context.rb
@@ -0,0 +1,21 @@
+class ProjectUpdateContext < BaseContext
+ def execute(role = :default)
+ namespace_id = params[:project].delete(:namespace_id)
+
+ if namespace_id.present?
+ if namespace_id == Namespace.global_id
+ if project.namespace.present?
+ # Transfer to global namespace from anyone
+ project.transfer(nil)
+ end
+ elsif namespace_id.to_i != project.namespace_id
+ # Transfer to someone namespace
+ namespace = Namespace.find(namespace_id)
+ project.transfer(namespace)
+ end
+ end
+
+ project.update_attributes(params[:project], as: role)
+ end
+end
+
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 0bba019918f..8a0a9e9b245 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -22,6 +22,7 @@ class Admin::GroupsController < AdminController
def create
@group = Group.new(params[:group])
+ @group.path = @group.name.dup.parameterize if @group.name
@group.owner = current_user
if @group.save
@@ -48,15 +49,17 @@ class Admin::GroupsController < AdminController
def project_update
project_ids = params[:project_ids]
- Project.where(id: project_ids).update_all(group_id: @group.id)
+
+ Project.where(id: project_ids).each do |project|
+ project.transfer(@group)
+ end
redirect_to :back, notice: 'Group was successfully updated.'
end
def remove_project
@project = Project.find(params[:project_id])
- @project.group_id = nil
- @project.save
+ @project.transfer(nil)
redirect_to :back, notice: 'Group was successfully updated.'
end
@@ -70,6 +73,6 @@ class Admin::GroupsController < AdminController
private
def group
- @group = Group.find_by_code(params[:id])
+ @group = Group.find_by_path(params[:id])
end
end
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index d27b657de3a..e61f94f8cf3 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -1,65 +1,50 @@
class Admin::ProjectsController < AdminController
- before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update]
+ before_filter :project, only: [:edit, :show, :update, :destroy, :team_update]
def index
- @admin_projects = Project.scoped
- @admin_projects = @admin_projects.search(params[:name]) if params[:name].present?
- @admin_projects = @admin_projects.order("name ASC").page(params[:page]).per(20)
+ @projects = Project.scoped
+ @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present?
+ @projects = @projects.search(params[:name]) if params[:name].present?
+ @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end
def show
@users = User.scoped
- @users = @users.not_in_project(@admin_project) if @admin_project.users.present?
+ @users = @users.not_in_project(@project) if @project.users.present?
@users = @users.all
end
- def new
- @admin_project = Project.new
- end
-
def edit
end
def team_update
- @admin_project.add_users_ids_to_team(params[:user_ids], params[:project_access])
-
- redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.'
- end
-
- def create
- @admin_project = Project.new(params[:project])
- @admin_project.owner = current_user
+ @project.add_users_ids_to_team(params[:user_ids], params[:project_access])
- if @admin_project.save
- redirect_to [:admin, @admin_project], notice: 'Project was successfully created.'
- else
- render action: "new"
- end
+ redirect_to [:admin, @project], notice: 'Project was successfully updated.'
end
def update
- owner_id = params[:project].delete(:owner_id)
+ status = ProjectUpdateContext.new(project, current_user, params).execute(:admin)
- if owner_id
- @admin_project.owner = User.find(owner_id)
- end
-
- if @admin_project.update_attributes(params[:project])
- redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.'
+ if status
+ redirect_to [:admin, @project], notice: 'Project was successfully updated.'
else
render action: "edit"
end
end
def destroy
- @admin_project.destroy
+ @project.destroy
- redirect_to admin_projects_url, notice: 'Project was successfully deleted.'
+ redirect_to admin_projects_path, notice: 'Project was successfully deleted.'
end
- private
+ protected
+
+ def project
+ id = params[:project_id] || params[:id]
- def admin_project
- @admin_project = Project.find_by_code(params[:id])
+ @project = Project.find_with_namespace(id)
+ @project || render_404
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 4b3623aec0f..5735c1d2916 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -2,6 +2,7 @@ class ApplicationController < ActionController::Base
before_filter :authenticate_user!
before_filter :reject_blocked!
before_filter :set_current_user_for_observers
+ before_filter :add_abilities
before_filter :dev_tools if Rails.env == 'development'
protect_from_forgery
@@ -63,11 +64,19 @@ class ApplicationController < ActionController::Base
end
def project
- @project ||= current_user.projects.find_by_code(params[:project_id] || params[:id])
- @project || render_404
+ id = params[:project_id] || params[:id]
+
+ @project = Project.find_with_namespace(id)
+
+ if @project and can?(current_user, :read_project, @project)
+ @project
+ else
+ @project = nil
+ render_404
+ end
end
- def add_project_abilities
+ def add_abilities
abilities << Ability
end
diff --git a/app/controllers/commit_controller.rb b/app/controllers/commit_controller.rb
index 97998352255..d671e9f9e9e 100644
--- a/app/controllers/commit_controller.rb
+++ b/app/controllers/commit_controller.rb
@@ -26,7 +26,8 @@ class CommitController < ProjectResourceController
end
end
- format.patch
+ format.diff { render text: @commit.to_diff }
+ format.patch { render text: @commit.to_patch }
end
end
end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 8d9329f2b32..461dd51b570 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -1,11 +1,21 @@
class DashboardController < ApplicationController
respond_to :html
+ before_filter :projects
before_filter :event_filter, only: :index
def index
- @groups = Group.where(id: current_user.projects.pluck(:group_id))
- @projects = current_user.projects_sorted_by_activity
+ @groups = current_user.authorized_groups
+
+ @projects = case params[:scope]
+ when 'personal' then
+ @projects.personal(current_user)
+ when 'joined' then
+ @projects.joined(current_user)
+ else
+ @projects
+ end
+
@projects = @projects.page(params[:page]).per(30)
@events = Event.in_projects(current_user.project_ids)
@@ -23,15 +33,16 @@ class DashboardController < ApplicationController
# Get authored or assigned open merge requests
def merge_requests
- @projects = current_user.projects.all
- @merge_requests = current_user.cared_merge_requests.recent.page(params[:page]).per(20)
+ @merge_requests = current_user.cared_merge_requests
+ @merge_requests = dashboard_filter(@merge_requests)
+ @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
end
# Get only assigned issues
def issues
- @projects = current_user.projects.all
- @user = current_user
- @issues = current_user.assigned_issues.opened.recent.page(params[:page]).per(20)
+ @issues = current_user.assigned_issues
+ @issues = dashboard_filter(@issues)
+ @issues = @issues.recent.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project)
respond_to do |format|
@@ -40,7 +51,32 @@ class DashboardController < ApplicationController
end
end
+ protected
+
+ def projects
+ @projects = current_user.authorized_projects.sorted_by_activity
+ end
+
def event_filter
@event_filter ||= EventFilter.new(params[:event_filter])
end
+
+ def dashboard_filter items
+ if params[:project_id]
+ items = items.where(project_id: params[:project_id])
+ end
+
+ if params[:search].present?
+ items = items.search(params[:search])
+ end
+
+ case params[:status]
+ when 'closed'
+ items.closed
+ when 'all'
+ items
+ else
+ items.opened
+ end
+ end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 63f70cd0027..93c495363d9 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -5,6 +5,9 @@ class GroupsController < ApplicationController
before_filter :group
before_filter :projects
+ # Authorize
+ before_filter :authorize_read_group!
+
def show
@events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0)
@last_push = current_user.recent_push
@@ -44,20 +47,32 @@ class GroupsController < ApplicationController
end
def people
- @users = group.users.all
+ @project = group.projects.find(params[:project_id]) if params[:project_id]
+ @users = @project ? @project.users : group.users
+
+ if @project
+ @team_member = @project.users_projects.new
+ end
end
protected
def group
- @group ||= Group.find_by_code(params[:id])
+ @group ||= Group.find_by_path(params[:id])
end
def projects
- @projects ||= current_user.projects_sorted_by_activity.where(group_id: @group.id)
+ @projects ||= group.projects.authorized_for(current_user).sorted_by_activity
end
def project_ids
projects.map(&:id)
end
+
+ # Dont allow unauthorized access to group
+ def authorize_read_group!
+ unless projects.present? or can?(current_user, :manage_group, @group)
+ return render_404
+ end
+ end
end
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index 8e180c9baae..362962707fd 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -1,7 +1,7 @@
class MergeRequestsController < ProjectResourceController
before_filter :module_enabled
- before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check, :raw]
- before_filter :validates_merge_request, only: [:show, :diffs, :raw]
+ before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check]
+ before_filter :validates_merge_request, only: [:show, :diffs]
before_filter :define_show_vars, only: [:show, :diffs]
# Allow read any merge_request
@@ -16,7 +16,6 @@ class MergeRequestsController < ProjectResourceController
# Allow destroy merge_request
before_filter :authorize_admin_merge_request!, only: [:destroy]
-
def index
@merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
end
@@ -25,11 +24,10 @@ class MergeRequestsController < ProjectResourceController
respond_to do |format|
format.html
format.js
- end
- end
- def raw
- send_file @merge_request.to_raw
+ format.diff { render text: @merge_request.to_diff }
+ format.patch { render text: @merge_request.to_patch }
+ end
end
def diffs
diff --git a/app/controllers/project_resource_controller.rb b/app/controllers/project_resource_controller.rb
index d297bba635f..81bc3a91bd1 100644
--- a/app/controllers/project_resource_controller.rb
+++ b/app/controllers/project_resource_controller.rb
@@ -1,5 +1,3 @@
class ProjectResourceController < ApplicationController
before_filter :project
- # Authorize
- before_filter :add_project_abilities
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 72080070bed..a6e7f1f93fb 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -34,8 +34,11 @@ class ProjectsController < ProjectResourceController
end
def update
+ status = ProjectUpdateContext.new(project, current_user, params).execute
+
respond_to do |format|
- if project.update_attributes(params[:project])
+ if status
+ flash[:notice] = 'Project was successfully updated.'
format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' }
format.js
else
diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb
index 37ed74b231f..311af62b8db 100644
--- a/app/controllers/team_members_controller.rb
+++ b/app/controllers/team_members_controller.rb
@@ -21,7 +21,11 @@ class TeamMembersController < ProjectResourceController
params[:project_access]
)
- redirect_to project_team_index_path(@project)
+ if params[:redirect_to]
+ redirect_to params[:redirect_to]
+ else
+ redirect_to project_team_index_path(@project)
+ end
end
def update
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index cba34c963a0..a689213bcee 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -75,7 +75,7 @@ module ApplicationHelper
end
def search_autocomplete_source
- projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } }
+ projects = current_user.projects.map{ |p| { label: p.name_with_namespace, url: project_path(p) } }
default_nav = [
{ label: "My Profile", url: profile_path },
@@ -126,6 +126,10 @@ module ApplicationHelper
Gitlab::Theme.css_class_by_id(current_user.try(:theme_id))
end
+ def user_color_scheme_class
+ current_user.dark_scheme ? :black : :white
+ end
+
def show_last_push_widget?(event)
event &&
event.last_push_to_non_root? &&
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
new file mode 100644
index 00000000000..0baa5b4108e
--- /dev/null
+++ b/app/helpers/dashboard_helper.rb
@@ -0,0 +1,32 @@
+module DashboardHelper
+ def dashboard_filter_path(entity, options={})
+ exist_opts = {
+ status: params[:status],
+ project_id: params[:project_id],
+ }
+
+ options = exist_opts.merge(options)
+
+ case entity
+ when 'issue' then
+ dashboard_issues_path(options)
+ when 'merge_request'
+ dashboard_merge_requests_path(options)
+ end
+ end
+
+ def entities_per_project project, entity
+ items = project.items_for(entity)
+
+ items = case params[:status]
+ when 'closed'
+ items.closed
+ when 'all'
+ items
+ else
+ items.opened
+ end
+
+ items.where(assignee_id: current_user.id).count
+ end
+end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
new file mode 100644
index 00000000000..fdf6725cc13
--- /dev/null
+++ b/app/helpers/namespaces_helper.rb
@@ -0,0 +1,26 @@
+module NamespacesHelper
+ def namespaces_options(selected = :current_user, scope = :default)
+ groups = current_user.namespaces.select {|n| n.type == 'Group'}
+
+ users = if scope == :all
+ Namespace.root
+ else
+ current_user.namespaces.reject {|n| n.type == 'Group'}
+ end
+
+ global_opts = ["Global", [['/', Namespace.global_id]] ]
+ group_opts = ["Groups", groups.map {|g| [g.human_name, g.id]} ]
+ users_opts = [ "Users", users.map {|u| [u.human_name, u.id]} ]
+
+ options = []
+ options << global_opts if current_user.admin
+ options << group_opts
+ options << users_opts
+
+ if selected == :current_user && current_user.namespace
+ selected = current_user.namespace.id
+ end
+
+ grouped_options_for_select(options, selected)
+ end
+end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 740700c3009..a4bec87caa7 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -84,4 +84,17 @@ module TabHelper
'active'
end
end
+
+ # Use nav_tab for save controller/action but different params
+ def nav_tab key, value, &block
+ o = {}
+ o[:class] = ""
+ o[:class] << " active" if params[key] == value
+
+ if block_given?
+ content_tag(:li, capture(&block), o)
+ else
+ content_tag(:li, nil, o)
+ end
+ end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 7f3862adb1d..29cebadaf94 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -89,14 +89,6 @@ class Notify < ActionMailer::Base
mail(to: recipient(recipient_id), subject: subject)
end
- def note_wiki_email(recipient_id, note_id)
- @note = Note.find(note_id)
- @wiki = @note.noteable
- @project = @note.project
- mail(to: recipient(recipient_id), subject: subject("note for wiki"))
- end
-
-
#
# Project
@@ -105,7 +97,7 @@ class Notify < ActionMailer::Base
def project_access_granted_email(user_project_id)
@users_project = UsersProject.find user_project_id
@project = @users_project.project
- mail(to: @users_project.user.email,
+ mail(to: @users_project.user.email,
subject: subject("access to project was granted"))
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index c3a212f473d..b09899f17dc 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -7,6 +7,7 @@ class Ability
when "Note" then note_abilities(object, subject)
when "Snippet" then snippet_abilities(object, subject)
when "MergeRequest" then merge_request_abilities(object, subject)
+ when "Group" then group_abilities(object, subject)
else []
end
end
@@ -14,7 +15,42 @@ class Ability
def project_abilities(user, project)
rules = []
- rules << [
+ # Rules based on role in project
+ if project.master_access_for?(user)
+ # TODO: replace with master rules.
+ # Only allow project administration for namespace owners
+ rules << project_admin_rules
+
+ elsif project.dev_access_for?(user)
+ rules << project_dev_rules
+
+ elsif project.report_access_for?(user)
+ rules << project_report_rules
+
+ elsif project.guest_access_for?(user)
+ rules << project_guest_rules
+ end
+
+ if project.namespace
+ # If user own project namespace
+ # (Ex. group owner or account owner)
+ if project.namespace.owner == user
+ rules << project_admin_rules
+ end
+ else
+ # For compatibility with global projects
+ # use projects.owner_id
+ if project.owner == user
+ rules << project_admin_rules
+ end
+ end
+
+
+ rules.flatten
+ end
+
+ def project_guest_rules
+ [
:read_project,
:read_wiki,
:read_issue,
@@ -26,28 +62,30 @@ class Ability
:write_project,
:write_issue,
:write_note
- ] if project.guest_access_for?(user)
+ ]
+ end
- rules << [
+ def project_report_rules
+ project_guest_rules + [
:download_code,
:write_merge_request,
:write_snippet
- ] if project.report_access_for?(user)
+ ]
+ end
- rules << [
+ def project_dev_rules
+ project_report_rules + [
:write_wiki,
:push_code
- ] if project.dev_access_for?(user)
-
- rules << [
- :push_code_to_protected_branches
- ] if project.master_access_for?(user)
+ ]
+ end
- rules << [
+ def project_master_rules
+ project_dev_rules + [
+ :push_code_to_protected_branches,
:modify_issue,
:modify_snippet,
:modify_merge_request,
- :admin_project,
:admin_issue,
:admin_milestone,
:admin_snippet,
@@ -56,7 +94,21 @@ class Ability
:admin_note,
:accept_mr,
:admin_wiki
- ] if project.master_access_for?(user) || project.owner == user
+ ]
+ end
+
+ def project_admin_rules
+ project_master_rules + [
+ :admin_project
+ ]
+ end
+
+ def group_abilities user, group
+ rules = []
+
+ rules << [
+ :manage_group
+ ] if group.owner == user
rules.flatten
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 5efb20cea3b..200c915a335 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -150,4 +150,19 @@ class Commit
def parents_count
parents && parents.count || 0
end
+
+ # Shows the diff between the commit's parent and the commit.
+ #
+ # Cuts out the header and stats from #to_patch and returns only the diff.
+ def to_diff
+ # see Grit::Commit#show
+ patch = to_patch
+
+ # discard lines before the diff
+ lines = patch.split("\n")
+ while !lines.first.start_with?("diff --git") do
+ lines.shift
+ end
+ lines.join("\n")
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 1ff6872f687..b668f5560ab 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -1,36 +1,24 @@
# == Schema Information
#
-# Table name: groups
+# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
-# code :string(255) not null
+# path :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
+# type :string(255)
#
-class Group < ActiveRecord::Base
- attr_accessible :code, :name, :owner_id
-
- has_many :projects
- belongs_to :owner, class_name: "User"
-
- validates :name, presence: true, uniqueness: true
- validates :code, presence: true, uniqueness: true
- validates :owner, presence: true
-
- delegate :name, to: :owner, allow_nil: true, prefix: true
-
- def self.search query
- where("name LIKE :query OR code LIKE :query", query: "%#{query}%")
- end
-
- def to_param
- code
+class Group < Namespace
+ def users
+ users = User.joins(:users_projects).where(users_projects: {project_id: project_ids})
+ users = users << owner
+ users.uniq
end
- def users
- User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq
+ def human_name
+ name
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 0766e5baa72..8039813ad1c 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -202,20 +202,22 @@ class MergeRequest < ActiveRecord::Base
false
end
- def to_raw
- FileUtils.mkdir_p(Rails.root.join("tmp", "patches"))
- patch_path = Rails.root.join("tmp", "patches", "merge_request_#{self.id}.patch")
-
- from = commits.last.id
- to = source_branch
-
- project.repo.git.run('', "format-patch" , " > #{patch_path.to_s}", {}, ["#{from}..#{to}", "--stdout"])
-
- patch_path
- end
-
def mr_and_commit_notes
commit_ids = commits.map(&:id)
Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND noteable_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids)
end
+
+ # Returns the raw diff for this merge request
+ #
+ # see "git diff"
+ def to_diff
+ project.repo.git.native(:diff, {timeout: 30, raise: true}, "#{target_branch}...#{source_branch}")
+ end
+
+ # Returns the commit as a series of email patches.
+ #
+ # see "git format-patch"
+ def to_patch
+ project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}")
+ end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
new file mode 100644
index 00000000000..e1c24de949a
--- /dev/null
+++ b/app/models/namespace.rb
@@ -0,0 +1,70 @@
+# == Schema Information
+#
+# Table name: namespaces
+#
+# id :integer not null, primary key
+# name :string(255) not null
+# path :string(255) not null
+# owner_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# type :string(255)
+#
+
+class Namespace < ActiveRecord::Base
+ attr_accessible :name, :path
+
+ has_many :projects, dependent: :destroy
+ belongs_to :owner, class_name: "User"
+
+ validates :name, presence: true, uniqueness: true
+ validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
+ format: { with: Gitlab::Regex.path_regex,
+ message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
+ validates :owner, presence: true
+
+ delegate :name, to: :owner, allow_nil: true, prefix: true
+
+ after_create :ensure_dir_exist
+ after_update :move_dir
+ after_destroy :rm_dir
+
+ scope :root, where('type IS NULL')
+
+ def self.search query
+ where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
+ end
+
+ def self.global_id
+ 'GLN'
+ end
+
+ def to_param
+ path
+ end
+
+ def human_name
+ owner_name
+ end
+
+ def ensure_dir_exist
+ namespace_dir_path = File.join(Gitlab.config.git_base_path, path)
+ system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path)
+ end
+
+ def move_dir
+ if path_changed?
+ old_path = File.join(Gitlab.config.git_base_path, path_was)
+ new_path = File.join(Gitlab.config.git_base_path, path)
+ if File.exists?(new_path)
+ raise "Already exists"
+ end
+ system("mv #{old_path} #{new_path}")
+ end
+ end
+
+ def rm_dir
+ dir_path = File.join(Gitlab.config.git_base_path, path)
+ system("rm -rf #{dir_path}")
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 3cbc9417b8f..74d981f26d6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -9,14 +9,13 @@
# created_at :datetime not null
# updated_at :datetime not null
# private_flag :boolean default(TRUE), not null
-# code :string(255)
# owner_id :integer
# default_branch :string(255)
# 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
-# group_id :integer
+# namespace_id :integer
#
require "grit"
@@ -27,12 +26,16 @@ class Project < ActiveRecord::Base
include Authority
include Team
- attr_accessible :name, :path, :description, :code, :default_branch, :issues_enabled,
- :wall_enabled, :merge_requests_enabled, :wiki_enabled
+ attr_accessible :name, :path, :description, :default_branch, :issues_enabled,
+ :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin]
+
+ attr_accessible :namespace_id, :owner_id, as: :admin
+
attr_accessor :error_code
# Relations
- belongs_to :group
+ belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
+ belongs_to :namespace
belongs_to :owner, class_name: "User"
has_many :users, through: :users_projects
has_many :events, dependent: :destroy
@@ -54,36 +57,79 @@ class Project < ActiveRecord::Base
# Validations
validates :owner, presence: true
validates :description, length: { within: 0..2000 }
- validates :name, uniqueness: true, presence: true, length: { within: 0..255 }
- validates :path, uniqueness: true, presence: true, length: { within: 0..255 },
- format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/,
- message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
- validates :code, presence: true, uniqueness: true, length: { within: 1..255 },
- format: { with: /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/,
+ validates :name, presence: true, length: { within: 0..255 }
+ validates :path, presence: true, length: { within: 0..255 },
+ format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
+
+ validates_uniqueness_of :name, scope: :namespace_id
+ validates_uniqueness_of :path, scope: :namespace_id
+
validate :check_limit, :repo_name
# Scopes
scope :public_only, where(private_flag: false)
scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.projects.map(&:id) ) }
scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) }
+ scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") }
+ scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
+ scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
class << self
+ def authorized_for user
+ projects = includes(:users_projects, :namespace)
+ projects = projects.where("users_projects.user_id = :user_id or projects.owner_id = :user_id or namespaces.owner_id = :user_id", user_id: user.id)
+ end
+
def active
joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
end
def search query
- where("name LIKE :query OR code LIKE :query OR path LIKE :query", query: "%#{query}%")
+ where("projects.name LIKE :query OR projects.path LIKE :query", query: "%#{query}%")
+ end
+
+ def find_with_namespace(id)
+ if id.include?("/")
+ id = id.split("/")
+ namespace_id = Namespace.find_by_path(id.first).id
+ where(namespace_id: namespace_id).find_by_path(id.last)
+ else
+ find_by_path(id)
+ end
end
def create_by_user(params, user)
+ namespace_id = params.delete(:namespace_id)
+
project = Project.new params
Project.transaction do
+
+ # Parametrize path for project
+ #
+ # Ex.
+ # 'GitLab HQ'.parameterize => "gitlab-hq"
+ #
+ project.path = project.name.dup.parameterize
+
project.owner = user
+
+ # Apply namespace if user has access to it
+ # else fallback to user namespace
+ if namespace_id != Namespace.global_id
+ project.namespace_id = user.namespace_id
+
+ if namespace_id
+ group = Group.find_by_id(namespace_id)
+ if user.can? :manage_group, group
+ project.namespace_id = namespace_id
+ end
+ end
+ end
+
project.save!
# Add user as project master
@@ -134,11 +180,15 @@ class Project < ActiveRecord::Base
end
def to_param
- code
+ if namespace
+ namespace.path + "/" + path
+ else
+ path
+ end
end
def web_url
- [Gitlab.config.url, code].join("/")
+ [Gitlab.config.url, path].join("/")
end
def common_notes
@@ -173,10 +223,6 @@ class Project < ActiveRecord::Base
last_event.try(:created_at) || updated_at
end
- def wiki_notes
- Note.where(noteable_id: wikis.pluck(:id), noteable_type: 'Wiki', project_id: self.id)
- end
-
def project_id
self.id
end
@@ -192,4 +238,62 @@ class Project < ActiveRecord::Base
def gitlab_ci?
gitlab_ci_service && gitlab_ci_service.active
end
+
+ def path_with_namespace
+ if namespace
+ namespace.path + '/' + path
+ else
+ path
+ end
+ end
+
+ # For compatibility with old code
+ def code
+ path
+ end
+
+ def transfer(new_namespace)
+ Project.transaction do
+ old_namespace = namespace
+ self.namespace = new_namespace
+
+ old_dir = old_namespace.try(:path) || ''
+ new_dir = new_namespace.try(:path) || ''
+
+ old_repo = if old_dir.present?
+ File.join(old_dir, self.path)
+ else
+ self.path
+ end
+
+ Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
+
+ git_host.move_repository(old_repo, self)
+
+ save!
+ end
+ end
+
+ def name_with_namespace
+ @name_with_namespace ||= begin
+ if namespace
+ namespace.human_name + " / " + name
+ else
+ name
+ end
+ end
+ end
+
+ def items_for entity
+ case entity
+ when 'issue' then
+ issues
+ when 'merge_request' then
+ merge_requests
+ end
+ end
+
+ def namespace_owner
+ namespace.try(:owner)
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 6d539c1f498..3f2d7c92ea8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -30,6 +30,7 @@
# locked_at :datetime
# extern_uid :string(255)
# provider :string(255)
+# username :string(255)
#
class User < ActiveRecord::Base
@@ -38,13 +39,17 @@ class User < ActiveRecord::Base
devise :database_authenticatable, :token_authenticatable, :lockable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
- attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name,
+ attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password,
- :extern_uid, :provider, :as => [:default, :admin]
- attr_accessible :projects_limit, :as => :admin
+ :extern_uid, :provider, as: [:default, :admin]
+ attr_accessible :projects_limit, as: :admin
attr_accessor :force_random_password
+ # Namespace for personal projects
+ has_one :namespace, class_name: "Namespace", foreign_key: :owner_id, conditions: 'type IS NULL', dependent: :destroy
+ has_many :groups, class_name: "Group", foreign_key: :owner_id
+
has_many :keys, dependent: :destroy
has_many :projects, through: :users_projects
has_many :users_projects, dependent: :destroy
@@ -58,13 +63,19 @@ class User < ActiveRecord::Base
has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy
validates :bio, length: { within: 0..255 }
- validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
+ validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
+ validates :username, presence: true, uniqueness: true,
+ format: { with: Gitlab::Regex.username_regex,
+ message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
+
before_validation :generate_password, on: :create
before_save :ensure_authentication_token
alias_attribute :private_token, :authentication_token
+ delegate :path, to: :namespace, allow_nil: true, prefix: true
+
# Scopes
scope :not_in_project, ->(project) { where("id not in (:ids)", ids: project.users.map(&:id) ) }
scope :admins, where(admin: true)
@@ -112,4 +123,16 @@ class User < ActiveRecord::Base
self.password = self.password_confirmation = Devise.friendly_token.first(8)
end
end
+
+ def authorized_groups
+ @authorized_groups ||= begin
+ groups = Group.where(id: self.projects.pluck(:namespace_id)).all
+ groups = groups + self.groups
+ groups.uniq
+ end
+ end
+
+ def authorized_projects
+ Project.authorized_for(self)
+ end
end
diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb
index 62fd9bf8ac9..9f9762aea07 100644
--- a/app/observers/issue_observer.rb
+++ b/app/observers/issue_observer.rb
@@ -3,7 +3,7 @@ class IssueObserver < ActiveRecord::Observer
def after_create(issue)
if issue.assignee && issue.assignee != current_user
- Notify.new_issue_email(issue.id).deliver
+ Notify.new_issue_email(issue.id).deliver
end
end
@@ -14,8 +14,8 @@ class IssueObserver < ActiveRecord::Observer
status = 'closed' if issue.is_being_closed?
status = 'reopened' if issue.is_being_reopened?
if status
- Note.create_status_change_note(issue, current_user, status)
- [issue.author, issue.assignee].compact.each do |recipient|
+ Note.create_status_change_note(issue, current_user, status)
+ [issue.author, issue.assignee].compact.each do |recipient|
Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user)
end
end
diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb
index 03a61709829..bd41e51e8e4 100644
--- a/app/observers/project_observer.rb
+++ b/app/observers/project_observer.rb
@@ -1,8 +1,11 @@
class ProjectObserver < ActiveRecord::Observer
- def after_save(project)
+ def after_create(project)
project.update_repository
end
+ def after_save(project)
+ end
+
def after_destroy(project)
log_info("Project \"#{project.name}\" was removed")
diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb
index 654621f7e1c..09b3c1d622f 100644
--- a/app/observers/user_observer.rb
+++ b/app/observers/user_observer.rb
@@ -9,6 +9,16 @@ class UserObserver < ActiveRecord::Observer
log_info("User \"#{user.name}\" (#{user.email}) was removed")
end
+ def after_save user
+ if user.username_changed?
+ if user.namespace
+ user.namespace.update_attributes(path: user.username)
+ else
+ user.create_namespace!(path: user.username, name: user.name)
+ end
+ end
+ end
+
protected
def log_info message
diff --git a/app/roles/account.rb b/app/roles/account.rb
index b80fbba0958..8157898fef1 100644
--- a/app/roles/account.rb
+++ b/app/roles/account.rb
@@ -26,6 +26,18 @@ module Account
is_admin?
end
+ def abilities
+ @abilities ||= begin
+ abilities = Six.new
+ abilities << Ability
+ abilities
+ end
+ end
+
+ def can? action, subject
+ abilities.allowed?(self, action, subject)
+ end
+
def last_activity_project
projects.first
end
@@ -68,6 +80,29 @@ module Account
end
def projects_sorted_by_activity
- projects.order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC")
+ projects.sorted_by_activity
+ end
+
+ def namespaces
+ namespaces = []
+
+ # Add user account namespace
+ namespaces << self.namespace if self.namespace
+
+ # Add groups you can manage
+ namespaces += if admin
+ Group.all
+ else
+ groups.all
+ end
+ namespaces
+ end
+
+ def several_namespaces?
+ namespaces.size > 1
+ end
+
+ def namespace_id
+ namespace.try :id
end
end
diff --git a/app/roles/push_observer.rb b/app/roles/push_observer.rb
index 2ee60646e97..c5c5203d7a6 100644
--- a/app/roles/push_observer.rb
+++ b/app/roles/push_observer.rb
@@ -114,7 +114,7 @@ module PushObserver
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
- url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}",
+ url: "#{Gitlab.config.url}/#{path}/commits/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
diff --git a/app/roles/repository.rb b/app/roles/repository.rb
index 88468117822..74cae5c8d5d 100644
--- a/app/roles/repository.rb
+++ b/app/roles/repository.rb
@@ -79,11 +79,15 @@ module Repository
end
def url_to_repo
- git_host.url_to_repo(path)
+ git_host.url_to_repo(path_with_namespace)
end
def path_to_repo
- File.join(Gitlab.config.git_base_path, "#{path}.git")
+ File.join(Gitlab.config.git_base_path, "#{path_with_namespace}.git")
+ end
+
+ def namespace_dir
+ namespace.try(:path) || ''
end
def update_repository
@@ -160,12 +164,12 @@ module Repository
return nil unless commit
# Build file path
- file_name = self.code + "-" + commit.id.to_s + ".tar.gz"
- storage_path = Rails.root.join("tmp", "repositories", self.code)
+ file_name = self.path + "-" + commit.id.to_s + ".tar.gz"
+ storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace)
file_path = File.join(storage_path, file_name)
# Put files into a directory before archiving
- prefix = self.code + "/"
+ prefix = self.path + "/"
# Create file if not exists
unless File.exists?(file_path)
@@ -181,7 +185,7 @@ module Repository
end
def http_url_to_repo
- http_url = [Gitlab.config.url, "/", path, ".git"].join('')
+ http_url = [Gitlab.config.url, "/", path_with_namespace, ".git"].join('')
end
# Check if current branch name is marked as protected in the system
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index b0b59a46fdb..4320bda4999 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -1,5 +1,29 @@
.admin_dash.row
- .span4
+ .span3
+ .ui-box
+ %h5 Projects
+ .data.padded
+ = link_to admin_projects_path do
+ %h1= Project.count
+ %hr
+ = link_to 'New Project', new_project_path, class: "btn small"
+ .span3
+ .ui-box
+ %h5 Groups
+ .data.padded
+ = link_to admin_groups_path do
+ %h1= Group.count
+ %hr
+ = link_to 'New Group', new_admin_group_path, class: "btn small"
+ .span3
+ .ui-box
+ %h5 Users
+ .data.padded
+ = link_to admin_users_path do
+ %h1= User.count
+ %hr
+ = link_to 'New User', new_admin_user_path, class: "btn small"
+ .span3
.ui-box
%h5
Resque Workers
@@ -19,32 +43,13 @@
%p
%strong Resque status unknown
-
- .span4
- .ui-box
- %h5 Projects
- .data.padded
- = link_to admin_projects_path do
- %h1= Project.count
- %hr
- = link_to 'New Project', new_admin_project_path, class: "btn small"
- .span4
- .ui-box
- %h5 Users
- .data.padded
- = link_to admin_users_path do
- %h1= User.count
- %hr
- = link_to 'New User', new_admin_user_path, class: "btn small"
-
-
.row
.span6
%h3 Latest projects
%hr
- @projects.each do |project|
%p
- = link_to project.name, [:admin, project]
+ = link_to project.name_with_namespace, [:admin, project]
.span6
%h3 Latest users
%hr
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index e85cce66ba1..67516eb26e3 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -7,13 +7,6 @@
Group name is
.input
= f.text_field :name, placeholder: "Example Group", class: "xxlarge"
- .clearfix
- = f.label :code do
- URL
- .input
- .input-prepend
- %span.add-on= web_app_url + 'groups/'
- = f.text_field :code, placeholder: "example"
.form-actions
= f.submit 'Save group', class: "btn save-btn"
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 6a0794cfd44..952d515103c 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -1,4 +1,3 @@
-= render 'admin/shared/projects_head'
%h3.page_title
Groups
%small
@@ -14,7 +13,7 @@
%table
%thead
%th Name
- %th Code
+ %th Path
%th Projects
%th Edit
%th.cred Danger Zone!
@@ -22,7 +21,7 @@
- @groups.each do |group|
%tr
%td= link_to group.name, [:admin, group]
- %td= group.code
+ %td= group.path
%td= group.projects.count
%td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small"
%td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger"
diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml
index d6b6ea1535e..6ff0e781d17 100644
--- a/app/views/admin/groups/new.html.haml
+++ b/app/views/admin/groups/new.html.haml
@@ -1,3 +1,21 @@
%h3.page_title New Group
-%br
-= render 'form'
+%hr
+= form_for [:admin, @group] do |f|
+ - if @group.errors.any?
+ .alert-message.block-message.error
+ %span= @group.errors.full_messages.first
+ .clearfix
+ = f.label :name do
+ Group name is
+ .input
+ = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
+ &nbsp;
+ = f.submit 'Create group', class: "btn primary"
+ %hr
+ .padded
+ %ul
+ %li Group is kind of directory for several projects
+ %li All created groups are private
+ %li People within a group see only projects they have access to
+ %li All projects of group will be stored in group directory
+ %li You will be able to move existing projects into group
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 309a10e5bb4..d371acadd15 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -1,4 +1,3 @@
-= render 'admin/shared/projects_head'
%h3.page_title
Group: #{@group.name}
= link_to edit_admin_group_path(@group), class: "btn right" do
@@ -20,9 +19,9 @@
%tr
%td
%b
- Code:
+ Path:
%td
- = @group.code
+ %span.monospace= File.join(Gitlab.config.git_base_path, @group.path)
%tr
%td
%b
@@ -43,10 +42,14 @@
= link_to 'Remove from group', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Are you sure?', method: :delete, class: "btn danger small"
.clearfix
-%br
-%h3 Add new project
-%br
+
= form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do
- = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
- .form-actions
- = submit_tag 'Add', class: "btn primary"
+ %fieldset
+ %legend Move projects to group
+ .clearfix
+ = label_tag :project_ids do
+ Projects
+ .input
+ = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
+ .form-actions
+ = submit_tag 'Add', class: "btn primary"
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index 0efe6db7483..e33c5468555 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -3,12 +3,18 @@
= link_to "githost.log", "#githost", 'data-toggle' => 'tab'
%li
= link_to "application.log", "#application", 'data-toggle' => 'tab'
+
+%p.light To prevent perfomance issues admin logs output the last 2000 lines
.tab-content
.tab-pane.active#githost
.file_holder#README
.file_title
%i.icon-file
githost.log
+ .right
+ = link_to '#', class: 'log-bottom' do
+ %i.icon-arrow-down
+ Scroll down
.file_content.logs
%ol
- Gitlab::GitLogger.read_latest.each do |line|
@@ -19,6 +25,10 @@
.file_title
%i.icon-file
application.log
+ .right
+ = link_to '#', class: 'log-bottom' do
+ %i.icon-arrow-down
+ Scroll down
.file_content.logs
%ol
- Gitlab::AppLogger.read_latest.each do |line|
diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml
index 4848e7391a3..e515c68c382 100644
--- a/app/views/admin/projects/_form.html.haml
+++ b/app/views/admin/projects/_form.html.haml
@@ -11,28 +11,18 @@
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
- %hr
- .adv_settings
- %h6 Advanced settings:
+ %fieldset.adv_settings
+ %legend Advanced settings:
.clearfix
= f.label :path do
Path
.input
- .input-prepend
- %strong
- = text_field_tag :ppath, @admin_project.path_to_repo, class: "xlarge", disabled: true
- .clearfix
- = f.label :code do
- URL
- .input
- .input-prepend
- %span.add-on= web_app_url
- = f.text_field :code, placeholder: "example"
+ = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
- unless project.new_record?
.clearfix
- = f.label :owner_id
- .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'}
+ = f.label :namespace_id
+ .input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'}
- if project.repo_exists?
.clearfix
@@ -40,9 +30,8 @@
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
- unless project.new_record?
- %hr
- .adv_settings
- %h6 Features:
+ %fieldset.adv_settings
+ %legend Features:
.clearfix
= f.label :issues_enabled, "Issues"
diff --git a/app/views/admin/projects/_new_form.html.haml b/app/views/admin/projects/_new_form.html.haml
deleted file mode 100644
index d793b6f3aff..00000000000
--- a/app/views/admin/projects/_new_form.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-= form_for [:admin, @admin_project] do |f|
- - if @admin_project.errors.any?
- .alert-message.block-message.error
- %span= @admin_project.errors.full_messages.first
- .clearfix.project_name_holder
- = f.label :name do
- Project name is
- .input
- = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
- = f.submit 'Create project', class: "btn primary project-submit"
-
- %hr
- %div.adv_settings
- %h6 Advanced settings:
- .clearfix
- = f.label :path do
- Git Clone
- .input
- .input-prepend
- %span.add-on= Gitlab.config.ssh_path
- = f.text_field :path, placeholder: "example_project", disabled: !@admin_project.new_record?
- %span.add-on= ".git"
- .clearfix
- = f.label :code do
- URL
- .input
- .input-prepend
- %span.add-on= web_app_url
- = f.text_field :code, placeholder: "example"
diff --git a/app/views/admin/projects/edit.html.haml b/app/views/admin/projects/edit.html.haml
index b5255671154..7b59a0cc753 100644
--- a/app/views/admin/projects/edit.html.haml
+++ b/app/views/admin/projects/edit.html.haml
@@ -1,3 +1,3 @@
-%h3.page_title #{@admin_project.name} &rarr; Edit project
+%h3.page_title #{@project.name} &rarr; Edit project
%hr
-= render 'form', project: @admin_project
+= render 'form', project: @project
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 3335fce0078..9bbcbc71111 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -1,9 +1,9 @@
-= render 'admin/shared/projects_head'
%h3.page_title
Projects
- = link_to 'New Project', new_admin_project_path, class: "btn small right"
+ = link_to 'New Project', new_project_path, class: "btn small right"
%br
= form_tag admin_projects_path, method: :get, class: 'form-inline' do
+ = select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen xlarge", prompt: "Project namespace"
= text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary"
@@ -16,12 +16,14 @@
%th Edit
%th.cred Danger Zone!
- - @admin_projects.each do |project|
+ - @projects.each do |project|
%tr
- %td= link_to project.name, [:admin, project]
- %td= project.path
+ %td
+ = link_to project.name_with_namespace, [:admin, project]
+ %td
+ %span.monospace= project.path_with_namespace + ".git"
%td= project.users_projects.count
%td= last_commit(project)
%td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small"
%td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger"
-= paginate @admin_projects, theme: "admin"
+= paginate @projects, theme: "admin"
diff --git a/app/views/admin/projects/new.html.haml b/app/views/admin/projects/new.html.haml
deleted file mode 100644
index 933cb671142..00000000000
--- a/app/views/admin/projects/new.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.project_new_holder
- %h3.page_title
- New Project
- %hr
- = render 'new_form'
-%div.save-project-loader.hide
- %center
- = image_tag "ajax_loader.gif"
- %h3 Creating project &amp; repository. Please wait a few minutes
-
-:javascript
- $(function(){ new Projects(); });
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 78df8f2d2e9..47185308f41 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -1,11 +1,10 @@
-= render 'admin/shared/projects_head'
%h3.page_title
- Project: #{@admin_project.name}
- = link_to edit_admin_project_path(@admin_project), class: "btn right" do
+ Project: #{@project.name_with_namespace}
+ = link_to edit_admin_project_path(@project), class: "btn right" do
%i.icon-edit
Edit
-- if !@admin_project.has_post_receive_file? && @admin_project.has_commits?
+- if !@project.has_post_receive_file? && @project.has_commits?
%br
.alert.alert-error
%span
@@ -25,36 +24,39 @@
%b
Name:
%td
- = @admin_project.name
+ = @project.name
%tr
%td
%b
- Code:
+ Namespace:
%td
- = @admin_project.code
+ - if @project.namespace
+ = @project.namespace.human_name
+ - else
+ Global
%tr
%td
%b
Path:
%td
- = @admin_project.path
+ %code= @project.path_to_repo
%tr
%td
%b
- Owner:
+ Created by:
%td
- = @admin_project.owner_name || '(deleted)'
+ = @project.owner_name || '(deleted)'
%tr
%td
%b
Post Receive File:
%td
- = check_box_tag :post_receive_file, 1, @admin_project.has_post_receive_file?, disabled: true
+ = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
%br
%h3
Team
%small
- (#{@admin_project.users_projects.count})
+ (#{@project.users_projects.count})
%br
%table.zebra-striped
%thead
@@ -64,7 +66,7 @@
%th Repository Access
%th
- - @admin_project.users_projects.each do |tm|
+ - @project.users_projects.each do |tm|
%tr
%td
= link_to tm.user_name, admin_user_path(tm.user)
@@ -75,7 +77,7 @@
%br
%h3 Add new team member
%br
-= form_tag team_update_admin_project_path(@admin_project), class: "bulk_import", method: :put do
+= form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do
%table.zebra-striped
%thead
%tr
diff --git a/app/views/admin/shared/_projects_head.html.haml b/app/views/admin/shared/_projects_head.html.haml
deleted file mode 100644
index 3f5c34c533c..00000000000
--- a/app/views/admin/shared/_projects_head.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-%ul.nav.nav-tabs
- = nav_link(controller: :projects) do
- = link_to 'Projects', admin_projects_path, class: "tab"
- = nav_link(controller: :groups) do
- = link_to 'Groups', admin_groups_path, class: "tab"
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 7010c2727c6..45195152cb7 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -6,47 +6,42 @@
- @admin_user.errors.full_messages.each do |msg|
%li= msg
- .row
- .span7
- .ui-box
- %br
- .clearfix
- = f.label :name
- .input
- = f.text_field :name
- %span.help-inline * required
- .clearfix
- = f.label :email
- .input
- = f.text_field :email
- %span.help-inline * required
- %hr
- -if f.object.new_record?
- .clearfix
- = f.label :force_random_password do
- %span Generate random password
- .input= f.check_box :force_random_password, {}, true, nil
-
- %div.password-fields
- .clearfix
- = f.label :password
- .input= f.password_field :password, disabled: f.object.force_random_password
- .clearfix
- = f.label :password_confirmation
- .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
- %hr
- .clearfix
- = f.label :skype
- .input= f.text_field :skype
- .clearfix
- = f.label :linkedin
- .input= f.text_field :linkedin
- .clearfix
- = f.label :twitter
- .input= f.text_field :twitter
- .span5
- .ui-box
- %br
+ %fieldset
+ %legend Account
+ .clearfix
+ = f.label :name
+ .input
+ = f.text_field :name, required: true
+ %span.help-inline * required
+ .clearfix
+ = f.label :username
+ .input
+ = f.text_field :username, required: true
+ %span.help-inline * required
+ .clearfix
+ = f.label :email
+ .input
+ = f.text_field :email, required: true
+ %span.help-inline * required
+
+ %fieldset
+ %legend Password
+ .clearfix
+ = f.label :password
+ .input= f.password_field :password, disabled: f.object.force_random_password
+ .clearfix
+ = f.label :password_confirmation
+ .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
+ -if f.object.new_record?
+ .clearfix
+ = f.label :force_random_password do
+ %span Generate random password
+ .input= f.check_box :force_random_password, {}, true, nil
+
+ %fieldset
+ %legend Access
+ .row
+ .span8
.clearfix
= f.label :projects_limit
.input= f.number_field :projects_limit
@@ -55,23 +50,27 @@
= f.label :admin do
%strong.cred Administrator
.input= f.check_box :admin
+ .span4
- unless @admin_user.new_record?
- %hr
- .padded.cred
+ .alert.alert-error
- if @admin_user.blocked
- %span
- This user is blocked and is not able to login to GitLab
- .clearfix
- = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right"
+ %p This user is blocked and is not able to login to GitLab
+ = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small"
- else
- %span
- Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
- .clearfix
- = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small right danger"
+ %p Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
+ = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
+ %fieldset
+ %legend Profile
+ .clearfix
+ = f.label :skype
+ .input= f.text_field :skype
+ .clearfix
+ = f.label :linkedin
+ .input= f.text_field :linkedin
+ .clearfix
+ = f.label :twitter
+ .input= f.text_field :twitter
- .row
- .span6
- .span6
.actions
= f.submit 'Save', class: "btn save-btn"
- if @admin_user.new_record?
diff --git a/app/views/admin/users/edit.html.haml b/app/views/admin/users/edit.html.haml
index 032e3cfaa99..f8ff77b8f53 100644
--- a/app/views/admin/users/edit.html.haml
+++ b/app/views/admin/users/edit.html.haml
@@ -1,3 +1,6 @@
-%h3.page_title #{@admin_user.name} &rarr; Edit user
+%h3.page_title
+ #{@admin_user.name} &rarr;
+ %i.icon-edit
+ Edit user
%hr
= render 'form'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 5ef94ef5f34..5d0f6fe1153 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -6,7 +6,7 @@
= form_tag admin_users_path, method: :get, class: 'form-inline' do
= text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary"
-%ul.nav.nav-pills
+%ul.nav.nav-tabs
%li{class: "#{'active' unless params[:filter]}"}
= link_to "Active", admin_users_path
%li{class: "#{'active' if params[:filter] == "admins"}"}
@@ -23,24 +23,25 @@
%thead
%th Admin
%th Name
+ %th Username
%th Email
%th Projects
%th Edit
- %th Blocked
%th.cred Danger Zone!
- @admin_users.each do |user|
%tr
%td= check_box_tag "admin", 1, user.admin, disabled: :disabled
%td= link_to user.name, [:admin, user]
+ %td= user.username
%td= user.email
%td= user.users_projects.count
%td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small"
- %td
+ %td.bgred
- if user.blocked
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
- else
= link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
- %td.bgred= link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
+ = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
= paginate @admin_users, theme: "admin"
diff --git a/app/views/admin/users/new.html.haml b/app/views/admin/users/new.html.haml
index 70ead0d3f7d..1e82b249cf1 100644
--- a/app/views/admin/users/new.html.haml
+++ b/app/views/admin/users/new.html.haml
@@ -1,3 +1,5 @@
-%h3.page_title New user
-%br
+%h3.page_title
+ %i.icon-plus
+ New user
+%hr
= render 'form'
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index e73f4d10876..6a42f787bab 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -24,6 +24,12 @@
%tr
%td
%b
+ Username:
+ %td
+ = @admin_user.username
+ %tr
+ %td
+ %b
Admin:
%td= check_box_tag "admin", 1, @admin_user.admin, disabled: :disabled
%tr
diff --git a/app/views/commit/show.patch.erb b/app/views/commit/show.patch.erb
deleted file mode 100644
index ce1c3d023f5..00000000000
--- a/app/views/commit/show.patch.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= @commit.to_patch %>
diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml
index 26753a1465f..8f7826e0c8d 100644
--- a/app/views/commits/_commit_box.html.haml
+++ b/app/views/commits/_commit_box.html.haml
@@ -5,9 +5,14 @@
%span.btn.disabled.grouped
%i.icon-comment
= @notes_count
- = link_to project_commit_path(@project, @commit, format: :patch), class: "btn small grouped" do
- %i.icon-download-alt
- Get Patch
+ .left.btn-group
+ %a.btn.small.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
+ %i.icon-download-alt
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch)
+ %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff)
= link_to project_tree_path(@project, @commit), class: "browse-button primary grouped" do
%strong Browse Code »
%h3.commit-title.page_title
diff --git a/app/views/dashboard/_filter.html.haml b/app/views/dashboard/_filter.html.haml
new file mode 100644
index 00000000000..4624af79948
--- /dev/null
+++ b/app/views/dashboard/_filter.html.haml
@@ -0,0 +1,33 @@
+= form_tag dashboard_filter_path(entity), method: 'get' do
+ %fieldset.dashboard-search-filter
+ = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'search-text-input' }
+ = button_tag type: 'submit', class: 'btn' do
+ %i.icon-search
+
+ %fieldset
+ %legend Status:
+ %ul.nav.nav-pills.nav-stacked
+ %li{class: ("active" if !params[:status])}
+ = link_to dashboard_filter_path(entity, status: nil) do
+ Open
+ %li{class: ("active" if params[:status] == 'closed')}
+ = link_to dashboard_filter_path(entity, status: 'closed') do
+ Closed
+ %li{class: ("active" if params[:status] == 'all')}
+ = link_to dashboard_filter_path(entity, status: 'all') do
+ All
+
+ %fieldset
+ %legend Projects:
+ %ul.nav.nav-pills.nav-stacked
+ - @projects.each do |project|
+ - unless entities_per_project(project, entity).zero?
+ %li{class: ("active" if params[:project_id] == project.id.to_s)}
+ = link_to dashboard_filter_path(entity, project_id: project.id) do
+ = project.name_with_namespace
+ %small.right= entities_per_project(project, entity)
+
+ %fieldset
+ %hr
+ = link_to "Reset", dashboard_filter_path(entity), class: 'btn right'
+
diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml
index 7c5e9f3fab0..8f66742098a 100644
--- a/app/views/dashboard/_groups.html.haml
+++ b/app/views/dashboard/_groups.html.haml
@@ -11,10 +11,10 @@
%ul.unstyled
- groups.each do |group|
%li.wll
- = link_to group_path(id: group.code), class: dom_class(group) do
+ = link_to group_path(id: group.path), class: dom_class(group) do
%strong.group_name= truncate(group.name, length: 25)
%span.arrow
&rarr;
%span.last_activity
%strong Projects:
- %span= group.projects.count
+ %span= group.projects.authorized_for(current_user).count
diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml
index 00f19ccdcc6..fac0a074691 100644
--- a/app/views/dashboard/_projects.html.haml
+++ b/app/views/dashboard/_projects.html.haml
@@ -8,11 +8,23 @@
= link_to new_project_path, class: "btn very_small info" do
%i.icon-plus
New Project
+ %ul.nav.nav-projects-tabs
+ = nav_tab :scope, nil do
+ = link_to "All", dashboard_path
+ = nav_tab :scope, 'personal' do
+ = link_to "Personal", dashboard_path(scope: 'personal')
+ = nav_tab :scope, 'joined' do
+ = link_to "Joined", dashboard_path(scope: 'joined')
+
%ul.unstyled
- projects.each do |project|
%li.wll
= link_to project_path(project), class: dom_class(project) do
- %strong.project_name= truncate(project.name, length: 25)
+ - if project.namespace
+ = project.namespace.human_name
+ \/
+ %strong.project_name
+ = truncate(project.name, length: 25)
%span.arrow
&rarr;
%span.last_activity
diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml
index d0882c6dab7..6b360dc1fef 100644
--- a/app/views/dashboard/index.html.haml
+++ b/app/views/dashboard/index.html.haml
@@ -2,7 +2,6 @@
.projects
.activities.span8
= render "events/event_last_push", event: @last_push
- = render 'shared/no_ssh'
.event_filter
= event_filter_link EventFilter.push, 'Push events'
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index 5bd07bcd89f..28bdc5ed814 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -1,9 +1,9 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
- xml.title "#{@user.name} issues"
- xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"
- xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"
- xml.id dashboard_issues_url(:private_token => @user.private_token)
+ xml.title "#{current_user.name} issues"
+ xml.link :href => dashboard_issues_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml"
+ xml.link :href => dashboard_issues_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html"
+ xml.id dashboard_issues_url(:private_token => current_user.private_token)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index cc488d57e9e..e3093bcfe2a 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -3,17 +3,21 @@
%small (assigned to you)
%small.right #{@issues.total_count} issues
-%br
-.clearfix
-- if @issues.any?
- - @issues.group_by(&:project).each do |group|
- %div.ui-box
- - @project = group[0]
- %h5= @project.name
- %ul.unstyled.issues_table
- - group[1].each do |issue|
- = render(partial: 'issues/show', locals: {issue: issue})
- %hr
- = paginate @issues, theme: "gitlab"
-- else
- %h3.nothing_here_message Nothing to show here
+%hr
+
+.row
+ .span3
+ = render 'filter', entity: 'issue'
+ .span9
+ - if @issues.any?
+ - @issues.group_by(&:project).each do |group|
+ %div.ui-box
+ - @project = group[0]
+ %h5= link_to(@project.name, project_path(@project))
+ %ul.unstyled.issues_table
+ - group[1].each do |issue|
+ = render(partial: 'issues/show', locals: {issue: issue})
+ %hr
+ = paginate @issues, theme: "gitlab"
+ - else
+ %p.nothing_here_message Nothing to show here
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index 23a7e7222d7..8454cfdc120 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -3,16 +3,20 @@
%small (authored by or assigned to you)
%small.right #{@merge_requests.total_count} merge requests
-%br
-- if @merge_requests.any?
- - @merge_requests.group_by(&:project).each do |group|
- %ul.unstyled.ui-box
- - @project = group[0]
- %h5= @project.name
- - group[1].each do |merge_request|
- = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request})
- %hr
- = paginate @merge_requests, theme: "gitlab"
+%hr
+.row
+ .span3
+ = render 'filter', entity: 'merge_request'
+ .span9
+ - if @merge_requests.any?
+ - @merge_requests.group_by(&:project).each do |group|
+ %ul.unstyled.ui-box
+ - @project = group[0]
+ %h5= @project.name
+ - group[1].each do |merge_request|
+ = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request})
+ %hr
+ = paginate @merge_requests, theme: "gitlab"
-- else
- %h3.nothing_here_message Nothing to show here
+ - else
+ %h3.nothing_here_message Nothing to show here
diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml
index 3b60ed8b0ee..f2d082cb77d 100644
--- a/app/views/errors/access_denied.html.haml
+++ b/app/views/errors/access_denied.html.haml
@@ -1,4 +1,5 @@
-%h1 Access Denied
+%h1.http_status_code 403
+%h3.page_title Access Denied
%hr
-%h2 You are not allowed to access this page.
+%p You are not allowed to access this page.
%p Read more about project permissions #{link_to "here", help_permissions_path, class: "vlink"}
diff --git a/app/views/errors/encoding.html.haml b/app/views/errors/encoding.html.haml
index d7b5e68e870..a0aa6306489 100644
--- a/app/views/errors/encoding.html.haml
+++ b/app/views/errors/encoding.html.haml
@@ -1,3 +1,4 @@
-%h1 Encoding Error
+%h1.http_status_code 500
+%h3.page_title Encoding Error
%hr
%p Page can't be loaded because of an encoding error.
diff --git a/app/views/errors/git_not_found.html.haml b/app/views/errors/git_not_found.html.haml
index cd01ea1b0e6..5c9c4953284 100644
--- a/app/views/errors/git_not_found.html.haml
+++ b/app/views/errors/git_not_found.html.haml
@@ -1,6 +1,6 @@
-%h1 404
+%h1.http_status_code 404
+%h3.page_title Git Resource Not found
%hr
-%h2 Git Resource Not found
%p
Application can't get access to some branch or commit in your repository. It
may have been moved.
diff --git a/app/views/errors/gitolite.html.haml b/app/views/errors/gitolite.html.haml
index 699e6984db6..2670f2d3fda 100644
--- a/app/views/errors/gitolite.html.haml
+++ b/app/views/errors/gitolite.html.haml
@@ -1,6 +1,6 @@
-%h1 Git Error
+%h1.http_status_code 500
+%h3.page_title GitLab was unable to access your Gitolite system.
%hr
-%h2 GitLab was unable to access your Gitolite system.
.git_error_tips
%h4 Tips for Administrator:
diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml
index a4e8d0204a9..ee23d2197b4 100644
--- a/app/views/errors/not_found.html.haml
+++ b/app/views/errors/not_found.html.haml
@@ -1,4 +1,4 @@
-%h1 404
+%h1.http_status_code 404
+%h3.page_title The resource you were looking for doesn't exist.
%hr
-%h2 The resource you were looking for doesn't exist.
%p You may have mistyped the address or the page may have moved.
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 0d91a67a60d..2446b764e4d 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -1,7 +1,7 @@
- if event.allowed?
%div.event-item
= event_image(event)
- = image_tag gravatar_icon(event.author_email), class: "avatar"
+ = image_tag gravatar_icon(event.author_email), class: "avatar s24"
- if event.push?
= render "events/event/push", event: event
diff --git a/app/views/groups/_new_member.html.haml b/app/views/groups/_new_member.html.haml
new file mode 100644
index 00000000000..f48c2c23d83
--- /dev/null
+++ b/app/views/groups/_new_member.html.haml
@@ -0,0 +1,18 @@
+= form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f|
+ %fieldset
+ %legend= "New Team member(s) for #{@project.name}"
+
+ %h6 1. Choose people you want in the team
+ .clearfix
+ = f.label :user_ids, "People"
+ .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true})
+
+ %h6 2. Set access level for them
+ .clearfix
+ = f.label :project_access, "Project Access"
+ .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen"
+
+ .form-actions
+ = hidden_field_tag :redirect_to, people_group_path(@group, project_id: @project.id)
+ = f.submit 'Add', class: "btn save-btn"
+
diff --git a/app/views/groups/_people_filter.html.haml b/app/views/groups/_people_filter.html.haml
new file mode 100644
index 00000000000..79a1b01a5fa
--- /dev/null
+++ b/app/views/groups/_people_filter.html.haml
@@ -0,0 +1,14 @@
+= form_tag people_group_path(@group), method: 'get' do
+ %fieldset
+ %legend Projects:
+ %ul.nav.nav-pills.nav-stacked
+ - @projects.each do |project|
+ %li{class: ("active" if params[:project_id] == project.id.to_s)}
+ = link_to people_group_path(@group, project_id: project.id) do
+ = project.name_with_namespace
+ %small.right= project.users.count
+
+ %fieldset
+ %hr
+ = link_to "Reset", people_group_path(@group), class: 'btn right'
+
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index b565dad37a9..39c0b6af685 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -3,7 +3,14 @@
Projects
%small
(#{projects.count})
+ - if can? current_user, :manage_group, @group
+ %span.right
+ = link_to new_project_path(namespace_id: @group.id), class: "btn very_small info" do
+ %i.icon-plus
+ New Project
%ul.unstyled
+ - if projects.blank?
+ %p.nothing_here_message This groups has no projects yet
- projects.each do |project|
%li.wll
= link_to project_path(project), class: dom_class(project) do
diff --git a/app/views/groups/people.html.haml b/app/views/groups/people.html.haml
index 258108089c3..68102b6a85a 100644
--- a/app/views/groups/people.html.haml
+++ b/app/views/groups/people.html.haml
@@ -1,12 +1,20 @@
-.ui-box
- %h5
- People
- %small
- (#{@users.size})
- %ul.unstyled
- - @users.each do |user|
- %li.wll
- = image_tag gravatar_icon(user.email, 16), class: "avatar s16"
- %strong= user.name
- %span.cgray= user.email
+.row
+ .span3
+ = render 'people_filter'
+ .span9
+ - if @project && can?(current_user, :manage_group, @group)
+ = render "new_member"
+ .ui-box
+ %h5
+ Team
+ %small
+ (#{@users.size})
+ %ul.unstyled
+ - @users.each do |user|
+ %li.wll
+ = image_tag gravatar_icon(user.email, 16), class: "avatar s16"
+ %strong= user.name
+ %span.cgray= user.email
+ - if @group.owner == user
+ %span.btn.btn-small.disabled.right Group Owner
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 72d7ad9a592..b929b267e8b 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -6,11 +6,10 @@
&nbsp;
%span.cgray Events and projects are filtered in scope of group
%hr
- = render 'shared/no_ssh'
- if @events.any?
.content_list= render @events
- else
- %h4.nothing_here_message Projects activity will be displayed here
+ %p.nothing_here_message Projects activity will be displayed here
.loading.hide
.side
= render "projects", projects: @projects
diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml
index 00085166bcf..3f16637dd2e 100644
--- a/app/views/help/api.html.haml
+++ b/app/views/help/api.html.haml
@@ -21,6 +21,8 @@
= link_to "Issues", "#issues", 'data-toggle' => 'tab'
%li
= link_to "Milestones", "#milestones", 'data-toggle' => 'tab'
+ %li
+ = link_to "Notes", "#notes", 'data-toggle' => 'tab'
.tab-content
.tab-pane.active#README
@@ -94,3 +96,12 @@
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "milestones.md"))
+
+ .tab-pane#notes
+ .file_holder
+ .file_title
+ %i.icon-file
+ Notes
+ .file_content.wiki
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "api", "notes.md"))
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 25fe9d806bc..4a0f60d36c2 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -2,7 +2,7 @@
%meta{charset: "utf-8"}
%title
GitLab
- = " > #{@project.name}" if @project && !@project.new_record?
+ = " > #{title}" if defined?(title)
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 38e1d7f0597..8fbec43f4a1 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -18,7 +18,7 @@
%li
= link_to profile_path, title: "Your Profile", class: 'has_bottom_tooltip', 'data-original-title' => 'Your profile' do
%i.icon-user
- %span.separator
+ %li.separator
%li
= render "layouts/search"
%li
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 502f289ec05..7b2a291d05c 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -1,6 +1,6 @@
:javascript
$(function() {
- GitLab.GfmAutoComplete.Members.url = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
+ GitLab.GfmAutoComplete.Members.url = "#{ "/api/v2/projects/#{@project.path}/members" if @project }";
GitLab.GfmAutoComplete.Members.params.private_token = "#{current_user.private_token}";
GitLab.GfmAutoComplete.Emoji.data = #{raw emoji_autocomplete_source};
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index 582f86ba32c..6b643ec8ccb 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Admin area"
@@ -8,8 +8,10 @@
%ul.main_menu
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to "Stats", admin_root_path
- = nav_link(controller: [:projects, :groups]) do
+ = nav_link(controller: :projects) do
= link_to "Projects", admin_projects_path
+ = nav_link(controller: :groups) do
+ = link_to "Groups", admin_groups_path
= nav_link(controller: :users) do
= link_to "Users", admin_users_path
= nav_link(controller: :logs) do
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 40f4f88cbce..a41de538436 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: "Dashboard"
%body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Dashboard"
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index 1f5c03bdced..3554d88f10c 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: "Error"
%body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: ""
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 985200e2539..d40d9525bb8 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: "#{@group.name}"
%body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "#{@group.name}"
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index 7b79897b653..35bf5577e1c 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -4,7 +4,7 @@
%title
GitLab
:css
- .header h1 {color: #BBBBBB !important; font: bold 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;}
+ .header h1 {color: #BBBBBB !important; font: bold 22px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;}
.header p {color: #c6c6c6; font: normal 12px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 18px;}
.content h2 {color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; }
.content p {color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif;}
@@ -20,7 +20,7 @@
%td{style: "font-size: 0px;", width: "20"}
\ 
%td{align: "left", style: "padding: 18px 0 10px;", width: "580"}
- %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"}
+ %h1{style: "color: #BBBBBB; font: normal 22px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;"}
GITLAB
- if @project
| #{@project.name}
@@ -35,5 +35,5 @@
%p{style: "font-size: 11px; color:#7d7a7a; margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif;"}
You're receiving this notification because you are a member of the
- if @project
- #{@project.name}
+ #{@project.name}
project team.
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 7a54bb7cf2f..b2743222281 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: "Profile"
%body{class: "#{app_theme} profile"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Profile"
diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml
index b1dbe41ce65..ab8e88c07cd 100644
--- a/app/views/layouts/project_resource.html.haml
+++ b/app/views/layouts/project_resource.html.haml
@@ -1,13 +1,15 @@
!!! 5
%html{ lang: "en"}
- = render "layouts/head"
+ = render "layouts/head", title: @project.name
%body{class: "#{app_theme} project"}
= render "layouts/flash"
= render "layouts/head_panel", title: @project.name
+ - if can?(current_user, :download_code, @project)
+ = render 'shared/no_ssh'
.container
%ul.main_menu
= nav_link(html_options: {class: "home #{project_tab_class}"}) do
- = link_to @project.code, project_path(@project), title: "Project"
+ = link_to @project.path, project_path(@project), title: "Project"
- if @project.repo_exists?
- if can? current_user, :download_code, @project
diff --git a/app/views/merge_requests/show/_diffs.html.haml b/app/views/merge_requests/show/_diffs.html.haml
index 7685090311a..0807454c4b0 100644
--- a/app/views/merge_requests/show/_diffs.html.haml
+++ b/app/views/merge_requests/show/_diffs.html.haml
@@ -1,8 +1,10 @@
- if @merge_request.valid_diffs?
= render "commits/diffs", diffs: @diffs
- elsif @merge_request.broken_diffs?
- %h4.nothing_here_message
+ %h4.nothing_here_message
Can't load diff.
- You can #{link_to "download MR patch", raw_project_merge_request_path(@project, @merge_request), class: "vlink"} instead.
+ You can
+ = link_to "download it", project_merge_request_path(@project, @merge_request), format: :diff, class: "vlink"
+ instead.
- else
%h4.nothing_here_message Nothing to merge
diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml
index 8708469cc5d..a5275650d86 100644
--- a/app/views/merge_requests/show/_mr_title.html.haml
+++ b/app/views/merge_requests/show/_mr_title.html.haml
@@ -13,9 +13,14 @@
= "MERGED"
- if can?(current_user, :modify_merge_request, @merge_request)
- if @merge_request.open?
- = link_to raw_project_merge_request_path(@project, @merge_request), class: "btn grouped" do
- %i.icon-download-alt
- Get Patch
+ .left.btn-group
+ %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
+ %i.icon-download-alt
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
+ %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
= link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close merge request"
diff --git a/app/views/notify/note_wiki_email.html.haml b/app/views/notify/note_wiki_email.html.haml
deleted file mode 100644
index 41a237fc53e..00000000000
--- a/app/views/notify/note_wiki_email.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"}
- %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"}
- %tr
- %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
- %td{align: "left", style: "padding: 20px 0 0;"}
- %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
- New comment for Wiki page
- = link_to_gfm @wiki.title, project_wiki_url(@wiki.project, @wiki, anchor: "note_#{@note.id}")
- %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
- %tr
- %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
- %td{style: "padding: 15px 0 15px;", valign: "top"}
- %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
- %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name}
- commented on Wiki page:
- %br
- %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"}
- %tr
- %td{valign: "top"}
- %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" }
- = markdown(@note.note)
- %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
-
diff --git a/app/views/profile/account.html.haml b/app/views/profile/account.html.haml
index 1e3a8b1a0d4..e2c5bcdb8e2 100644
--- a/app/views/profile/account.html.haml
+++ b/app/views/profile/account.html.haml
@@ -8,6 +8,7 @@
= link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
+
%fieldset
%legend
Private token
@@ -41,14 +42,28 @@
.clearfix
= f.label :password
- .input= f.password_field :password
+ .input= f.password_field :password, required: true
.clearfix
= f.label :password_confirmation
- .input= f.password_field :password_confirmation
- .actions
- = f.submit 'Save', class: "btn save-btn"
+ .input
+ = f.password_field :password_confirmation, required: true
+ .clearfix
+ .input
+ = f.submit 'Save password', class: "btn save-btn"
+%fieldset
+ %legend
+ Username
+ %small.right
+ Changing your username can have unintended side effects!
+ = form_for @user, url: profile_update_path, method: :put do |f|
+ .padded
+ = f.label :username
+ .input
+ = f.text_field :username, required: true
+ .input
+ = f.submit 'Save username', class: "btn save-btn"
diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml
index 461f4feaf61..2962ad980b3 100644
--- a/app/views/projects/_clone_panel.html.haml
+++ b/app/views/projects/_clone_panel.html.haml
@@ -6,12 +6,12 @@
.right
- unless @project.empty_repo?
- if can? current_user, :download_code, @project
- = link_to archive_project_repository_path(@project), class: "btn grouped" do
+ = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do
%i.icon-download-alt
Download
- if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
- = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn grouped" do
+ = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn-small btn grouped" do
Merge Request
- if @project.issues_enabled && can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), title: "New Issue", class: "btn grouped" do
+ = link_to new_project_issue_path(@project), title: "New Issue", class: "btn-small btn grouped" do
Issue
diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml
index 9ee65942fe9..5c60132cc82 100644
--- a/app/views/projects/_form.html.haml
+++ b/app/views/projects/_form.html.haml
@@ -9,48 +9,45 @@
Project name is
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
-
%fieldset
%legend Advanced settings:
- .clearfix
+ .control-group
= f.label :path do
- Path
- .input
- .input-prepend
- %strong
- = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
- .clearfix
- = f.label :code do
- URL
- .input
- .input-prepend
- %span.add-on= web_app_url
- = f.text_field :code, placeholder: "example"
-
- - unless @project.new_record? || @project.heads.empty?
+ Repository
+ .controls
+ = text_field_tag :ppath, @project.path_to_repo, class: "xxlarge", readonly: true
+
+ .control-group
+ = f.label :namespace_id do
+ %span Namespace
+ .controls
+ = f.select :namespace_id, namespaces_options(@project.namespace_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'}
+ &nbsp;
+ %span.cred Be careful. Changing project namespace can have unintended side effects
+
+ - unless @project.heads.empty?
.clearfix
= f.label :default_branch, "Default Branch"
.input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;")
- - unless @project.new_record?
- %fieldset
- %legend Features:
+ %fieldset
+ %legend Features:
- .clearfix
- = f.label :issues_enabled, "Issues"
- .input= f.check_box :issues_enabled
+ .clearfix
+ = f.label :issues_enabled, "Issues"
+ .input= f.check_box :issues_enabled
- .clearfix
- = f.label :merge_requests_enabled, "Merge Requests"
- .input= f.check_box :merge_requests_enabled
+ .clearfix
+ = f.label :merge_requests_enabled, "Merge Requests"
+ .input= f.check_box :merge_requests_enabled
- .clearfix
- = f.label :wall_enabled, "Wall"
- .input= f.check_box :wall_enabled
+ .clearfix
+ = f.label :wall_enabled, "Wall"
+ .input= f.check_box :wall_enabled
- .clearfix
- = f.label :wiki_enabled, "Wiki"
- .input= f.check_box :wiki_enabled
+ .clearfix
+ = f.label :wiki_enabled, "Wiki"
+ .input= f.check_box :wiki_enabled
%br
diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml
index e6d5e93fca7..2ef29cb0c65 100644
--- a/app/views/projects/_new_form.html.haml
+++ b/app/views/projects/_new_form.html.haml
@@ -9,21 +9,12 @@
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit 'Create project', class: "btn primary project-submit"
- %hr
- %div.adv_settings
- %h6 Advanced settings:
- .clearfix
- = f.label :path do
- Git Clone
- .input
- .input-prepend
- %span.add-on= Gitlab.config.ssh_path
- = f.text_field :path, placeholder: "example_project", disabled: !@project.new_record?
- %span.add-on= ".git"
+ - if current_user.several_namespaces?
.clearfix
- = f.label :code do
- URL
+ = f.label :namespace_id do
+ %span.cgray Namespace
.input
- .input-prepend
- %span.add-on= web_app_url
- = f.text_field :code, placeholder: "example"
+ = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'}
+ %hr
+ %p.padded
+ All created project are private. You choose who can see project and commit to repository.
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index d9a151fc706..f331ae7fadc 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,31 +1,33 @@
-= render 'shared/no_ssh'
= render 'clone_panel'
%div.git-empty
- %h4 Git global setup:
- %pre.dark
- = preserve do
- git config --global user.name "#{current_user.name}"
- git config --global user.email "#{current_user.email}"
+ %fieldset
+ %legend Git global setup:
+ %pre.dark
+ = preserve do
+ git config --global user.name "#{current_user.name}"
+ git config --global user.email "#{current_user.email}"
- %h4.prepend-top-20 Create Repository
- %pre.dark
- = preserve do
- mkdir #{@project.path}
- cd #{@project.path}
- git init
- touch README
- git add README
- git commit -m 'first commit'
- git remote add origin #{@project.url_to_repo}
- git push -u origin master
+ %fieldset
+ %legend Create Repository
+ %pre.dark
+ = preserve do
+ mkdir #{@project.path}
+ cd #{@project.path}
+ git init
+ touch README
+ git add README
+ git commit -m 'first commit'
+ git remote add origin #{@project.url_to_repo}
+ git push -u origin master
- %h4.prepend-top-20 Existing Git Repo?
- %pre.dark
- = preserve do
- cd existing_git_repo
- git remote add origin #{@project.url_to_repo}
- git push -u origin master
+ %fieldset
+ %legend Existing Git Repo?
+ %pre.dark
+ = preserve do
+ cd existing_git_repo
+ git remote add origin #{@project.url_to_repo}
+ git push -u origin master
- if can? current_user, :admin_project, @project
.prepend-top-20
diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml
index 8aaa0e491dd..f44ed529182 100644
--- a/app/views/projects/update.js.haml
+++ b/app/views/projects/update.js.haml
@@ -1,6 +1,6 @@
- if @project.valid?
:plain
- location.href = "#{edit_project_path(@project, notice: 'Project was successfully updated.')}";
+ location.href = "#{edit_project_path(@project)}";
- else
:plain
$('.project_edit_holder').show();
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 0d5f545850a..8448193deb9 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -23,7 +23,7 @@
%tr
%td
= link_to project do
- %strong.term= project.name
+ %strong.term= project.name_with_namespace
%small.cgray
last activity at
= project.last_activity_date.stamp("Aug 25, 2011")
diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml
index 3c9820b32b4..4c1ec5bc348 100644
--- a/app/views/services/_gitlab_ci.html.haml
+++ b/app/views/services/_gitlab_ci.html.haml
@@ -25,7 +25,7 @@
= f.check_box :active
.control-group
- = f.label :active, "Project URL", class: "control-label"
+ = f.label :project_url, "Project URL", class: "control-label"
.controls
= f.text_field :project_url, class: "input-xlarge", placeholder: "http://ci.gitlabhq.com/projects/3"
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 924eb3fcae4..f632e1221f9 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -1,4 +1,4 @@
.input-prepend.project_clone_holder
%button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH
%button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.web_protocol.upcase
- = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5"
+ = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge"
diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml
index c75a1d93b70..5fdcea850b2 100644
--- a/app/views/shared/_no_ssh.html.haml
+++ b/app/views/shared/_no_ssh.html.haml
@@ -1,3 +1,3 @@
- if current_user.require_ssh_key?
- %p.error_message
- You won't be able to pull or push project code until you #{link_to 'add an SSH key', new_key_path} to your profile
+ %p.error_message.centered
+ You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_key_path} to your profile
diff --git a/app/views/snippets/_blob.html.haml b/app/views/snippets/_blob.html.haml
new file mode 100644
index 00000000000..ed518300ac0
--- /dev/null
+++ b/app/views/snippets/_blob.html.haml
@@ -0,0 +1,12 @@
+.file_holder
+ .file_title
+ %i.icon-file
+ %strong= @snippet.file_name
+ %span.options
+ = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank"
+ .file_content.code
+ - unless @snippet.content.empty?
+ %div{class: user_color_scheme_class}
+ = raw @snippet.colorize(formatter: :gitlab)
+ - else
+ %p.nothing_here_message Empty file
diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml
index e61e61a7e5e..981c7cf0c12 100644
--- a/app/views/snippets/_form.html.haml
+++ b/app/views/snippets/_form.html.haml
@@ -1,27 +1,27 @@
-%h3= @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
+%h3.page_title
+ = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
%hr
= form_for [@project, @snippet] do |f|
- %table.no-borders
- -if @snippet.errors.any?
- .alert-message.block-message.error
- %ul
- - @snippet.errors.full_messages.each do |msg|
- %li= msg
+ -if @snippet.errors.any?
+ .alert-message.block-message.error
+ %ul
+ - @snippet.errors.full_messages.each do |msg|
+ %li= msg
- .clearfix
- = f.label :title
- .input= f.text_field :title, placeholder: "Example Snippet"
- .clearfix
- = f.label :file_name
- .input= f.text_field :file_name, placeholder: "example.rb"
- .clearfix
- = f.label "Lifetime"
- .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
- .clearfix
- = f.label :content, "Code"
- .input= f.text_area :content, class: "span8"
+ .clearfix
+ = f.label :title
+ .input= f.text_field :title, placeholder: "Example Snippet"
+ .clearfix
+ = f.label :file_name
+ .input= f.text_field :file_name, placeholder: "example.rb"
+ .clearfix
+ = f.label "Lifetime"
+ .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
+ .clearfix
+ = f.label :content, "Code"
+ .input= f.text_area :content, class: "span8"
- .actions
+ .form-actions
= f.submit 'Save', class: "primary btn"
= link_to "Cancel", project_snippets_path(@project), class: " btn"
- unless @snippet.new_record?
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 1b8701e91ed..f3e01928077 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -7,17 +7,5 @@
= link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn small right"
%br
-%div
- .file_holder
- .file_title
- %i.icon-file
- %strong= @snippet.file_name
- %span.options
- = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank"
- .file_content.code
- %div{class: current_user.dark_scheme ? "black" : ""}
- = raw @snippet.colorize(options: { linenos: 'True'})
-
-
-%div
- = render "notes/notes_with_form", tid: @snippet.id, tt: "snippet"
+%div= render 'blob'
+%div#notes= render "notes/notes_with_form", tid: @snippet.id, tt: "snippet"
diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml
index f68f8eb471f..8938c7d8a6d 100644
--- a/app/views/team_members/_show.html.haml
+++ b/app/views/team_members/_show.html.haml
@@ -1,26 +1,28 @@
- user = member.user
- allow_admin = can? current_user, :admin_project, @project
-%tr{id: dom_id(member), class: "team_member_row user_#{user.id}"}
- %td.span6
- = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
- = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
- = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
- %strong= truncate(user.name, lenght: 40)
- %br
- %small.cgray= user.email
+%li.wll{id: dom_id(member), class: "team_member_row user_#{user.id}"}
+ .row
+ .span6
+ = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
+ = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
+ = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
+ %strong= truncate(user.name, lenght: 40)
+ %br
+ %small.cgray= user.email
- %td.span5
- .right
- - if current_user == user
- %span.btn.disabled This is you!
- - if @project.owner == user
- %span.btn.disabled.success Owner
- - elsif user.blocked
- %span.btn.disabled.blocked Blocked
- - elsif allow_admin
- = link_to project_team_member_path(project_id: @project, id: member.id), confirm: remove_from_team_message(@project, member), method: :delete, class: "very_small btn danger" do
- %i.icon-minus.icon-white
+ .span5.right
+ - if allow_admin
+ .left
+ = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|
+ = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2"
+ .right
+ - if current_user == user
+ %span.btn.disabled This is you!
+ - if @project.namespace_owner == user
+ %span.btn.disabled.success Owner
+ - elsif user.blocked
+ %span.btn.disabled.blocked Blocked
+ - elsif allow_admin
+ = link_to project_team_member_path(project_id: @project, id: member.id), confirm: remove_from_team_message(@project, member), method: :delete, class: "very_small btn danger" do
+ %i.icon-minus.icon-white
- - if allow_admin
- = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|
- = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2"
diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml
index 26d13533b5c..65f17864814 100644
--- a/app/views/team_members/_team.html.haml
+++ b/app/views/team_members/_team.html.haml
@@ -1,11 +1,9 @@
- grouper_project_members(@project).each do |access, members|
- %table.low
- %thead
- %tr
- %th.span7
- = Project.access_options.key(access).pluralize
- %th
- %tbody
+ %fieldset
+ %legend
+ = Project.access_options.key(access).pluralize
+ %small= members.size
+ %ul.unstyled
- members.each do |up|
= render(partial: 'team_members/show', locals: {member: up})
diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml
index ca3edcf7ffb..e413c81bb6c 100644
--- a/app/views/team_members/index.html.haml
+++ b/app/views/team_members/index.html.haml
@@ -1,18 +1,20 @@
= render "projects/project_head"
%h3.page_title
Team Members
- %small (#{@project.users_projects.count})
-
-- if can? current_user, :admin_team_member, @project
- %p.slead
+ (#{@project.users_projects.count})
+ %small
Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
+ - if can? current_user, :admin_team_member, @project
%span.right
= link_to import_project_team_members_path(@project), class: "btn small grouped", title: "Import team from another project" do
Import team from another project
= link_to new_project_team_member_path(@project), class: "btn success small grouped", title: "New Team Member" do
New Team Member
+%hr
+
- .clearfix
-= render partial: "team_members/team", locals: {project: @project}
+.clearfix
+%div.team-table
+ = render partial: "team_members/team", locals: {project: @project}
diff --git a/app/views/tree/_head.html.haml b/app/views/tree/_head.html.haml
index f8e5c99f06a..f14526cf23a 100644
--- a/app/views/tree/_head.html.haml
+++ b/app/views/tree/_head.html.haml
@@ -4,4 +4,4 @@
= nav_link(controller: :tree) do
= link_to 'Source', project_tree_path(@project, @ref)
%li.right
- = render "shared/clone_panel" \ No newline at end of file
+ = render "shared/clone_panel"
diff --git a/app/views/tree/blob/_text.html.haml b/app/views/tree/blob/_text.html.haml
index 9e0f4bc4bc1..122e275219d 100644
--- a/app/views/tree/blob/_text.html.haml
+++ b/app/views/tree/blob/_text.html.haml
@@ -8,8 +8,7 @@
- else
.file_content.code
- unless blob.empty?
- %div{class: current_user.dark_scheme ? "black" : "white"}
- = preserve do
- = raw blob.colorize(formatter: :gitlab)
+ %div{class: user_color_scheme_class}
+ = raw blob.colorize(formatter: :gitlab)
- else
- %h4.nothing_here_message Empty file
+ %p.nothing_here_message Empty file
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index 579ea1b3ad6..c3074539054 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -19,6 +19,3 @@
- if can? current_user, :admin_wiki, @project
= link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete do
Delete this page
-
-%hr
-.wiki_notes#notes= render "notes/notes_with_form", tid: @wiki.id, tt: "wiki"
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 10128660cd4..4f4f69c4ece 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -7,8 +7,8 @@ class PostReceive
# Ignore push from non-gitlab users
user = if identifier.eql? Gitlab.config.gitolite_admin_key
- email = project.commit(newrev).author.email
- User.find_by_email(email)
+ email = project.commit(newrev).author.email rescue nil
+ User.find_by_email(email) if email
elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier)
User.find_by_email(identifier)
else
diff --git a/config/database.yml.sqlite b/config/database.yml.sqlite
deleted file mode 100644
index 591448f6bee..00000000000
--- a/config/database.yml.sqlite
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# PRODUCTION
-#
-# SQLite version 3.x
-# gem install sqlite3
-#
-# Ensure the SQLite 3 gem is defined in your Gemfile
-# gem 'sqlite3'
-production:
- adapter: sqlite3
- database: db/production.sqlite3
- pool: 5
- timeout: 5000
-
-#
-# Development specific
-#
-development:
- adapter: sqlite3
- database: db/development.sqlite3
- pool: 5
- timeout: 5000
-
-# Warning: The database defined as "test" will be erased and
-# re-generated from your development database when you run "rake".
-# Do not set this db to the same as development or production.
-test: &test
- adapter: sqlite3
- database: db/test.sqlite3
- pool: 5
- timeout: 5000
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index 3549b8362bb..8f8bef42bef 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -4,4 +4,5 @@
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone
-Mime::Type.register_alias 'text/plain', :patch
+Mime::Type.register_alias "text/plain", :diff
+Mime::Type.register_alias "text/plain", :patch
diff --git a/config/routes.rb b/config/routes.rb
index 98cf7e812c9..9c58ce17fc2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,7 +18,7 @@ Gitlab::Application.routes.draw do
project_root: Gitlab.config.git_base_path,
upload_pack: Gitlab.config.git_upload_pack,
receive_pack: Gitlab.config.git_receive_pack
- }), at: '/:path', constraints: { path: /[\w\.-]+\.git/ }
+ }), at: '/:path', constraints: { path: /[-\/\w\.-]+\.git/ }
#
# Help
@@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do
delete :remove_project
end
end
- resources :projects, constraints: { id: /[^\/]+/ } do
+ resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create] do
member do
get :team
put :team_update
@@ -107,7 +107,7 @@ Gitlab::Application.routes.draw do
#
# Project Area
#
- resources :projects, constraints: { id: /[^\/]+/ }, except: [:new, :create, :index], path: "/" do
+ resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do
member do
get "wall"
get "graph"
@@ -159,12 +159,11 @@ Gitlab::Application.routes.draw do
end
end
- resources :merge_requests do
+ resources :merge_requests, constraints: {id: /\d+/} do
member do
get :diffs
get :automerge
get :automerge_check
- get :raw
end
collection do
diff --git a/db/fixtures/development/001_admin.rb b/db/fixtures/development/001_admin.rb
index c857f6bcb3f..fbe41e4d22d 100644
--- a/db/fixtures/development/001_admin.rb
+++ b/db/fixtures/development/001_admin.rb
@@ -1,21 +1,11 @@
-unless User.count > 0
- admin = User.create(
- :email => "admin@local.host",
- :name => "Administrator",
- :password => "5iveL!fe",
- :password_confirmation => "5iveL!fe"
- )
-
- admin.projects_limit = 10000
- admin.admin = true
- admin.save!
-
- if admin.valid?
- puts %q[
- Administrator account created:
-
- login.........admin@local.host
- password......5iveL!fe
- ]
- end
-end
+User.seed(:id, [
+ {
+ id: 1,
+ name: "Administrator",
+ email: "admin@local.host",
+ username: 'root',
+ password: "5iveL!fe",
+ password_confirmation: "5iveL!fe",
+ admin: true,
+ }
+])
diff --git a/db/fixtures/development/002_project.rb b/db/fixtures/development/002_project.rb
index eb68b5fe93a..91d42a14201 100644
--- a/db/fixtures/development/002_project.rb
+++ b/db/fixtures/development/002_project.rb
@@ -1,5 +1,5 @@
Project.seed(:id, [
- { id: 1, name: "Underscore.js", path: "underscore", code: "underscore", owner_id: 1 },
- { id: 2, name: "Diaspora", path: "diaspora", code: "diaspora", owner_id: 1 },
- { id: 3, name: "Ruby on Rails", path: "rails", code: "rails", owner_id: 1 }
+ { id: 1, name: "Underscore.js", path: "underscore", owner_id: 1, namespace_id: 1 },
+ { id: 2, name: "Diaspora", path: "diaspora", owner_id: 1 },
+ { id: 3, name: "Ruby on Rails", path: "rails", owner_id: 1 }
])
diff --git a/db/fixtures/development/003_users.rb b/db/fixtures/development/003_users.rb
index 309eb90b1bf..25705f1b726 100644
--- a/db/fixtures/development/003_users.rb
+++ b/db/fixtures/development/003_users.rb
@@ -1,11 +1,11 @@
User.seed(:id, [
- { :id => 2, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 3, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 4, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 5, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 6, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 7, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 8, :name => Faker::Internet.user_name, :email => Faker::Internet.email},
- { :id => 9, :name => Faker::Internet.user_name, :email => Faker::Internet.email}
+ { id: 2, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 3, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 4, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 5, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 6, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 7, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 8, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email},
+ { id: 9, username: Faker::Internet.user_name, name: Faker::Name.name, email: Faker::Internet.email}
])
diff --git a/db/fixtures/development/009_source_code.rb b/db/fixtures/development/009_source_code.rb
index 489bd02ea32..849d1aab8ae 100644
--- a/db/fixtures/development/009_source_code.rb
+++ b/db/fixtures/development/009_source_code.rb
@@ -1,7 +1,7 @@
root = Gitlab.config.git_base_path
projects = [
- { path: 'underscore.git', git: 'https://github.com/documentcloud/underscore.git' },
+ { path: 'root/underscore.git', git: 'https://github.com/documentcloud/underscore.git' },
{ path: 'diaspora.git', git: 'https://github.com/diaspora/diaspora.git' },
{ path: 'rails.git', git: 'https://github.com/rails/rails.git' },
]
@@ -13,9 +13,10 @@ projects.each do |project|
next if File.exists?(project_path)
cmds = [
- "cd #{root} && sudo -u git -H git clone --bare #{project[:git]}",
+ "cd #{root} && sudo -u git -H git clone --bare #{project[:git]} ./#{project[:path]}",
"sudo cp ./lib/hooks/post-receive #{project_path}/hooks/post-receive",
- "sudo chown git:git #{project_path}/hooks/post-receive"
+ "sudo chown git:git -R #{project_path}",
+ "sudo chmod 770 -R #{project_path}",
]
cmds.each do |cmd|
diff --git a/db/fixtures/development/010_groups.rb b/db/fixtures/development/010_groups.rb
new file mode 100644
index 00000000000..09371b00751
--- /dev/null
+++ b/db/fixtures/development/010_groups.rb
@@ -0,0 +1,11 @@
+Group.seed(:id, [
+ { id: 100, name: "Gitlab", path: 'gitlab', owner_id: 1},
+ { id: 101, name: "Rails", path: 'rails', owner_id: 1 },
+ { id: 102, name: "KDE", path: 'kde', owner_id: 1 }
+])
+
+Project.seed(:id, [
+ { id: 10, name: "kdebase", path: "kdebase", owner_id: 1, namespace_id: 102 },
+ { id: 11, name: "kdelibs", path: "kdelibs", owner_id: 1, namespace_id: 102 },
+ { id: 12, name: "amarok", path: "amarok", owner_id: 1, namespace_id: 102 }
+])
diff --git a/db/fixtures/production/001_admin.rb b/db/fixtures/production/001_admin.rb
index cfff6bf8bc2..f119694d11d 100644
--- a/db/fixtures/production/001_admin.rb
+++ b/db/fixtures/production/001_admin.rb
@@ -1,8 +1,9 @@
admin = User.create(
- :email => "admin@local.host",
- :name => "Administrator",
- :password => "5iveL!fe",
- :password_confirmation => "5iveL!fe"
+ email: "admin@local.host",
+ name: "Administrator",
+ username: 'root',
+ password: "5iveL!fe",
+ password_confirmation: "5iveL!fe"
)
admin.projects_limit = 10000
diff --git a/db/migrate/20121122145155_convert_group_to_namespace.rb b/db/migrate/20121122145155_convert_group_to_namespace.rb
new file mode 100644
index 00000000000..fc8b023d814
--- /dev/null
+++ b/db/migrate/20121122145155_convert_group_to_namespace.rb
@@ -0,0 +1,13 @@
+class ConvertGroupToNamespace < ActiveRecord::Migration
+ def up
+ rename_table 'groups', 'namespaces'
+ add_column :namespaces, :type, :string, null: true
+
+ # Migrate old groups
+ Namespace.update_all(type: 'Group')
+ end
+
+ def down
+ raise 'Rollback is not allowed'
+ end
+end
diff --git a/db/migrate/20121122150932_add_namespace_id_to_project.rb b/db/migrate/20121122150932_add_namespace_id_to_project.rb
new file mode 100644
index 00000000000..904f3aa32be
--- /dev/null
+++ b/db/migrate/20121122150932_add_namespace_id_to_project.rb
@@ -0,0 +1,5 @@
+class AddNamespaceIdToProject < ActiveRecord::Migration
+ def change
+ rename_column :projects, :group_id, :namespace_id
+ end
+end
diff --git a/db/migrate/20121123104937_add_username_to_user.rb b/db/migrate/20121123104937_add_username_to_user.rb
new file mode 100644
index 00000000000..04232a119d9
--- /dev/null
+++ b/db/migrate/20121123104937_add_username_to_user.rb
@@ -0,0 +1,5 @@
+class AddUsernameToUser < ActiveRecord::Migration
+ def change
+ add_column :users, :username, :string, null: true
+ end
+end
diff --git a/db/migrate/20121123164910_rename_code_to_path.rb b/db/migrate/20121123164910_rename_code_to_path.rb
new file mode 100644
index 00000000000..fb10baf58cf
--- /dev/null
+++ b/db/migrate/20121123164910_rename_code_to_path.rb
@@ -0,0 +1,11 @@
+class RenameCodeToPath < ActiveRecord::Migration
+ def up
+ remove_column :projects, :code
+ rename_column :namespaces, :code, :path
+ end
+
+ def down
+ add_column :projects, :code, :string
+ rename_column :namespaces, :path, :code
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 27b1f4aa84a..32dafed2b63 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20121120113838) do
+ActiveRecord::Schema.define(:version => 20121123164910) do
create_table "events", :force => true do |t|
t.string "target_type"
@@ -25,14 +25,6 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.integer "author_id"
end
- create_table "groups", :force => true do |t|
- t.string "name", :null => false
- t.string "code", :null => false
- t.integer "owner_id", :null => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
create_table "issues", :force => true do |t|
t.string "title"
t.integer "assignee_id"
@@ -88,6 +80,15 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "updated_at", :null => false
end
+ create_table "namespaces", :force => true do |t|
+ t.string "name", :null => false
+ t.string "path", :null => false
+ t.integer "owner_id", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "type"
+ end
+
create_table "notes", :force => true do |t|
t.text "note"
t.string "noteable_id"
@@ -110,14 +111,13 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "private_flag", :default => true, :null => false
- t.string "code"
t.integer "owner_id"
t.string "default_branch"
t.boolean "issues_enabled", :default => true, :null => false
t.boolean "wall_enabled", :default => true, :null => false
t.boolean "merge_requests_enabled", :default => true, :null => false
t.boolean "wiki_enabled", :default => true, :null => false
- t.integer "group_id"
+ t.integer "namespace_id"
end
create_table "protected_branches", :force => true do |t|
@@ -194,6 +194,7 @@ ActiveRecord::Schema.define(:version => 20121120113838) do
t.datetime "locked_at"
t.string "extern_uid"
t.string "provider"
+ t.string "username"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
diff --git a/doc/api/notes.md b/doc/api/notes.md
new file mode 100644
index 00000000000..97899fa0f6e
--- /dev/null
+++ b/doc/api/notes.md
@@ -0,0 +1,136 @@
+## List notes
+
+### List project wall notes
+
+Get a list of project wall notes.
+
+```
+GET /projects/:id/notes
+```
+
+```json
+[
+ {
+ "id": 522,
+ "body": "The solution is rather tricky",
+ "author": {
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z"
+ },
+ "created_at": "2012-11-27T19:16:44Z"
+ }
+]
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
+
+### List issue notes
+
+Get a list of issue notes.
+
+```
+GET /projects/:id/issues/:issue_id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of an issue
+
+### List snippet notes
+
+Get a list of snippet notes.
+
+```
+GET /projects/:id/snippets/:snippet_id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a snippet
+
+## Single note
+
+### Single issue note
+
+Get an issue note.
+
+```
+GET /projects/:id/issues/:issue_id/:notes/:note_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of a project issue
++ `note_id` (required) - The ID of an issue note
+
+### Single snippet note
+
+Get a snippet note.
+
+```
+GET /projects/:id/issues/:snippet_id/:notes/:note_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of a project snippet
++ `note_id` (required) - The ID of an snippet note
+
+## New note
+
+### New wall note
+
+Create a new wall note.
+
+```
+POST /projects/:id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `body` (required) - The content of a note
+
+Will return created note with status `201 Created` on success, or `404 Not found` on fail.
+
+
+### New issue note
+
+Create a new issue note.
+
+```
+POST /projects/:id/issues/:issue_id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of an issue
++ `body` (required) - The content of a note
+
+Will return created note with status `201 Created` on success, or `404 Not found` on fail.
+
+### New snippet note
+
+Create a new snippet note.
+
+```
+POST /projects/:id/snippets/:snippet_id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `snippet_id` (required) - The ID of an snippet
++ `body` (required) - The content of a note
+
+Will return created note with status `201 Created` on success, or `404 Not found` on fail.
diff --git a/doc/install/databases.md b/doc/install/databases.md
index b7beff26a0f..1a6f739ecdc 100644
--- a/doc/install/databases.md
+++ b/doc/install/databases.md
@@ -1,12 +1,8 @@
# Databases:
-GitLab use mysql as default database but you are free to use PostgreSQL or SQLite.
+GitLab use MySQL as default database but you are free to use PostgreSQL.
-## SQLite
-
- sudo apt-get install -y sqlite3 libsqlite3-dev
-
## MySQL
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
@@ -47,9 +43,6 @@ GitLab use mysql as default database but you are free to use PostgreSQL or SQLit
#### Select the database you want to use
- # SQLite
- sudo -u gitlab cp config/database.yml.sqlite config/database.yml
-
# Mysql
sudo -u gitlab cp config/database.yml.mysql config/database.yml
@@ -61,11 +54,7 @@ GitLab use mysql as default database but you are free to use PostgreSQL or SQLit
#### Install gems
# mysql
- sudo -u gitlab -H bundle install --without development test sqlite postgres --deployment
+ sudo -u gitlab -H bundle install --without development test postgres --deployment
# or postgres
- sudo -u gitlab -H bundle install --without development test sqlite mysql --deployment
-
- # or sqlite
- sudo -u gitlab -H bundle install --without development test mysql postgres --deployment
-
+ sudo -u gitlab -H bundle install --without development test mysql --deployment
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 07ed0b0f9de..6876a8756b1 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -178,7 +178,7 @@ and ensure you have followed all of the above steps carefully.
sudo gem install charlock_holmes --version '0.6.9'
sudo gem install bundler
- sudo -u gitlab -H bundle install --without development test sqlite postgres --deployment
+ sudo -u gitlab -H bundle install --without development test postgres --deployment
#### Configure git client
@@ -269,7 +269,7 @@ You can login via web using admin generated with setup:
# Advanced setup tips:
-_Checkout databases.md for postgres or sqlite_
+_Checkout databases.md for PostgreSQL_
## Customizing Resque's Redis connection
diff --git a/features/admin/active_tab.feature b/features/admin/active_tab.feature
index fce85ce9901..226d3d5d5b5 100644
--- a/features/admin/active_tab.feature
+++ b/features/admin/active_tab.feature
@@ -12,6 +12,11 @@ Feature: Admin active tab
Then the active main tab should be Projects
And no other main tabs should be active
+ Scenario: On Admin Groups
+ Given I visit admin groups page
+ Then the active main tab should be Groups
+ And no other main tabs should be active
+
Scenario: On Admin Users
Given I visit admin users page
Then the active main tab should be Users
diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature
index 24296f46579..972f8e36609 100644
--- a/features/dashboard/dashboard.feature
+++ b/features/dashboard/dashboard.feature
@@ -15,6 +15,12 @@ Feature: Dashboard
And I visit dashboard page
Then I should see groups list
+ Scenario: I should see correct projects count
+ Given I have group with projects
+ And group has a projects that does not belongs to me
+ When I visit dashboard page
+ Then I should see 1 project at group list
+
Scenario: I should see last push widget
Then I should see last push widget
And I click "Create Merge Request" link
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index 596e8bd7d41..99529373d4d 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -57,13 +57,14 @@ Feature: Project Issues
Then I should see "Release 0.3" in issues
And I should not see "Release 0.4" in issues
- @javascript
- Scenario: I clear search
- Given I click link "All"
- And I fill in issue search with "Something"
- And I fill in issue search with ""
- Then I should see "Release 0.4" in issues
- And I should see "Release 0.3" in issues
+ # TODO: find out solution for poltergeist/phantomjs or remove
+ # @javascript
+ # Scenario: I clear search
+ # Given I click link "All"
+ # And I fill in issue search with "Something"
+ # And I fill in issue search with ""
+ # Then I should see "Release 0.4" in issues
+ # And I should see "Release 0.3" in issues
@javascript
Scenario: I create Issue with pre-selected milestone
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 51370565a3b..f052e2f244c 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -7,9 +7,3 @@ Feature: Project Wiki
Scenario: Add new page
Given I create Wiki page
Then I should see newly created wiki page
-
- @javascript
- Scenario: I comment wiki page
- Given I create Wiki page
- And I leave a comment like "XML attached"
- Then I should see comment "XML attached"
diff --git a/features/steps/admin/admin_active_tab.rb b/features/steps/admin/admin_active_tab.rb
index 29290892823..05a9a686e01 100644
--- a/features/steps/admin/admin_active_tab.rb
+++ b/features/steps/admin/admin_active_tab.rb
@@ -11,6 +11,10 @@ class AdminActiveTab < Spinach::FeatureSteps
ensure_active_main_tab('Projects')
end
+ Then 'the active main tab should be Groups' do
+ ensure_active_main_tab('Groups')
+ end
+
Then 'the active main tab should be Users' do
ensure_active_main_tab('Users')
end
diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb
index e1759013ce7..5386f473320 100644
--- a/features/steps/admin/admin_groups.rb
+++ b/features/steps/admin/admin_groups.rb
@@ -9,8 +9,7 @@ class AdminGroups < Spinach::FeatureSteps
And 'submit form with new group info' do
fill_in 'group_name', :with => 'gitlab'
- fill_in 'group_code', :with => 'gitlab'
- click_button "Save group"
+ click_button "Create group"
end
Then 'I should see newly created group' do
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
index 99c48738876..775a721f1a4 100644
--- a/features/steps/dashboard/dashboard.rb
+++ b/features/steps/dashboard/dashboard.rb
@@ -103,4 +103,14 @@ class Dashboard < Spinach::FeatureSteps
page.should have_link group.name
end
end
+
+ And 'group has a projects that does not belongs to me' do
+ @forbidden_project1 = create(:project, group: @group)
+ @forbidden_project2 = create(:project, group: @group)
+ end
+
+ Then 'I should see 1 project at group list' do
+ page.find('span.last_activity/span').should have_content('1')
+ end
+
end
diff --git a/features/steps/dashboard/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb
index e5caf905f95..5ace88023f0 100644
--- a/features/steps/dashboard/dashboard_issues.rb
+++ b/features/steps/dashboard/dashboard_issues.rb
@@ -7,6 +7,7 @@ class DashboardIssues < Spinach::FeatureSteps
issues.each do |issue|
page.should have_content(issue.title[0..10])
page.should have_content(issue.project.name)
+ page.should have_link(issue.project.name)
end
end
diff --git a/features/steps/project/create_project.rb b/features/steps/project/create_project.rb
index 6d2ca3f9b56..b9b4534ed68 100644
--- a/features/steps/project/create_project.rb
+++ b/features/steps/project/create_project.rb
@@ -4,8 +4,6 @@ class CreateProject < Spinach::FeatureSteps
And 'fill project form with valid data' do
fill_in 'project_name', :with => 'NewProject'
- fill_in 'project_code', :with => 'NPR'
- fill_in 'project_path', :with => 'newproject'
click_button "Create project"
end
diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb
index 88bfac638d0..cc0acb5b481 100644
--- a/features/steps/project/project_issues.rb
+++ b/features/steps/project/project_issues.rb
@@ -73,7 +73,6 @@ class ProjectIssues < Spinach::FeatureSteps
end
And 'I fill in issue search with ""' do
- page.execute_script("$('.issue_search').val('').keyup();");
fill_in 'issue_search', with: ""
end
diff --git a/features/support/env.rb b/features/support/env.rb
index 1a72d765197..a30b357718e 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -32,6 +32,11 @@ end
DatabaseCleaner.strategy = :truncation
Spinach.hooks.before_scenario do
+ # Use tmp dir for FS manipulations
+ Gitlab.config.stub(git_base_path: Rails.root.join('tmp', 'test-git-base-path'))
+ FileUtils.rm_rf Gitlab.config.git_base_path
+ FileUtils.mkdir_p Gitlab.config.git_base_path
+
DatabaseCleaner.start
end
diff --git a/lib/api.rb b/lib/api.rb
index 7a1845443e7..99e2074f306 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -19,5 +19,6 @@ module Gitlab
mount Milestones
mount Session
mount MergeRequests
+ mount Notes
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 9e605a607a2..f985636aa10 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -70,8 +70,15 @@ module Gitlab
end
class Note < Grape::Entity
+ expose :id
+ expose :note, as: :body
expose :author, using: Entities::UserBasic
+ expose :created_at
+ end
+
+ class MRNote < Grape::Entity
expose :note
+ expose :author, using: Entities::UserBasic
end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index a339ec4a6fc..e9305b40836 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -6,7 +6,7 @@ module Gitlab
def user_project
if @project ||= current_user.projects.find_by_id(params[:id]) ||
- current_user.projects.find_by_code(params[:id])
+ current_user.projects.find_by_path(params[:id])
else
not_found!
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index d8f2c51293a..1fa0c549b13 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -4,9 +4,9 @@ module Gitlab
before { authenticate! }
resource :projects do
-
+
# List merge requests
- #
+ #
# Parameters:
# id (required) - The ID or code name of a project
#
@@ -15,24 +15,24 @@ module Gitlab
#
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
-
+
present paginate(user_project.merge_requests), with: Entities::MergeRequest
end
-
+
# Show MR
- #
+ #
# Parameters:
# id (required) - The ID or code name of a project
# merge_request_id (required) - The ID of MR
- #
+ #
# Example:
# GET /projects/:id/merge_request/:merge_request_id
#
get ":id/merge_request/:merge_request_id" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
-
+
authorize! :read_merge_request, merge_request
-
+
present merge_request, with: Entities::MergeRequest
end
@@ -45,17 +45,17 @@ module Gitlab
# target_branch (required) - The target branch
# assignee_id - Assignee user ID
# title (required) - Title of MR
- #
+ #
# Example:
# POST /projects/:id/merge_requests
#
post ":id/merge_requests" do
authorize! :write_merge_request, user_project
-
+
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title]
merge_request = user_project.merge_requests.new(attrs)
merge_request.author = current_user
-
+
if merge_request.save
merge_request.reload_code
present merge_request, with: Entities::MergeRequest
@@ -80,9 +80,9 @@ module Gitlab
put ":id/merge_request/:merge_request_id" do
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
-
+
authorize! :modify_merge_request, merge_request
-
+
if merge_request.update_attributes attrs
merge_request.reload_code
merge_request.mark_as_unchecked
@@ -98,7 +98,7 @@ module Gitlab
# id (required) - The ID or code name of a project
# merge_request_id (required) - ID of MR
# note (required) - Text of comment
- # Examples:
+ # Examples:
# POST /projects/:id/merge_request/:merge_request_id/comments
#
post ":id/merge_request/:merge_request_id/comments" do
@@ -107,7 +107,7 @@ module Gitlab
note.author = current_user
if note.save
- present note, with: Entities::Note
+ present note, with: Entities::MRNote
else
not_found!
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
new file mode 100644
index 00000000000..b47ff5c300f
--- /dev/null
+++ b/lib/api/notes.rb
@@ -0,0 +1,94 @@
+module Gitlab
+ # Notes API
+ class Notes < Grape::API
+ before { authenticate! }
+
+ NOTEABLE_TYPES = [Issue, Snippet]
+
+ resource :projects do
+ # Get a list of project wall notes
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # Example Request:
+ # GET /projects/:id/notes
+ get ":id/notes" do
+ @notes = user_project.common_notes
+ present paginate(@notes), with: Entities::Note
+ end
+
+ # Create a new project wall note
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # body (required) - The content of a note
+ # Example Request:
+ # POST /projects/:id/notes
+ post ":id/notes" do
+ @note = user_project.notes.new(note: params[:body])
+ @note.author = current_user
+
+ if @note.save
+ present @note, with: Entities::Note
+ else
+ not_found!
+ end
+ end
+
+ NOTEABLE_TYPES.each do |noteable_type|
+ noteables_str = noteable_type.to_s.underscore.pluralize
+ noteable_id_str = "#{noteable_type.to_s.underscore}_id"
+
+ # Get a list of project +noteable+ notes
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # noteable_id (required) - The ID of an issue or snippet
+ # Example Request:
+ # GET /projects/:id/issues/:noteable_id/notes
+ # GET /projects/:id/snippets/:noteable_id/notes
+ get ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
+ @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
+ present paginate(@noteable.notes), with: Entities::Note
+ end
+
+ # Get a single +noteable+ note
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # noteable_id (required) - The ID of an issue or snippet
+ # note_id (required) - The ID of a note
+ # Example Request:
+ # GET /projects/:id/issues/:noteable_id/notes/:note_id
+ # GET /projects/:id/snippets/:noteable_id/notes/:note_id
+ get ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
+ @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
+ @note = @noteable.notes.find(params[:note_id])
+ present @note, with: Entities::Note
+ end
+
+ # Create a new +noteable+ note
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # noteable_id (required) - The ID of an issue or snippet
+ # body (required) - The content of a note
+ # Example Request:
+ # POST /projects/:id/issues/:noteable_id/notes
+ # POST /projects/:id/snippets/:noteable_id/notes
+ post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
+ @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
+ @note = @noteable.notes.new(note: params[:body])
+ @note.author = current_user
+ @note.project = user_project
+
+ if @note.save
+ present @note, with: Entities::Note
+ else
+ not_found!
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index ac20bbeccab..384dbcd5473 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -38,11 +38,7 @@ module Gitlab
# Example Request
# POST /projects
post do
- params[:code] ||= params[:name]
- params[:path] ||= params[:name]
- attrs = attributes_for_keys [:code,
- :path,
- :name,
+ attrs = attributes_for_keys [:name,
:description,
:default_branch,
:issues_enabled,
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 57e0aa108cf..cad99fd9f7b 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -38,7 +38,7 @@ module Gitlab
# POST /users
post do
authenticated_as_admin!
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit]
+ attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username]
user = User.new attrs, as: :admin
if user.save
present user, with: Entities::User
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 5a24c5d01b5..056fb034daf 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -34,6 +34,7 @@ module Gitlab
extern_uid: uid,
provider: provider,
name: name,
+ username: email.match(/^[^@]*/)[0],
email: email,
password: password,
password_confirmation: password,
diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb
index fe5dcef40a9..7c3861bdd13 100644
--- a/lib/gitlab/backend/gitolite.rb
+++ b/lib/gitlab/backend/gitolite.rb
@@ -23,7 +23,14 @@ module Gitlab
end
def update_repository project
- config.update_project!(project.path, project)
+ config.update_project!(project)
+ end
+
+ def move_repository(old_repo, project)
+ config.apply do |config|
+ config.clean_repo(old_repo)
+ config.update_project(project)
+ end
end
def remove_repository project
@@ -38,6 +45,12 @@ module Gitlab
config.admin_all_repo!
end
+ def update_repositories projects
+ config.apply do |config|
+ config.update_projects(projects)
+ end
+ end
+
alias_method :create_repository, :update_repository
end
end
diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb
index 7ae34de66bc..70ccc4782c6 100644
--- a/lib/gitlab/backend/gitolite_config.rb
+++ b/lib/gitlab/backend/gitolite_config.rb
@@ -83,7 +83,11 @@ module Gitlab
def destroy_project(project)
FileUtils.rm_rf(project.path_to_repo)
- conf.rm_repo(project.path)
+ conf.rm_repo(project.path_with_namespace)
+ end
+
+ def clean_repo repo_name
+ conf.rm_repo(repo_name)
end
def destroy_project!(project)
@@ -105,18 +109,18 @@ module Gitlab
end
# update or create
- def update_project(repo_name, project)
+ def update_project(project)
repo = update_project_config(project, conf)
conf.add_repo(repo, true)
end
- def update_project!(repo_name, project)
+ def update_project!( project)
apply do |config|
- config.update_project(repo_name, project)
+ config.update_project(project)
end
end
- # Updates many projects and uses project.path as the repo path
+ # Updates many projects and uses project.path_with_namespace as the repo path
# An order of magnitude faster than update_project
def update_projects(projects)
projects.each do |project|
@@ -126,7 +130,7 @@ module Gitlab
end
def update_project_config(project, conf)
- repo_name = project.path
+ repo_name = project.path_with_namespace
repo = if conf.has_repo?(repo_name)
conf.get_repo(repo_name)
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index dd5a9becafc..9fafc9617d1 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -4,10 +4,14 @@ module Grack
def valid?
# Authentication with username and password
- email, password = @auth.credentials
- self.user = User.find_by_email(email)
+ login, password = @auth.credentials
+
+ self.user = User.find_by_email(login) || User.find_by_username(login)
+
return false unless user.try(:valid_password?, password)
+ email = user.email
+
# Set GL_USER env variable
ENV['GL_USER'] = email
# Pass Gitolite update hook
@@ -18,8 +22,8 @@ module Grack
@env['SCRIPT_NAME'] = ""
# Find project by PATH_INFO from env
- if m = /^\/([\w\.-]+)\.git/.match(@request.path_info).to_a
- self.project = Project.find_by_path(m.last)
+ if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
+ self.project = Project.find_with_namespace(m.last)
return false unless project
end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index cf9a4c4afa2..8b4eee5da06 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -11,7 +11,7 @@ module Gitlab
def self.read_latest
path = Rails.root.join("log", file_name)
self.build unless File.exist?(path)
- logs = File.read(path).split("\n")
+ logs = `tail -n 2000 #{path}`.split("\n")
end
def self.build
diff --git a/lib/gitlab/project_mover.rb b/lib/gitlab/project_mover.rb
new file mode 100644
index 00000000000..eeab22ae6e7
--- /dev/null
+++ b/lib/gitlab/project_mover.rb
@@ -0,0 +1,44 @@
+# ProjectMover class
+#
+# Used for moving project repositories from one subdir to another
+module Gitlab
+ class ProjectMover
+ class ProjectMoveError < StandardError; end
+
+ attr_reader :project, :old_dir, :new_dir
+
+ def initialize(project, old_dir, new_dir)
+ @project = project
+ @old_dir = old_dir
+ @new_dir = new_dir
+ end
+
+ def execute
+ # Create new dir if missing
+ new_dir_path = File.join(Gitlab.config.git_base_path, new_dir)
+ system("mkdir -m 770 #{new_dir_path}") unless File.exists?(new_dir_path)
+
+ old_path = File.join(Gitlab.config.git_base_path, old_dir, "#{project.path}.git")
+ new_path = File.join(new_dir_path, "#{project.path}.git")
+
+ if File.exists? new_path
+ raise ProjectMoveError.new("Destination #{new_path} already exists")
+ end
+
+ if system("mv #{old_path} #{new_path}")
+ log_info "Project #{project.name} was moved from #{old_path} to #{new_path}"
+ true
+ else
+ message = "Project #{project.name} cannot be moved from #{old_path} to #{new_path}"
+ log_info "Error! #{message}"
+ raise ProjectMoveError.new(message)
+ end
+ end
+
+ protected
+
+ def log_info message
+ Gitlab::AppLogger.info message
+ end
+ end
+end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
new file mode 100644
index 00000000000..a3f38b1c360
--- /dev/null
+++ b/lib/gitlab/regex.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Regex
+ extend self
+
+ def username_regex
+ default_regex
+ end
+
+ def path_regex
+ default_regex
+ end
+
+ protected
+
+ def default_regex
+ /\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/
+ end
+ end
+end
diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb
index 28b6f538d00..91c83d81029 100644
--- a/lib/gitlab/satellite/satellite.rb
+++ b/lib/gitlab/satellite/satellite.rb
@@ -41,11 +41,11 @@ module Gitlab
end
def lock_file
- Rails.root.join("tmp", "#{project.path}.lock")
+ Rails.root.join("tmp", "satellite_#{project.id}.lock")
end
def path
- Rails.root.join("tmp", "repo_satellites", project.path)
+ Rails.root.join("tmp", "repo_satellites", project.path_with_namespace)
end
def repo
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 48b4da9d339..bd590f92734 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -12,10 +12,12 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
def block_code(code, language)
options = { options: {encoding: 'utf-8'} }
- if Pygments::Lexer.find(language)
- Pygments.highlight(code, options.merge(lexer: language.downcase))
- else
- Pygments.highlight(code, options)
+ h.content_tag :div, class: h.user_color_scheme_class do
+ if Pygments::Lexer.find(language)
+ Pygments.highlight(code, options.merge(lexer: language.downcase))
+ else
+ Pygments.highlight(code, options)
+ end.html_safe
end
end
diff --git a/lib/tasks/gitlab/activate_namespaces.rake b/lib/tasks/gitlab/activate_namespaces.rake
new file mode 100644
index 00000000000..08df0a8040b
--- /dev/null
+++ b/lib/tasks/gitlab/activate_namespaces.rake
@@ -0,0 +1,67 @@
+namespace :gitlab do
+ desc "GITLAB | Enable usernames and namespaces for user projects"
+ task activate_namespaces: :environment do
+ print "\nUsernames for users:".yellow
+
+ User.find_each(batch_size: 500) do |user|
+ next if user.namespace
+
+ User.transaction do
+ username = user.email.match(/^[^@]*/)[0]
+ if user.update_attributes!(username: username)
+ print '.'.green
+ else
+ print 'F'.red
+ end
+ end
+ end
+
+ print "\n\nDirs for groups:".yellow
+
+ Group.find_each(batch_size: 500) do |group|
+ if group.ensure_dir_exist
+ print '.'.green
+ else
+ print 'F'.red
+ end
+ end
+
+ print "\n\nMove projects from groups under groups dirs:".yellow
+ git_path = Gitlab.config.git_base_path
+
+ Project.where('namespace_id IS NOT NULL').find_each(batch_size: 500) do |project|
+ next unless project.group
+
+ group = project.group
+
+ puts "\n"
+ print " * #{project.name}: "
+
+ new_path = File.join(git_path, project.path_with_namespace + '.git')
+
+ if File.exists?(new_path)
+ print "ok. already at #{new_path}".cyan
+ next
+ end
+
+ old_path = File.join(git_path, project.path + '.git')
+
+ unless File.exists?(old_path)
+ print "missing. not found at #{old_path}".red
+ next
+ end
+
+ begin
+ Gitlab::ProjectMover.new(project, '', group.path).execute
+ print "ok. Moved to #{new_path}".green
+ rescue
+ print "Failed moving to #{new_path}".red
+ end
+ end
+
+ print "\n\nRebuild gitolite:".yellow
+ gitolite = Gitlab::Gitolite.new
+ gitolite.update_repositories(Project.where('namespace_id IS NOT NULL'))
+ puts "\n"
+ end
+end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 17a0e336bb5..c01fe479dba 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -82,7 +82,7 @@ namespace :gitlab do
end
settings = YAML.load_file("backup_information.yml")
- ENV["VERSION"] = "#{settings["db_version"]}" if settings["db_version"].to_i > 0
+ ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0
# restoring mismatching backups can lead to unexpected problems
if settings[:gitlab_version] != %x{git rev-parse HEAD}.gsub(/\n/,"")
diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake
index 9b30bb0a292..e6987e17639 100644
--- a/lib/tasks/resque.rake
+++ b/lib/tasks/resque.rake
@@ -1 +1,14 @@
require 'resque/tasks'
+
+# Fix Exception
+# ActiveRecord::StatementInvalid
+# Error
+# PGError: ERROR: prepared statement "a3" already exists
+task "resque:setup" => :environment do
+ Resque.after_fork do |job|
+ ActiveRecord::Base.establish_connection
+ end
+end
+
+desc "Alias for resque:work (To run workers on Heroku)"
+task "jobs:work" => "resque:work"
diff --git a/public/404.html b/public/404.html
index 3e56e52cc18..867f193a98f 100644
--- a/public/404.html
+++ b/public/404.html
@@ -7,9 +7,8 @@
<body>
<h1>404</h1>
- <div>
- <h2>The page you were looking for doesn't exist.</h2>
- <p>You may have mistyped the address or the page may have moved.</p>
- </div>
+ <h3>The page you were looking for doesn't exist.</h3>
+ <hr/>
+ <p>You may have mistyped the address or the page may have moved.</p>
</body>
</html>
diff --git a/public/500.html b/public/500.html
index 3be1cc259c0..5b78e3e38cb 100644
--- a/public/500.html
+++ b/public/500.html
@@ -4,13 +4,10 @@
<title>We're sorry, but something went wrong (500)</title>
<link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
</head>
-
<body>
- <!-- This file lives in public/500.html -->
<h1>500</h1>
- <div>
- <h2>We're sorry, but something went wrong.</h2>
- <p>We've been notified about this issue and we'll take a look at it shortly.</p>
- </div>
+ <h3>We're sorry, but something went wrong.</h3>
+ <hr/>
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
</body>
</html>
diff --git a/public/githost_error.html b/public/githost_error.html
deleted file mode 100644
index b5258ce160e..00000000000
--- a/public/githost_error.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>We're sorry, but we can't get access to your gitolite</title>
- <style type="text/css">
- body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; }
- div.dialog {
- width: 600px;
- padding: 0 4em;
- margin: 4em auto 0 auto;
- }
- h1 { font-size: 48px; color: #444; line-height: 1.5em; }
- h2 { font-size: 24px; color: #666; line-height: 1.5em; }
- h3, code { text-align:left; }
- code pre { margin-left:40px; }
- </style>
-</head>
-
-<body>
- <!-- This file lives in public/500.html -->
- <div class="dialog">
- <h1>Gitolite Error</h1>
- <h2>Application can't get access to your gitolite system.</h2>
- <hr>
- <h3> 1. Check 'config/gitlab.yml' for correct settings.</h3>
- <h3> 2. Make sure web server user has access to gitolite. <a href="https://github.com/gitlabhq/gitlabhq/wiki/Gitolite">Setup tutorial</a></h3>
- <h3> 3. Try: </h3>
- <code>
- <pre>
-sudo chmod -R 770 /home/git/repositories/
-sudo chown -R git:git /home/git/repositories/
- </pre>
- </code>
- </div>
-</body>
-</html>
diff --git a/public/static.css b/public/static.css
index 6090d7b2abb..aa834553a1c 100644
--- a/public/static.css
+++ b/public/static.css
@@ -1,57 +1,31 @@
-body { color: #666; text-align: center; font-family: arial, sans-serif; margin:0; padding:0; }
-h1 { font-size: 48px; color: #444; line-height: 1.5em; }
+body {
+ color: #666;
+ text-align: center;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ sans-serif;
+ margin:0;
+ width: 800px;
+ margin: auto;
+ font-size: 14px;
+}
+h1 {
+ font-size: 56px;
+ line-height: 100px;
+ font-weight: normal;
+ color: #456;
+}
h2 { font-size: 24px; color: #666; line-height: 1.5em; }
-.alert-message {
- position: relative;
- padding: 7px 15px;
- margin-bottom: 18px;
- color: #404040;
- background-color: #eedc94;
- background-repeat: repeat-x;
- background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));
- background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
- background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));
- background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
- background-image: -o-linear-gradient(top, #fceec1, #eedc94);
- background-image: linear-gradient(top, #fceec1, #eedc94);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFCEEC1', endColorstr='#FFEEDC94', GradientType=0);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- border-color: #eedc94 #eedc94 #e4c652;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) fadein(rgba(0, 0, 0, 0.1), 15%);
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- border-width: 1px;
- border-style: solid;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
-}
-.alert-message .close {
- margin-top: 1px;
- *margin-top: 0;
-}
-.alert-message a {
- font-weight: bold;
- color: #404040;
-}
-.alert-message.danger p a, .alert-message.error p a, .alert-message.success p a, .alert-message.info p a {
- color: #404040;
-}
-.alert-message h5 {
- line-height: 18px;
-}
-.alert-message p {
- margin-bottom: 0;
-}
-.alert-message div {
- margin-top: 5px;
- margin-bottom: 2px;
+h3 {
+ color: #456;
+ font-size: 20px;
+ font-weight: normal;
line-height: 28px;
}
-.alert-message.block-message.error {
- background: #FDDFDE;
- border-color: #FBC7C6;
+hr {
+ margin: 18px 0;
+ border: 0;
+ border-top: 1px solid #EEE;
+ border-bottom: 1px solid white;
}
-
diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb
new file mode 100644
index 00000000000..5aef4c676ee
--- /dev/null
+++ b/spec/controllers/commit_controller_spec.rb
@@ -0,0 +1,74 @@
+require 'spec_helper'
+
+describe CommitController do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:commit) { project.last_commit_for("master") }
+
+ before do
+ sign_in(user)
+
+ project.add_access(user, :read, :admin)
+ end
+
+ describe "#show" do
+ shared_examples "export as" do |format|
+ it "should generally work" do
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response).to be_success
+ end
+
+ it "should generate it" do
+ Commit.any_instance.should_receive(:"to_#{format}")
+
+ get :show, project_id: project.code, id: commit.id, format: format
+ end
+
+ it "should render it" do
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response.body).to eq(commit.send(:"to_#{format}"))
+ end
+
+ it "should not escape Html" do
+ Commit.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
+
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response.body).to_not include('&amp;')
+ expect(response.body).to_not include('&gt;')
+ expect(response.body).to_not include('&lt;')
+ expect(response.body).to_not include('&quot;')
+ end
+ end
+
+ describe "as diff" do
+ include_examples "export as", :diff
+ let(:format) { :diff }
+
+ it "should really only be a git diff" do
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response.body).to start_with("diff --git")
+ end
+ end
+
+ describe "as patch" do
+ include_examples "export as", :patch
+ let(:format) { :patch }
+
+ it "should really be a git email patch" do
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response.body).to start_with("From #{commit.id}")
+ end
+
+ it "should contain a git diff" do
+ get :show, project_id: project.code, id: commit.id, format: format
+
+ expect(response.body).to match(/^diff --git/)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb
index bf335634da9..da33fd8a2b5 100644
--- a/spec/controllers/commits_controller_spec.rb
+++ b/spec/controllers/commits_controller_spec.rb
@@ -13,7 +13,7 @@ describe CommitsController do
describe "GET show" do
context "as atom feed" do
it "should render as atom" do
- get :show, project_id: project.code, id: "master.atom"
+ get :show, project_id: project.path, id: "master.atom"
response.should be_success
response.content_type.should == 'application/atom+xml'
end
diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb
new file mode 100644
index 00000000000..7aebe06cf0c
--- /dev/null
+++ b/spec/controllers/merge_requests_controller_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+describe MergeRequestsController do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request_with_diffs, project: project) }
+
+ before do
+ sign_in(user)
+ project.add_access(user, :read, :admin)
+ MergeRequestsController.any_instance.stub(validates_merge_request: true)
+ end
+
+ describe "#show" do
+ shared_examples "export as" do |format|
+ it "should generally work" do
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response).to be_success
+ end
+
+ it "should generate it" do
+ MergeRequest.any_instance.should_receive(:"to_#{format}")
+
+ get :show, project_id: project.code, id: merge_request.id, format: format
+ end
+
+ it "should render it" do
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response.body).to eq(merge_request.send(:"to_#{format}"))
+ end
+
+ it "should not escape Html" do
+ MergeRequest.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
+
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response.body).to_not include('&amp;')
+ expect(response.body).to_not include('&gt;')
+ expect(response.body).to_not include('&lt;')
+ expect(response.body).to_not include('&quot;')
+ end
+ end
+
+ describe "as diff" do
+ include_examples "export as", :diff
+ let(:format) { :diff }
+
+ it "should really only be a git diff" do
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response.body).to start_with("diff --git")
+ end
+ end
+
+ describe "as patch" do
+ include_examples "export as", :patch
+ let(:format) { :patch }
+
+ it "should really be a git email patch with commit" do
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}")
+ end
+
+ # TODO: fix or remove
+ #it "should contain as many patches as there are commits" do
+ #get :show, project_id: project.code, id: merge_request.id, format: format
+
+ #patch_count = merge_request.commits.count
+ #merge_request.commits.each_with_index do |commit, patch_num|
+ #expect(response.body).to match(/^From #{commit.id}/)
+ #expect(response.body).to match(/^Subject: \[PATCH #{patch_num}\/#{patch_count}\]/)
+ #end
+ #end
+
+ it "should contain git diffs" do
+ get :show, project_id: project.code, id: merge_request.id, format: format
+
+ expect(response.body).to match(/^diff --git/)
+ end
+ end
+ end
+end
diff --git a/spec/factories.rb b/spec/factories.rb
index 7c33f0ecc8b..a26a77dd860 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -12,6 +12,7 @@ FactoryGirl.define do
factory :user, aliases: [:author, :assignee, :owner] do
email { Faker::Internet.email }
name
+ username { Faker::Internet.user_name }
password "123456"
password_confirmation { password }
@@ -25,13 +26,19 @@ FactoryGirl.define do
factory :project do
sequence(:name) { |n| "project#{n}" }
path { name.downcase.gsub(/\s/, '_') }
- code { name.downcase.gsub(/\s/, '_') }
owner
end
factory :group do
sequence(:name) { |n| "group#{n}" }
- code { name.downcase.gsub(/\s/, '_') }
+ path { name.downcase.gsub(/\s/, '_') }
+ owner
+ type 'Group'
+ end
+
+ factory :namespace do
+ sequence(:name) { |n| "group#{n}" }
+ path { name.downcase.gsub(/\s/, '_') }
owner
end
@@ -63,7 +70,22 @@ FactoryGirl.define do
closed true
end
+ # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d)
+ trait :with_diffs do
+ target_branch "bcf03b5d~3"
+ source_branch "bcf03b5d"
+ st_commits do
+ [Commit.new(project.repo.commit('bcf03b5d')),
+ Commit.new(project.repo.commit('bcf03b5d~1')),
+ Commit.new(project.repo.commit('bcf03b5d~2'))]
+ end
+ st_diffs do
+ project.repo.diff("bcf03b5d~3", "bcf03b5d")
+ end
+ end
+
factory :closed_merge_request, traits: [:closed]
+ factory :merge_request_with_diffs, traits: [:with_diffs]
end
factory :note do
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index ec830e40ecd..05e4527b278 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -329,9 +329,11 @@ describe GitlabMarkdownHelper do
end
it "should leave code blocks untouched" do
- markdown("\n some code from $#{snippet.id}\n here too\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div>"
+ helper.stub(:user_color_scheme_class).and_return(:white)
- markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div>"
+ helper.markdown("\n some code from $#{snippet.id}\n here too\n").should == "<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>"
+
+ helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == "<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>"
end
it "should leave inline code untouched" do
diff --git a/spec/lib/project_mover_spec.rb b/spec/lib/project_mover_spec.rb
new file mode 100644
index 00000000000..af24635d82b
--- /dev/null
+++ b/spec/lib/project_mover_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Gitlab::ProjectMover do
+ let(:base_path) { Rails.root.join('tmp', 'rspec-sandbox') }
+
+ before do
+ FileUtils.rm_rf base_path if File.exists? base_path
+
+ Gitlab.config.stub(git_base_path: base_path)
+
+ @project = create(:project)
+ end
+
+ after do
+ FileUtils.rm_rf base_path
+ end
+
+ it "should move project to subdir" do
+ mk_dir base_path, '', @project.path
+ mover = Gitlab::ProjectMover.new(@project, '', 'opensource')
+
+ mover.execute.should be_true
+ moved?('opensource', @project.path).should be_true
+ end
+
+ it "should move project from one subdir to another" do
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', 'randx')
+
+ mover.execute.should be_true
+ moved?('randx', @project.path).should be_true
+ end
+
+ it "should move project from subdir to base" do
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ mover.execute.should be_true
+ moved?('', @project.path).should be_true
+ end
+
+ it "should raise if destination exists" do
+ mk_dir base_path, '', @project.path
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError)
+ end
+
+ it "should raise if move failed" do
+ mk_dir base_path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError)
+ end
+
+
+ def mk_dir base_path, namespace = '', project_path = ''
+ FileUtils.mkdir_p File.join(base_path, namespace, project_path + ".git")
+ end
+
+ def moved? namespace, path
+ File.exists?(File.join(base_path, namespace, path + '.git'))
+ end
+end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index b6b1769fc80..58698eec9f4 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -169,9 +169,7 @@ describe Notify do
end
describe 'project access changed' do
- let(:project) { create(:project,
- path: "Fuu",
- code: "Fuu") }
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:users_project) { create(:users_project,
project: project,
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 6ae2cb20169..108bc303540 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -1,13 +1,14 @@
# == Schema Information
#
-# Table name: groups
+# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
-# code :string(255) not null
+# path :string(255) not null
# owner_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
+# type :string(255)
#
require 'spec_helper'
@@ -18,7 +19,15 @@ describe Group do
it { should have_many :projects }
it { should validate_presence_of :name }
it { should validate_uniqueness_of(:name) }
- it { should validate_presence_of :code }
- it { should validate_uniqueness_of(:code) }
+ it { should validate_presence_of :path }
+ it { should validate_uniqueness_of(:path) }
it { should validate_presence_of :owner }
+
+ describe :users do
+ it { group.users.should == [group.owner] }
+ end
+
+ describe :human_name do
+ it { group.human_name.should == group.name }
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
new file mode 100644
index 00000000000..d0de4a7b7fb
--- /dev/null
+++ b/spec/models/namespace_spec.rb
@@ -0,0 +1,78 @@
+# == Schema Information
+#
+# Table name: namespaces
+#
+# id :integer not null, primary key
+# name :string(255) not null
+# path :string(255) not null
+# owner_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# type :string(255)
+#
+
+require 'spec_helper'
+
+describe Namespace do
+ let!(:namespace) { create(:namespace) }
+
+ it { should have_many :projects }
+ it { should validate_presence_of :name }
+ it { should validate_uniqueness_of(:name) }
+ it { should validate_presence_of :path }
+ it { should validate_uniqueness_of(:path) }
+ it { should validate_presence_of :owner }
+
+ describe "Mass assignment" do
+ it { should allow_mass_assignment_of(:name) }
+ it { should allow_mass_assignment_of(:path) }
+ end
+
+ describe "Respond to" do
+ it { should respond_to(:human_name) }
+ it { should respond_to(:to_param) }
+ end
+
+ it { Namespace.global_id.should == 'GLN' }
+
+ describe :to_param do
+ it { namespace.to_param.should == namespace.path }
+ end
+
+ describe :human_name do
+ it { namespace.human_name.should == namespace.owner_name }
+ end
+
+ describe :search do
+ before do
+ @namespace = create :namespace
+ end
+
+ it { Namespace.search(@namespace.path).should == [@namespace] }
+ it { Namespace.search('unknown').should == [] }
+ end
+
+ describe :move_dir do
+ before do
+ @namespace = create :namespace
+ @namespace.stub(path_changed?: true)
+ end
+
+ it "should raise error when dirtory exists" do
+ expect { @namespace.move_dir }.to raise_error("Already exists")
+ end
+
+ it "should move dir if path changed" do
+ new_path = @namespace.path + "_new"
+ @namespace.stub(path_was: @namespace.path)
+ @namespace.stub(path: new_path)
+ @namespace.move_dir.should be_true
+ end
+ end
+
+ describe :rm_dir do
+ it "should remove dir" do
+ namespace.rm_dir.should be_true
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 5bcab924496..db0d30727b4 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -9,14 +9,13 @@
# created_at :datetime not null
# updated_at :datetime not null
# private_flag :boolean default(TRUE), not null
-# code :string(255)
# owner_id :integer
# default_branch :string(255)
# 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
-# group_id :integer
+# namespace_id :integer
#
require 'spec_helper'
@@ -24,6 +23,7 @@ require 'spec_helper'
describe Project do
describe "Associations" do
it { should belong_to(:group) }
+ it { should belong_to(:namespace) }
it { should belong_to(:owner).class_name('User') }
it { should have_many(:users) }
it { should have_many(:events).dependent(:destroy) }
@@ -40,6 +40,7 @@ describe Project do
end
describe "Mass assignment" do
+ it { should_not allow_mass_assignment_of(:namespace_id) }
it { should_not allow_mass_assignment_of(:owner_id) }
it { should_not allow_mass_assignment_of(:private_flag) }
end
@@ -58,9 +59,6 @@ describe Project do
it { should ensure_length_of(:description).is_within(0..2000) }
- it { should validate_presence_of(:code) }
- it { should validate_uniqueness_of(:code) }
- it { should ensure_length_of(:code).is_within(1..255) }
# TODO: Formats
it { should validate_presence_of(:owner) }
@@ -151,7 +149,7 @@ describe Project do
end
it "returns the full web URL for this repo" do
- project = Project.new(code: "somewhere")
+ project = Project.new(path: "somewhere")
project.web_url.should == "#{Gitlab.config.url}/somewhere"
end
@@ -162,7 +160,7 @@ describe Project do
end
it "should be invalid repo" do
- project = Project.new(name: "ok_name", path: "/INVALID_PATH/", code: "NEOK")
+ project = Project.new(name: "ok_name", path: "/INVALID_PATH/", path: "NEOK")
project.valid_repo?.should be_false
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 4ac699b1c45..279e315b693 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -30,14 +30,17 @@
# locked_at :datetime
# extern_uid :string(255)
# provider :string(255)
+# username :string(255)
#
require 'spec_helper'
describe User do
describe "Associations" do
+ it { should have_one(:namespace) }
it { should have_many(:users_projects).dependent(:destroy) }
it { should have_many(:projects) }
+ it { should have_many(:groups) }
it { should have_many(:my_own_projects).class_name('Project') }
it { should have_many(:keys).dependent(:destroy) }
it { should have_many(:events).class_name('Event').dependent(:destroy) }
@@ -55,6 +58,7 @@ describe User do
end
describe 'validations' do
+ it { should validate_presence_of(:username) }
it { should validate_presence_of(:projects_limit) }
it { should validate_numericality_of(:projects_limit) }
it { should allow_value(0).for(:projects_limit) }
diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb
index 08254f44026..4ba0f05df5d 100644
--- a/spec/observers/user_observer_spec.rb
+++ b/spec/observers/user_observer_spec.rb
@@ -13,7 +13,12 @@ describe UserObserver do
end
context 'when a new user is created' do
- let(:user) { double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local') }
+ let(:user) { double(:user, id: 42,
+ password: 'P@ssword!',
+ name: 'John',
+ email: 'u@mail.local',
+ username: 'root',
+ create_namespace: true) }
let(:notification) { double :notification }
it 'sends an email' do
diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb
index cbe42248033..548f1893848 100644
--- a/spec/observers/users_project_observer_spec.rb
+++ b/spec/observers/users_project_observer_spec.rb
@@ -2,9 +2,7 @@ require 'spec_helper'
describe UsersProjectObserver do
let(:user) { create(:user) }
- let(:project) { create(:project,
- code: "Fuu",
- path: "Fuu" ) }
+ let(:project) { create(:project) }
let(:users_project) { create(:users_project,
project: project,
user: user )}
diff --git a/spec/requests/admin/admin_hooks_spec.rb b/spec/requests/admin/admin_hooks_spec.rb
index 3f35b2fd37d..bc0586b2712 100644
--- a/spec/requests/admin/admin_hooks_spec.rb
+++ b/spec/requests/admin/admin_hooks_spec.rb
@@ -2,9 +2,7 @@ require 'spec_helper'
describe "Admin::Hooks" do
before do
- @project = create(:project,
- name: "LeGiT",
- code: "LGT")
+ @project = create(:project)
login_as :admin
@system_hook = create(:system_hook)
diff --git a/spec/requests/admin/admin_projects_spec.rb b/spec/requests/admin/admin_projects_spec.rb
index 43e39d7cbcd..c9ddf1f4534 100644
--- a/spec/requests/admin/admin_projects_spec.rb
+++ b/spec/requests/admin/admin_projects_spec.rb
@@ -2,9 +2,7 @@ require 'spec_helper'
describe "Admin::Projects" do
before do
- @project = create(:project,
- name: "LeGiT",
- code: "LGT")
+ @project = create(:project)
login_as :admin
end
@@ -29,7 +27,7 @@ describe "Admin::Projects" do
end
it "should have project info" do
- page.should have_content(@project.code)
+ page.should have_content(@project.path)
page.should have_content(@project.name)
end
end
@@ -41,67 +39,27 @@ describe "Admin::Projects" do
end
it "should have project edit page" do
- page.should have_content("Project name")
- page.should have_content("URL")
+ page.should have_content("Edit project")
+ page.should have_button("Save Project")
end
describe "Update project" do
before do
fill_in "project_name", with: "Big Bang"
- fill_in "project_code", with: "BB1"
click_button "Save Project"
@project.reload
end
it "should show page with new data" do
- page.should have_content("BB1")
page.should have_content("Big Bang")
end
it "should change project entry" do
@project.name.should == "Big Bang"
- @project.code.should == "BB1"
end
end
end
- describe "GET /admin/projects/new" do
- before do
- visit admin_projects_path
- click_link "New Project"
- end
-
- it "should be correct path" do
- current_path.should == new_admin_project_path
- end
-
- it "should have labels for new project" do
- page.should have_content("Project name is")
- page.should have_content("Git Clone")
- page.should have_content("URL")
- end
- end
-
- describe "POST /admin/projects" do
- before do
- visit new_admin_project_path
- fill_in 'project_name', with: 'NewProject'
- fill_in 'project_code', with: 'NPR'
- fill_in 'project_path', with: 'gitlabhq_1'
- expect { click_button "Create project" }.to change { Project.count }.by(1)
- @project = Project.last
- end
-
- it "should be correct path" do
- current_path.should == admin_project_path(@project)
- end
-
- it "should show project" do
- page.should have_content(@project.name)
- page.should have_content(@project.path)
- end
- end
-
describe "Add new team member" do
before do
@new_user = create(:user)
diff --git a/spec/requests/admin/admin_users_spec.rb b/spec/requests/admin/admin_users_spec.rb
index 9f43f07a476..ca134c2d4f7 100644
--- a/spec/requests/admin/admin_users_spec.rb
+++ b/spec/requests/admin/admin_users_spec.rb
@@ -23,6 +23,7 @@ describe "Admin::Users" do
@password = "123ABC"
visit new_admin_user_path
fill_in "user_name", with: "Big Bang"
+ fill_in "user_username", with: "bang"
fill_in "user_email", with: "bigbang@mail.com"
fill_in "user_password", with: @password
fill_in "user_password_confirmation", with: @password
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 6ea7e9b5579..1850ecb95cc 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -28,7 +28,7 @@ describe Gitlab::API do
describe "GET /projects/:id/issues" do
it "should return project issues" do
- get api("/projects/#{project.code}/issues", user)
+ get api("/projects/#{project.path}/issues", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == issue.title
@@ -37,7 +37,7 @@ describe Gitlab::API do
describe "GET /projects/:id/issues/:issue_id" do
it "should return a project issue by id" do
- get api("/projects/#{project.code}/issues/#{issue.id}", user)
+ get api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 200
json_response['title'].should == issue.title
end
@@ -45,7 +45,7 @@ describe Gitlab::API do
describe "POST /projects/:id/issues" do
it "should create a new project issue" do
- post api("/projects/#{project.code}/issues", user),
+ post api("/projects/#{project.path}/issues", user),
title: 'new issue', labels: 'label, label2'
response.status.should == 201
json_response['title'].should == 'new issue'
@@ -56,7 +56,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/issues/:issue_id" do
it "should update a project issue" do
- put api("/projects/#{project.code}/issues/#{issue.id}", user),
+ put api("/projects/#{project.path}/issues/#{issue.id}", user),
title: 'updated title', labels: 'label2', closed: 1
response.status.should == 200
json_response['title'].should == 'updated title'
@@ -67,7 +67,7 @@ describe Gitlab::API do
describe "DELETE /projects/:id/issues/:issue_id" do
it "should delete a project issue" do
- delete api("/projects/#{project.code}/issues/#{issue.id}", user)
+ delete api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 405
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index e83f24671ed..43931aedcda 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -11,14 +11,14 @@ describe Gitlab::API do
describe "GET /projects/:id/merge_requests" do
context "when unauthenticated" do
it "should return authentication error" do
- get api("/projects/#{project.code}/merge_requests")
+ get api("/projects/#{project.path}/merge_requests")
response.status.should == 401
end
end
context "when authenticated" do
it "should return an array of merge_requests" do
- get api("/projects/#{project.code}/merge_requests", user)
+ get api("/projects/#{project.path}/merge_requests", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == merge_request.title
@@ -28,7 +28,7 @@ describe Gitlab::API do
describe "GET /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
- get api("/projects/#{project.code}/merge_request/#{merge_request.id}", user)
+ get api("/projects/#{project.path}/merge_request/#{merge_request.id}", user)
response.status.should == 200
json_response['title'].should == merge_request.title
end
@@ -36,7 +36,7 @@ describe Gitlab::API do
describe "POST /projects/:id/merge_requests" do
it "should return merge_request" do
- post api("/projects/#{project.code}/merge_requests", user),
+ post api("/projects/#{project.path}/merge_requests", user),
title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user
response.status.should == 201
json_response['title'].should == 'Test merge_request'
@@ -45,7 +45,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
- put api("/projects/#{project.code}/merge_request/#{merge_request.id}", user), title: "New title"
+ put api("/projects/#{project.path}/merge_request/#{merge_request.id}", user), title: "New title"
response.status.should == 200
json_response['title'].should == 'New title'
end
@@ -53,7 +53,7 @@ describe Gitlab::API do
describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
it "should return comment" do
- post api("/projects/#{project.code}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
+ post api("/projects/#{project.path}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
response.status.should == 201
json_response['note'].should == 'My comment'
end
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 860825ab2db..dc96d46d894 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::API do
describe "GET /projects/:id/milestones" do
it "should return project milestones" do
- get api("/projects/#{project.code}/milestones", user)
+ get api("/projects/#{project.path}/milestones", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == milestone.title
@@ -20,7 +20,7 @@ describe Gitlab::API do
describe "GET /projects/:id/milestones/:milestone_id" do
it "should return a project milestone by id" do
- get api("/projects/#{project.code}/milestones/#{milestone.id}", user)
+ get api("/projects/#{project.path}/milestones/#{milestone.id}", user)
response.status.should == 200
json_response['title'].should == milestone.title
end
@@ -28,7 +28,7 @@ describe Gitlab::API do
describe "POST /projects/:id/milestones" do
it "should create a new project milestone" do
- post api("/projects/#{project.code}/milestones", user),
+ post api("/projects/#{project.path}/milestones", user),
title: 'new milestone'
response.status.should == 201
json_response['title'].should == 'new milestone'
@@ -38,7 +38,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/milestones/:milestone_id" do
it "should update a project milestone" do
- put api("/projects/#{project.code}/milestones/#{milestone.id}", user),
+ put api("/projects/#{project.path}/milestones/#{milestone.id}", user),
title: 'updated title'
response.status.should == 200
json_response['title'].should == 'updated title'
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
new file mode 100644
index 00000000000..dc02e7a3efa
--- /dev/null
+++ b/spec/requests/api/notes_spec.rb
@@ -0,0 +1,98 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+ include ApiHelpers
+
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, owner: user) }
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:snippet) { create(:snippet, project: project, author: user) }
+ let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
+ let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
+ let!(:wall_note) { create(:note, project: project, author: user) }
+ before { project.add_access(user, :read) }
+
+ describe "GET /projects/:id/notes" do
+ context "when unauthenticated" do
+ it "should return authentication error" do
+ get api("/projects/#{project.id}/notes")
+ response.status.should == 401
+ end
+ end
+
+ context "when authenticated" do
+ it "should return project wall notes" do
+ get api("/projects/#{project.id}/notes", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['body'].should == wall_note.note
+ end
+ end
+ end
+
+ describe "POST /projects/:id/notes" do
+ it "should create a new wall note" do
+ post api("/projects/#{project.id}/notes", user), body: 'hi!'
+ response.status.should == 201
+ json_response['body'].should == 'hi!'
+ end
+ end
+
+ describe "GET /projects/:id/noteable/:noteable_id/notes" do
+ context "when noteable is an Issue" do
+ it "should return an array of issue notes" do
+ get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['body'].should == issue_note.note
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "should return an array of snippet notes" do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['body'].should == snippet_note.note
+ end
+ end
+ end
+
+ describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
+ context "when noteable is an Issue" do
+ it "should return an issue note by id" do
+ get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
+ response.status.should == 200
+ json_response['body'].should == issue_note.note
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "should return a snippet note by id" do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
+ response.status.should == 200
+ json_response['body'].should == snippet_note.note
+ end
+ end
+ end
+
+ describe "POST /projects/:id/noteable/:noteable_id/notes" do
+ context "when noteable is an Issue" do
+ it "should create a new issue note" do
+ post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
+ response.status.should == 201
+ json_response['body'].should == 'hi!'
+ json_response['author']['email'].should == user.email
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "should create a new snippet note" do
+ post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+ response.status.should == 201
+ json_response['body'].should == 'hi!'
+ json_response['author']['email'].should == user.email
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index d24ce43d3f2..b4e2fbbdab8 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -33,7 +33,7 @@ describe Gitlab::API do
end
describe "POST /projects" do
- it "should create new project without code and path" do
+ it "should create new project without path" do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
end
@@ -53,8 +53,6 @@ describe Gitlab::API do
it "should assign attributes to project" do
project = attributes_for(:project, {
- path: 'path',
- code: 'code',
description: Faker::Lorem.sentence,
default_branch: 'stable',
issues_enabled: false,
@@ -79,8 +77,8 @@ describe Gitlab::API do
json_response['owner']['email'].should == user.email
end
- it "should return a project by code name" do
- get api("/projects/#{project.code}", user)
+ it "should return a project by path name" do
+ get api("/projects/#{project.path}", user)
response.status.should == 200
json_response['name'].should == project.name
end
@@ -94,7 +92,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
- get api("/projects/#{project.code}/repository/branches", user)
+ get api("/projects/#{project.path}/repository/branches", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
@@ -103,7 +101,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do
- get api("/projects/#{project.code}/repository/branches/new_design", user)
+ get api("/projects/#{project.path}/repository/branches/new_design", user)
response.status.should == 200
json_response['name'].should == 'new_design'
@@ -113,7 +111,7 @@ describe Gitlab::API do
describe "GET /projects/:id/members" do
it "should return project team members" do
- get api("/projects/#{project.code}/members", user)
+ get api("/projects/#{project.path}/members", user)
response.status.should == 200
json_response.should be_an Array
json_response.count.should == 2
@@ -123,7 +121,7 @@ describe Gitlab::API do
describe "GET /projects/:id/members/:user_id" do
it "should return project team member" do
- get api("/projects/#{project.code}/members/#{user.id}", user)
+ get api("/projects/#{project.path}/members/#{user.id}", user)
response.status.should == 200
json_response['email'].should == user.email
json_response['access_level'].should == UsersProject::MASTER
@@ -133,7 +131,7 @@ describe Gitlab::API do
describe "POST /projects/:id/members" do
it "should add user to project team" do
expect {
- post api("/projects/#{project.code}/members", user), user_id: user2.id,
+ post api("/projects/#{project.path}/members", user), user_id: user2.id,
access_level: UsersProject::DEVELOPER
}.to change { UsersProject.count }.by(1)
@@ -145,7 +143,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/members/:user_id" do
it "should update project team member" do
- put api("/projects/#{project.code}/members/#{user3.id}", user), access_level: UsersProject::MASTER
+ put api("/projects/#{project.path}/members/#{user3.id}", user), access_level: UsersProject::MASTER
response.status.should == 200
json_response['email'].should == user3.email
json_response['access_level'].should == UsersProject::MASTER
@@ -155,14 +153,14 @@ describe Gitlab::API do
describe "DELETE /projects/:id/members/:user_id" do
it "should remove user from project team" do
expect {
- delete api("/projects/#{project.code}/members/#{user3.id}", user)
+ delete api("/projects/#{project.path}/members/#{user3.id}", user)
}.to change { UsersProject.count }.by(-1)
end
end
describe "GET /projects/:id/hooks" do
it "should return project hooks" do
- get api("/projects/#{project.code}/hooks", user)
+ get api("/projects/#{project.path}/hooks", user)
response.status.should == 200
@@ -174,7 +172,7 @@ describe Gitlab::API do
describe "GET /projects/:id/hooks/:hook_id" do
it "should return a project hook" do
- get api("/projects/#{project.code}/hooks/#{hook.id}", user)
+ get api("/projects/#{project.path}/hooks/#{hook.id}", user)
response.status.should == 200
json_response['url'].should == hook.url
end
@@ -183,7 +181,7 @@ describe Gitlab::API do
describe "POST /projects/:id/hooks" do
it "should add hook to project" do
expect {
- post api("/projects/#{project.code}/hooks", user),
+ post api("/projects/#{project.path}/hooks", user),
"url" => "http://example.com"
}.to change {project.hooks.count}.by(1)
end
@@ -191,7 +189,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/hooks/:hook_id" do
it "should update an existing project hook" do
- put api("/projects/#{project.code}/hooks/#{hook.id}", user),
+ put api("/projects/#{project.path}/hooks/#{hook.id}", user),
url: 'http://example.org'
response.status.should == 200
json_response['url'].should == 'http://example.org'
@@ -202,7 +200,7 @@ describe Gitlab::API do
describe "DELETE /projects/:id/hooks" do
it "should delete hook from project" do
expect {
- delete api("/projects/#{project.code}/hooks", user),
+ delete api("/projects/#{project.path}/hooks", user),
hook_id: hook.id
}.to change {project.hooks.count}.by(-1)
end
@@ -210,7 +208,7 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/tags" do
it "should return an array of project tags" do
- get api("/projects/#{project.code}/repository/tags", user)
+ get api("/projects/#{project.path}/repository/tags", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
@@ -222,7 +220,7 @@ describe Gitlab::API do
before { project.add_access(user2, :read) }
it "should return project commits" do
- get api("/projects/#{project.code}/repository/commits", user)
+ get api("/projects/#{project.path}/repository/commits", user)
response.status.should == 200
json_response.should be_an Array
@@ -232,7 +230,7 @@ describe Gitlab::API do
context "unauthorized user" do
it "should not return project commits" do
- get api("/projects/#{project.code}/repository/commits")
+ get api("/projects/#{project.path}/repository/commits")
response.status.should == 401
end
end
@@ -240,7 +238,7 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets" do
it "should return an array of project snippets" do
- get api("/projects/#{project.code}/snippets", user)
+ get api("/projects/#{project.path}/snippets", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == snippet.title
@@ -249,7 +247,7 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets/:snippet_id" do
it "should return a project snippet" do
- get api("/projects/#{project.code}/snippets/#{snippet.id}", user)
+ get api("/projects/#{project.path}/snippets/#{snippet.id}", user)
response.status.should == 200
json_response['title'].should == snippet.title
end
@@ -257,7 +255,7 @@ describe Gitlab::API do
describe "POST /projects/:id/snippets" do
it "should create a new project snippet" do
- post api("/projects/#{project.code}/snippets", user),
+ post api("/projects/#{project.path}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test'
response.status.should == 201
json_response['title'].should == 'api test'
@@ -266,7 +264,7 @@ describe Gitlab::API do
describe "PUT /projects/:id/snippets/:shippet_id" do
it "should update an existing project snippet" do
- put api("/projects/#{project.code}/snippets/#{snippet.id}", user),
+ put api("/projects/#{project.path}/snippets/#{snippet.id}", user),
code: 'updated code'
response.status.should == 200
json_response['title'].should == 'example'
@@ -277,31 +275,31 @@ describe Gitlab::API do
describe "DELETE /projects/:id/snippets/:snippet_id" do
it "should delete existing project snippet" do
expect {
- delete api("/projects/#{project.code}/snippets/#{snippet.id}", user)
+ delete api("/projects/#{project.path}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1)
end
end
describe "GET /projects/:id/snippets/:snippet_id/raw" do
it "should get a raw project snippet" do
- get api("/projects/#{project.code}/snippets/#{snippet.id}/raw", user)
+ get api("/projects/#{project.path}/snippets/#{snippet.id}/raw", user)
response.status.should == 200
end
end
describe "GET /projects/:id/:sha/blob" do
it "should get the raw file contents" do
- get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.md", user)
+ get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.md", user)
response.status.should == 200
end
it "should return 404 for invalid branch_name" do
- get api("/projects/#{project.code}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
+ get api("/projects/#{project.path}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
response.status.should == 404
end
it "should return 404 for invalid file" do
- get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.invalid", user)
+ get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.invalid", user)
response.status.should == 404
end
end
diff --git a/spec/requests/gitlab_flavored_markdown_spec.rb b/spec/requests/gitlab_flavored_markdown_spec.rb
index aedd435e617..ad5d7cd7607 100644
--- a/spec/requests/gitlab_flavored_markdown_spec.rb
+++ b/spec/requests/gitlab_flavored_markdown_spec.rb
@@ -197,18 +197,6 @@ describe "Gitlab Flavored Markdown" do
page.should have_link("##{issue.id}")
end
-
- it "should render in wikis#index", js: true do
- visit project_wiki_path(project, :index)
- fill_in "Title", with: 'Test title'
- fill_in "Content", with: '[link test](test)'
- click_on "Save"
-
- fill_in "note_note", with: "see ##{issue.id}"
- click_button "Add Comment"
-
- page.should have_link("##{issue.id}")
- end
end
diff --git a/spec/requests/projects_spec.rb b/spec/requests/projects_spec.rb
index c44bea89f96..8c0f8e5fbc1 100644
--- a/spec/requests/projects_spec.rb
+++ b/spec/requests/projects_spec.rb
@@ -3,16 +3,6 @@ require 'spec_helper'
describe "Projects" do
before { login_as :user }
- describe 'GET /project/new' do
- it "should work autocomplete", :js => true do
- visit new_project_path
-
- fill_in 'project_name', with: 'Awesome'
- find("#project_path").value.should == 'awesome'
- find("#project_code").value.should == 'awesome'
- end
- end
-
describe "GET /projects/show" do
before do
@project = create(:project, owner: @user)
@@ -53,7 +43,6 @@ describe "Projects" do
visit edit_project_path(@project)
fill_in 'project_name', with: 'Awesome'
- fill_in 'project_code', with: 'gitlabhq'
click_button "Save"
@project = @project.reload
end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 60261c7ae71..fb26bf98d0f 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -78,14 +78,6 @@ describe Admin::ProjectsController, "routing" do
get("/admin/projects").should route_to('admin/projects#index')
end
- it "to #create" do
- post("/admin/projects").should route_to('admin/projects#create')
- end
-
- it "to #new" do
- get("/admin/projects/new").should route_to('admin/projects#new')
- end
-
it "to #edit" do
get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab')
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index dc687d2a7ac..25db2f91d4d 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -208,7 +208,6 @@ end
# diffs_project_merge_request GET /:project_id/merge_requests/:id/diffs(.:format) merge_requests#diffs
# automerge_project_merge_request GET /:project_id/merge_requests/:id/automerge(.:format) merge_requests#automerge
# automerge_check_project_merge_request GET /:project_id/merge_requests/:id/automerge_check(.:format) merge_requests#automerge_check
-# raw_project_merge_request GET /:project_id/merge_requests/:id/raw(.:format) merge_requests#raw
# branch_from_project_merge_requests GET /:project_id/merge_requests/branch_from(.:format) merge_requests#branch_from
# branch_to_project_merge_requests GET /:project_id/merge_requests/branch_to(.:format) merge_requests#branch_to
# project_merge_requests GET /:project_id/merge_requests(.:format) merge_requests#index
@@ -231,10 +230,6 @@ describe MergeRequestsController, "routing" do
get("/gitlabhq/merge_requests/1/automerge_check").should route_to('merge_requests#automerge_check', project_id: 'gitlabhq', id: '1')
end
- it "to #raw" do
- get("/gitlabhq/merge_requests/1/raw").should route_to('merge_requests#raw', project_id: 'gitlabhq', id: '1')
- end
-
it "to #branch_from" do
get("/gitlabhq/merge_requests/branch_from").should route_to('merge_requests#branch_from', project_id: 'gitlabhq')
end
@@ -243,6 +238,11 @@ describe MergeRequestsController, "routing" do
get("/gitlabhq/merge_requests/branch_to").should route_to('merge_requests#branch_to', project_id: 'gitlabhq')
end
+ it "to #show" do
+ get("/gitlabhq/merge_requests/1.diff").should route_to('merge_requests#show', project_id: 'gitlabhq', id: '1', format: 'diff')
+ get("/gitlabhq/merge_requests/1.patch").should route_to('merge_requests#show', project_id: 'gitlabhq', id: '1', format: 'patch')
+ end
+
it_behaves_like "RESTful project resources" do
let(:controller) { 'merge_requests' }
end
@@ -285,6 +285,7 @@ end
describe CommitController, "routing" do
it "to #show" do
get("/gitlabhq/commit/4246fb").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb')
+ get("/gitlabhq/commit/4246fb.diff").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb', format: 'diff')
get("/gitlabhq/commit/4246fb.patch").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb', format: 'patch')
get("/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5')
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index ace5ca00cc1..7728b1e9d84 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -40,5 +40,10 @@ RSpec.configure do |config|
# !!! Observers disabled by default in tests
ActiveRecord::Base.observers.disable(:all)
# ActiveRecord::Base.observers.enable(:all)
+
+ # Use tmp dir for FS manipulations
+ Gitlab.config.stub(git_base_path: Rails.root.join('tmp', 'test-git-base-path'))
+ FileUtils.rm_rf Gitlab.config.git_base_path
+ FileUtils.mkdir_p Gitlab.config.git_base_path
end
end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
new file mode 100644
index 00000000000..d9aa0543969
--- /dev/null
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+require 'rake'
+
+describe 'gitlab:app namespace rake task' do
+ before :all do
+ Rake.application.rake_require "tasks/gitlab/backup"
+ # empty task as env is already loaded
+ Rake::Task.define_task :environment
+ end
+
+ describe 'backup_restore' do
+ before do
+ # avoid writing task output to spec progress
+ $stdout.stub :write
+ end
+
+ let :run_rake_task do
+ Rake::Task["gitlab:app:backup_restore"].reenable
+ Rake.application.invoke_task "gitlab:app:backup_restore"
+ end
+
+ context 'gitlab version' do
+ before do
+ Dir.stub :glob => []
+ Dir.stub :chdir
+ File.stub :exists? => true
+ Kernel.stub :system => true
+ end
+
+ let(:gitlab_version) { %x{git rev-parse HEAD}.gsub(/\n/,"") }
+
+ it 'should fail on mismach' do
+ YAML.stub :load_file => {:gitlab_version => gitlab_version.reverse}
+ expect { run_rake_task }.to raise_error SystemExit
+ end
+
+ it 'should invoke restoration on mach' do
+ YAML.stub :load_file => {:gitlab_version => gitlab_version}
+ Rake::Task["gitlab:app:db_restore"].should_receive :invoke
+ Rake::Task["gitlab:app:repo_restore"].should_receive :invoke
+ expect { run_rake_task }.to_not raise_error SystemExit
+ end
+ end
+
+ end # backup_restore task
+end # gitlab:app namespace