diff --git a/CHANGELOG b/CHANGELOG
index 06008e78d6..5f42f851b0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,26 @@
v 6.6.0
+ - Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys
- Permissions: Developer now can manage issue tracker (modify any issue)
+ - Improve Code Compare page performance
+ - Group avatar
+ - Pygments.rb replaced with highlight.js
+ - Improve Merge request diff store logic
+ - Improve render performnace for MR show page
+ - Fixed Assembla hardcoded project name
+ - Jira integration documentation
+ - Refactored app/services
+ - Remove snippet expiration
+ - Mobile UI improvements (Drew Blessing)
+ - Fix block/remove UI for admin::users#show page
+ - Show users' group membership on users' activity page
+ - User pages are visible without login if user is authorized to a public project
+ - Markdown rendered headers have id derived from their name and link to their id
+ - Improve application to work faster with large groups (100+ members)
+ - Multiple emails per user
+ - Show last commit for file when view file source
+ - Restyle Issue#show page and MR#show page
+ - Ability to filter by multiple labels for Issues page
+ - Rails version to 4.0.3
v 6.5.1
- Fix branch selectbox when create merge request from fork
@@ -33,7 +54,7 @@ v6.4.3
v6.4.2
- Fixed wrong behaviour of script/upgrade.rb
-v6.4.1
+v6.4.1
- Fixed bug with repository rename
- Fixed bug with project transfer
diff --git a/Gemfile b/Gemfile
index 0c0addb780..ba7f6a7f52 100644
--- a/Gemfile
+++ b/Gemfile
@@ -29,22 +29,19 @@ gem 'omniauth-github'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", "~> 4.0.0"
+gem "gitlab_git", '~> 5.4.0'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
# LDAP Auth
-gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
-
-# Syntax highlighter
-gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
+gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
# Git Wiki
-gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib'
+gem "gitlab-gollum-lib", "~> 1.1.0", require: 'gollum-lib'
# Language detection
-gem "gitlab-linguist", "~> 2.9.6", require: "linguist"
+gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
# API
gem "grape", "~> 0.6.1"
@@ -139,6 +136,9 @@ gem "sanitize"
# Protect against bruteforcing
gem "rack-attack"
+# Ace editor
+gem 'ace-rails-ap'
+
gem "sass-rails"
gem "coffee-rails"
gem "uglifier"
@@ -208,6 +208,10 @@ group :development, :test do
gem 'spork', '~> 1.0rc'
gem 'jasmine', '2.0.0.rc5'
+
+ gem "spring", '1.1.1'
+ gem "spring-commands-rspec", '1.0.1'
+ gem "spring-commands-spinach", '1.0.0'
end
group :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index 2c821a9b90..ba29e0ddc7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,11 +8,12 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- actionmailer (4.0.2)
- actionpack (= 4.0.2)
+ ace-rails-ap (2.0.1)
+ actionmailer (4.0.3)
+ actionpack (= 4.0.3)
mail (~> 2.5.4)
- actionpack (4.0.2)
- activesupport (= 4.0.2)
+ actionpack (4.0.3)
+ activesupport (= 4.0.3)
builder (~> 3.1.0)
erubis (~> 2.7.0)
rack (~> 1.5.2)
@@ -21,16 +22,16 @@ GEM
actionpack (>= 4.0.0, < 5.0)
actionpack-page_caching (1.0.2)
actionpack (>= 4.0.0, < 5)
- activemodel (4.0.2)
- activesupport (= 4.0.2)
+ activemodel (4.0.3)
+ activesupport (= 4.0.3)
builder (~> 3.1.0)
- activerecord (4.0.2)
- activemodel (= 4.0.2)
+ activerecord (4.0.3)
+ activemodel (= 4.0.3)
activerecord-deprecated_finders (~> 1.0.2)
- activesupport (= 4.0.2)
+ activesupport (= 4.0.3)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
- activesupport (4.0.2)
+ activesupport (4.0.3)
i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2)
multi_json (~> 1.3)
@@ -42,7 +43,7 @@ GEM
annotate (2.6.0)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
- arel (4.0.1)
+ arel (4.0.2)
asciidoctor (0.1.4)
atomic (1.1.14)
awesome_print (1.2.0)
@@ -158,36 +159,32 @@ GEM
gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1)
multi_json
- gitlab-gollum-lib (1.0.2)
+ gitlab-gollum-lib (1.1.0)
github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0)
gitlab-grit (~> 2.6.1)
- gitlab-pygments.rb (~> 0.5.4)
nokogiri (~> 1.5.9)
sanitize (~> 2.0.3)
stringex (~> 1.5.1)
gitlab-grack (2.0.0.pre)
rack (~> 1.5.1)
- gitlab-grit (2.6.3)
+ gitlab-grit (2.6.4)
charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
- gitlab-linguist (2.9.6)
+ gitlab-linguist (3.0.0)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
- gitlab-pygments.rb (~> 0.5.4)
mime-types (~> 1.19)
- gitlab-pygments.rb (0.5.4)
- posix-spawn (~> 0.3.6)
- yajl-ruby (~> 1.1.0)
- gitlab_git (4.0.0)
+ gitlab_git (5.4.0)
activesupport (~> 4.0.0)
+ charlock_holmes (~> 0.6.9)
gitlab-grit (~> 2.6.1)
- gitlab-linguist (~> 2.9.5)
- gitlab-pygments.rb (~> 0.5.4)
+ gitlab-linguist (~> 3.0.0)
+ rugged (~> 0.19.0)
gitlab_meta (6.0)
- gitlab_omniauth-ldap (1.0.3)
+ gitlab_omniauth-ldap (1.0.4)
net-ldap (~> 0.3.1)
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1)
@@ -323,8 +320,8 @@ GEM
cliver (~> 0.2.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
- polyglot (0.3.3)
- posix-spawn (0.3.6)
+ polyglot (0.3.4)
+ posix-spawn (0.3.8)
protected_attributes (1.0.5)
activemodel (>= 4.0.1, < 5.0)
pry (0.9.12.4)
@@ -349,13 +346,13 @@ GEM
rack
rack-test (0.6.2)
rack (>= 1.0)
- rails (4.0.2)
- actionmailer (= 4.0.2)
- actionpack (= 4.0.2)
- activerecord (= 4.0.2)
- activesupport (= 4.0.2)
+ rails (4.0.3)
+ actionmailer (= 4.0.3)
+ actionpack (= 4.0.3)
+ activerecord (= 4.0.3)
+ activesupport (= 4.0.3)
bundler (>= 1.3.0, < 2.0)
- railties (= 4.0.2)
+ railties (= 4.0.3)
sprockets-rails (~> 2.0.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
@@ -368,13 +365,13 @@ GEM
i18n
require_all
ruby-progressbar
- railties (4.0.2)
- actionpack (= 4.0.2)
- activesupport (= 4.0.2)
+ railties (4.0.3)
+ actionpack (= 4.0.3)
+ activesupport (= 4.0.3)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
raindrops (0.12.0)
- rake (10.1.0)
+ rake (10.1.1)
raphael-rails (2.1.2)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
@@ -423,6 +420,7 @@ GEM
ruby-hmac (0.4.0)
ruby-progressbar (1.2.0)
rubyntlm (0.1.1)
+ rugged (0.19.0)
safe_yaml (0.9.7)
sanitize (2.0.6)
nokogiri (>= 1.4.4)
@@ -472,6 +470,11 @@ GEM
railties (>= 3)
spinach (>= 0.4)
spork (1.0.0rc4)
+ spring (1.1.1)
+ spring-commands-rspec (1.0.1)
+ spring (>= 0.9.1)
+ spring-commands-spinach (1.0.0)
+ spring (>= 0.9.1)
sprockets (2.10.1)
hike (~> 1.2)
multi_json (~> 1.0)
@@ -543,12 +546,12 @@ GEM
websocket-driver (0.3.1)
xpath (2.0.0)
nokogiri (~> 1.3)
- yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
+ ace-rails-ap
actionpack-action_caching
actionpack-page_caching
acts-as-taggable-on
@@ -578,13 +581,12 @@ DEPENDENCIES
gemoji (~> 1.3.0)
github-markup (~> 0.7.4)!
gitlab-flowdock-git-hook (~> 0.4.2)
- gitlab-gollum-lib (~> 1.0.2)
+ gitlab-gollum-lib (~> 1.1.0)
gitlab-grack (~> 2.0.0.pre)
- gitlab-linguist (~> 2.9.6)
- gitlab-pygments.rb (~> 0.5.4)
- gitlab_git (~> 4.0.0)
+ gitlab-linguist (~> 3.0.0)
+ gitlab_git (~> 5.4.0)
gitlab_meta (= 6.0)
- gitlab_omniauth-ldap (= 1.0.3)
+ gitlab_omniauth-ldap (= 1.0.4)
gon (~> 5.0.0)
grape (~> 0.6.1)
grape-entity (~> 0.3.0)
@@ -640,6 +642,9 @@ DEPENDENCIES
slim
spinach-rails
spork (~> 1.0rc)
+ spring (= 1.1.1)
+ spring-commands-rspec (= 1.0.1)
+ spring-commands-spinach (= 1.0.0)
stamp
state_machine
test_after_commit
diff --git a/LICENSE b/LICENSE
index 7cecc2485f..8ebd322ffc 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2011 Dmitriy Zaporozhets
+Copyright (c) 2011-2014 Dmitriy Zaporozhets
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/MAINTENANCE.md b/MAINTENANCE.md
index 0dca62974c..95d9f0a5e7 100644
--- a/MAINTENANCE.md
+++ b/MAINTENANCE.md
@@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one
(eg. `5.0 -> 5.1`).
We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable.
+
+More information about the release procedures can be found in the doc/release directory.
diff --git a/README.md b/README.md
index 0d5dfa8540..02766a334f 100644
--- a/README.md
+++ b/README.md
@@ -4,26 +4,21 @@

-### GitLab allows you to
- * keep your code secure on your own server
- * manage repositories, users and access permissions
- * communicate through issues, line-comments and wiki pages
- * perform code review with merge requests
+### Gitlab is open source software to collaborate on code
-### GitLab is
-
-* powered by Ruby on Rails
-* completely free and open source (MIT license)
-* used by more than 25.000 organizations to keep their code secure
+* Manage git repositories with fine grained access controls that keep your code secure
+* Perform code reviews and enhance collaboration with merge requests
+* Each project can also have an issue tracker and a wiki
+* Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises
+* Completely free and open source (MIT Expat license)
+* Powered by Ruby on Rails
### Code status
-* [](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
+* [](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
* [](https://codeclimate.com/github/gitlabhq/gitlabhq)
-* [](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available), gems are updated in major releases of GitLab.
-
* [](https://coveralls.io/r/gitlabhq/gitlabhq)
### Resources
@@ -36,6 +31,8 @@
* [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab.
+* Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab
+
### Requirements
* Ubuntu/Debian**
@@ -50,13 +47,17 @@
#### Official installation methods
-* [Manual installation guide for a production server](doc/install/installation.md)
+* [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS.
+
+* [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions.
* [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies.
+* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions.
+
#### Third party one-click installers
-* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab.
+* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. We recommend selecting a droplet with [1GB of memory](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md).
* [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.).
@@ -68,11 +69,9 @@
### New versions and upgrading
-Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide.
+Since 2011 GitLab is released on the 22nd of every month. Every new release includes an [upgrade guide](doc/update) and new features are detailed in the [Changelog](CHANGELOG).
-* [Upgrade guides](doc/update)
-
-* [Changelog](CHANGELOG)
+It is recommended to follow a monthly upgrade schedule. Security releases come out when needed. For more information about the release process see the documentation for [monthly](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/monthly.md) and [security](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/security.md) releases.
* Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
@@ -155,6 +154,8 @@ or start each component separately
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
+* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
+
### Getting in touch
diff --git a/VERSION b/VERSION
index c07edf251a..e6b7e47e12 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-6.6.0.pre
+6.6.0.rc1
diff --git a/app/assets/images/ajax_loader.gif b/app/assets/images/ajax_loader.gif
deleted file mode 100644
index d0f093033d..0000000000
Binary files a/app/assets/images/ajax_loader.gif and /dev/null differ
diff --git a/app/assets/images/ajax_loader_gray.gif b/app/assets/images/ajax_loader_gray.gif
deleted file mode 100644
index fdf2c98a96..0000000000
Binary files a/app/assets/images/ajax_loader_gray.gif and /dev/null differ
diff --git a/app/assets/images/ajax_loader_tree.gif b/app/assets/images/ajax_loader_tree.gif
deleted file mode 100644
index 47ba01264c..0000000000
Binary files a/app/assets/images/ajax_loader_tree.gif and /dev/null differ
diff --git a/app/assets/images/icon-link.png b/app/assets/images/icon-link.png
new file mode 100644
index 0000000000..32ade0fe9a
Binary files /dev/null and b/app/assets/images/icon-link.png differ
diff --git a/app/assets/images/no_group_avatar.png b/app/assets/images/no_group_avatar.png
new file mode 100644
index 0000000000..a97d451598
Binary files /dev/null and b/app/assets/images/no_group_avatar.png differ
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index 5f4a38ebbd..fafa5cdfaa 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -3,6 +3,7 @@
user_path: "/api/:version/users/:id.json"
notes_path: "/api/:version/projects/:id/notes.json"
namespaces_path: "/api/:version/namespaces.json"
+ project_users_path: "/api/:version/projects/:id/users.json"
# Get 20 (depends on api) recent notes
# and sort the ascending from oldest to newest
@@ -50,6 +51,23 @@
).done (users) ->
callback(users)
+ # Return project users list. Filtered by query
+ # Only active users retrieved
+ projectUsers: (project_id, query, callback) ->
+ url = Api.buildUrl(Api.project_users_path)
+ url = url.replace(':id', project_id)
+
+ $.ajax(
+ url: url
+ data:
+ private_token: gon.api_token
+ search: query
+ per_page: 20
+ active: true
+ dataType: "json"
+ ).done (users) ->
+ callback(users)
+
# Return namespaces list. Filtered by query
namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index aa2db1fc93..4a393dbfe8 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -24,7 +24,8 @@
//= require g.raphael-min
//= require g.bar-min
//= require branch-graph
-//= require ace-src-noconflict/ace
+//= require highlightjs.min
+//= require ace/ace
//= require_tree .
//= require d3
//= require underscore
diff --git a/app/assets/javascripts/blob.js.coffee b/app/assets/javascripts/blob.js.coffee
index 99cb1cec91..584f6faea1 100644
--- a/app/assets/javascripts/blob.js.coffee
+++ b/app/assets/javascripts/blob.js.coffee
@@ -17,7 +17,7 @@ class BlobView
setHash(hash)
e.preventDefault()
-
+
# See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = (e) ->
@@ -64,7 +64,7 @@ class BlobView
nodes.attr("id", hash)
# initialize multi-line select
- $("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect)
+ $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
# Highlight the correct lines on load
highlightBlobLines()
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 8ea302f256..46d6db0f05 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -4,6 +4,7 @@ $ ->
class Dispatcher
constructor: () ->
@initSearch()
+ @initHighlight()
@initPageScripts()
initPageScripts: ->
@@ -18,6 +19,8 @@ class Dispatcher
switch page
when 'projects:issues:index'
Issues.init()
+ when 'projects:issues:show'
+ new Issue()
when 'projects:issues:new', 'projects:merge_requests:new'
GitLab.GfmAutoComplete.setup()
when 'dashboard:show'
@@ -53,3 +56,10 @@ class Dispatcher
project_ref = opts.data('autocomplete-project-ref')
new SearchAutocomplete(path, project_id, project_ref)
+
+ initHighlight: ->
+ $('.highlight pre code').each (i, e) ->
+ hljs.highlightBlock(e)
+ $(e).html($.map($(e).html().split("\n"), (line, i) ->
+ "

diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index eb8bc0d63c..d5522f00f5 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -5,6 +5,7 @@
*= require jquery.ui.gitlab
*= require jquery.atwho
*= require select2
+ *= require highlightjs.min
*= require_self
*/
@@ -38,6 +39,7 @@
@import "generic/lists.scss";
@import "generic/forms.scss";
@import "generic/selects.scss";
+@import "generic/highlight.scss";
/**
* Page specific styles (issues, projects etc):
@@ -63,6 +65,7 @@
@import "sections/wall.scss";
@import "sections/dashboard.scss";
@import "sections/stat_graph.scss";
+@import "sections/groups.scss";
/**
* Code ighlight
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index 219e6ebd68..4cb41a79ff 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -118,7 +118,6 @@
@extend .btn-primary;
}
- &.btn-close,
&.btn-remove {
@extend .btn-danger;
}
@@ -143,6 +142,22 @@
line-height: 16px;
margin: 2px;
}
+
+ &.btn-close {
+ color: #B94A48;
+ font-weight: bold;
+ &:hover {
+ color: #B94A48;
+ }
+ }
+
+ &.btn-reopen {
+ color: #468847;
+ font-weight: bold;
+ &:hover {
+ color: #468847;
+ }
+ }
}
.btn-block {
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 507e7197d5..7afa74400c 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -88,11 +88,15 @@ pre.well-pre {
/** Big Labels **/
.state-label {
font-size: 14px;
- padding: 6px 25px;
+ padding: 9px 25px;
text-align: center;
- @include border-radius(4px);
text-shadow: none;
- margin-left: 10px;
+ margin-right: 20px;
+
+ &.state-label-blue {
+ background: #31708f;
+ color: #FFF;
+ }
&.state-label-green {
background: #4A4;
@@ -112,6 +116,7 @@ pre.well-pre {
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: #29b;
+ color: #FFF
}
.breadcrumb > li + li:before {
@@ -173,12 +178,10 @@ table a code {
.loading {
margin: 20px auto;
- background: url(ajax_loader.gif) no-repeat center center;
- width: 40px;
height: 40px;
- &.loading-gray {
- background: url(ajax_loader_gray.gif) no-repeat center center;
- }
+ color: #555;
+ font-size: 32px;
+ text-align: center;
}
span.update-author {
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index 11bb715f7b..12559f7605 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -50,9 +50,9 @@
}
&.wiki {
- padding: 20px;
font-size: 14px;
line-height: 1.6;
+ padding: 25px;
.highlight {
margin-bottom: 9px;
@@ -143,75 +143,6 @@
*/
&.code {
padding: 0;
-
- table.lines {
- border: none;
- box-shadow: none;
- margin: 0px;
- padding: 0px;
- table-layout: fixed;
-
- pre {
- border: none;
- border-radius: 0;
- font-family: $monospace_font;
- font-size: 12px !important;
- line-height: 16px !important;
- margin: 0;
- padding: 10px 0;
- }
- td {
- border: none;
- margin: 0;
- padding: 0;
- vertical-align: top;
-
- &:first-child {
- background: #eee;
- width: 50px;
- }
- &:last-child {
- }
- }
- tr:hover {
- background: none;
- }
-
- pre.line_numbers {
- color: #666;
- padding: 10px 6px 10px 0;
- text-align: right;
- background: #EEE;
-
- a {
- color: #666;
-
- i {
- display: none;
- font-size: 14px;
- line-height: 14px;
- }
- &:hover i {
- display: inherit;
- }
- }
- }
-
- .highlight {
- border-left: 1px solid #DEE2E3;
- overflow: auto;
- overflow-y: hidden;
-
- pre {
- white-space: pre;
- word-wrap: normal;
-
- .line {
- padding: 0 10px;
- }
- }
- }
- }
}
}
}
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index 931b75a323..19e3e7a953 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -51,3 +51,27 @@ label {
.input-mn-300 {
min-width: 300px;
}
+
+.custom-form-control {
+ width: 150px;
+}
+
+@media (min-width: $screen-sm-min) {
+ .custom-form-control {
+ width: 150px;
+ }
+}
+
+/* Medium devices (desktops, 992px and up) */
+@media (min-width: $screen-md-min) {
+ .custom-form-control {
+ width: 170px;
+ }
+}
+
+/* Large devices (large desktops, 1200px and up) */
+@media (min-width: $screen-lg-min) {
+ .custom-form-control {
+ width: 200px;
+ }
+}
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/generic/highlight.scss
new file mode 100644
index 0000000000..4110bddf4f
--- /dev/null
+++ b/app/assets/stylesheets/generic/highlight.scss
@@ -0,0 +1,64 @@
+.highlighted-data {
+ border: none;
+ box-shadow: none;
+ margin: 0px;
+ padding: 0px;
+ table-layout: fixed;
+
+ pre {
+ padding: 10px;
+ border: none;
+ border-radius: 0;
+ font-family: $monospace_font;
+ font-size: 12px !important;
+ line-height: 16px !important;
+ margin: 0;
+
+ code {
+ white-space: pre;
+ word-wrap: normal;
+ padding: 0;
+
+ .line {
+ display: inline;
+ }
+ }
+ }
+
+ .hljs {
+ padding: 0;
+ }
+
+ .line-numbers {
+ padding: 10px;
+ text-align: right;
+ float: left;
+
+ a {
+ font-family: $monospace_font;
+ display: block;
+ font-size: 12px !important;
+ line-height: 16px !important;
+ white-space: nowrap;
+
+ i {
+ visibility: hidden;
+ @extend .pull-left;
+ }
+
+ &:hover i {
+ visibility: visible;
+ }
+ }
+ }
+
+ .highlight {
+ overflow: auto;
+ overflow-y: hidden;
+
+ pre {
+ white-space: pre;
+ word-wrap: normal;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 6330523ea2..0e0a365a82 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -11,34 +11,39 @@
color: #666;
margin:20px 0;
background: #FAFAFA;
- border: 1px solid #DDD;
+ border: 1px solid #EEE;
.control-group {
margin-bottom: 0;
}
+ .state {
+ height: 34px;
+ border-bottom: 1px solid #DDD;
+ line-height: 32px;
+ }
+
.title {
- font-size: 20px;
+ font-size: 22px;
font-weight: 500;
- line-height: 28px;
+ line-height: 1.5;
margin: 0;
- color: #444;
+ color: #333;
+ padding-bottom: 0;
+ padding: 15px 25px;
}
.context {
- border: none;
- background-color: #f5f5f5;
border: none;
border-top: 1px solid #eee;
+ padding: 15px 25px;
}
.description {
- border-top: 1px solid #eee;
+ padding: 0 25px 15px 25px;
}
.title, .context, .description {
- padding: 15px;
-
.clearfix {
margin: 0;
}
diff --git a/app/assets/stylesheets/generic/lists.scss b/app/assets/stylesheets/generic/lists.scss
index 245cccf855..de70e47333 100644
--- a/app/assets/stylesheets/generic/lists.scss
+++ b/app/assets/stylesheets/generic/lists.scss
@@ -23,6 +23,12 @@
}
}
+ &.warning-row {
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+ color: #8a6d3b;
+ }
+
&.smoke { background-color: #f5f5f5; }
&:hover {
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index c506bff8a7..7ee1fec4e0 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -1,5 +1,4 @@
/** Select2 selectbox style override **/
-
.select2-container, .select2-container.select2-drop-above {
.select2-choice {
background: #FFF;
@@ -12,9 +11,13 @@
}
.select2-drop-active {
- border: 1px solid #BBB;
+ border: 1px solid #BBB !important;
margin-top: 4px;
+ &.select2-drop-above {
+ margin-bottom: 8px;
+ }
+
.select2-search input {
background: #fafafa;
border-color: #DDD;
@@ -78,3 +81,9 @@ select {
.project-refs-form .select2-container {
margin-right: 10px;
}
+
+.ajax-users-dropdown, .ajax-project-users-dropdown {
+ .select2-search {
+ padding-top: 4px;
+ }
+}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
index 4490566d4e..1a07fde53f 100644
--- a/app/assets/stylesheets/generic/typography.scss
+++ b/app/assets/stylesheets/generic/typography.scss
@@ -90,9 +90,27 @@ a:focus {
font-size: 14px;
line-height: 1.6;
- .white .highlight pre {
- background: #f5f5f5;
+
+ /* Link to current header. */
+ h1, h2, h3, h4, h5, h6 {
+ position: relative;
+ &:hover > :last-child {
+ $size: 16px;
+ position: absolute;
+ right: 100%;
+ top: 50%;
+ margin-top: -$size/2;
+ margin-right: 0px;
+ padding-right: 20px;
+ display: inline-block;
+ width: $size;
+ height: $size;
+ background-image: url("icon-link.png");
+ background-size: contain;
+ background-repeat: no-repeat;
+ }
}
+
ul {
padding: 0;
margin: 0 0 9px 25px !important;
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 7f45d64fb7..169f1268cd 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color;
// Nav tabs
.nav.nav-tabs {
+ margin-bottom: 15px;
+
li {
> a {
padding: 8px 20px;
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 129d33dcac..ca51da3fdd 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,71 +1,199 @@
-.dark .highlight {
+.dark {
+ background-color: #232323;
- background-color: #333;
-
- pre {
- background-color: #333;
- color: #eee;
+ .line.hll {
+ background: #558;
}
- .hll { display: block; background-color: darken($hover, 65%) }
- .c { color: #888888; font-style: italic } /* Comment */
- .err { color: #a61717; background-color: #e3d2d2 } /* Error */
- .k { color: #CDA869; font-weight: bold } /* Keyword */
- .kp { color: #CDA869; font-weight: bold } /* Keyword */
- .cm { color: #888888 } /* Comment.Multiline */
- .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
- .c1 { color: #888888 } /* Comment.Single */
- .cs { color: #cc0000; font-weight: bold; background-color: transparent } /* Comment.Special */
- .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
- .ge { font-style: italic } /* Generic.Emph */
- .gr { color: #aa0000 } /* Generic.Error */
- .gh { color: #303030 } /* Generic.Heading */
- .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
- .go { color: #888888 } /* Generic.Output */
- .gp { color: #555555 } /* Generic.Prompt */
- .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 */
- .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 */
- .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 */
- .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
- .sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */
- .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 */
- .bp { color: #D58 } /* Name.Builtin.Pseudo */
- .vc { color: #336699 } /* Name.Variable.Class */
- .vg { color: #dd7700 } /* Name.Variable.Global */
- .vi { color: cyan }
-}
+ .highlight{
+ border-left: 1px solid #444;
+ }
+ .no-highlight {
+ color: #DDD;
+ }
+
+ .line-numbers a {
+ color: #666;
+ }
+
+ pre {
+ background-color: #232323;
+ }
+
+ .hljs {
+ display: block;
+ background: #232323;
+ color: #E6E1DC;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .hljs-javadoc,
+ .hljs-shebang {
+ color: #BC9458;
+ font-style: italic;
+ }
+
+ .hljs-keyword,
+ .ruby .hljs-function .hljs-keyword,
+ .hljs-request,
+ .hljs-status,
+ .nginx .hljs-title,
+ .method,
+ .hljs-list .hljs-title {
+ color: #C26230;
+ }
+
+ .hljs-string,
+ .hljs-number,
+ .hljs-regexp,
+ .hljs-tag .hljs-value,
+ .hljs-cdata,
+ .hljs-filter .hljs-argument,
+ .hljs-attr_selector,
+ .apache .hljs-cbracket,
+ .hljs-date,
+ .tex .hljs-command,
+ .markdown .hljs-link_label {
+ color: #A5C261;
+ }
+
+ .hljs-subst {
+ color: #519F50;
+ }
+
+ .hljs-tag,
+ .hljs-tag .hljs-keyword,
+ .hljs-tag .hljs-title,
+ .hljs-doctype,
+ .hljs-sub .hljs-identifier,
+ .hljs-pi,
+ .input_number {
+ color: #E8BF6A;
+ }
+
+ .hljs-identifier {
+ color: #D0D0FF;
+ }
+
+ .hljs-class .hljs-title,
+ .haskell .hljs-type,
+ .smalltalk .hljs-class,
+ .hljs-javadoctag,
+ .hljs-yardoctag,
+ .hljs-phpdoc {
+ text-decoration: none;
+ }
+
+ .hljs-constant {
+ color: #DA4939;
+ }
+
+
+ .hljs-symbol,
+ .hljs-built_in,
+ .ruby .hljs-symbol .hljs-string,
+ .ruby .hljs-symbol .hljs-identifier,
+ .markdown .hljs-link_url,
+ .hljs-attribute {
+ color: #6D9CBE;
+ }
+
+ .markdown .hljs-link_url {
+ text-decoration: underline;
+ }
+
+
+
+ .hljs-params,
+ .hljs-variable,
+ .clojure .hljs-attribute {
+ color: #D0D0FF;
+ }
+
+ .css .hljs-tag,
+ .hljs-rules .hljs-property,
+ .hljs-pseudo,
+ .tex .hljs-special {
+ color: #CDA869;
+ }
+
+ .css .hljs-class {
+ color: #9B703F;
+ }
+
+ .hljs-rules .hljs-keyword {
+ color: #C5AF75;
+ }
+
+ .hljs-rules .hljs-value {
+ color: #CF6A4C;
+ }
+
+ .css .hljs-id {
+ color: #8B98AB;
+ }
+
+ .hljs-annotation,
+ .apache .hljs-sqbracket,
+ .nginx .hljs-built_in {
+ color: #9B859D;
+ }
+
+ .hljs-preprocessor,
+ .hljs-preprocessor *,
+ .hljs-pragma {
+ color: #8996A8 !important;
+ }
+
+ .hljs-hexcolor,
+ .css .hljs-value .hljs-number {
+ color: #A5C261;
+ }
+
+ .hljs-title,
+ .hljs-decorator,
+ .css .hljs-function {
+ color: #FFC66D;
+ }
+
+ .diff .hljs-header,
+ .hljs-chunk {
+ background-color: #2F33AB;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .diff .hljs-change {
+ background-color: #4A410D;
+ color: #F8F8F8;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .hljs-addition {
+ background-color: #144212;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .hljs-deletion {
+ background-color: #600;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .coffeescript .javascript,
+ .javascript .xml,
+ .tex .hljs-formula,
+ .xml .javascript,
+ .xml .vbscript,
+ .xml .css,
+ .xml .hljs-cdata {
+ opacity: 0.7;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index c9709fa7f1..36bc5df2f4 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,89 +1,148 @@
-$monokai-fg: #f8f8f2;
-$monokai-comment: #75715e;
-$monokai-pink: #f92672;
-$monokai-blue: #66d9ef;
-$monokai-green: #a6e22e;
-$monokai-gold: #e6db74;
-$monokai-dark: #3b3a32;
-$monokai-purple: #ae81ff;
-
-.monokai .highlight {
-
+.monokai {
background-color: #272822;
+ .highlight{
+ border-left: 1px solid #444;
+ }
+
+ .line.hll {
+ background: #558;
+ }
+
+ .no-highlight {
+ color: #DDD;
+ }
+
+ .line-numbers a {
+ color: #666;
+ }
+
pre {
background-color: #272822;
- color: $monokai-fg;
+ color: #f8f8f2;
}
- .hll { background-color: darken($hover, 65%) }
- .c { color: $monokai-comment } /* Comment */
- .err { color: $monokai-fg } /* Error */
- .g { color: $monokai-fg } /* Generic */
- .k { color: $monokai-pink } /* Keyword */
- .l { color: $monokai-fg } /* Literal */
- .n { color: $monokai-blue } /* Name */
- .o { color: $monokai-fg } /* Operator */
- .x { color: $monokai-fg } /* Other */
- .p { color: $monokai-fg } /* Punctuation */
- .cm { color: $monokai-comment } /* Comment.Multiline */
- .cp { color: $monokai-comment } /* Comment.Preproc */
- .c1 { color: $monokai-comment } /* Comment.Single */
- .cs { color: $monokai-comment } /* Comment.Special */
- .gd { color: #8b0807 } /* Generic.Deleted */
- .ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */
- .gr { color: $monokai-fg } /* Generic.Error */
- .gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */
- .gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */
- .go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */
- .gp { color: $monokai-fg } /* Generic.Prompt */
- .gs { color: $monokai-fg } /* Generic.Strong */
- .gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */
- .gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */
- .kc { color: $monokai-purple } /* Keyword.Constant */
- .kd { color: $monokai-pink } /* Keyword.Declaration */
- .kn { color: $monokai-pink } /* Keyword.Namespace */
- .kp { color: $monokai-pink } /* Keyword.Pseudo */
- .kr { color: $monokai-pink } /* Keyword.Reserved */
- .kt { color: $monokai-fg } /* Keyword.Type */
- .ld { color: $monokai-fg } /* Literal.Date */
- .m { color: $monokai-purple } /* Literal.Number */
- .s { color: $monokai-gold } /* Literal.String */
- .na { color: $monokai-purple } /* Name.Attribute */
- .nb { color: $monokai-blue } /* Name.Builtin */
- .nc { color: $monokai-fg } /* Name.Class */
- .no { color: $monokai-fg } /* Name.Constant */
- .nd { color: $monokai-fg } /* Name.Decorator */
- .ni { color: $monokai-fg } /* Name.Entity */
- .ne { color: $monokai-fg } /* Name.Exception */
- .nf { color: $monokai-green } /* Name.Function */
- .nl { color: $monokai-gold } /* Name.Label */
- .nn { color: $monokai-fg } /* Name.Namespace */
- .nx { color: $monokai-fg } /* Name.Other */
- .nt { color: $monokai-pink } /* Name.Tag */
- .nv { color: $monokai-blue; font-style: italic } /* Name.Variable */
- .py { color: $monokai-fg } /* Name.Property */
- .ow { color: $monokai-pink } /* Operator.Word */
- .w { color: $monokai-fg } /* Text.Whitespace */
- .mf { color: $monokai-purple } /* Literal.Number.Float */
- .mh { color: $monokai-purple } /* Literal.Number.Hex */
- .mi { color: $monokai-purple } /* Literal.Number.Integer */
- .mo { color: $monokai-purple } /* Literal.Number.Oct */
- .sb { color: $monokai-gold } /* Literal.String.Backtick */
- .sc { color: $monokai-gold } /* Literal.String.Char */
- .sd { color: $monokai-gold } /* Literal.String.Doc */
- .s2 { color: $monokai-gold } /* Literal.String.Double */
- .se { color: $monokai-gold } /* Literal.String.Escape */
- .sh { color: $monokai-gold } /* Literal.String.Heredoc */
- .si { color: $monokai-gold } /* Literal.String.Interpol */
- .sx { color: $monokai-gold } /* Literal.String.Other */
- .sr { color: $monokai-gold } /* Literal.String.Regex */
- .s1 { color: $monokai-gold } /* Literal.String.Single */
- .ss { color: $monokai-gold } /* Literal.String.Symbol */
- .bp { color: $monokai-fg } /* Name.Builtin.Pseudo */
- .vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */
- .vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */
- .vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */
- .il { color: $monokai-purple } /* Literal.Number.Integer.Long */
-}
+ .hljs {
+ display: block;
+ background: #272822;
+ }
+ .hljs-tag,
+ .hljs-tag .hljs-title,
+ .hljs-keyword,
+ .hljs-literal,
+ .hljs-strong,
+ .hljs-change,
+ .hljs-winutils,
+ .hljs-flow,
+ .lisp .hljs-title,
+ .clojure .hljs-built_in,
+ .nginx .hljs-title,
+ .tex .hljs-special {
+ color: #F92672;
+ }
+
+ .hljs {
+ color: #DDD;
+ }
+
+ .hljs .hljs-constant,
+ .asciidoc .hljs-code {
+ color: #66D9EF;
+ }
+
+ .hljs-code,
+ .hljs-class .hljs-title,
+ .hljs-header {
+ color: white;
+ }
+
+ .hljs-link_label,
+ .hljs-attribute,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .hljs-value,
+ .hljs-regexp {
+ color: #BF79DB;
+ }
+
+ .hljs-link_url,
+ .hljs-tag .hljs-value,
+ .hljs-string,
+ .hljs-bullet,
+ .hljs-subst,
+ .hljs-title,
+ .hljs-emphasis,
+ .haskell .hljs-type,
+ .hljs-preprocessor,
+ .hljs-pragma,
+ .ruby .hljs-class .hljs-parent,
+ .hljs-built_in,
+ .sql .hljs-aggregate,
+ .django .hljs-template_tag,
+ .django .hljs-variable,
+ .smalltalk .hljs-class,
+ .hljs-javadoc,
+ .django .hljs-filter .hljs-argument,
+ .smalltalk .hljs-localvars,
+ .smalltalk .hljs-array,
+ .hljs-attr_selector,
+ .hljs-pseudo,
+ .hljs-addition,
+ .hljs-stream,
+ .hljs-envvar,
+ .apache .hljs-tag,
+ .apache .hljs-cbracket,
+ .tex .hljs-command,
+ .hljs-prompt {
+ color: #A6E22E;
+ }
+
+ .hljs-comment,
+ .java .hljs-annotation,
+ .smartquote,
+ .hljs-blockquote,
+ .hljs-horizontal_rule,
+ .python .hljs-decorator,
+ .hljs-template_comment,
+ .hljs-pi,
+ .hljs-doctype,
+ .hljs-deletion,
+ .hljs-shebang,
+ .apache .hljs-sqbracket,
+ .tex .hljs-formula {
+ color: #75715E;
+ }
+
+ .hljs-keyword,
+ .hljs-literal,
+ .css .hljs-id,
+ .hljs-phpdoc,
+ .hljs-title,
+ .hljs-header,
+ .haskell .hljs-type,
+ .vbscript .hljs-built_in,
+ .sql .hljs-aggregate,
+ .rsl .hljs-built_in,
+ .smalltalk .hljs-class,
+ .diff .hljs-header,
+ .hljs-chunk,
+ .hljs-winutils,
+ .bash .hljs-variable,
+ .apache .hljs-tag,
+ .tex .hljs-special,
+ .hljs-request,
+ .hljs-status {
+ font-weight: bold;
+ }
+
+ .coffeescript .javascript,
+ .javascript .xml,
+ .tex .hljs-formula,
+ .xml .javascript,
+ .xml .vbscript,
+ .xml .css,
+ .xml .hljs-cdata {
+ opacity: 0.5;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index cc82f39ac9..b9bec22518 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,80 +1,125 @@
-.solarized-dark .highlight {
-
+.solarized-dark {
background-color: #002B36;
-
+
+ .highlight{
+ border-left: 1px solid #113b46;
+ }
+
+ .line.hll {
+ background: #000;
+ }
+
+ .no-highlight {
+ color: #DDD;
+ }
+
pre {
background-color: #002B36;
color: #eee;
}
- .hll { background-color: #073642 }
- .c { color: #586E75 } /* Comment */
- .err { color: #93A1A1 } /* Error */
- .g { color: #93A1A1 } /* Generic */
- .k { color: #859900 } /* Keyword */
- .l { color: #93A1A1 } /* Literal */
- .n { color: #93A1A1 } /* Name */
- .o { color: #859900 } /* Operator */
- .x { color: #CB4B16 } /* Other */
- .p { color: #93A1A1 } /* Punctuation */
- .cm { color: #586E75 } /* Comment.Multiline */
- .cp { color: #859900 } /* Comment.Preproc */
- .c1 { color: #586E75 } /* Comment.Single */
- .cs { color: #859900 } /* Comment.Special */
- .gd { color: #2AA198 } /* Generic.Deleted */
- .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */
- .gr { color: #DC322F } /* Generic.Error */
- .gh { color: #CB4B16 } /* Generic.Heading */
- .gi { color: #859900 } /* Generic.Inserted */
- .go { color: #93A1A1 } /* Generic.Output */
- .gp { color: #93A1A1 } /* Generic.Prompt */
- .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */
- .gu { color: #CB4B16 } /* Generic.Subheading */
- .gt { color: #93A1A1 } /* Generic.Traceback */
- .kc { color: #CB4B16 } /* Keyword.Constant */
- .kd { color: #268BD2 } /* Keyword.Declaration */
- .kn { color: #859900 } /* Keyword.Namespace */
- .kp { color: #859900 } /* Keyword.Pseudo */
- .kr { color: #268BD2 } /* Keyword.Reserved */
- .kt { color: #DC322F } /* Keyword.Type */
- .ld { color: #93A1A1 } /* Literal.Date */
- .m { color: #2AA198 } /* Literal.Number */
- .s { color: #2AA198 } /* Literal.String */
- .na { color: #93A1A1 } /* Name.Attribute */
- .nb { color: #B58900 } /* Name.Builtin */
- .nc { color: #268BD2 } /* Name.Class */
- .no { color: #CB4B16 } /* Name.Constant */
- .nd { color: #268BD2 } /* Name.Decorator */
- .ni { color: #CB4B16 } /* Name.Entity */
- .ne { color: #CB4B16 } /* Name.Exception */
- .nf { color: #268BD2 } /* Name.Function */
- .nl { color: #93A1A1 } /* Name.Label */
- .nn { color: #93A1A1 } /* Name.Namespace */
- .nx { color: #93A1A1 } /* Name.Other */
- .py { color: #93A1A1 } /* Name.Property */
- .nt { color: #268BD2 } /* Name.Tag */
- .nv { color: #268BD2 } /* Name.Variable */
- .ow { color: #859900 } /* Operator.Word */
- .w { color: #93A1A1 } /* Text.Whitespace */
- .mf { color: #2AA198 } /* Literal.Number.Float */
- .mh { color: #2AA198 } /* Literal.Number.Hex */
- .mi { color: #2AA198 } /* Literal.Number.Integer */
- .mo { color: #2AA198 } /* Literal.Number.Oct */
- .sb { color: #586E75 } /* Literal.String.Backtick */
- .sc { color: #2AA198 } /* Literal.String.Char */
- .sd { color: #93A1A1 } /* Literal.String.Doc */
- .s2 { color: #2AA198 } /* Literal.String.Double */
- .se { color: #CB4B16 } /* Literal.String.Escape */
- .sh { color: #93A1A1 } /* Literal.String.Heredoc */
- .si { color: #2AA198 } /* Literal.String.Interpol */
- .sx { color: #2AA198 } /* Literal.String.Other */
- .sr { color: #DC322F } /* Literal.String.Regex */
- .s1 { color: #2AA198 } /* Literal.String.Single */
- .ss { color: #2AA198 } /* Literal.String.Symbol */
- .bp { color: #268BD2 } /* Name.Builtin.Pseudo */
- .vc { color: #268BD2 } /* Name.Variable.Class */
- .vg { color: #268BD2 } /* Name.Variable.Global */
- .vi { color: #268BD2 } /* Name.Variable.Instance */
- .il { color: #2AA198 } /* Literal.Number.Integer.Long */
-}
+ .line-numbers a {
+ color: #666;
+ }
+ .hljs {
+ display: block;
+ background: #002b36;
+ color: #839496;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .diff .hljs-header,
+ .hljs-doctype,
+ .hljs-pi,
+ .lisp .hljs-string,
+ .hljs-javadoc {
+ color: #586e75;
+ }
+
+ /* Solarized Green */
+ .hljs-keyword,
+ .hljs-winutils,
+ .method,
+ .hljs-addition,
+ .css .hljs-tag,
+ .hljs-request,
+ .hljs-status,
+ .nginx .hljs-title {
+ color: #859900;
+ }
+
+ /* Solarized Cyan */
+ .hljs-number,
+ .hljs-command,
+ .hljs-string,
+ .hljs-tag .hljs-value,
+ .hljs-rules .hljs-value,
+ .hljs-phpdoc,
+ .tex .hljs-formula,
+ .hljs-regexp,
+ .hljs-hexcolor,
+ .hljs-link_url {
+ color: #2aa198;
+ }
+
+ /* Solarized Blue */
+ .hljs-title,
+ .hljs-localvars,
+ .hljs-chunk,
+ .hljs-decorator,
+ .hljs-built_in,
+ .hljs-identifier,
+ .vhdl .hljs-literal,
+ .hljs-id,
+ .css .hljs-function {
+ color: #268bd2;
+ }
+
+ /* Solarized Yellow */
+ .hljs-attribute,
+ .hljs-variable,
+ .lisp .hljs-body,
+ .smalltalk .hljs-number,
+ .hljs-constant,
+ .hljs-class .hljs-title,
+ .hljs-parent,
+ .haskell .hljs-type,
+ .hljs-link_reference {
+ color: #b58900;
+ }
+
+ /* Solarized Orange */
+ .hljs-preprocessor,
+ .hljs-preprocessor .hljs-keyword,
+ .hljs-pragma,
+ .hljs-shebang,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .diff .hljs-change,
+ .hljs-special,
+ .hljs-attr_selector,
+ .hljs-subst,
+ .hljs-cdata,
+ .clojure .hljs-title,
+ .css .hljs-pseudo,
+ .hljs-header {
+ color: #cb4b16;
+ }
+
+ /* Solarized Red */
+ .hljs-deletion,
+ .hljs-important {
+ color: #dc322f;
+ }
+
+ /* Solarized Violet */
+ .hljs-link_label {
+ color: #6c71c4;
+ }
+
+ .tex .hljs-formula {
+ background: #073642;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index df127a7c49..880387a348 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,70 +1,178 @@
-.white .highlight {
-
+.white {
background-color: #fff;
-
+
+ .line.hll {
+ background: #FFA;
+ }
+
+ .highlight{
+ border-left: 1px solid #eee;
+ }
+
pre {
background-color: #fff;
color: #333;
}
- .hll { display: block; background-color: $hover }
- .c { color: #888888; font-style: italic } /* Comment */
- .err { color: #a61717; background-color: #e3d2d2 } /* Error */
- .k { color: #000000; font-weight: bold } /* Keyword */
- .cm { color: #888888 } /* Comment.Multiline */
- .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
- .c1 { color: #888888 } /* Comment.Single */
- .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
- .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
- .ge { font-style: italic } /* Generic.Emph */
- .gr { color: #aa0000 } /* Generic.Error */
- .gh { color: #303030 } /* Generic.Heading */
- .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
- .go { color: #888888 } /* Generic.Output */
- .gp { color: #555555 } /* Generic.Prompt */
- .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 */
- .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 */
- .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 */
- .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
- .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
- .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 */
- .bp { color: #003388 } /* Name.Builtin.Pseudo */
- .vc { color: #336699 } /* Name.Variable.Class */
- .vg { color: #dd7700 } /* Name.Variable.Global */
- .vi { color: #3333bb }
+ .hljs {
+ background: #FFF;
+ }
+
+ .line-numbers a {
+ color: #999;
+ }
+
+ .hljs {
+ display: block;
+ background: #fff; color: black;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .hljs-javadoc,
+ .hljs-comment * {
+ color: #006a00;
+ }
+
+ .hljs-keyword,
+ .hljs-literal,
+ .nginx .hljs-title {
+ color: #aa0d91;
+ }
+ .method,
+ .hljs-list .hljs-title,
+ .hljs-tag .hljs-title,
+ .setting .hljs-value,
+ .hljs-winutils,
+ .tex .hljs-command,
+ .http .hljs-title,
+ .hljs-request,
+ .hljs-status {
+ color: #008;
+ }
+
+ .hljs-envvar,
+ .tex .hljs-special {
+ color: #660;
+ }
+
+ .hljs-string {
+ color: #c41a16;
+ }
+ .hljs-tag .hljs-value,
+ .hljs-cdata,
+ .hljs-filter .hljs-argument,
+ .hljs-attr_selector,
+ .apache .hljs-cbracket,
+ .hljs-date,
+ .hljs-regexp {
+ color: #080;
+ }
+
+ .hljs-sub .hljs-identifier,
+ .hljs-pi,
+ .hljs-tag,
+ .hljs-tag .hljs-keyword,
+ .hljs-decorator,
+ .ini .hljs-title,
+ .hljs-shebang,
+ .hljs-prompt,
+ .hljs-hexcolor,
+ .hljs-rules .hljs-value,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .hljs-number,
+ .css .hljs-function,
+ .clojure .hljs-title,
+ .clojure .hljs-built_in,
+ .hljs-function .hljs-title,
+ .coffeescript .hljs-attribute {
+ color: #1c00cf;
+ }
+
+ .hljs-class .hljs-title,
+ .haskell .hljs-type,
+ .smalltalk .hljs-class,
+ .hljs-javadoctag,
+ .hljs-yardoctag,
+ .hljs-phpdoc,
+ .hljs-typename,
+ .hljs-tag .hljs-attribute,
+ .hljs-doctype,
+ .hljs-class .hljs-id,
+ .hljs-built_in,
+ .setting,
+ .hljs-params,
+ .clojure .hljs-attribute {
+ color: #5c2699;
+ }
+
+ .hljs-variable {
+ color: #3f6e74;
+ }
+ .css .hljs-tag,
+ .hljs-rules .hljs-property,
+ .hljs-pseudo,
+ .hljs-subst {
+ color: #000;
+ }
+
+ .css .hljs-class,
+ .css .hljs-id {
+ color: #9B703F;
+ }
+
+ .hljs-value .hljs-important {
+ color: #ff7700;
+ font-weight: bold;
+ }
+
+ .hljs-rules .hljs-keyword {
+ color: #C5AF75;
+ }
+
+ .hljs-annotation,
+ .apache .hljs-sqbracket,
+ .nginx .hljs-built_in {
+ color: #9B859D;
+ }
+
+ .hljs-preprocessor,
+ .hljs-preprocessor *,
+ .hljs-pragma {
+ color: #643820;
+ }
+
+ .tex .hljs-formula {
+ background-color: #EEE;
+ font-style: italic;
+ }
+
+ .diff .hljs-header,
+ .hljs-chunk {
+ color: #808080;
+ font-weight: bold;
+ }
+
+ .diff .hljs-change {
+ background-color: #BCCFF9;
+ }
+
+ .hljs-addition {
+ background-color: #BAEEBA;
+ }
+
+ .hljs-deletion {
+ background-color: #FFC8BD;
+ }
+
+ .hljs-comment .hljs-yardoctag {
+ font-weight: bold;
+ }
+
+ .method .hljs-id {
+ color: #000;
+ }
}
.shadow {
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index e637b645b5..4afe61d756 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -106,12 +106,12 @@
h3 {
margin-top: 35px;
- font-size: 2em;
+ font-size: 1.5em;
}
h4 {
margin-top: 30px;
- font-size: 1.5em;
+ font-size: 1.2em;
}
blockquote p {
@@ -128,7 +128,7 @@
}
}
- code {
+ p > code {
font-size: inherit;
font-weight: inherit;
color: #555;
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index decc5f5046..4b5fa0979b 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -5,6 +5,7 @@ $primary_color: #2FA0BB;
$link_color: #3A89A3;
$style_color: #474D57;
$bg_style_color: #2299BB;
+$list-group-active-bg: $bg_style_color;
$hover: #D9EDF7;
/**
diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/sections/admin.scss
index 8ad9bc732b..a558633d11 100644
--- a/app/assets/stylesheets/sections/admin.scss
+++ b/app/assets/stylesheets/sections/admin.scss
@@ -2,7 +2,7 @@
* Admin area
*
*/
-.admin_dash {
+.admin-dashboard {
.data {
a {
h1 {
@@ -14,6 +14,10 @@
}
}
}
+
+ .str-truncated {
+ max-width: 60%;
+ }
}
.admin-filter form {
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index ff293bc4a0..158db38549 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -153,6 +153,7 @@
img{
border: 1px solid #FFF;
background: url('trans_bg.gif');
+ max-width: 100%;
}
&.deleted {
border: 1px solid $deleted;
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
index 1fd82c84fc..6fc394e2e2 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -41,7 +41,7 @@
.dash-sidebar-tabs {
margin-bottom: 2px;
border: none;
- margin: 0;
+ margin: 0 !important;
li {
&.active {
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index a576fefdea..6ef12b20a5 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -37,8 +37,8 @@
&.event-inline {
.avatar {
- width: 16px;
- height: 16px;
+ position: relative;
+ top: -2px;
}
}
@@ -113,6 +113,7 @@
&.commit {
background: transparent;
padding: 3px;
+ padding-left: 0;
border: none;
color: #666;
.commit-row-title {
@@ -122,6 +123,7 @@
&.commits-stat {
display: block;
padding: 3px;
+ padding-left: 0;
&:hover {
background: none;
diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/sections/groups.scss
new file mode 100644
index 0000000000..60ec79acad
--- /dev/null
+++ b/app/assets/stylesheets/sections/groups.scss
@@ -0,0 +1,9 @@
+.new-group-member-holder {
+ margin-top: 50px;
+ background: #f9f9f9;
+ padding-top: 20px;
+}
+
+.member-search-form {
+ float: left;
+}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index 780f281dd7..883c9a859e 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -46,12 +46,17 @@ header {
}
}
+ .turbolink-spinner {
+ font-size: 20px;
+ margin-right: 10px;
+ }
+
@media (max-width: $screen-xs-max) {
border-width: 0;
font-size: 18px;
.app_logo { margin-left: -15px; }
- .project_name {
+ .title {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
@@ -103,7 +108,7 @@ header {
h1 {
margin: 0;
- background: url('logo-black.png') no-repeat center center;
+ background: image-url('logo-black.png') no-repeat center center;
background-size: 32px;
float: left;
height: 46px;
@@ -122,7 +127,7 @@ header {
* Project / Area name
*
*/
- .project_name {
+ .title {
position: relative;
float: left;
margin: 0;
@@ -215,18 +220,18 @@ header {
.app_logo {
a {
h1 {
- background: url('logo-white.png') no-repeat center center;
+ background: image-url('logo-white.png') no-repeat center center;
background-size: 32px;
color: #fff;
text-shadow: 0 1px 1px #444;
}
}
}
- .project_name {
+ .title {
a {
- color: #BBB;
+ color: #FFF;
&:hover {
- color: #FFF;
+ text-decoration: underline;
}
}
color: #fff;
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index 81d945a9b3..4cb8117633 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -14,8 +14,8 @@
.issue-check {
float: left;
- padding: 8px 0;
padding-right: 8px;
+ margin-bottom: 10px;
min-width: 15px;
}
@@ -38,13 +38,21 @@
}
}
-input.check_all_issues {
+.check-all-holder {
+ height: 32px;
float: left;
- padding: 0;
- margin: 0;
- margin-right: 10px;
- position: relative;
- top: 13px;
+ margin-right: 12px;
+ padding: 6px 10px;
+ border: 1px solid #ccc;
+ @include border-radius(4px);
+
+
+ input.check_all_issues {
+ padding: 0;
+ margin: 0;
+ position: relative;
+ top: 3px;
+ }
}
.issues_content {
@@ -57,23 +65,6 @@ input.check_all_issues {
}
}
-.btn.close_issue {
- color: #B94A48;
- font-weight: bold;
- @include shade;
- &:hover {
- color: #B94A48;
- }
-}
-.btn.reopen_issue {
- color: #468847;
- font-weight: bold;
- @include shade;
- &:hover {
- color: #468847;
- }
-}
-
@media (min-width: 800px) { .issues_filters select { width: 160px; } }
@media (min-width: 1200px) { .issues_filters select { width: 220px; } }
@@ -93,6 +84,13 @@ input.check_all_issues {
.update_selected_issues {
margin-left: 4px;
}
+
+ .select2-container .select2-choice {
+ height: 32px;
+ line-height: 28px;
+ color: #444 !important;
+ font-weight: 500;
+ }
}
}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 4388da0073..6e21bf0b0a 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -31,10 +31,10 @@
.mr_source_commit,
.mr_target_commit {
+ margin-top: 10px;
.commit {
margin: 0;
- padding: 0;
- padding: 5px 0;
+ padding: 2px 0;
list-style: none;
&:hover {
background: none;
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 7dd80dc52f..88f16a2159 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -35,9 +35,8 @@
width: 1%;
&.active {
a {
- color: $style_color;
- font-weight: bolder;
-
+ color: #333;
+ font-weight: bold;
&:after {
content: '';
display: block;
@@ -46,7 +45,7 @@
left: 50%;
width: 0;
height: 0;
- border-color: transparent transparent #777 transparent;
+ border-color: transparent transparent #333 transparent;
border-style: solid;
border-width: 6px;
margin-left: -6px;
@@ -56,7 +55,20 @@
&:hover {
a {
- color: $style_color;
+ color: $link_color;
+ &:after {
+ content: '';
+ display: block;
+ position: relative;
+ bottom: 8px;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-color: transparent transparent #29b transparent;
+ border-style: solid;
+ border-width: 6px;
+ margin-left: -6px;
+ }
}
}
@@ -73,7 +85,7 @@
a {
display: block;
text-align: center;
- font-weight: normal;
+ font-weight: 500;
height: 38px;
line-height: 34px;
color: #777;
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 1ae0e161aa..9f5f1579fb 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -92,10 +92,6 @@ ul.notes {
.note-body {
@include md-typography;
margin-left: 45px;
-
- .highlight {
- @include border-radius(4px);
- }
}
.note-header {
padding-bottom: 5px;
@@ -292,7 +288,7 @@ ul.notes {
box-shadow: none;
font-size: 14px;
height: 80px;
- width: 98.6%;
+ width: 100%;
}
}
}
@@ -341,7 +337,7 @@ ul.notes {
box-shadow: none;
font-size: 14px;
height: 80px;
- width: 98.6%;
+ width: 100%;
}
.form-actions {
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index 3a3bf7cdf2..7a696c21e4 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -105,3 +105,23 @@
}
}
}
+
+.profile-groups-avatars {
+ margin: 0 5px 10px 0;
+
+ img {
+ width: 50px;
+ height: 50px;
+ }
+}
+
+.global-notifications-form .level-title {
+ font-size: 15px;
+ color: #333;
+ font-weight: bold;
+}
+
+.notification-icon-holder {
+ width: 20px;
+ float: left;
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 178364835a..5757858a1c 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -123,14 +123,9 @@
}
.save-project-loader {
- img {
- margin-top: 50px;
- margin-bottom: 50px;
- }
- h3 {
- @extend .page-title;
- }
-
+ margin-top: 50px;
+ margin-bottom: 50px;
+ color: #555;
}
ul.nav.nav-projects-tabs {
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index dfdcbb59b6..55a5819b55 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -127,9 +127,27 @@
border-top: 1px dashed #CCC;
padding-top: 10px;
- h4 {
+ .readme-file-title {
font-size: 14px;
margin-bottom: 20px;
color: #777;
}
}
+
+.blob-commit-info {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ margin-bottom: 10px;
+
+ .commit {
+ .commit-row-title {
+ font-size: 13px;
+
+ .commit-row-message {
+ font-weight: normal;
+ color: #555;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss
index 0fc72d4e0a..edac4290e7 100644
--- a/app/assets/stylesheets/themes/ui_color.scss
+++ b/app/assets/stylesheets/themes/ui_color.scss
@@ -36,4 +36,8 @@
}
}
}
+
+ .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
+ background: #769;
+ }
}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 442b1b65ce..acb2f2c21d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base
end
end
- def render_404
- render file: Rails.root.join("public", "404"), layout: false, status: "404"
+ def render_403
+ head :forbidden
end
- def render_403
- render file: Rails.root.join("public", "403"), layout: false, status: "403"
+ def render_404
+ render file: Rails.root.join("public", "404"), layout: false, status: "404"
end
def require_non_empty_project
@@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base
gon.api_token = current_user.private_token if current_user
gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
+ gon.gravatar_enabled = Gitlab.config.gravatar.enabled
end
def check_password_expiration
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 656eda9dec..b95233c0e9 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -54,12 +54,12 @@ class DashboardController < ApplicationController
def merge_requests
@merge_requests = FilteringService.new.execute(MergeRequest, current_user, params)
- @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.page(params[:page]).per(20)
end
def issues
@issues = FilteringService.new.execute(Issue, current_user, params)
- @issues = @issues.recent.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(20)
@issues = @issues.includes(:author, :project)
respond_to do |format|
diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb
new file mode 100644
index 0000000000..38071410f4
--- /dev/null
+++ b/app/controllers/groups/avatars_controller.rb
@@ -0,0 +1,12 @@
+class Groups::AvatarsController < ApplicationController
+ layout "profile"
+
+ def destroy
+ @group = Group.find_by(path: params[:group_id])
+ @group.remove_avatar!
+
+ @group.save
+
+ redirect_to edit_group_path(@group)
+ end
+end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 7b418ec98f..b927dd2f20 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -63,7 +63,14 @@ class GroupsController < ApplicationController
def members
@project = group.projects.find(params[:project_id]) if params[:project_id]
- @members = group.users_groups.order('group_access DESC')
+ @members = group.users_groups
+
+ if params[:search].present?
+ users = group.users.search(params[:search])
+ @members = @members.where(user_id: users)
+ end
+
+ @members = @members.order('group_access DESC').page(params[:page]).per(50)
@users_group = UsersGroup.new
end
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
new file mode 100644
index 0000000000..9996b67a8a
--- /dev/null
+++ b/app/controllers/profiles/emails_controller.rb
@@ -0,0 +1,26 @@
+class Profiles::EmailsController < ApplicationController
+ layout "profile"
+
+ def index
+ @primary = current_user.email
+ @emails = current_user.emails
+ end
+
+ def create
+ @email = current_user.emails.new(params[:email])
+
+ flash[:alert] = @email.errors.full_messages.first unless @email.save
+
+ redirect_to profile_emails_url
+ end
+
+ def destroy
+ @email = current_user.emails.find(params[:id])
+ @email.destroy
+
+ respond_to do |format|
+ format.html { redirect_to profile_emails_url }
+ format.js { render nothing: true }
+ end
+ end
+end
diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/profiles/groups_controller.rb
index bdd991bec0..9a4d088651 100644
--- a/app/controllers/profiles/groups_controller.rb
+++ b/app/controllers/profiles/groups_controller.rb
@@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController
def leave
@users_group = group.users_groups.where(user_id: current_user.id).first
-
- if group.last_owner?(current_user)
- redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
- else
+ if can?(current_user, :destroy, @users_group)
@users_group.destroy
redirect_to(profile_groups_path, info: "You left #{group.name} group.")
+ else
+ return render_403
end
end
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index 541319e8d0..b4f14e649e 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -1,5 +1,6 @@
class Profiles::KeysController < ApplicationController
layout "profile"
+ skip_before_filter :authenticate_user!, only: [:get_keys]
def index
@keys = current_user.keys.order('id DESC')
@@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController
format.js { render nothing: true }
end
end
+
+ # Get all keys of a user(params[:username]) in a text format
+ # Helpful for sysadmins to put in respective servers
+ def get_keys
+ if params[:username].present?
+ begin
+ user = User.find_by_username(params[:username])
+ if user.present?
+ render text: user.all_ssh_keys.join("\n")
+ else
+ render_404 and return
+ end
+ rescue => e
+ render text: e.message
+ end
+ else
+ render_404 and return
+ end
+ end
+
end
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index b7531e2cef..234b6058ff 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController
end
def show
- compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to])
+ compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
@commits = compare.commits
@commit = compare.commit
@diffs = compare.diffs
@refs_are_same = compare.same
@line_notes = []
+ @timeout = compare.timeout
diff_line_count = Commit::diff_line_count(@diffs)
@suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff]
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index f260a2e059..dd11948edd 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -9,7 +9,10 @@ class Projects::IssuesController < Projects::ApplicationController
before_filter :authorize_write_issue!, only: [:new, :create]
# Allow modify issue
- before_filter :authorize_modify_issue!, only: [:edit, :update, :bulk_update]
+ before_filter :authorize_modify_issue!, only: [:edit, :update]
+
+ # Allow issues bulk update
+ before_filter :authorize_admin_issues!, only: [:bulk_update]
respond_to :html
@@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
sort_param = params[:sort] || 'newest'
@sort = sort_param.humanize unless sort_param.empty?
-
+ @assignees = User.where(id: @project.issues.pluck(:assignee_id))
respond_to do |format|
format.html
@@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless can?(current_user, :modify_issue, @issue)
end
- def authorize_admin_issue!
- return render_404 unless can?(current_user, :admin_issue, @issue)
+ def authorize_admin_issues!
+ return render_404 unless can?(current_user, :admin_issue, @project)
end
def module_enabled
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a00138fdb3..2b410c5a61 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
+ @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id))
end
def show
@@ -60,7 +61,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request = MergeRequest.new(params[:merge_request])
@merge_request.source_project = @project unless @merge_request.source_project
@merge_request.target_project = @project unless @merge_request.target_project
- @target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
@source_project = @merge_request.source_project
@merge_request
end
@@ -106,10 +106,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params[:merge_request].delete(:target_project_id)
if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
- @merge_request.reload_code
- @merge_request.mark_as_unchecked
@merge_request.reset_events_cache
- redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
+
+ respond_to do |format|
+ format.js
+ format.html do
+ redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
+ end
+ end
else
render "edit"
end
@@ -167,7 +171,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
protected
def selected_target_project
- ((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project
+ if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
+ @project
+ else
+ @project.forked_project_link.forked_from_project
+ end
end
def merge_request
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 18ace028b0..a6b7ae3f12 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController
@blob = @repository.blob_at(@commit.id, @path)
if @blob
- type = if @blob.mime_type =~ /html|javascript/
- 'text/plain; charset=utf-8'
- else
- @blob.mime_type
- end
+ type = get_blob_type
headers['X-Content-Type-Options'] = 'nosniff'
@@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController
not_found!
end
end
+
+ private
+
+ def get_blob_type
+ if @blob.mime_type =~ /html|javascript/
+ 'text/plain; charset=utf-8'
+ elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/
+ 'application/octet-stream'
+ else
+ @blob.mime_type
+ end
+ end
end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 16621c0371..7b8026cff9 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController
contents = tree.entries
@logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name
- last_commit = @repo.commits(@commit.id, file, 1).last
+ last_commit = @repo.last_commit_for_path(@commit.id, file)
{
file_name: content.name,
commit: last_commit
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 9dbb0d8188..818c5d971e 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController
before_filter :authorize_admin_project!, only: [:destroy]
def index
- @tags = Kaminari.paginate_array(@repository.tags).page(params[:page]).per(30)
+ @tags = Kaminari.paginate_array(@repository.tags.reverse).page(params[:page]).per(30)
end
def create
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 6a5ce62909..e86601a439 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,11 +1,23 @@
class UsersController < ApplicationController
- layout 'navless'
+
+ skip_before_filter :authenticate_user!, only: [:show]
+ layout :determine_layout
def show
- @user = User.find_by!(username: params[:username])
- @projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace)
+ @user = User.find_by_username!(params[:username])
+ @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)}
+ if !current_user && @projects.empty?
+ return authenticate_user!
+ end
@events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
-
@title = @user.name
end
+
+ def determine_layout
+ if current_user
+ 'navless'
+ else
+ 'public_users'
+ end
+ end
end
diff --git a/app/controllers/users_groups_controller.rb b/app/controllers/users_groups_controller.rb
index bc5db44552..b9bdc18952 100644
--- a/app/controllers/users_groups_controller.rb
+++ b/app/controllers/users_groups_controller.rb
@@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController
def destroy
@users_group = @group.users_groups.find(params[:id])
- @users_group.destroy
-
- respond_to do |format|
- format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
- format.js { render nothing: true }
+ if can?(current_user, :destroy, @users_group) # May fail if last owner.
+ @users_group.destroy
+ respond_to do |format|
+ format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
+ format.js { render nothing: true }
+ end
+ else
+ return render_403
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e60cba2bb2..4e7d01acd2 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -49,6 +49,15 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name }
end
+ def group_icon(group_path)
+ group = Group.find_by(path: group_path)
+ if group && group.avatar.present?
+ group.avatar.url
+ else
+ '/assets/no_group_avatar.png'
+ end
+ end
+
def avatar_icon(user_email = '', size = nil)
user = User.find_by(email: user_email)
if user && user.avatar.present?
@@ -153,15 +162,6 @@ module ApplicationHelper
alias_method :url_to_image, :image_url
- def users_select_tag(id, opts = {})
- css_class = "ajax-users-select "
- css_class << "multiselect " if opts[:multiple]
- css_class << (opts[:class] || '')
- value = opts[:selected] || ''
-
- hidden_field_tag(id, value, class: css_class)
- end
-
def body_data_page
path = controller.controller_path.split('/')
namespace = path.first if path.second
@@ -203,8 +203,14 @@ module ApplicationHelper
def highlight_js(&block)
string = capture(&block)
- content_tag :div, class: user_color_scheme_class do
- Pygments::Lexer[:js].highlight(string).html_safe
+ content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do
+ content_tag :div, class: 'highlight' do
+ content_tag :pre do
+ content_tag :code do
+ string.html_safe
+ end
+ end
+ end
end
end
@@ -221,4 +227,10 @@ module ApplicationHelper
def render_markup(file_name, file_content)
GitHub::Markup.render(file_name, file_content).html_safe
end
+
+ def spinner(text = nil)
+ content_tag :div, class: 'loading hide' do
+ content_tag(:i, nil, class: 'icon-spinner icon-spin') + text
+ end
+ end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 663369e458..5e5f3f77a2 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -122,17 +122,18 @@ module CommitsHelper
def commit_person_link(commit, options = {})
source_name = commit.send "#{options[:source]}_name".to_sym
source_email = commit.send "#{options[:source]}_email".to_sym
+
+ user = User.find_for_commit(source_email, source_name)
+ person_name = user.nil? ? source_name : user.name
+ person_email = user.nil? ? source_email : user.email
+
text = if options[:avatar]
- avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
- %Q{#{avatar}
#{source_name}}
+ avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
+ %Q{#{avatar}
#{person_name}}
else
- source_name
+ person_name
end
- # Prefer email match over name match
- user = User.where(email: source_email).first
- user ||= User.where(name: source_name).first
-
options = {
class: "commit-#{options[:source]}-link has_tooltip",
data: { :'original-title' => sanitize(source_email) }
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 60f9d4e764..b25662e3ba 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -28,14 +28,16 @@ module GitlabMarkdownHelper
link_to(gfm_body.html_safe, url, html_options)
end
- def markdown(text)
- unless @markdown
- gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
- # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
- filter_html: true,
- with_toc_data: true,
- hard_wrap: true,
- safe_links_only: true)
+ def markdown(text, options={})
+ unless (@markdown and options == @options)
+ @options = options
+ gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
+ # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
+ filter_html: true,
+ with_toc_data: true,
+ hard_wrap: true,
+ safe_links_only: true
+ }.merge(options))
@markdown = Redcarpet::Markdown.new(gitlab_renderer,
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
no_intra_emphasis: true,
@@ -47,7 +49,6 @@ module GitlabMarkdownHelper
space_after_headers: true,
superscript: true)
end
-
@markdown.render(text).html_safe
end
@@ -166,18 +167,27 @@ module GitlabMarkdownHelper
def file_exists?(path)
return false if path.nil? || path.empty?
- File.exists?(path_on_fs(path))
+ return @repository.blob_at(current_sha, path).present? || @repository.tree(current_sha, path).entries.any?
end
# Check if the path is pointing to a directory(tree) or a file(blob)
# eg. doc/api is directory and doc/README.md is file
def local_path(path)
- File.directory?(path_on_fs(path)) ? "tree" : "blob"
+ return "tree" if @repository.tree(current_sha, path).entries.any?
+ return "raw" if @repository.blob_at(current_sha, path).image?
+ return "blob"
end
- # Path to the file in the satellites repository on the filesystem
- def path_on_fs(path)
- [@path_to_satellite, path].join("/")
+ def current_ref
+ @commit.nil? ? "master" : @commit.id
+ end
+
+ def current_sha
+ if @commit
+ @commit.id
+ else
+ @repository.head_commit.sha
+ end
end
# We will assume that if no ref exists we can point to master
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 7c09273d53..5865396b69 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -1,6 +1,10 @@
module GroupsHelper
def remove_user_from_group_message(group, user)
- "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
+ "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?"
+ end
+
+ def leave_group_message(group)
+ "Are you sure you want to leave \"#{group}\" group?"
end
def group_head_title
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index cdba6ce84d..0374992ebf 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -70,11 +70,11 @@ module IssuesHelper
end
def bulk_update_milestone_options
- options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
+ options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
end
def bulk_update_assignee_options
- options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
+ options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
end
def assignee_options object
@@ -84,4 +84,12 @@ module IssuesHelper
def milestone_options object
options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
end
+
+ def issue_alert_class(issue)
+ if issue.closed?
+ 'alert-danger'
+ else
+ 'alert-success'
+ end
+ end
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 5e3f82fe9c..62f061bb07 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -41,4 +41,14 @@ module MergeRequestsHelper
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
end
end
+
+ def merge_request_alert_class(merge_request)
+ if merge_request.merged?
+ 'alert-info'
+ elsif merge_request.closed?
+ 'alert-danger'
+ else
+ 'alert-success'
+ end
+ end
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 695147cd6d..7ae104b8fd 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -17,7 +17,7 @@ module NotesHelper
def link_to_merge_request_diff_line_note(note)
if note.for_merge_request_diff_line? and note.diff
- link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code)
+ link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code)
end
end
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index ae3402b261..b2399bb6db 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -1,11 +1,11 @@
module NotificationsHelper
def notification_icon(notification)
if notification.disabled?
- content_tag :i, nil, class: 'icon-circle cred'
+ content_tag :i, nil, class: 'icon-volume-off cred'
elsif notification.participating?
- content_tag :i, nil, class: 'icon-circle cblue'
+ content_tag :i, nil, class: 'icon-volume-down cblue'
elsif notification.watch?
- content_tag :i, nil, class: 'icon-circle cgreen'
+ content_tag :i, nil, class: 'icon-volume-up cgreen'
else
content_tag :i, nil, class: 'icon-circle-blank cblue'
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index a6a507360b..e943045e41 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -64,6 +64,31 @@ module ProjectsHelper
project_nav_tabs.include? name
end
+ def selected_label?(label_name)
+ params[:label_name].to_s.split(',').include?(label_name)
+ end
+
+ def labels_filter_path(label_name)
+ label_name =
+ if selected_label?(label_name)
+ params[:label_name].split(',').reject { |l| l == label_name }.join(',')
+ elsif params[:label_name].present?
+ "#{params[:label_name]},#{label_name}"
+ else
+ label_name
+ end
+
+ project_filter_path(label_name: label_name)
+ end
+
+ def label_filter_class(label_name)
+ if selected_label?(label_name)
+ 'label-filter-item active'
+ else
+ 'label-filter-item light'
+ end
+ end
+
def project_filter_path(options={})
exist_opts = {
state: params[:state],
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
new file mode 100644
index 0000000000..a1fe4488ae
--- /dev/null
+++ b/app/helpers/selects_helper.rb
@@ -0,0 +1,20 @@
+module SelectsHelper
+ def users_select_tag(id, opts = {})
+ css_class = "ajax-users-select "
+ css_class << "multiselect " if opts[:multiple]
+ css_class << (opts[:class] || '')
+ value = opts[:selected] || ''
+
+ hidden_field_tag(id, value, class: css_class)
+ end
+
+ def project_users_select_tag(id, opts = {})
+ css_class = "ajax-project-users-select "
+ css_class << "multiselect " if opts[:multiple]
+ css_class << (opts[:class] || '')
+ value = opts[:selected] || ''
+ placeholder = opts[:placeholder] || 'Select user'
+
+ hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder)
+ end
+end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
new file mode 100644
index 0000000000..56f6e4d9cc
--- /dev/null
+++ b/app/helpers/submodule_helper.rb
@@ -0,0 +1,43 @@
+module SubmoduleHelper
+ include Gitlab::ShellAdapter
+
+ # links to files listing for submodule if submodule is a project on this server
+ def submodule_links(submodule_item)
+ url = @repository.submodule_url_for(@ref, submodule_item.path)
+
+ return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
+
+ project = $1
+ project.chomp!('.git')
+
+ if self_url?(url, project)
+ return project_path(project), project_tree_path(project, submodule_item.id)
+ elsif github_dot_com_url?(url)
+ standard_links('github.com', project, submodule_item.id)
+ elsif gitlab_dot_com_url?(url)
+ standard_links('gitlab.com', project, submodule_item.id)
+ else
+ return url, nil
+ end
+ end
+
+ protected
+
+ def github_dot_com_url?(url)
+ url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/
+ end
+
+ def gitlab_dot_com_url?(url)
+ url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
+ end
+
+ def self_url?(url, project)
+ return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('')
+ url == gitlab_shell.url_to_repo(project)
+ end
+
+ def standard_links(host, project, commit)
+ base = [ 'https://', host, '/', project ].join('')
+ return base, [ base, '/tree/', commit ].join('')
+ end
+end
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index bcd44f9476..c91660a02b 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -6,6 +6,12 @@ module Emails
mail(to: @user.email, subject: subject("Account was created for you"))
end
+ def new_email_email(email_id)
+ @email = Email.find(email_id)
+ @user = @email.user
+ mail(to: @user.email, subject: subject("Email was added to your account"))
+ end
+
def new_ssh_key_email(key_id)
@key = Key.find(key_id)
@user = @key.user
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index df21d7b5b0..428d74d83c 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -17,6 +17,7 @@ module Emails
def repository_push_email(project_id, recipient, author_id, branch, compare)
@project = Project.find(project_id)
@author = User.find(author_id)
+ @compare = compare
@commits = Commit.decorate(compare.commits)
@diffs = compare.diffs
@branch = branch
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 038668fccf..ba0ce527f6 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -14,6 +14,7 @@ class Ability
when "MergeRequest" then merge_request_abilities(user, subject)
when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject)
+ when "UsersGroup" then users_group_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
@@ -126,6 +127,7 @@ class Ability
:write_merge_request,
:write_wiki,
:modify_issue,
+ :admin_issue,
:push_code
]
end
@@ -218,5 +220,19 @@ class Ability
end
end
end
+
+ def users_group_abilities(user, subject)
+ rules = []
+ target_user = subject.user
+ group = subject.group
+ can_manage = group_abilities(user, group).include?(:manage_group)
+ if can_manage && (user != target_user)
+ rules << :modify
+ end
+ if !group.last_owner?(user) && (can_manage || (user == target_user))
+ rules << :destroy
+ end
+ rules
+ end
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index dd1f980187..bcc1bcbd96 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -16,29 +16,31 @@ class Commit
DIFF_HARD_LIMIT_FILES = 500
DIFF_HARD_LIMIT_LINES = 10000
- def self.decorate(commits)
- commits.map { |c| self.new(c) }
- end
+ class << self
+ def decorate(commits)
+ commits.map { |c| self.new(c) }
+ end
- # Calculate number of lines to render for diffs
- def self.diff_line_count(diffs)
- diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
- end
+ # Calculate number of lines to render for diffs
+ def diff_line_count(diffs)
+ diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
+ end
- def self.diff_suppress?(diffs, line_count = nil)
- # optimize - check file count first
- return true if diffs.size > DIFF_SAFE_FILES
+ def diff_suppress?(diffs, line_count = nil)
+ # optimize - check file count first
+ return true if diffs.size > DIFF_SAFE_FILES
- line_count ||= Commit::diff_line_count(diffs)
- line_count > DIFF_SAFE_LINES
- end
+ line_count ||= Commit::diff_line_count(diffs)
+ line_count > DIFF_SAFE_LINES
+ end
- def self.diff_force_suppress?(diffs, line_count = nil)
- # optimize - check file count first
- return true if diffs.size > DIFF_HARD_LIMIT_FILES
+ def diff_force_suppress?(diffs, line_count = nil)
+ # optimize - check file count first
+ return true if diffs.size > DIFF_HARD_LIMIT_FILES
- line_count ||= Commit::diff_line_count(diffs)
- line_count > DIFF_HARD_LIMIT_LINES
+ line_count ||= Commit::diff_line_count(diffs)
+ line_count > DIFF_HARD_LIMIT_LINES
+ end
end
attr_accessor :raw
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 0f1dad4ef1..bf2c2157d3 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -48,13 +48,13 @@ module Issuable
def sort(method)
case method.to_s
- when 'newest' then reorder('created_at DESC')
- when 'oldest' then reorder('created_at ASC')
- when 'recently_updated' then reorder('updated_at DESC')
- when 'last_updated' then reorder('updated_at ASC')
+ when 'newest' then reorder("#{table_name}.created_at DESC")
+ when 'oldest' then reorder("#{table_name}.created_at ASC")
+ when 'recently_updated' then reorder("#{table_name}.updated_at DESC")
+ when 'last_updated' then reorder("#{table_name}.updated_at ASC")
when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
- else reorder('created_at DESC')
+ else reorder("#{table_name}.created_at DESC")
end
end
end
diff --git a/app/models/email.rb b/app/models/email.rb
new file mode 100644
index 0000000000..22e71e4f10
--- /dev/null
+++ b/app/models/email.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: emails
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# email :string not null
+# created_at :datetime not null
+class Email < ActiveRecord::Base
+ attr_accessible :email, :user_id
+
+ #
+ # Relations
+ #
+ belongs_to :user
+
+ #
+ # Validations
+ #
+ validates :user_id, presence: true
+ validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
+ validate :unique_email, if: ->(email) { email.email_changed? }
+
+ before_validation :cleanup_email
+
+ def cleanup_email
+ self.email = self.email.downcase.strip
+ end
+
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
+ end
+end
\ No newline at end of file
diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb
index 7ebaaff61c..613a7110d1 100644
--- a/app/models/gollum_wiki.rb
+++ b/app/models/gollum_wiki.rb
@@ -1,4 +1,5 @@
class GollumWiki
+ include Gitlab::ShellAdapter
MARKUPS = {
"Markdown" => :markdown,
@@ -113,10 +114,6 @@ class GollumWiki
"#{@user.username} #{action} page: #{title}"
end
- def gitlab_shell
- @gitlab_shell ||= Gitlab::Shell.new
- end
-
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 0b64d5b4f7..8de0c78c15 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -12,10 +12,20 @@
# description :string(255) default(""), not null
#
+require 'carrierwave/orm/activerecord'
+require 'file_size_validator'
+
class Group < Namespace
has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups
+ attr_accessible :avatar
+
+ validate :avatar_type, if: ->(user) { user.avatar_changed? }
+ validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
+
+ mount_uploader :avatar, AttachmentUploader
+
def human_name
name
end
@@ -50,4 +60,10 @@ class Group < Namespace
def members
users_groups
end
+
+ def avatar_type
+ unless self.avatar.image?
+ self.errors.add :avatar, "only images allowed"
+ end
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index c6d2f74f2b..b596d7eb9c 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
has_one :merge_request_diff, dependent: :destroy
+
after_create :create_merge_request_diff
+ after_update :update_merge_request_diff
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
@@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base
end
end
+ def update_merge_request_diff
+ if source_branch_changed? || target_branch_changed?
+ reload_code
+ mark_as_unchecked
+ end
+ end
+
def reload_code
if merge_request_diff && opened?
merge_request_diff.reload_content
@@ -219,6 +228,14 @@ class MergeRequest < ActiveRecord::Base
end
end
+ def source_project_namespace
+ if source_project && source_project.namespace
+ source_project.namespace.path
+ else
+ "(removed)"
+ end
+ end
+
def source_branch_exists?
return false unless self.source_project
@@ -253,4 +270,24 @@ class MergeRequest < ActiveRecord::Base
message << description.to_s
message
end
+
+ # Return array of possible target branches
+ # dependes on target project of MR
+ def target_branches
+ if target_project.nil?
+ []
+ else
+ target_project.repository.branch_names
+ end
+ end
+
+ # Return array of possible source branches
+ # dependes on source project of MR
+ def source_branches
+ if source_project.nil?
+ []
+ else
+ source_project.repository.branch_names
+ end
+ end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 3ea610197e..a226fef734 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base
Gitlab::Git::Diff.between(repository, source_branch, target_branch)
end
- if diffs == broken_diffs
- self.state = :timeout
- diffs = []
- end
-
diffs ||= []
diffs
+ rescue Gitlab::Git::Diff::TimeoutError => ex
+ self.state = :timeout
+ diffs = []
end
def repository
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 8f837c72ff..0bc5e1862e 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -10,6 +10,7 @@
# updated_at :datetime not null
# type :string(255)
# description :string(255) default(""), not null
+# avatar :string(255)
#
class Namespace < ActiveRecord::Base
@@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base
format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :description, length: { within: 0..255 }
- validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
+ validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
diff --git a/app/models/note.rb b/app/models/note.rb
index f4c0be3307..48c03c9d58 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -72,14 +72,20 @@ class Note < ActiveRecord::Base
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
# Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+.
def create_cross_reference_note(noteable, mentioner, author, project)
- create({
- noteable: noteable,
- commit_id: (noteable.sha if noteable.respond_to? :sha),
+ note_options = {
project: project,
author: author,
note: "_mentioned in #{mentioner.gfm_reference}_",
system: true
- }, without_protection: true)
+ }
+
+ if noteable.kind_of?(Commit)
+ note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id)
+ else
+ note_options.merge!(noteable: noteable)
+ end
+
+ create(note_options, without_protection: true)
end
def create_assignee_change_note(noteable, project, author, assignee)
diff --git a/app/models/notification.rb b/app/models/notification.rb
index ff6a18d6a5..b0f8ed6a4e 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -9,12 +9,23 @@ class Notification
attr_accessor :target
- def self.notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH]
- end
+ class << self
+ def notification_levels
+ [N_DISABLED, N_PARTICIPATING, N_WATCH]
+ end
- def self.project_notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
+ def options_with_labels
+ {
+ disabled: N_DISABLED,
+ participating: N_PARTICIPATING,
+ watch: N_WATCH,
+ global: N_GLOBAL
+ }
+ end
+
+ def project_notification_levels
+ [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
+ end
end
def initialize(target)
@@ -36,4 +47,8 @@ class Notification
def global?
target.notification_level == N_GLOBAL
end
+
+ def level
+ target.notification_level
+ end
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index c0ba9f1e7f..d4795867ba 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -40,7 +40,7 @@ class HipchatService < Service
end
def execute(push_data)
- gate[room].send('Gitlab', create_message(push_data))
+ gate[room].send('GitLab', create_message(push_data))
end
private
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 1255b81453..99d908b5d8 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -57,7 +57,7 @@ class Repository
def recent_branches(limit = 20)
branches.sort do |a, b|
- b.commit.committed_date <=> a.commit.committed_date
+ commit(b.target).committed_date <=> commit(a.target).committed_date
end[0..limit]
end
@@ -163,7 +163,49 @@ class Repository
def readme
Rails.cache.fetch(cache_key(:readme)) do
- Tree.new(self, self.root_ref).readme
+ tree(:head).readme
end
end
+
+ def head_commit
+ commit(self.root_ref)
+ end
+
+ def tree(sha = :head, path = nil)
+ if sha == :head
+ sha = head_commit.sha
+ end
+
+ Tree.new(self, sha, path)
+ end
+
+ def blob_at_branch(branch_name, path)
+ last_commit = commit(branch_name)
+
+ if last_commit
+ blob_at(last_commit.sha, path)
+ else
+ nil
+ end
+ end
+
+ # Returns url for submodule
+ #
+ # Ex.
+ # @repository.submodule_url_for('master', 'rack')
+ # # => git@localhost:rack.git
+ #
+ def submodule_url_for(ref, path)
+ if submodules.any?
+ submodule = submodules(ref)[path]
+
+ if submodule
+ submodule['url']
+ end
+ end
+ end
+
+ def last_commit_for_path(sha, path)
+ commits(sha, path, 1).last
+ end
end
diff --git a/app/models/tree.rb b/app/models/tree.rb
index ed06cb1a12..4f866f1a33 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -23,4 +23,8 @@ class Tree
def submodules
@entries.select(&:submodule?)
end
+
+ def sorted_entries
+ trees + blobs + submodules
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 1acf330cab..855fe58ffe 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -78,6 +78,7 @@ class User < ActiveRecord::Base
# Profile
has_many :keys, dependent: :destroy
+ has_many :emails, dependent: :destroy
# Groups
has_many :users_groups, dependent: :destroy
@@ -108,7 +109,7 @@ class User < ActiveRecord::Base
validates :bio, length: { maximum: 255 }, allow_blank: true
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,
+ validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
@@ -116,6 +117,7 @@ class User < ActiveRecord::Base
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar_changed? }
+ validate :unique_email, if: ->(user) { user.email_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
before_validation :generate_password, on: :create
@@ -183,6 +185,13 @@ class User < ActiveRecord::Base
where(conditions).first
end
end
+
+ def find_for_commit(email, name)
+ # Prefer email match over name match
+ User.where(email: email).first ||
+ User.joins(:emails).where(emails: { email: email }).first ||
+ User.where(name: name).first
+ end
def filter filter_name
case filter_name
@@ -250,6 +259,10 @@ class User < ActiveRecord::Base
end
end
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
+ end
+
# Groups user has access to
def authorized_groups
@authorized_groups ||= begin
@@ -435,4 +448,8 @@ class User < ActiveRecord::Base
def short_website_url
website_url.gsub(/https?:\/\//, '')
end
+
+ def all_ssh_keys
+ keys.map(&:key)
+ end
end
diff --git a/app/observers/email_observer.rb b/app/observers/email_observer.rb
new file mode 100644
index 0000000000..026ad8b1d9
--- /dev/null
+++ b/app/observers/email_observer.rb
@@ -0,0 +1,5 @@
+class EmailObserver < BaseObserver
+ def after_create(email)
+ notification.new_email(email)
+ end
+end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index 185ab26d96..1998fb79e7 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -24,7 +24,7 @@ module Files
return error("Your changes could not be committed, because file name contains not allowed characters")
end
- blob = repository.blob_at(ref, file_path)
+ blob = repository.blob_at_branch(ref, file_path)
if blob
return error("Your changes could not be committed, because file with such name exists")
diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb
index 30e512d091..ff5dc6ef34 100644
--- a/app/services/files/delete_service.rb
+++ b/app/services/files/delete_service.rb
@@ -17,7 +17,7 @@ module Files
return error("You can only create files if you are on top of a branch")
end
- blob = repository.blob_at(ref, path)
+ blob = repository.blob_at_branch(ref, path)
unless blob
return error("You can only edit text files")
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index d59802ae48..c631f28749 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -17,7 +17,7 @@ module Files
return error("You can only create files if you are on top of a branch")
end
- blob = repository.blob_at(ref, path)
+ blob = repository.blob_at_branch(ref, path)
unless blob
return error("You can only edit text files")
diff --git a/app/services/filtering_service.rb b/app/services/filtering_service.rb
index b339065890..52537f7ba4 100644
--- a/app/services/filtering_service.rb
+++ b/app/services/filtering_service.rb
@@ -24,7 +24,8 @@ class FilteringService
@current_user = current_user
@params = params
- items = by_scope
+ items = init_collection
+ items = by_scope(items)
items = by_state(items)
items = by_group(items)
items = by_project(items)
@@ -37,20 +38,30 @@ class FilteringService
private
- def by_scope
+ def init_collection
table_name = klass.table_name
+ return klass.of_projects(Project.public_only) unless current_user
+
+ if project
+ if current_user.can?(:read_project, project)
+ project.send(table_name)
+ else
+ []
+ end
+ else
+ klass.of_projects(current_user.authorized_projects)
+ end
+ end
+
+ def by_scope(items)
case params[:scope]
when 'created-by-me', 'authored' then
- current_user.send(table_name)
+ items.where(author_id: current_user.id)
when 'all' then
- if current_user
- klass.of_projects(current_user.authorized_projects.pluck(:id))
- else
- klass.of_projects(Project.public_only)
- end
+ items
when 'assigned-to-me' then
- current_user.send("assigned_#{table_name}")
+ items.where(assignee_id: current_user.id)
else
raise 'You must specify default scope'
end
@@ -120,4 +131,8 @@ class FilteringService
items
end
+
+ def project
+ Project.where(id: params[:project_id]).first if params[:project_id].present?
+ end
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index e54f88e42d..fcc03c3e4b 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -188,8 +188,6 @@ class GitPushService
end
def commit_user commit
- User.where(email: commit.author_email).first ||
- User.where(name: commit.author_name).first ||
- user
+ User.find_for_commit(commit.author_email, commit.author_name) || user
end
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index fb87e17593..ff6dfb6113 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -3,6 +3,7 @@ module Notes
def execute
note = project.notes.new(params[:note])
note.author = current_user
+ note.system = false
note.save
note
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 7c02777e91..9d7bb9639a 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -17,6 +17,13 @@ class NotificationService
end
end
+ # Always notify user about email added to profile
+ def new_email(email)
+ if email.user
+ mailer.new_email_email(email.id)
+ end
+ end
+
# When create an issue we should send next emails:
#
# * issue assignee if their notification level is not Disabled
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index dd663945ea..bbd60bc622 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -3,136 +3,137 @@
%p.light
You can manage projects, users and other GitLab data from here.
%hr
-.admin_dash.row
- .col-sm-4
- .light-well
- %h4 Projects
- .data
- = link_to admin_projects_path do
- %h1= Project.count
- %hr
- = link_to 'New Project', new_project_path, class: "btn btn-new"
- .col-sm-4
- .light-well
- %h4 Users
- .data
- = link_to admin_users_path do
- %h1= User.count
- %hr
- = link_to 'New User', new_admin_user_path, class: "btn btn-new"
- .col-sm-4
- .light-well
- %h4 Groups
- .data
- = link_to admin_groups_path do
- %h1= Group.count
- %hr
- = link_to 'New Group', new_admin_group_path, class: "btn btn-new"
+.admin-dashboard
+ .row
+ .col-sm-4
+ .light-well
+ %h4 Projects
+ .data
+ = link_to admin_projects_path do
+ %h1= Project.count
+ %hr
+ = link_to 'New Project', new_project_path, class: "btn btn-new"
+ .col-sm-4
+ .light-well
+ %h4 Users
+ .data
+ = link_to admin_users_path do
+ %h1= User.count
+ %hr
+ = link_to 'New User', new_admin_user_path, class: "btn btn-new"
+ .col-sm-4
+ .light-well
+ %h4 Groups
+ .data
+ = link_to admin_groups_path do
+ %h1= Group.count
+ %hr
+ = link_to 'New Group', new_admin_group_path, class: "btn btn-new"
-.row.prepend-top-10
- .col-md-4
- %h4 Latest projects
- %hr
- - @projects.each do |project|
+ .row.prepend-top-10
+ .col-md-4
+ %h4 Latest projects
+ %hr
+ - @projects.each do |project|
+ %p
+ = link_to project.name_with_namespace, [:admin, project], class: 'str-truncated'
+ %span.light.pull-right
+ #{time_ago_with_tooltip(project.created_at)}
+
+ .col-md-4
+ %h4 Latest users
+ %hr
+ - @users.each do |user|
+ %p
+ = link_to [:admin, user], class: 'str-truncated' do
+ = user.name
+ %span.light.pull-right
+ #{time_ago_with_tooltip(user.created_at)}
+
+ .col-md-4
+ %h4 Latest groups
+ %hr
+ - @groups.each do |group|
+ %p
+ = link_to [:admin, group], class: 'str-truncated' do
+ = group.name
+ %span.light.pull-right
+ #{time_ago_with_tooltip(group.created_at)}
+
+ %br
+ .row
+ .col-md-4
+ %h4 Stats
+ %hr
%p
- = link_to project.name_with_namespace, [:admin, project]
+ Forks
%span.light.pull-right
- #{time_ago_with_tooltip(project.created_at)}
-
- .col-md-4
- %h4 Latest users
- %hr
- - @users.each do |user|
+ = ForkedProjectLink.count
%p
- = link_to [:admin, user] do
- = user.name
+ Issues
%span.light.pull-right
- #{time_ago_with_tooltip(user.created_at)}
-
- .col-md-4
- %h4 Latest groups
- %hr
- - @groups.each do |group|
+ = Issue.count
%p
- = link_to [:admin, group] do
- = group.name
+ Merge Requests
%span.light.pull-right
- #{time_ago_with_tooltip(group.created_at)}
+ = MergeRequest.count
+ %p
+ Notes
+ %span.light.pull-right
+ = Note.count
+ %p
+ Snippets
+ %span.light.pull-right
+ = Snippet.count
+ %p
+ SSH Keys
+ %span.light.pull-right
+ = Key.count
+ %p
+ Milestones
+ %span.light.pull-right
+ = Milestone.count
+ .col-md-4
+ %h4
+ Features
+ %hr
+ %p
+ Sign up
+ %span.light.pull-right
+ = boolean_to_icon gitlab_config.signup_enabled
+ %p
+ LDAP
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.ldap.enabled
+ %p
+ Gravatar
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.gravatar.enabled
+ %p
+ OmniAuth
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.omniauth.enabled
+ .col-md-4
+ %h4 Components
+ %hr
+ %p
+ GitLab
+ %span.pull-right
+ = Gitlab::VERSION
+ %p
+ GitLab Shell
+ %span.pull-right
+ = Gitlab::Shell.new.version
+ %p
+ GitLab API
+ %span.pull-right
+ = API::API::version
+ %p
+ Ruby
+ %span.pull-right
+ #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
-%br
-.row
- .col-md-4
- %h4 Stats
- %hr
- %p
- Forks
- %span.light.pull-right
- = ForkedProjectLink.count
- %p
- Issues
- %span.light.pull-right
- = Issue.count
- %p
- Merge Requests
- %span.light.pull-right
- = MergeRequest.count
- %p
- Notes
- %span.light.pull-right
- = Note.count
- %p
- Snippets
- %span.light.pull-right
- = Snippet.count
- %p
- SSH Keys
- %span.light.pull-right
- = Key.count
- %p
- Milestones
- %span.light.pull-right
- = Milestone.count
- .col-md-4
- %h4
- Features
- %hr
- %p
- Sign up
- %span.light.pull-right
- = boolean_to_icon gitlab_config.signup_enabled
- %p
- LDAP
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.ldap.enabled
- %p
- Gravatar
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.gravatar.enabled
- %p
- OmniAuth
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.omniauth.enabled
- .col-md-4
- %h4 Components
- %hr
- %p
- GitLab
- %span.pull-right
- = Gitlab::VERSION
- %p
- GitLab Shell
- %span.pull-right
- = Gitlab::Shell.new.version
- %p
- GitLab API
- %span.pull-right
- = API::API::version
- %p
- Ruby
- %span.pull-right
- #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
-
- %p
- Rails
- %span.pull-right
- #{Rails::VERSION::STRING}
+ %p
+ Rails
+ %span.pull-right
+ #{Rails::VERSION::STRING}
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 7a373ee586..9a0d596792 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -1,11 +1,12 @@
%h3.page-title
Groups (#{@groups.total_count})
- %small
- allows you to keep projects organized.
- Use groups for uniting related projects.
-
= link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right"
-%br
+
+%p.light
+ Group allows you to keep projects organized.
+ Use groups for uniting related projects.
+
+%hr
= form_tag admin_groups_path, method: :get, class: 'form-inline' do
.form-group
= text_field_tag :name, params[:name], class: "form-control input-mn-300"
@@ -23,24 +24,18 @@
%h4
= link_to [:admin, group] do
+ %i.icon-folder-close
= group.name
→
%span.monospace
- %i.icon-folder-close
%strong #{group.path}/
-
- .clearfix.light.append-bottom-10
- %span
- %b Members:
- %span.badge= group.members.size
- \|
- %span
- %b Projects:
- %span.badge= group.projects.count
-
.clearfix
%p
= truncate group.description, length: 150
+ .clearfix
+ %p.light
+ #{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
+
= paginate @groups, theme: "gitlab"
diff --git a/app/views/admin/hooks/_data_ex.html.erb b/app/views/admin/hooks/_data_ex.html.erb
deleted file mode 100644
index 5b16dfb398..0000000000
--- a/app/views/admin/hooks/_data_ex.html.erb
+++ /dev/null
@@ -1,71 +0,0 @@
-<% data_ex_str = <
-<% js_lexer = Pygments::Lexer[:js] %>
-<%= raw js_lexer.highlight(data_ex_str) %>
diff --git a/app/views/admin/hooks/_data_ex.html.haml b/app/views/admin/hooks/_data_ex.html.haml
new file mode 100644
index 0000000000..9861e372ef
--- /dev/null
+++ b/app/views/admin/hooks/_data_ex.html.haml
@@ -0,0 +1,67 @@
+= highlight_js do
+ :erb
+ 1. Project created:
+ {
+ "created_at": "2012-07-21T07:30:54Z",
+ "event_name": "project_create",
+ "name": "StoreCloud",
+ "owner_email": "johnsmith@gmail.com"
+ "owner_name": "John Smit",
+ "path": "stormcloud",
+ "path_with_namespace": "jsmith/stormcloud",
+ "project_id": 74,
+ }
+
+ 2. Project destroyed:
+ {
+ "created_at": "2012-07-21T07:30:58Z",
+ "event_name": "project_destroy",
+ "name": "Underscore",
+ "owner_email": "johnsmith@gmail.com"
+ "owner_name": "John Smith",
+ "path": "underscore",
+ "path_with_namespace": "jsmith/underscore",
+ "project_id": 73,
+ }
+
+ 3. New Team Member:
+ {
+ "created_at": "2012-07-21T07:30:56Z",
+ "event_name": "user_add_to_team",
+ "project_access": "Master",
+ "project_id": 74,
+ "project_name": "StoreCloud",
+ "project_path": "storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ }
+
+ 4. Team Member Removed:
+ {
+ "created_at": "2012-07-21T07:30:56Z",
+ "event_name": "user_remove_from_team",
+ "project_access": "Master",
+ "project_id": 74,
+ "project_name": "StoreCloud",
+ "project_path": "storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ }
+
+ 5. User created:
+ {
+ "created_at": "2012-07-21T07:44:07Z",
+ "email": "js@gitlabhq.com",
+ "event_name": "user_create",
+ "name": "John Smith",
+ "user_id": 41
+ }
+
+ 6. User removed:
+ {
+ "created_at": "2012-07-21T07:44:07Z",
+ "email": "js@gitlabhq.com",
+ "event_name": "user_destroy",
+ "name": "John Smith",
+ "user_id": 41
+ }
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 1fa6fdfaff..0b3934a712 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -1,12 +1,6 @@
.row
.col-md-3
.admin-filter
- = form_tag admin_users_path, method: :get, class: 'form-inline' do
- .append-bottom-10
- .form-group
- = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
- = button_tag type: 'submit', class: 'btn btn-primary' do
- %i.icon-search
%ul.nav.nav-pills.nav-stacked
%li{class: "#{'active' unless params[:filter]}"}
= link_to admin_users_path do
@@ -25,6 +19,12 @@
Without projects
%small.pull-right= User.without_projects.count
%hr
+ = form_tag admin_users_path, method: :get, class: 'form-inline' do
+ .form-group
+ = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
+ = button_tag type: 'submit', class: 'btn btn-primary' do
+ %i.icon-search
+ %hr
= link_to 'Reset', admin_users_path, class: "btn btn-cancel"
.col-md-9
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index bd276f2222..e888358dc6 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -78,7 +78,6 @@
- if @user.blocked?
.alert.alert-info
%h4 This user is blocked
- %br
%p Blocking user has the following effects:
%ul
%li User will not be able to login
@@ -86,11 +85,11 @@
%li User will be removed from joined projects and groups
%li Personal projects will be left
%li Owned groups will be left
+ %br
= link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-new", data: { confirm: 'Are you sure?' }
- else
- .alert
+ .alert.alert-warning
%h4 Block this user
- %br
%p Blocking user has the following effects:
%ul
%li User will not be able to login
@@ -98,12 +97,12 @@
%li User will be removed from joined projects and groups
%li Personal projects will be left
%li Owned groups will be left
+ %br
= link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-remove"
.alert.alert-danger
%h4
Remove user
- %br
%p Deleting a user has the following effects:
%ul
%li All user content like authored issues, snippets, comments will be removed
@@ -114,6 +113,7 @@
%li
Next groups with all content will be removed:
%strong #{@user.solo_owned_groups.map(&:name).join(', ')}
+ %br
= link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
.col-md-6
@@ -150,5 +150,3 @@
- if tm.respond_to? :project
= link_to project_team_member_path(project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
%i.icon-remove
-
-
diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml
index 8911772631..39dd600dba 100644
--- a/app/views/dashboard/_activities.html.haml
+++ b/app/views/dashboard/_activities.html.haml
@@ -5,4 +5,5 @@
.content_list
- else
%p.nothing_here_message Projects activity will be displayed here
-.loading.hide
+
+= spinner
diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml
index d6937ca481..2ff1c33c53 100644
--- a/app/views/dashboard/_groups.html.haml
+++ b/app/views/dashboard/_groups.html.haml
@@ -10,6 +10,7 @@
- groups.each do |group|
%li.group-row
= link_to group_path(id: group.path), class: dom_class(group) do
+ = image_tag group_icon(group.path), class: "avatar s24"
%span.group-name.filter-title
= truncate(group.name, length: 35)
%span.arrow
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
old mode 100644
new mode 100755
index 19bd4e7bd5..af627588ad
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -3,7 +3,7 @@
%span.pull-right #{@issues.total_count} issues
%p.light
- List all issues from all project's you have access to.
+ List all issues from all projects you have access to.
%hr
.row
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
old mode 100644
new mode 100755
index b487a4d666..550a93e178
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -4,7 +4,7 @@
%p.light
- List all merge requests from all project's you have access to.
+ List all merge requests from all projects you have access to.
%hr
.row
.col-md-3
diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml
old mode 100644
new mode 100755
index dd63a232fe..bf634d9de6
--- a/app/views/devise/confirmations/new.html.haml
+++ b/app/views/devise/confirmations/new.html.haml
@@ -3,7 +3,8 @@
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
.devise-errors
= devise_error_messages!
- = f.email_field :email, placeholder: 'Email', class: "form-control", required: true
+ .clearfix.append-bottom-20
+ = f.email_field :email, placeholder: 'Email', class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Resend confirmation instructions", class: 'btn btn-success'
%hr
diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml
old mode 100644
new mode 100755
index a14ef2995c..040821ca32
--- a/app/views/devise/passwords/new.html.haml
+++ b/app/views/devise/passwords/new.html.haml
@@ -2,7 +2,8 @@
%h3.page-title Reset password
.devise-errors
= devise_error_messages!
- = f.email_field :email, placeholder: "Email", class: "form-control", required: true
+ .clearfix.append-bottom-20
+ = f.email_field :email, placeholder: "Email", class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Reset password", class: "btn-primary btn"
%hr
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index 938f61d209..bb87d9ecb4 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,7 +1,7 @@
.login-box
%h3.page-title Sign in
- if ldap_enabled?
- %ul.nav.nav-tabs.append-bottom-20
+ %ul.nav.nav-tabs
%li.active
= link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
%li
diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml
index 5801139a9f..3ab9276c54 100644
--- a/app/views/groups/_new_group_member.html.haml
+++ b/app/views/groups/_new_group_member.html.haml
@@ -1,15 +1,8 @@
= form_for @users_group, url: group_users_groups_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
- %h4.append-bottom-20
- New member(s) for
- %strong #{@group.name}
- group
-
- %p 1. Choose users you want in the group
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large')
- %p 2. Set access level for them
.form-group
= f.label :group_access, "Group Access", class: 'control-label'
.col-sm-10= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select select2"
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 77734815b8..f14fe92340 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -4,13 +4,15 @@
%li.active
= link_to '#tab-edit', 'data-toggle' => 'tab' do
%i.icon-edit
- Edit Group
+ Group
%li
= link_to '#tab-projects', 'data-toggle' => 'tab' do
%i.icon-folder-close
Projects
%li
- = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab'
+ = link_to '#tab-remove', 'data-toggle' => 'tab' do
+ %i.icon-remove-sign
+ Remove
.col-md-10
.tab-content
@@ -20,7 +22,7 @@
%strong= @group.name
group settings:
%div.form-holder
- = form_for @group, html: { class: "form-horizontal" } do |f|
+ = form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f|
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
@@ -35,6 +37,26 @@
.col-sm-10
= f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+ .form-group
+ .col-sm-2
+ .col-sm-10
+ = image_tag group_icon(@group.to_param), alt: '', class: 'avatar s160'
+ %p.light
+ - if @group.avatar?
+ You can change your group avatar here
+ - else
+ You can upload an group avatar here
+ %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
+ %i.icon-paper-clip
+ %span Choose File ...
+
+ %span.file_name.js-avatar-filename File name...
+ = f.file_field :avatar, class: "js-group-avatar-input hidden"
+ .light The maximum file size allowed is 100KB.
+ - if @group.avatar?
+ %hr
+ = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
+
.form-actions
= f.submit 'Save group', class: "btn btn-save"
diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml
index 124560e478..38069feb37 100644
--- a/app/views/groups/members.html.haml
+++ b/app/views/groups/members.html.haml
@@ -6,15 +6,34 @@
%strong= link_to "here", help_permissions_path, class: "vlink"
%hr
-- can_manage_group = current_user.can? :manage_group, @group
-.ui-box
+
+.clearfix
+ = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
+ .form-group
+ = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' }
+ = submit_tag 'Search', class: 'btn'
+
+ - if current_user.can? :manage_group, @group
+ .pull-right
+ = link_to '#', class: 'btn btn-new js-toggle-visibility-link' do
+ Add members
+ %i.icon-chevron-down
+
+ .js-toggle-visibility-container.hide.new-group-member-holder
+ = render "new_group_member"
+
+.ui-box.prepend-top-20
.title
%strong #{@group.name}
group members
%small
- (#{@members.count})
+ (#{@members.total_count})
%ul.well-list
- @members.each do |member|
- = render 'users_groups/users_group', member: member, show_controls: can_manage_group
-- if can_manage_group
- = render "new_group_member"
+ = render 'users_groups/users_group', member: member, show_controls: true
+= paginate @members, theme: 'gitlab'
+
+:coffeescript
+ $('form.member-search-form').on 'submit', (event) ->
+ event.preventDefault()
+ Turbolinks.visit @.action + '?' + $(@).serialize()
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 5332d383c4..6256c04792 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -11,11 +11,15 @@
.content_list
- else
%p.nothing_here_message Project activity will be displayed here
- .loading.hide
+ = spinner
.side.col-md-4
- - if @group.description.present?
- .description-block
- = @group.description
+ .light-well.append-bottom-20
+ = image_tag group_icon(@group.path), class: "avatar s90"
+ .clearfix.light
+ %h3.page-title
+ = @group.name
+ - if @group.description.present?
+ %p= @group.description
= render "projects", projects: @projects
.prepend-top-20
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
diff --git a/app/views/help/_api_layout.html.haml b/app/views/help/_api_layout.html.haml
index c211b65841..af723f906d 100644
--- a/app/views/help/_api_layout.html.haml
+++ b/app/views/help/_api_layout.html.haml
@@ -5,7 +5,7 @@
%i.icon-angle-left
Back to help
%ul.nav.nav-pills.nav-stacked
- - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file|
+ - %w(README projects project_snippets repositories repository_files commits deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file|
%li{class: file == @category ? 'active' : nil}
= link_to file.titleize, help_api_file_path(file)
diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml
index a413616bad..201d63ca24 100644
--- a/app/views/help/_layout.html.haml
+++ b/app/views/help/_layout.html.haml
@@ -8,4 +8,5 @@
= link_to title, path
.col-md-9
- = yield
+ .wiki
+ = yield
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index f1cb723eba..c82acd917d 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -6,9 +6,15 @@
%p.slead
GitLab is open source software to collaborate on code.
%br
- Create projects and repositories, manage access and do code reviews.
+ Manage git repositories with fine grained access controls that keep your code secure.
%br
- Read more about GitLab at #{link_to "gitlab.org", "http://gitlab.org/", target: "_blank"}.
+ Perform code reviews and enhance collaboration with merge requests.
+ %br
+ Each project can also have an issue tracker and a wiki.
+ %br
+ Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.
+ %br
+ Read more about GitLab at #{link_to "www.gitlab.com", "https://www.gitlab.com/", target: "_blank"}.
.row
.col-md-4
diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml
index 6505609022..7fd0c74057 100644
--- a/app/views/help/permissions.html.haml
+++ b/app/views/help/permissions.html.haml
@@ -217,3 +217,4 @@
%td
%td
%td.permission-x ✓
+ %p.light Any user can remove himself from a group, unless he is the last Owner of the group.
diff --git a/app/views/help/public_access.html.haml b/app/views/help/public_access.html.haml
index ba2df8c355..e1b2a2ce1f 100644
--- a/app/views/help/public_access.html.haml
+++ b/app/views/help/public_access.html.haml
@@ -44,3 +44,18 @@
%li Go to your project dashboard
%li Click on the "Edit" tab
%li Change "Visibility Level"
+
+ %h4 Visibility of users
+ The public page of users, located at
+ = succeed "," do
+ %code u/username
+ is visible if either:
+ %ul
+ %li
+ You are logged in.
+ %li
+ %p
+ You are logged out, and the target user is authorized to (is Guest, Reporter, etc.)
+ at least one public project.
+ %p Otherwise, you will be redirected to the sign in page.
+ When visiting the public page of an user, you will only see listed projects which you can view yourself.
diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml
index 2b8950cd5c..2ac5cd3a65 100644
--- a/app/views/help/workflow.html.haml
+++ b/app/views/help/workflow.html.haml
@@ -1,6 +1,8 @@
= render layout: 'help/layout' do
%h3.page-title Workflow
+ %h4 Summary
+
%ol.help
%li
%p Clone project
@@ -35,3 +37,37 @@
%li
%p Your team lead will review code & merge it to main branch
+ %h3 Authorization for Merge Requests
+ %p
+ There are two main ways to have a merge request flow with GitLab: working with protected branches in a single repository, or working with forks of an authoritative project.
+
+ %h4 Protected branch flow
+ %p
+ With the protected branch flow everybody works within the same GitLab project.
+ The project maintainers get Master access and the regular developers get Developer access.
+ The maintainers mark the authoritative branches as 'Protected'.
+ The developers push feature branches to the project and create merge requests to have their feature branches reviewed and merged into one of the protected branches.
+ Only users with Master access can merge changes into a protected branch.
+
+ %h5 Advantages
+ %ul
+ %li fewer projects means less clutter
+ %li developers need to consider only one remote repository
+
+ %h5 Disadvantages
+ %ul
+ %li manual setup of protected branch required for each new project
+
+ %h4 Forking workflow
+ %p
+ With the forking workflow the maintainers get Master access and the regular developers get Reporter access to the authoritative repository, which prohibits them from pushing any changes to it.
+ Developers create forks of the authoritative project and push their feature branches to their own forks.
+ To get their changes into master they need to create a merge request across forks.
+
+ %h5 Advantages
+ %ul
+ %li in an appropriately configured GitLab group, new projects automatically get the required access restrictions for regular developers: fewer manual steps to configure authorization for new projects
+
+ %h5 Disadvantages
+ %ul
+ %li all developers on the project need to keep their forks up to date, which requires more advanced Git skills (managing multiple remotes)
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 32debb8c7a..5080a1b7ef 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -6,7 +6,7 @@
= link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do
%h1 GITLAB
%span.separator
- %h1.project_name= title
+ %h1.title= title
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
%span.sr-only Toggle navigation
@@ -18,7 +18,6 @@
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
- Loading...
%li.hidden-sm.hidden-xs
= render "layouts/search"
%li.visible-sm.visible-xs
diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml
index 7d188fb28e..99e11cd2b5 100644
--- a/app/views/layouts/_public_head_panel.html.haml
+++ b/app/views/layouts/_public_head_panel.html.haml
@@ -6,11 +6,7 @@
= link_to public_root_path, class: "home" do
%h1 GITLAB
%span.separator
- %h1.project_name
- - if @project
- = project_title(@project)
- - else
- Public Projects
+ %h1.title= title
.pull-right
= link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
@@ -20,4 +16,3 @@
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
- Loading...
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index 439cb978a7..53e0dbaef9 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "Admin area"
= render "layouts/flash"
%nav.main-nav.navbar-collapse.collapse
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index d44cb975ea..35d0d41750 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -4,6 +4,10 @@
%i.icon-home
= nav_link(controller: :accounts) do
= link_to "Account", profile_account_path
+ = nav_link(controller: :emails) do
+ = link_to profile_emails_path do
+ Emails
+ %span.count= current_user.emails.count + 1
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= link_to "Password", edit_profile_password_path
diff --git a/app/views/layouts/navless.html.haml b/app/views/layouts/navless.html.haml
index 7325664bc1..c43d688a2c 100644
--- a/app/views/layouts/navless.html.haml
+++ b/app/views/layouts/navless.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: @title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: @title
= render "layouts/flash"
diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml
index 8f490f61a9..3c76bbb957 100644
--- a/app/views/layouts/public.html.haml
+++ b/app/views/layouts/public.html.haml
@@ -2,10 +2,10 @@
%html{ lang: "en"}
= render "layouts/head", title: "Public Projects"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
- if current_user
= render "layouts/head_panel", title: "Public Projects"
- else
- = render "layouts/public_head_panel"
-
+ = render "layouts/public_head_panel", title: "Public Projects"
.container.navless-container
.content= yield
diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml
index a8e3236d86..5fcf9f99e7 100644
--- a/app/views/layouts/public_projects.html.haml
+++ b/app/views/layouts/public_projects.html.haml
@@ -2,8 +2,9 @@
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
- = render "layouts/public_head_panel"
- %nav.main-nav.navbar-collapse.collapse
+ = render "layouts/broadcast"
+ = render "layouts/public_head_panel", title: @project.name_with_namespace
+ %nav.main-nav
.container= render 'layouts/nav/project'
.container
.content= yield
diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml
new file mode 100644
index 0000000000..4aa258fea0
--- /dev/null
+++ b/app/views/layouts/public_users.html.haml
@@ -0,0 +1,8 @@
+!!! 5
+%html{ lang: "en"}
+ = render "layouts/head", title: @title
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
+ = render "layouts/public_head_panel", title: @title
+ .container.navless-container
+ .content= yield
diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml
index 177b3a4f8f..97ed8ba12d 100644
--- a/app/views/layouts/search.html.haml
+++ b/app/views/layouts/search.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: "Search"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "Search"
= render "layouts/flash"
diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml
index 191ad406c3..ce13853ed7 100644
--- a/app/views/layouts/user_team.html.haml
+++ b/app/views/layouts/user_team.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: "#{@team.name}"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "team: #{@team.name}"
= render "layouts/flash"
%nav.main-nav.navbar-collapse.collapse
diff --git a/app/views/notify/new_email_email.html.haml b/app/views/notify/new_email_email.html.haml
new file mode 100644
index 0000000000..4a0448a573
--- /dev/null
+++ b/app/views/notify/new_email_email.html.haml
@@ -0,0 +1,10 @@
+%p
+ Hi #{@user.name}!
+%p
+ A new email was added to your account:
+%p
+ email:
+ %code= @email.email
+%p
+ If this email was added in error, you can remove it here:
+ = link_to "Emails", profile_emails_url
diff --git a/app/views/notify/new_email_email.text.erb b/app/views/notify/new_email_email.text.erb
new file mode 100644
index 0000000000..51cba99ad0
--- /dev/null
+++ b/app/views/notify/new_email_email.text.erb
@@ -0,0 +1,7 @@
+Hi <%= @user.name %>!
+
+A new email was added to your account:
+
+email.................. <%= @email.email %>
+
+If this email was added in error, you can remove it here: <%= profile_emails_url %>
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index d0b30c0833..ab0d6c653b 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -21,3 +21,8 @@
%pre
= diff.diff
%br
+
+- if @compare.timeout
+ %h5 Huge diff. To prevent performance issues it was hidden
+- elsif @compare.commits_over_limit?
+ %h5 Diff for big amount of commits is disabled
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index 6718ca6835..93b344d2c8 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -18,3 +18,8 @@ Diff:
= diff.new_path || diff.old_path
\=====================================
= diff.diff
+\
+- if @compare.timeout
+ Huge diff. To prevent performance issues it was hidden
+- elsif @compare.commits_over_limit?
+ Diff for big amount of commits is disabled
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 3220736b07..c60e1ca929 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -50,7 +50,10 @@
%div
= f.text_field :username, required: true, class: 'form-control'
- %span.loading-gif.hide= image_tag "ajax_loader.gif"
+ .loading-gif.hide
+ %p
+ %i.icon-spinner.icon-spin
+ Saving new username
%p.light
= user_url(@user)
%div
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
new file mode 100644
index 0000000000..b5f1e438cc
--- /dev/null
+++ b/app/views/profiles/emails/index.html.haml
@@ -0,0 +1,33 @@
+%h3.page-title
+ My email addresses
+%p.light
+ Your
+ %b Primary Email
+ will be used for account notifications, avatar detection and web based operations, such as edits and merges.
+ %br
+ All email addresses will be used to identify your commits.
+
+%hr
+
+.ui-box
+ .title
+ Emails (#{@emails.count + 1})
+ %ul.well-list#emails-table
+ %li
+ %strong= @primary
+ %span.label.label-success Primary Email
+ - @emails.each do |email|
+ %li
+ %strong= email.email
+ %span.cgray
+ added #{time_ago_with_tooltip(email.created_at)}
+ = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right'
+
+%h4 Add email address
+= form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f|
+ .form-group
+ = f.label :email, class: 'control-label'
+ .col-sm-10
+ = f.text_field :email, class: 'form-control'
+ .form-actions
+ = f.submit 'Add', class: 'btn btn-create'
diff --git a/app/views/profiles/groups/index.html.haml b/app/views/profiles/groups/index.html.haml
index 1d24e636bf..eefebf98c5 100644
--- a/app/views/profiles/groups/index.html.haml
+++ b/app/views/profiles/groups/index.html.haml
@@ -22,9 +22,10 @@
%i.icon-cogs
Settings
- = link_to leave_profile_group_path(group), data: { confirm: "Are you sure you want to leave #{group.name} group?"}, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do
- %i.icon-signout
- Leave
+ - if can?(current_user, :destroy, user_group)
+ = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do
+ %i.icon-signout
+ Leave
= link_to group, class: 'group-name' do
%strong= group.name
diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml
index d123b8f940..218d51d31a 100644
--- a/app/views/profiles/notifications/_settings.html.haml
+++ b/app/views/profiles/notifications/_settings.html.haml
@@ -1,31 +1,17 @@
%li
- .row
- .col-sm-4
- %span
- = notification_icon(notification)
-
- - if membership.kind_of? UsersGroup
- = link_to membership.group.name, membership.group
- - else
- = link_to_project(membership.project)
- .col-sm-8
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
- = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
- = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Use global setting
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Disabled
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_PARTICIPATING, notification.participating?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Participating
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_WATCH, notification.watch?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Watch
+ %span.notification-icon-holder
+ - if notification.global?
+ = notification_icon(@notification)
+ - else
+ = notification_icon(notification)
+ %span.str-truncated
+ - if membership.kind_of? UsersGroup
+ = link_to membership.group.name, membership.group
+ - else
+ = link_to_project(membership.project)
+ .pull-right
+ = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
+ = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
+ = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
+ = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'trigger-submit'
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 878d7f7743..efe9c03219 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -3,56 +3,49 @@
%p.light
GitLab uses the email specified in your profile for notifications
%hr
-.alert.alert-info
- %p
- %i.icon-circle.cred
- %strong Disabled
- – You will not get any notifications via email
- %p
- %i.icon-circle.cblue
- %strong Participating
- – You will only receive notifications from related resources (e.g. from your commits or assigned issues)
- %p
- %i.icon-circle.cgreen
- %strong Watch
- – You will receive all notifications from projects in which you participate
+= form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications form-horizontal global-notifications-form' do
+ = hidden_field_tag :notification_type, 'global'
-.row
- .col-sm-4
- %h4
- = notification_icon(@notification)
- Global setting
- .col-sm-8
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
- = hidden_field_tag :notification_type, 'global'
-
- = label_tag nil, class: 'radio-inline' do
+ = label_tag :notification_level, 'Notification level', class: 'control-label'
+ .col-sm-10
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled?, class: 'trigger-submit'
- %span Disabled
+ .level-title
+ Disabled
+ %p You will not get any notifications via email
- = label_tag nil, class: 'radio-inline' do
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating?, class: 'trigger-submit'
- %span Participating
+ .level-title
+ Participating
+ %p You will only receive notifications from related resources (e.g. from your commits or assigned issues)
- = label_tag nil, class: 'radio-inline' do
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit'
- %span Watch
+ .level-title
+ Watch
+ %p You will receive all notifications from projects in which you participate
-%br
-= link_to '#', class: 'js-toggle-visibility-link' do
- %span.btn.btn-tiny
- %i.icon-chevron-down
- %span Advanced notifications settings
-.js-toggle-visibility-container.hide
+.clearfix
%hr
- %h4 Groups:
- %ul.bordered-list
- - @users_groups.each do |users_group|
- - notification = Notification.new(users_group)
- = render 'settings', type: 'group', membership: users_group, notification: notification
+ %p
+ You can also specify notification level per group or per project
+ %br
+ By default all projects and groups uses notification level set above
+.row.all-notifications
+ .col-md-6
+ %h4 Groups:
+ %ul.bordered-list
+ - @users_groups.each do |users_group|
+ - notification = Notification.new(users_group)
+ = render 'settings', type: 'group', membership: users_group, notification: notification
- %h4 Projects:
- %ul.bordered-list
- - @users_projects.each do |users_project|
- - notification = Notification.new(users_project)
- = render 'settings', type: 'project', membership: users_project, notification: notification
+ .col-md-6
+ %h4 Projects:
+ %ul.bordered-list
+ - @users_projects.each do |users_project|
+ - notification = Notification.new(users_project)
+ = render 'settings', type: 'project', membership: users_project, notification: notification
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index f333879cf6..b72232ee36 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -1,22 +1,22 @@
-= form_for @user, url: profile_password_path, method: :post do |f|
- .light-well.padded
- %p.slead
- Please set new password before proceed.
- %br
- After successful password update you will be redirected to login screen
- -if @user.errors.any?
- .alert.alert-danger
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
+%h3.page-title Setup new password
+%hr
+= form_for @user, url: profile_password_path, method: :post, html: { class: 'form-horizontal '} do |f|
+ %p.slead
+ Please set a new password before proceeding.
+ %br
+ After a successful password update you will be redirected to login screen.
+ -if @user.errors.any?
+ .alert.alert-danger
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
- .form-group
- = f.label :password
- .col-sm-10= f.password_field :password, required: true
- .form-group
- = f.label :password_confirmation
- .col-sm-10
- = f.password_field :password_confirmation, required: true
- .form-group
- .col-sm-10
- = f.submit 'Set new password', class: "btn btn-create"
+ .form-group
+ = f.label :password, class: 'control-label'
+ .col-sm-10= f.password_field :password, required: true, class: 'form-control'
+ .form-group
+ = f.label :password_confirmation, class: 'control-label'
+ .col-sm-10
+ = f.password_field :password_confirmation, required: true, class: 'form-control'
+ .form-actions
+ = f.submit 'Set new password', class: "btn btn-create"
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index e4cfabc310..4c7b088ae9 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -1,19 +1,21 @@
-%ul.nav.nav-pills.nav-stacked.nav-stacked-menu.append-bottom-20
+%ul.nav.nav-pills.nav-stacked.nav-stacked-menu.append-bottom-20.project-settings-nav
= nav_link(path: 'projects#edit') do
= link_to edit_project_path(@project), class: "stat-tab tab " do
- Edit Project
+ %i.icon-edit
+ Project
= nav_link(controller: [:team_members, :teams]) do
= link_to project_team_index_path(@project), class: "team-tab tab" do
+ %i.icon-group
Members
= nav_link(controller: :deploy_keys) do
= link_to project_deploy_keys_path(@project) do
- %span
+ %i.icon-key
Deploy Keys
= nav_link(controller: :hooks) do
= link_to project_hooks_path(@project) do
- %span
+ %i.icon-link
Web Hooks
= nav_link(controller: :services) do
= link_to project_services_path(@project) do
- %span
+ %i.icon-cogs
Services
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 32ea967105..e59d970bf4 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -15,6 +15,10 @@
- else
= link_to title, '#'
+%ul.blob-commit-info.bs-callout.bs-callout-info
+ - blob_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
+ = render blob_commit, project: @project
+
%div#tree-content-holder.tree-content-holder
.file-holder
.file-title
diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml
index d03b53888a..080a39ab94 100644
--- a/app/views/projects/blob/_text.html.haml
+++ b/app/views/projects/blob/_text.html.haml
@@ -8,7 +8,6 @@
- else
.file-content.code
- unless blob.empty?
- %div{class: user_color_scheme_class}
- = raw blob.colorize(formatter: :gitlab)
+ = render 'shared/file_hljs', blob: blob
- else
%p.nothing_here_message Empty file
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index 56220e520f..69167654c3 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -1,5 +1,6 @@
%div.tree-ref-holder
= render 'shared/ref_switcher', destination: 'blob', path: @path
+
%div#tree-holder.tree-holder
= render 'blob', blob: @blob
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 4fd708517f..902dfcea31 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,4 +1,4 @@
-- commit = Commit.new(Gitlab::Git::Commit.new(branch.commit))
+- commit = @repository.commit(branch.target)
%li
%h4
= link_to project_commits_path(@project, branch.name) do
@@ -11,18 +11,23 @@
.pull-right
- if can?(current_user, :download_code, @project)
= render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'grouped btn-group-small'
- = link_to project_compare_index_path(@project, from: branch.name, to: branch.name), class: 'btn grouped btn-small', title: "Compare" do
- %i.icon-copy
- Compare
+ - if branch.name != @repository.root_ref
+ = link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name), class: 'btn grouped btn-small', method: :post, title: "Compare" do
+ %i.icon-copy
+ Compare
- if can?(current_user, :admin_project, @project) && branch.name != @repository.root_ref
= link_to project_branch_path(@project, branch.name), class: 'btn grouped btn-small remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
%i.icon-trash
- %p
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
- %span.light
- = gfm escape_once(truncate(commit.title, length: 40))
- #{time_ago_with_tooltip(commit.committed_date)}
+ - if commit
+ %p
+ = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
+ = commit.short_id
+ = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
+ %span.light
+ = gfm escape_once(truncate(commit.title, length: 40))
+ #{time_ago_with_tooltip(commit.committed_date)}
+ - else
+ %p
+ Cant find HEAD commit for this branch
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index b9ab27d212..81e3374391 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-15
+%ul.nav.nav-tabs
%li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'}
= nav_link(controller: [:commit, :commits]) do
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 723c5a1c34..3a4f304a25 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -9,7 +9,7 @@
%div{id: dom_id(@project)}
#commits-list= render "commits"
.clear
-.loading{ style: "display:none;"}
+= spinner
- if @commits.count == @limit
:javascript
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 0762655fb9..da6157cf1b 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -14,7 +14,7 @@
= submit_tag "Compare", class: "btn btn-create commits-compare-btn"
- if compare_to_mr_button?
- = link_to compare_mr_path, class: 'prepend-left-10' do
+ = link_to compare_mr_path, class: 'prepend-left-10 btn' do
%strong Make a merge request
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index e9456c2496..9bd4985536 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -5,21 +5,32 @@
= render "form"
-- if @commits.size > 100
- .alert.alert-warning
- %p
- %strong Warning! This comparison includes more than 100 commits.
- %p To preserve performance the line diff is not shown.
-
- if @commits.present?
%div.ui-box
.title
Commits (#{@commits.count})
- %ul.well-list= render Commit.decorate(@commits), project: @project
+ - if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ %ul.well-list
+ - Commit.decorate(@commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE)).each do |commit|
+ = render "projects/commits/inline_commit", commit: commit, project: @project
+ %li.warning-row.unstyled
+ other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden to prevent performance issues.
+ - else
+ %ul.well-list= render Commit.decorate(@commits), project: @project
- - unless @diffs.empty?
- %h4 Diff
+ %h4 Diff
+ - if @diffs.present?
= render "projects/commits/diffs", diffs: @diffs, project: @project
+ - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ .bs-callout.bs-callout-danger
+ %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
+ %p To preserve performance the line diff is not shown.
+ - elsif @timeout
+ .bs-callout.bs-callout-danger
+ %h4 Diff for this comparison is extremely large.
+ %p Use command line to browse diff for this comparison.
+
+
- else
.light-well
%center
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 79234fe4fa..b9cd5a20d5 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -189,6 +189,7 @@
.save-project-loader.hide
%center
- = image_tag "ajax_loader.gif"
- %h3 Saving project.
+ %h2
+ %i.icon-spinner.icon-spin
+ Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 10dae3c8ff..433131640a 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -31,7 +31,7 @@
= link_to "Cancel", project_blob_path(@project, @id), class: "btn btn-cancel", data: { confirm: leave_edit_message}
:javascript
- ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
+ ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
if (ace_mode) {
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index eae4949fcd..489b9b0e95 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -3,8 +3,9 @@
- if @project.import? && !@project.imported
.save-project-loader
%center
- = image_tag "ajax_loader.gif"
- %h3 Importing repository.
+ %h2
+ %i.icon-spinner.icon-spin
+ Importing repository.
%p.monospace git clone --bare #{@project.import_url}
%p Please wait while we import the repository for you. Refresh at will.
:javascript
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index a21cb9e786..27348232ba 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,7 +1,8 @@
.loading-graph
%center
- .loading
- %h3.page-title Building repository graph.
+ %h3.page-title
+ %i.icon-spinner.icon-spin
+ Building repository graph.
%p Please wait a moment, this page will automatically refresh when ready.
.stat-graph
diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml
index c95e817859..f725db57ad 100644
--- a/app/views/projects/issues/_form.html.haml
+++ b/app/views/projects/issues/_form.html.haml
@@ -24,7 +24,7 @@
%i.icon-user
Assign to
.col-sm-10
- = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Select a user" }, {class: 'select2'})
+ = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id)
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.form-group
diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml
index 61213e752f..0b7697622b 100644
--- a/app/views/projects/issues/_head.html.haml
+++ b/app/views/projects/issues/_head.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-15
+%ul.nav.nav-tabs
= nav_link(controller: :issues) do
= link_to project_issues_path(@project), class: "tab" do
Browse Issues
@@ -17,10 +17,10 @@
%li.pull-right
.pull-right
- = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'inline issue-search-form' do
+ = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
.append-right-10.hidden-xs.hidden-sm
= search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
- if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
+ = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
New Issue
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 7ddf470b6a..aae101cf40 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -1,25 +1,22 @@
= form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
- Created by #{link_to_member(@project, issue.author)}
- - if issue.assignee
- \ and currently assigned to
+ %strong.append-right-10
+ Assignee:
- if can?(current_user, :modify_issue, @issue)
- = link_to profile_path(issue.assignee) do
- = image_tag(avatar_icon(issue.assignee.email), class: 'avatar avatar-inline s16 assignee') if issue.assignee
- = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Assign to user (none):" }, {class: 'select2'})
+ = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id)
- elsif issue.assignee
= link_to_member(@project, @issue.assignee)
+ - else
+ None
-
- .pull-right.hidden-sm
- - if issue.milestone
- - milestone = issue.milestone
- %cite.cgray Attached to milestone
-
+ .pull-right
+ %strong.append-right-10
+ Milestone:
- if can?(current_user, :modify_issue, @issue)
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
-
= hidden_field_tag :issue_context
= f.submit class: 'btn'
- elsif issue.milestone
= link_to issue.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 87d30a4a16..2d69af0b2d 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,87 +1,67 @@
-.ui-box
- .title
+.append-bottom-10
+ .check-all-holder
= check_box_tag "check_all_issues", nil, false, class: "check_all_issues left"
- .clearfix
- .issues_bulk_update.hide
- = form_tag bulk_update_project_issues_path(@project), method: :post do
- %span Update selected issues with
- = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
- = select_tag('update[assignee_id]', bulk_update_assignee_options, prompt: "Assignee")
- = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
- = hidden_field_tag 'update[issues_ids]', []
- = hidden_field_tag :status, params[:status]
- = button_tag "Save", class: "btn update_selected_issues btn-small btn-save"
- .issues-filters
- %span Filter by
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-tags
- %span.light labels:
- - if params[:label_name].present?
- %strong= params[:label_name]
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(label_name: nil) do
- Any
- - issue_label_names.each do |label_name|
- %li
- = link_to project_filter_path(label_name: label_name) do
- %span{class: "label #{label_css_class(label_name)}"}
- %i.icon-tag
- = label_name
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @project.team.members.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
+ .issues-filters
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(assignee_id: nil) do
+ Any
+ = link_to project_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-time
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-time
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(milestone_id: nil) do
+ Any
+ = link_to project_filter_path(milestone_id: 0) do
+ None (backlog)
+ - project_active_milestones.each do |milestone|
+ %li
+ = link_to project_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
- .pull-right
- = render 'shared/sort_dropdown'
+ .pull-right
+ = render 'shared/sort_dropdown'
+ .clearfix
+ .issues_bulk_update.hide
+ = form_tag bulk_update_project_issues_path(@project), method: :post do
+ = select_tag('update[status]', options_for_select(['Open', 'Closed']), prompt: "Status")
+ = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee')
+ = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
+ = hidden_field_tag 'update[issues_ids]', []
+ = hidden_field_tag :status, params[:status]
+ = button_tag "Update issues", class: "btn update_selected_issues btn-save"
+.ui-box
%ul.well-list.issues-list
= render @issues
- if @issues.blank?
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 71a89af61a..5e899d412c 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,6 +1,6 @@
= render "head"
.row
.col-md-3
- = render 'shared/project_filter', project_entities_path: project_issues_path(@project)
+ = render 'shared/project_filter', project_entities_path: project_issues_path(@project), labels: true
.col-md-9.issues-holder
= render "issues"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index cd4a158e42..7aa37eda96 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,14 +1,6 @@
%h3.page-title
Issue ##{@issue.iid}
- %small
- created #{time_ago_with_tooltip(@issue.created_at)}
-
- - if @issue.closed?
- %span.state-label.state-label-red Closed
- - else
- %span.state-label.state-label-green Open
-
%span.pull-right
- if can?(current_user, :write_issue, @project)
= link_to new_project_issue_path(@project), class: "btn grouped", title: "New Issue", id: "new_issue_link" do
@@ -16,9 +8,9 @@
New Issue
- if can?(current_user, :modify_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue"
+ = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped btn-reopen"
- else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
+ = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close Issue"
= link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
%i.icon-edit
@@ -38,25 +30,34 @@
= @issue.milestone.title
.issue-box
+ .state{ class: issue_alert_class(@issue) }
+ - if @issue.closed?
+ %span.state-label.state-label-red Closed
+ - else
+ %span.state-label.state-label-green Open
+
+ %span.creator
+ Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)}
+
%h4.title
= gfm escape_once(@issue.title)
- .context
- %cite.cgray
- = render partial: 'issue_context', locals: { issue: @issue }
-
- if @issue.description.present?
.description
.wiki
= preserve do
= markdown @issue.description
+ .context
+ %cite.cgray
+ = render partial: 'issue_context', locals: { issue: @issue }
+
- content_for :note_actions do
- if can?(current_user, :modify_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue"
+ = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped btn-reopen"
- else
- = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
+ = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close Issue"
.participants
%cite.cgray #{@issue.participants.count} participants
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
index 59524e0f22..5199e9fc61 100644
--- a/app/views/projects/issues/update.js.haml
+++ b/app/views/projects/issues/update.js.haml
@@ -3,10 +3,7 @@
:plain
$("##{dom_id(@issue)}").fadeOut();
- elsif params[:issue_context]
- $('.issue-box .context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
$('.issue-box .context').effect('highlight');
- $('.select2').select2();
- $('.edit-issue.inline-update input[type="submit"]').hide();
- if @issue.milestone
$('.milestone-nav-link').replaceWith("| Milestone #{escape_javascript(link_to @issue.milestone.title, project_milestone_path(@issue.project, @issue.milestone))}")
- else
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index 63ebaadaa8..9502ff95d8 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -6,27 +6,30 @@
%li= msg
.merge-request-branches
- .row
- .col-md-5
+ .form-group
+ = label_tag nil, class: 'control-label' do
+ From
+ .col-sm-10
.clearfix
.pull-left
= f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted? })
.pull-left
- = f.select(:source_branch, @merge_request.source_project.repository.branch_names, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
- .mr_source_commit.prepend-top-10
- .col-md-2
- .merge-request-angle
- %i.icon-long-arrow-right
- .col-md-5
+ = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
+ .mr_source_commit
+ %br
+ .form-group
+ = label_tag nil, class: 'control-label' do
+ To
+ .col-sm-10
.clearfix
.pull-left
- projects = @project.forked_from_project.nil? ? [@project] : [ @project,@project.forked_from_project]
= f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace'), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted? })
.pull-left
- = f.select(:target_branch, @target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
- .mr_target_commit.prepend-top-10
+ = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
+ .mr_target_commit
%hr
.merge-request-form-info
@@ -47,7 +50,7 @@
%i.icon-user
Assign to
.col-sm-10
- = f.select(:assignee_id, assignee_options(@merge_request), { include_blank: "Select a user" }, {class: 'select2'})
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.form-group
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ff763bca30..980ac12674 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -10,14 +10,14 @@
%span.pull-right
- if merge_request.for_fork?
%span.light
- = "#{merge_request.source_project_path}"
- = "#{merge_request.source_branch}"
+ #{merge_request.source_project_namespace}:
+ = merge_request.source_branch
%i.icon-angle-right.light
- = "#{merge_request.target_branch}"
+ = merge_request.target_branch
- else
- = "#{merge_request.source_branch}"
+ = merge_request.source_branch
%i.icon-angle-right.light
- = "#{merge_request.target_branch}"
+ = merge_request.target_branch
.merge-request-info
- if merge_request.author
authored by #{link_to_member(merge_request.source_project, merge_request.author)}
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 42641765c5..ec9249be00 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -12,7 +12,7 @@
= render "projects/merge_requests/show/commits"
- if @commits.present?
- %ul.nav.nav-tabs.append-bottom-10
+ %ul.nav.nav-tabs
%li.notes-tab{data: {action: 'notes'}}
= link_to project_merge_request_path(@project, @merge_request) do
%i.icon-comment
@@ -22,6 +22,12 @@
%i.icon-list-alt
Diff
+ - content_for :note_actions do
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ - unless @merge_request.closed?
+ = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request"
+
+
.notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
= render "projects/notes/notes_with_form"
.diffs.tab-content
diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml
index ec4d7f2121..d3147188d1 100644
--- a/app/views/projects/merge_requests/branch_from.js.haml
+++ b/app/views/projects/merge_requests/branch_from.js.haml
@@ -1,5 +1,5 @@
:plain
- $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project)}");
+ $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
var mrTitle = $('#merge_request_title');
if(mrTitle.val().length == 0) {
diff --git a/app/views/projects/merge_requests/branch_to.js.haml b/app/views/projects/merge_requests/branch_to.js.haml
index f4e2886ee4..f7ede0ded5 100644
--- a/app/views/projects/merge_requests/branch_to.js.haml
+++ b/app/views/projects/merge_requests/branch_to.js.haml
@@ -1,2 +1,2 @@
:plain
- $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project)}");
+ $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index a525a49015..d45bec3a23 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -10,59 +10,57 @@
.col-md-3
= render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project)
.col-md-9
+ .mr-filters.append-bottom-10
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(assignee_id: nil) do
+ Any
+ = link_to project_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
+
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-time
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(milestone_id: nil) do
+ Any
+ = link_to project_filter_path(milestone_id: 0) do
+ None (backlog)
+ - project_active_milestones.each do |milestone|
+ %li
+ = link_to project_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
+
+ .pull-right
+ = render 'shared/sort_dropdown'
+
.ui-box
- .title
- .mr-filters
- %span Filter by
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @project.team.members.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
-
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-time
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
-
- .pull-right
- = render 'shared/sort_dropdown'
-
%ul.well-list.mr-list
= render @merge_requests
- if @merge_requests.blank?
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
new file mode 100644
index 0000000000..2bd850426a
--- /dev/null
+++ b/app/views/projects/merge_requests/show/_context.html.haml
@@ -0,0 +1,22 @@
+= form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
+ %strong.append-right-10
+ Assignee:
+
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id)
+ - elsif merge_request.assignee
+ = link_to_member(@project, @merge_request.assignee)
+ - else
+ None
+
+ .pull-right
+ %strong.append-right-10
+ Milestone:
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
+ = hidden_field_tag :merge_request_context
+ = f.submit class: 'btn'
+ - elsif merge_request.milestone
+ = link_to merge_request.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml
index 2c7507cfb8..2917accdb5 100644
--- a/app/views/projects/merge_requests/show/_diffs.html.haml
+++ b/app/views/projects/merge_requests/show/_diffs.html.haml
@@ -3,8 +3,10 @@
- elsif @merge_request_diff.empty?
%h4.nothing_here_message Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
- %h4.nothing_here_message
- Can't load diff.
- You can
- = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request), format: :diff, class: "vlink"
- instead.
+ .bs-callout.bs-callout-warning
+ %h4
+ Diff for this comparison is extremely large.
+ %p
+ You can
+ = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink"
+ instead.
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index 352d843f49..a9cbe43fb1 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -55,15 +55,15 @@
.automerge_widget.unchecked
.bs-callout.bs-callout-warning
%strong
- %i.icon-refresh.icon-spin
+ %i.icon-spinner.icon-spin
Checking for ability to automatically merge…
.automerge_widget.already_cannot_be_merged.hide
.bs-callout.bs-callout-info
- %strong This merge request already can not be merged. Try to reload page.
+ %strong This merge request can not be merged. Try to reload the page.
.merge-in-progress.hide
.bs-callout.bs-callout-success
- %i.icon-refresh.icon-spin
+ %i.icon-spinner.icon-spin
Merge is in progress. Please wait. Page will be automatically reloaded.
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index b4f648ab19..803e00292b 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,41 +1,46 @@
.issue-box
+ .state{ class: merge_request_alert_class(@merge_request) }
+ - if @merge_request.merged?
+ %span.state-label.state-label-blue
+ Merged
+ - elsif @merge_request.closed?
+ %span.state-label.state-label-red
+ Closed
+ - else
+ %span.state-label.state-label-green
+ Open
+ %span.creator
+ Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
+
%h4.title
= gfm escape_once(@merge_request.title)
- .context
- %cite.cgray
- Created by #{link_to_member(@project, @merge_request.author)}.
- - if @merge_request.assignee
- Currently assigned to #{link_to_member(@project, @merge_request.assignee)}.
- - if @merge_request.milestone
- .pull-right
- - milestone = @merge_request.milestone
- %cite.cgray Attached to milestone
- %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
-
-
- if @merge_request.description.present?
.description
.wiki
= preserve do
= markdown @merge_request.description
- - if @merge_request.closed?
- .description.alert-danger
- %span
- %i.icon-remove
- Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
- #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}.
- - if @merge_request.merged?
- .description.alert-success
- %span
- %i.icon-ok
- Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
- #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}.
- - if !@closes_issues.empty? && @merge_request.opened?
- .description.alert-info
- %span
- %i.icon-ok
- Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
- = succeed '.' do
- != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
+ .context
+ %cite.cgray
+ = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
+
+- if @merge_request.closed?
+ .alert.alert-info
+ %span
+ %i.icon-remove
+ Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
+ #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}.
+- if @merge_request.merged?
+ .alert.alert-info
+ %span
+ %i.icon-ok
+ Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
+ #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}.
+- if !@closes_issues.empty? && @merge_request.opened?
+ .alert.alert-info.alert-info
+ %span
+ %i.icon-ok
+ Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
+ = succeed '.' do
+ != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml
index 2e923ec5f3..915d24dd02 100644
--- a/app/views/projects/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml
@@ -25,7 +25,7 @@
.ci_widget
.alert.alert-warning
%strong
- %i.icon-refresh
+ %i.icon-spinner
Checking for CI status for #{@merge_request.last_commit_short_sha}
.ci_widget.ci-error{style: "display:none"}
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 08a3fdf869..b27522e46a 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,20 +1,5 @@
%h3.page-title
= "Merge Request ##{@merge_request.iid}"
- %small
- created #{time_ago_with_tooltip(@merge_request.created_at)}
-
- - if @merge_request.merged?
- %span.state-label.state-label-green
- %i.icon-ok
- Merged
- - elsif @merge_request.closed?
- %span.state-label.state-label-red
- Closed
- - else
- %span.state-label.state-label-green
- Open
-
-
%span.pull-right
- if can?(current_user, :modify_merge_request, @merge_request)
@@ -34,7 +19,7 @@
%i.icon-edit
Edit
-.votes-holder
+.votes-holder.hidden-sm.hidden-xs
#votes= render 'votes/votes_block', votable: @merge_request
.back-link
diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml
new file mode 100644
index 0000000000..6452cc6382
--- /dev/null
+++ b/app/views/projects/merge_requests/update.js.haml
@@ -0,0 +1,2 @@
+- if params[:merge_request_context]
+ $('.issue-box .context').effect('highlight');
diff --git a/app/views/projects/milestones/_issues.html.haml b/app/views/projects/milestones/_issues.html.haml
index 21939ad013..c277dcc536 100644
--- a/app/views/projects/milestones/_issues.html.haml
+++ b/app/views/projects/milestones/_issues.html.haml
@@ -4,7 +4,7 @@
- issues.each do |issue|
%li
= link_to [@project, issue] do
- %span.badge{class: issue.closed? ? 'badge-important' : 'badge-info'} ##{issue.iid}
+ %span.label{class: issue.closed? ? 'label-danger' : 'label-info'} ##{issue.iid}
= link_to_gfm truncate(issue.title, length: 40), [@project, issue]
- if issue.assignee
.pull-right
diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml
index 8e30a42a60..faa35a25f2 100644
--- a/app/views/projects/milestones/_merge_request.html.haml
+++ b/app/views/projects/milestones/_merge_request.html.haml
@@ -1,5 +1,5 @@
%li
= link_to [@project, merge_request] do
- %span.badge.badge-info ##{merge_request.iid}
+ %span.label.label-info ##{merge_request.iid}
–
= link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request]
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index e7c3785c05..31eb5765fa 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -42,14 +42,13 @@
.progress.progress-info
.progress-bar{style: "width: #{@milestone.percent_complete}%;"}
-
- if @milestone.description.present?
.description
- = preserve do
- = markdown @milestone.description
+ .wiki
+ = preserve do
+ = markdown @milestone.description
-
-%ul.nav.nav-tabs.append-bottom-10
+%ul.nav.nav-tabs
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab' do
Issues
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 492f77341f..da0cfa84c2 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -3,7 +3,7 @@
.tip
You can move around the graph by using the arrow keys.
.network-graph
- .loading.loading-gray
+ = spinner
:javascript
new Network({
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index f21cef6f2e..9ee54fef06 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -62,6 +62,7 @@
.save-project-loader.hide
%center
- = image_tag "ajax_loader.gif"
- %h3 Creating project & repository.
+ %h2
+ %i.icon-spinner.icon-spin
+ Creating project & repository.
%p Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index fd2a3f4367..217e36e38d 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -31,7 +31,7 @@
.note-body
.note-text
= preserve do
- = markdown(note.note)
+ = markdown(note.note, {no_header_anchors: true})
.note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index e0d058de79..a32679a18d 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -3,7 +3,7 @@
.col-md-3
= render "projects/branches/filter"
.col-md-9
- .alert.alert-info
+ .bs-callout.bs-callout-info
%p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}.
%p This ability allows:
%ul
@@ -12,18 +12,18 @@
%p Read more about project permissions #{link_to "here", help_permissions_path, class: "underlined_link"}
- if can? current_user, :admin_project, @project
- = form_for [@project, @protected_branch] do |f|
+ = form_for [@project, @protected_branch], html: { class: 'form-horizontal' } do |f|
-if @protected_branch.errors.any?
.alert.alert-danger
%ul
- @protected_branch.errors.full_messages.each do |msg|
%li= msg
- .entry.clearfix
- = f.label :name, "Branch"
- .col-md-3
- = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2 span3"})
-
+ .form-group
+ = f.label :name, "Branch", class: 'control-label'
+ .col-sm-10
+ = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2"})
+ .form-actions
= f.submit 'Protect', class: "btn-create btn"
- unless @branches.empty?
%h5 Already Protected:
diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml
index b03feded0a..88c1cfa28e 100644
--- a/app/views/projects/repositories/_download_archive.html.haml
+++ b/app/views/projects/repositories/_download_archive.html.haml
@@ -3,7 +3,7 @@
- split_button = split_button || false
- if split_button == true
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span Download zip
%a.btn.dropdown-toggle{ 'data-toggle' => 'dropdown' }
@@ -12,26 +12,26 @@
Select Archive Format
%ul.dropdown-menu{ role: 'menu' }
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), rel: 'nofollow' do
%i.icon-download-alt
%span Download zip
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar.gz
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar.bz2
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar
- else
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span zip
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span tar.gz
\ No newline at end of file
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 59075abf98..8a1e1d3354 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -5,7 +5,7 @@
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
.content_list
- .loading.hide
+ = spinner
.col-md-3.project-side.hidden-sm
.clearfix
- if @project.archived?
@@ -51,7 +51,7 @@
%p
%span.light Owned by
- if @project.group
- #{link_to @project.group.name, @project.group} Group
+ #{link_to @project.group.name, @project.group} group
- else
#{link_to @project.owner_name, @project.owner}
diff --git a/app/views/projects/snippets/_blob.html.haml b/app/views/projects/snippets/_blob.html.haml
index f14a2bd4ec..af326a1a99 100644
--- a/app/views/projects/snippets/_blob.html.haml
+++ b/app/views/projects/snippets/_blob.html.haml
@@ -6,10 +6,5 @@
.btn-group.tree-btn-group.pull-right
- if can?(current_user, :admin_project_snippet, @project) || @snippet.author == current_user
= link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-tiny", title: 'Edit Snippet'
- = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", 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
+ = link_to "Raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank"
+ = render 'snippets/blob_content'
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
new file mode 100644
index 0000000000..70dedcf915
--- /dev/null
+++ b/app/views/projects/tags/_tag.html.haml
@@ -0,0 +1,22 @@
+- commit = @repository.commit(tag.target)
+%li
+ %h4
+ = link_to project_commits_path(@project, tag.name), class: "" do
+ %i.icon-tag
+ = tag.name
+ .pull-right
+ %small.cdark
+ %i.icon-calendar
+ #{time_ago_with_tooltip(commit.committed_date)}
+ %p.prepend-left-20
+ = link_to commit.short_id(8), project_commit_path(@project, commit), class: "monospace"
+ –
+ = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "cdark"
+
+ %span.pull-right
+ - if can? current_user, :download_code, @project
+ = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'grouped btn-group-small'
+ - if can?(current_user, :admin_project, @project)
+ = link_to project_tag_path(@project, tag.name), class: 'btn btn-small remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
+ %i.icon-trash
+
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index c88e42a107..2d53a5dd66 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -13,29 +13,7 @@
- unless @tags.empty?
%ul.bordered-list
- @tags.each do |tag|
- - commit = Commit.new(Gitlab::Git::Commit.new(tag.commit))
- %li
- %h4
- = link_to project_commits_path(@project, tag.name), class: "" do
- %i.icon-tag
- = tag.name
- %small
- = truncate(tag.message || '', length: 70)
- .pull-right
- %small.cdark
- %i.icon-calendar
- #{time_ago_with_tooltip(commit.committed_date)}
- %p.prepend-left-20
- = link_to commit.short_id(8), project_commit_path(@project, commit), class: "monospace"
- –
- = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "cdark"
-
- %span.pull-right
- - if can? current_user, :download_code, @project
- = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'grouped btn-group-small'
- - if can?(current_user, :admin_project, @project)
- = link_to project_tag_path(@project, tag.name), class: 'btn btn-small remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
- %i.icon-trash
+ = render 'tag', tag: tag
= paginate @tags, theme: 'gitlab'
diff --git a/app/views/projects/team_members/_group_members.html.haml b/app/views/projects/team_members/_group_members.html.haml
index 68f0800685..eceec6627b 100644
--- a/app/views/projects/team_members/_group_members.html.haml
+++ b/app/views/projects/team_members/_group_members.html.haml
@@ -1,10 +1,14 @@
+- group_users_count = @group.users_groups.count
.ui-box
.title
%strong #{@group.name}
- group members (#{@group.users_groups.count})
+ group members (#{group_users_count})
.pull-right
= link_to members_group_path(@group), class: 'btn btn-small' do
%i.icon-edit
%ul.well-list
- - @group.users_groups.order('group_access DESC').each do |member|
+ - @group.users_groups.order('group_access DESC').limit(20).each do |member|
= render 'users_groups/users_group', member: member, show_controls: false
+ - if group_users_count > 20
+ %li
+ and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)}
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 92dfd7537c..6fee604b55 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -4,7 +4,5 @@
%span.str-truncated
= link_to blob_item.name, project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray
- %span.log_loading.hide
- Loading commit data...
- = image_tag "ajax_loader_tree.gif", width: 14
+ = render 'spinner'
%td.tree_commit{ colspan: 2 }
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index ab572f2e97..16a9602ac9 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,5 +1,5 @@
.readme-holder#README
- %h4
+ %h4.readme-file-title
%i.icon-file
= readme.name
.wiki
diff --git a/app/views/projects/tree/_spinner.html.haml b/app/views/projects/tree/_spinner.html.haml
new file mode 100644
index 0000000000..5a9e77b63d
--- /dev/null
+++ b/app/views/projects/tree/_spinner.html.haml
@@ -0,0 +1,3 @@
+%span.log_loading.hide
+ %i.icon-spinner.icon-spin
+ Loading commit data...
diff --git a/app/views/projects/tree/_submodule_item.html.haml b/app/views/projects/tree/_submodule_item.html.haml
index badc7d992b..ae87dbde67 100644
--- a/app/views/projects/tree/_submodule_item.html.haml
+++ b/app/views/projects/tree/_submodule_item.html.haml
@@ -1,10 +1,15 @@
+- tree, commit = submodule_links(submodule_item)
%tr{ class: "tree-item" }
%td.tree-item-file-name
= image_tag "submodule.png"
%span
- = link_to truncate(submodule_item.name, length: 40), submodule_item.submodule_url
+ = link_to truncate(submodule_item.name, length: 40), tree
@
- %span.monospace #{submodule_item.id[0..10]}
+ %span.monospace
+ - if commit.nil?
+ #{submodule_item.id[0..10]}
+ - else
+ = link_to "#{submodule_item.id[0..10]}", commit
%td
%td
%td
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index b4dd6f48b6..1b3900bcba 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -4,7 +4,5 @@
%span.str-truncated
= link_to tree_item.name, project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name))
%td.tree_time_ago.cgray
- %span.log_loading.hide
- Loading commit data...
- = image_tag "ajax_loader_tree.gif", width: 14
+ = render 'spinner'
%td.tree_commit{ colspan: 2 }
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 5e5aa5170d..0a7e51e974 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-20
+%ul.nav.nav-tabs
= nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do
= link_to 'Home', project_wiki_path(@project, :home)
diff --git a/app/views/search/_project_results.html.haml b/app/views/search/_project_results.html.haml
index ea324b3a9a..f285bda573 100644
--- a/app/views/search/_project_results.html.haml
+++ b/app/views/search/_project_results.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-10
+%ul.nav.nav-tabs
%li{class: ("active" if params[:search_code].present?)}
= link_to search_path(params.merge(search_code: true)) do
Repository Code
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index a2e4a00b71..f9d217e840 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -6,5 +6,4 @@
%strong
= blob.filename
.file-content.code.term
- %div{class: user_color_scheme_class}
- = raw blob.colorize( formatter: :gitlab, options: { first_line_number: blob.startline } )
+ = render 'shared/file_hljs', blob: blob, first_line_number: blob.startline
diff --git a/app/views/shared/_file_hljs.html.haml b/app/views/shared/_file_hljs.html.haml
new file mode 100644
index 0000000000..338236c075
--- /dev/null
+++ b/app/views/shared/_file_hljs.html.haml
@@ -0,0 +1,12 @@
+%div.highlighted-data{class: user_color_scheme_class}
+ .line-numbers
+ - blob.data.lines.to_a.size.times do |index|
+ - offset = defined?(first_line_number) ? first_line_number : 1
+ - i = index + offset
+ = link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do
+ %i.icon-link
+ = i
+ .highlight
+ %pre
+ %code
+ = blob.data
diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml
index 9b89c5c800..1315c76fbb 100644
--- a/app/views/shared/_project_filter.html.haml
+++ b/app/views/shared/_project_filter.html.haml
@@ -26,6 +26,20 @@
= link_to project_filter_path(state: 'all') do
All
+ - if defined?(labels)
+ %fieldset
+ %legend Labels
+ %ul.nav.nav-pills.nav-stacked.nav-small.labels-filter
+ - issue_label_names.each do |label_name|
+ %li{class: label_filter_class(label_name)}
+ = link_to labels_filter_path(label_name) do
+ %span{class: "label #{label_css_class(label_name)}"}
+ %i.icon-tag
+ = label_name
+ - if selected_label?(label_name)
+ .pull-right
+ %i.icon-remove
+
%fieldset
- if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
= link_to project_entities_path, class: 'cgray pull-right' do
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index 2e87566996..7b37b39780 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -1,5 +1,5 @@
.dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort:
- if @sort.present?
= @sort
diff --git a/app/views/snippets/_blob.html.haml b/app/views/snippets/_blob.html.haml
index e6ae33f38f..15867f071e 100644
--- a/app/views/snippets/_blob.html.haml
+++ b/app/views/snippets/_blob.html.haml
@@ -8,18 +8,4 @@
= link_to "Edit", edit_snippet_path(@snippet), class: "btn btn-tiny", title: 'Edit Snippet'
= link_to "Delete", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-tiny", title: 'Delete Snippet'
= link_to "Raw", raw_snippet_path(@snippet), class: "btn btn-tiny", target: "_blank"
- - unless @snippet.content.empty?
- - if gitlab_markdown?(@snippet.file_name)
- .file-content.wiki
- = preserve do
- = markdown(@snippet.data)
- - elsif markup?(@snippet.file_name)
- .file-content.wiki
- = render_markup(@snippet.file_name, @snippet.data)
- - else
- .file-content.code
- %div{class: user_color_scheme_class}
- = raw @snippet.colorize(formatter: :gitlab)
- - else
- .file-content.code
- %p.nothing_here_message Empty file
+ = render 'snippets/blob_content'
diff --git a/app/views/snippets/_blob_content.html.haml b/app/views/snippets/_blob_content.html.haml
new file mode 100644
index 0000000000..81055451b6
--- /dev/null
+++ b/app/views/snippets/_blob_content.html.haml
@@ -0,0 +1,14 @@
+- unless @snippet.content.empty?
+ - if gitlab_markdown?(@snippet.file_name)
+ .file-content.wiki
+ = preserve do
+ = markdown(@snippet.data)
+ - elsif markup?(@snippet.file_name)
+ .file-content.wiki
+ = render_markup(@snippet.file_name, @snippet.data)
+ - else
+ .file-content.code
+ = render 'shared/file_hljs', blob: @snippet
+- else
+ .file-content.code
+ %p.nothing_here_message Empty file
diff --git a/app/views/users/_groups.html.haml b/app/views/users/_groups.html.haml
new file mode 100644
index 0000000000..412df943fc
--- /dev/null
+++ b/app/views/users/_groups.html.haml
@@ -0,0 +1,3 @@
+- groups.each do |group|
+ = link_to group, class: 'profile-groups-avatars', :title => group.name do
+ = image_tag group_icon(group.path)
\ No newline at end of file
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 65f46500a8..98210af1e3 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -13,6 +13,8 @@
%br
%small member since #{@user.created_at.stamp("Nov 12, 2031")}
.clearfix
+ %h4 Groups:
+ = render 'groups', groups: @user.groups
%hr
%h4 User Activity:
= render @events
diff --git a/app/views/users_groups/_users_group.html.haml b/app/views/users_groups/_users_group.html.haml
index 5f477f3c97..b66b486fbc 100644
--- a/app/views/users_groups/_users_group.html.haml
+++ b/app/views/users_groups/_users_group.html.haml
@@ -9,12 +9,17 @@
%span.pull-right
%strong= member.human_access
-
- - if show_controls && can?(current_user, :manage_group, @group) && current_user != user
- = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
- %i.icon-edit
- = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
- %i.icon-minus.icon-white
+ - if show_controls
+ - if can?(current_user, :modify, member)
+ = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
+ %i.icon-edit
+ - if can?(current_user, :destroy, member)
+ - if current_user == member.user
+ = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ %i.icon-minus.icon-white
+ - else
+ = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ %i.icon-minus.icon-white
.edit-member.hide.js-toggle-content
= form_for [@group, member], remote: true do |f|
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 9982b362a1..5e81810cbd 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -13,13 +13,13 @@ class EmailsOnPushWorker
return true
end
- compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
+ compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha, MergeRequestDiff::COMMITS_SAFE_SIZE)
# Do not send emails if git compare failed
return false unless compare && compare.commits.present?
recipients.split(" ").each do |recipient|
- Notify.delay.repository_push_email(project_id, recipient, author_id, branch, compare)
+ Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver
end
end
end
diff --git a/bin/bundle b/bin/bundle
new file mode 100644
index 0000000000..66e9889e8b
--- /dev/null
+++ b/bin/bundle
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+load Gem.bin_path('bundler', 'bundle')
diff --git a/bin/rails b/bin/rails
new file mode 100644
index 0000000000..7feb6a30e6
--- /dev/null
+++ b/bin/rails
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+end
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+require_relative '../config/boot'
+require 'rails/commands'
diff --git a/bin/rake b/bin/rake
new file mode 100644
index 0000000000..8017a0271d
--- /dev/null
+++ b/bin/rake
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+end
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/bin/rspec b/bin/rspec
new file mode 100644
index 0000000000..41e37089ac
--- /dev/null
+++ b/bin/rspec
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+end
+require 'bundler/setup'
+load Gem.bin_path('rspec', 'rspec')
diff --git a/bin/spinach b/bin/spinach
new file mode 100644
index 0000000000..a080e286cf
--- /dev/null
+++ b/bin/spinach
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path("../spring", __FILE__)
+rescue LoadError
+end
+require 'bundler/setup'
+load Gem.bin_path('spinach', 'spinach')
diff --git a/bin/spring b/bin/spring
new file mode 100644
index 0000000000..253ec37c34
--- /dev/null
+++ b/bin/spring
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+# This file loads spring without using Bundler, in order to be fast
+# It gets overwritten when you run the `spring binstub` command
+
+unless defined?(Spring)
+ require "rubygems"
+ require "bundler"
+
+ if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m)
+ ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
+ ENV["GEM_HOME"] = ""
+ Gem.paths = ENV
+
+ gem "spring", match[1]
+ require "spring/binstub"
+ end
+end
diff --git a/config/application.rb b/config/application.rb
index 88759ce7cf..c53257090c 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -62,7 +62,9 @@ module Gitlab
# Enable the asset pipeline
config.assets.enabled = true
-
+ config.assets.paths << Emoji.images_path
+ config.assets.precompile << "emoji/*.png"
+
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index be9ca8dc8c..ce57465d68 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -14,7 +14,7 @@ production: &base
## GitLab settings
gitlab:
- ## Web server settings
+ ## Web server settings (note: host is the FQDN, do not include http://)
host: localhost
port: 80
https: false
@@ -124,7 +124,7 @@ production: &base
base: '_the_base_where_you_search_for_users'
port: 636
uid: 'sAMAccountName'
- method: 'ssl' # "ssl" or "plain"
+ method: 'ssl' # "tls" or "ssl" or "plain"
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user'
# If allow_username_or_email_login is enabled, GitLab will ignore everything
diff --git a/config/initializers/3_grit_ext.rb b/config/initializers/3_grit_ext.rb
index 8b298e821e..6540ac839c 100644
--- a/config/initializers/3_grit_ext.rb
+++ b/config/initializers/3_grit_ext.rb
@@ -1,5 +1,4 @@
require 'grit'
-require 'pygments'
Grit::Git.git_binary = Gitlab.config.git.bin_path
Grit::Git.git_timeout = Gitlab.config.git.timeout
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 25390978cf..a02bf9d4ae 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -77,11 +77,11 @@ Devise.setup do |config|
# ==> Configuration for :confirmable
# The time you want to give a user to confirm their account. During this time
# they will be able to access your application without confirming. Default is 0.days
- # When confirm_within is zero, the user won't be able to sign in without confirming.
+ # When allow_unconfirmed_access_for is zero, the user won't be able to sign in without confirming.
# You can use this to let your user access some features of your application
# without confirming the account, but blocking it after a certain period
# (ie 2 days).
- # config.confirm_within = 2.days
+ # config.allow_unconfirmed_access_for = 2.days
# Defines which key will be used when confirming an account
# config.confirmation_keys = [ :email ]
@@ -227,15 +227,21 @@ Devise.setup do |config|
end
Gitlab.config.omniauth.providers.each do |provider|
+ provider_arguments = []
+
+ %w[app_id app_secret].each do |argument|
+ provider_arguments << provider[argument] if provider[argument]
+ end
+
case provider['args']
when Array
# An Array from the configuration will be expanded.
- config.omniauth provider['name'].to_sym, provider['app_id'], provider['app_secret'], *provider['args']
+ provider_arguments.concat provider['args']
when Hash
# A Hash from the configuration will be passed as is.
- config.omniauth provider['name'].to_sym, provider['app_id'], provider['app_secret'], provider['args']
- else
- config.omniauth provider['name'].to_sym, provider['app_id'], provider['app_secret']
+ provider_arguments << provider['args']
end
+
+ config.omniauth provider['name'].to_sym, *provider_arguments
end
end
diff --git a/config/routes.rb b/config/routes.rb
index 611e497c9e..fdca1e6266 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -12,6 +12,9 @@ Gitlab::Application.routes.draw do
API::API.logger Rails.logger
mount API::API => '/api'
+ # Get all keys of user
+ get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ }
+
constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? }
constraints constraint do
mount Sidekiq::Web, at: "/admin/sidekiq", as: :sidekiq
@@ -121,6 +124,7 @@ Gitlab::Application.routes.draw do
end
end
resources :keys
+ resources :emails, only: [:index, :create, :destroy]
resources :groups, only: [:index] do
member do
delete :leave
@@ -156,6 +160,9 @@ Gitlab::Application.routes.draw do
end
resources :users_groups, only: [:create, :update, :destroy]
+ scope module: :groups do
+ resource :avatar, only: [:destroy]
+ end
end
resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
diff --git a/db/migrate/20110913200833_devise_create_users.rb b/db/migrate/20110913200833_devise_create_users.rb
deleted file mode 100644
index e00f275c55..0000000000
--- a/db/migrate/20110913200833_devise_create_users.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-class DeviseCreateUsers < ActiveRecord::Migration
- def self.up
- create_table(:users) do |t|
- ## Database authenticatable
- t.string :email, :null => false, :default => ""
- t.string :encrypted_password, :null => false, :default => ""
-
- ## Recoverable
- t.string :reset_password_token
- t.datetime :reset_password_sent_at
-
- ## Rememberable
- t.datetime :remember_created_at
-
- ## Trackable
- t.integer :sign_in_count, :default => 0
- t.datetime :current_sign_in_at
- t.datetime :last_sign_in_at
- t.string :current_sign_in_ip
- t.string :last_sign_in_ip
-
- ## Encryptable
- # t.string :password_salt
-
- ## Confirmable
- # t.string :confirmation_token
- # t.datetime :confirmed_at
- # t.datetime :confirmation_sent_at
- # t.string :unconfirmed_email # Only if using reconfirmable
-
- ## Lockable
- # t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
- # t.string :unlock_token # Only if unlock strategy is :email or :both
- # t.datetime :locked_at
-
- # Token authenticatable
- # t.string :authentication_token
-
- ## Invitable
- # t.string :invitation_token
-
- t.timestamps
- end
-
- add_index :users, :email, :unique => true
- add_index :users, :reset_password_token, :unique => true
- # add_index :users, :confirmation_token, :unique => true
- # add_index :users, :unlock_token, :unique => true
- # add_index :users, :authentication_token, :unique => true
- end
-
- def self.down
- drop_table :users
- end
-end
diff --git a/db/migrate/20110913204141_create_projects.rb b/db/migrate/20110913204141_create_projects.rb
deleted file mode 100644
index 45b76f9556..0000000000
--- a/db/migrate/20110913204141_create_projects.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreateProjects < ActiveRecord::Migration
- def change
- create_table :projects do |t|
- t.string :name
- t.string :path
- t.text :description
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20110914221600_create_users_projects.rb b/db/migrate/20110914221600_create_users_projects.rb
deleted file mode 100644
index a89798ae86..0000000000
--- a/db/migrate/20110914221600_create_users_projects.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class CreateUsersProjects < ActiveRecord::Migration
- def change
- create_table :users_projects do |t|
- t.integer :user_id, :null => false
- t.integer :project_id, :null => false
- t.boolean :read, :default => false
- t.boolean :write, :default => false
- t.boolean :admin, :default => false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20110915205627_add_private_flag_to_project.rb b/db/migrate/20110915205627_add_private_flag_to_project.rb
deleted file mode 100644
index 73c0b9df83..0000000000
--- a/db/migrate/20110915205627_add_private_flag_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddPrivateFlagToProject < ActiveRecord::Migration
- def change
- add_column :projects, :private_flag, :boolean, :default => true, :null => false
- end
-end
diff --git a/db/migrate/20110915213352_create_keys.rb b/db/migrate/20110915213352_create_keys.rb
deleted file mode 100644
index d4615b4bab..0000000000
--- a/db/migrate/20110915213352_create_keys.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class CreateKeys < ActiveRecord::Migration
- def change
- create_table :keys do |t|
- t.integer :user_id, :null => false
- t.text :project_id, :null => false
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20110916123731_add_name_to_user.rb b/db/migrate/20110916123731_add_name_to_user.rb
deleted file mode 100644
index 74142b05cb..0000000000
--- a/db/migrate/20110916123731_add_name_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddNameToUser < ActiveRecord::Migration
- def change
- add_column :users, :name, :string
- end
-end
diff --git a/db/migrate/20110916162511_add_key_title_to_key.rb b/db/migrate/20110916162511_add_key_title_to_key.rb
deleted file mode 100644
index b2eaa51ccc..0000000000
--- a/db/migrate/20110916162511_add_key_title_to_key.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddKeyTitleToKey < ActiveRecord::Migration
- def change
- add_column :keys, :key, :text
- add_column :keys, :title, :string
- remove_column :keys, :project_id
- end
-end
diff --git a/db/migrate/20110917212932_add_identifier_to_key.rb b/db/migrate/20110917212932_add_identifier_to_key.rb
deleted file mode 100644
index e572793952..0000000000
--- a/db/migrate/20110917212932_add_identifier_to_key.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddIdentifierToKey < ActiveRecord::Migration
- def change
- add_column :keys, :identifier, :string
- end
-end
diff --git a/db/migrate/20110921192501_create_issues.rb b/db/migrate/20110921192501_create_issues.rb
deleted file mode 100644
index 63b42ad998..0000000000
--- a/db/migrate/20110921192501_create_issues.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class CreateIssues < ActiveRecord::Migration
- def change
- create_table :issues do |t|
- t.string :title
- t.text :content
- t.integer :assignee_id
- t.integer :author_id
- t.integer :project_id
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20110922110156_add_code_to_project.rb b/db/migrate/20110922110156_add_code_to_project.rb
deleted file mode 100644
index f54a02bd70..0000000000
--- a/db/migrate/20110922110156_add_code_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddCodeToProject < ActiveRecord::Migration
- def change
- add_column :projects, :code, :string
- end
-end
diff --git a/db/migrate/20110923211333_add_status_to_issue.rb b/db/migrate/20110923211333_add_status_to_issue.rb
deleted file mode 100644
index c53bf46ef7..0000000000
--- a/db/migrate/20110923211333_add_status_to_issue.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddStatusToIssue < ActiveRecord::Migration
- def change
- add_column :issues, :closed, :boolean, :default => false, :null => false
- end
-end
diff --git a/db/migrate/20110924214549_create_rails_admin_histories_table.rb b/db/migrate/20110924214549_create_rails_admin_histories_table.rb
deleted file mode 100644
index 3c743aa287..0000000000
--- a/db/migrate/20110924214549_create_rails_admin_histories_table.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class CreateRailsAdminHistoriesTable < ActiveRecord::Migration
- def self.up
- create_table :rails_admin_histories do |t|
- t.text :message # title, name, or object_id
- t.string :username
- t.integer :item
- t.string :table
- t.integer :month, :limit => 2
- t.integer :year, :limit => 5
- t.timestamps
- end
- add_index(:rails_admin_histories, [:item, :table, :month, :year], :name => 'index_rails_admin_histories' )
- end
-
- def self.down
- drop_table :rails_admin_histories
- end
-end
diff --git a/db/migrate/20110924215658_add_admin_field_to_user.rb b/db/migrate/20110924215658_add_admin_field_to_user.rb
deleted file mode 100644
index 321587e695..0000000000
--- a/db/migrate/20110924215658_add_admin_field_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAdminFieldToUser < ActiveRecord::Migration
- def change
- add_column :users, :admin, :boolean, :default => false, :null => false
- end
-end
diff --git a/db/migrate/20110926082616_remove_admin.rb b/db/migrate/20110926082616_remove_admin.rb
deleted file mode 100644
index aac9ff7888..0000000000
--- a/db/migrate/20110926082616_remove_admin.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveAdmin < ActiveRecord::Migration
- def up
- drop_table :rails_admin_histories
- end
-
- def down
- raise "No rollback"
- end
-end
diff --git a/db/migrate/20110927130352_create_notes.rb b/db/migrate/20110927130352_create_notes.rb
deleted file mode 100644
index 72a0e81761..0000000000
--- a/db/migrate/20110927130352_create_notes.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateNotes < ActiveRecord::Migration
- def change
- create_table :notes do |t|
- t.string :note
- t.integer :noteable_id
- t.string :noteable_type
- t.integer :author_id
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20110928140106_add_project_id_for_note.rb b/db/migrate/20110928140106_add_project_id_for_note.rb
deleted file mode 100644
index 3e64108979..0000000000
--- a/db/migrate/20110928140106_add_project_id_for_note.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddProjectIdForNote < ActiveRecord::Migration
- def up
- add_column :notes, :project_id, :integer
- end
-
- def down
- remove_column :notes, :project_id, :integer
- end
-end
diff --git a/db/migrate/20110928142747_change_noteable_id_for_note.rb b/db/migrate/20110928142747_change_noteable_id_for_note.rb
deleted file mode 100644
index dc9d1f0171..0000000000
--- a/db/migrate/20110928142747_change_noteable_id_for_note.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class ChangeNoteableIdForNote < ActiveRecord::Migration
- def up
- change_column :notes, :noteable_id, :string
- end
-
- def down
- change_column :notes, :noteable_id, :integer
- end
-end
diff --git a/db/migrate/20110928161328_add_attachment_to_note.rb b/db/migrate/20110928161328_add_attachment_to_note.rb
deleted file mode 100644
index 37d9cf1025..0000000000
--- a/db/migrate/20110928161328_add_attachment_to_note.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAttachmentToNote < ActiveRecord::Migration
- def change
- add_column :notes, :attachment, :string
- end
-end
diff --git a/db/migrate/20111005193700_add_allow_repo_creation_for_user.rb b/db/migrate/20111005193700_add_allow_repo_creation_for_user.rb
deleted file mode 100644
index 82bd94b808..0000000000
--- a/db/migrate/20111005193700_add_allow_repo_creation_for_user.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddAllowRepoCreationForUser < ActiveRecord::Migration
- def up
- add_column :users, :allowed_create_repo, :boolean, :default => true, :null => false
- end
-
- def down
- remove_column :users, :allowed_create_repo
- end
-end
diff --git a/db/migrate/20111009101738_add_ownerto_project.rb b/db/migrate/20111009101738_add_ownerto_project.rb
deleted file mode 100644
index 8d265533ad..0000000000
--- a/db/migrate/20111009101738_add_ownerto_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddOwnertoProject < ActiveRecord::Migration
- def change
- add_column :projects, :owner_id, :integer
- end
-end
diff --git a/db/migrate/20111009110913_add_projects_limit_to_user.rb b/db/migrate/20111009110913_add_projects_limit_to_user.rb
deleted file mode 100644
index 8eb8382b51..0000000000
--- a/db/migrate/20111009110913_add_projects_limit_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddProjectsLimitToUser < ActiveRecord::Migration
- def change
- add_column :users, :projects_limit, :integer, :default => 10
- end
-end
diff --git a/db/migrate/20111009111204_remove_allow_create_repo_from_user.rb b/db/migrate/20111009111204_remove_allow_create_repo_from_user.rb
deleted file mode 100644
index 6145200639..0000000000
--- a/db/migrate/20111009111204_remove_allow_create_repo_from_user.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveAllowCreateRepoFromUser < ActiveRecord::Migration
- def up
- remove_column :users, :allowed_create_repo
- end
-
- def down
- add_column :users, :allowed_create_repo, :boolean, :default => true, :null => false
- end
-end
diff --git a/db/migrate/20111015154310_add_position_to_issues.rb b/db/migrate/20111015154310_add_position_to_issues.rb
deleted file mode 100644
index 41451a0cab..0000000000
--- a/db/migrate/20111015154310_add_position_to_issues.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddPositionToIssues < ActiveRecord::Migration
- def change
- add_column :issues, :position, :integer, :default => 0
- end
-end
diff --git a/db/migrate/20111016183422_create_snippets.rb b/db/migrate/20111016183422_create_snippets.rb
deleted file mode 100644
index 9b0bf201cb..0000000000
--- a/db/migrate/20111016183422_create_snippets.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateSnippets < ActiveRecord::Migration
- def change
- create_table :snippets do |t|
- t.string :title
- t.text :content
- t.integer :author_id, :null => false
- t.integer :project_id, :null => false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20111016193417_add_content_type_to_snippets.rb b/db/migrate/20111016193417_add_content_type_to_snippets.rb
deleted file mode 100644
index 511a6793f4..0000000000
--- a/db/migrate/20111016193417_add_content_type_to_snippets.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddContentTypeToSnippets < ActiveRecord::Migration
- def change
- add_column :snippets, :content_type, :string, :null => false, :default => "txt"
- end
-end
diff --git a/db/migrate/20111016195506_add_file_name_to_snippets.rb b/db/migrate/20111016195506_add_file_name_to_snippets.rb
deleted file mode 100644
index d378d225ec..0000000000
--- a/db/migrate/20111016195506_add_file_name_to_snippets.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddFileNameToSnippets < ActiveRecord::Migration
- def change
- add_column :snippets, :file_name, :string
- remove_column :snippets, :content_type
- end
-end
diff --git a/db/migrate/20111019212429_add_social_to_user.rb b/db/migrate/20111019212429_add_social_to_user.rb
deleted file mode 100644
index b0ffe5366a..0000000000
--- a/db/migrate/20111019212429_add_social_to_user.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddSocialToUser < ActiveRecord::Migration
- def change
- add_column :users, :skype, :string
- add_column :users, :linkedin, :string
- add_column :users, :twitter, :string
- end
-end
diff --git a/db/migrate/20111021101550_change_social_fields_in_users.rb b/db/migrate/20111021101550_change_social_fields_in_users.rb
deleted file mode 100644
index 6e506c1cf9..0000000000
--- a/db/migrate/20111021101550_change_social_fields_in_users.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class ChangeSocialFieldsInUsers < ActiveRecord::Migration
- def up
- remove_column :users, :skype
- remove_column :users, :linkedin
- remove_column :users, :twitter
-
- add_column :users, :skype, :string, {:null => false, :default => ''}
- add_column :users, :linkedin, :string, {:null => false, :default => ''}
- add_column :users, :twitter, :string, {:null => false, :default => ''}
- end
-
- def down
- end
-end
diff --git a/db/migrate/20111025134235_add_high_label_to_issue.rb b/db/migrate/20111025134235_add_high_label_to_issue.rb
deleted file mode 100644
index 676eaaf8c1..0000000000
--- a/db/migrate/20111025134235_add_high_label_to_issue.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddHighLabelToIssue < ActiveRecord::Migration
- def change
- add_column :issues, :critical, :boolean, :default => false, :null => false
- end
-end
diff --git a/db/migrate/20111027051828_add_expires_at_to_snippets.rb b/db/migrate/20111027051828_add_expires_at_to_snippets.rb
deleted file mode 100644
index 0d94b33376..0000000000
--- a/db/migrate/20111027051828_add_expires_at_to_snippets.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddExpiresAtToSnippets < ActiveRecord::Migration
- def change
- add_column :snippets, :expires_at, :datetime
- end
-end
diff --git a/db/migrate/20111027142641_change_note_note_to_text.rb b/db/migrate/20111027142641_change_note_note_to_text.rb
deleted file mode 100644
index d762d361ae..0000000000
--- a/db/migrate/20111027142641_change_note_note_to_text.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class ChangeNoteNoteToText < ActiveRecord::Migration
- def up
- change_column :notes, :note, :text
- end
-
- def down
- end
-end
diff --git a/db/migrate/20111027152724_issue_conten_to_note.rb b/db/migrate/20111027152724_issue_conten_to_note.rb
deleted file mode 100644
index 0677fee6b9..0000000000
--- a/db/migrate/20111027152724_issue_conten_to_note.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class IssueContenToNote < ActiveRecord::Migration
- def up
- puts "Issue content is deprecated -> move to notes"
- Issue.find_each(:batch_size => 100) do |issue|
- next if issue.content.blank?
- note = Note.new(
- :note => issue.content,
- :project_id => issue.project_id,
- :noteable => issue,
- :created_at => issue.created_at,
- :updated_at => issue.created_at
- )
- note.author_id = issue.author_id
-
- if note.save
- issue.update_attributes(:content => nil)
- print "."
- else
- print "F"
- end
- end
-
- total = Issue.where("content is not null").count
-
- if total > 0
- puts "content of #{total} issues were not migrated"
- else
- puts "Done"
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20111101222453_acts_as_taggable_on_migration.rb b/db/migrate/20111101222453_acts_as_taggable_on_migration.rb
deleted file mode 100644
index 16610615f9..0000000000
--- a/db/migrate/20111101222453_acts_as_taggable_on_migration.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-class ActsAsTaggableOnMigration < ActiveRecord::Migration
- def self.up
- create_table :tags do |t|
- t.string :name
- end
-
- create_table :taggings do |t|
- t.references :tag
-
- # You should make sure that the column created is
- # long enough to store the required class names.
- t.references :taggable, :polymorphic => true
- t.references :tagger, :polymorphic => true
-
- t.string :context
-
- t.datetime :created_at
- end
-
- add_index :taggings, :tag_id
- add_index :taggings, [:taggable_id, :taggable_type, :context]
- end
-
- def self.down
- drop_table :taggings
- drop_table :tags
- end
-end
diff --git a/db/migrate/20111111093150_remove_content_from_issues.rb b/db/migrate/20111111093150_remove_content_from_issues.rb
deleted file mode 100644
index 30bcdfb543..0000000000
--- a/db/migrate/20111111093150_remove_content_from_issues.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveContentFromIssues < ActiveRecord::Migration
- def up
- remove_column :issues, :content
- end
-
- def down
- add_column :issues, :content, :text
- end
-end
diff --git a/db/migrate/20111115063954_add_authentication_token_to_users.rb b/db/migrate/20111115063954_add_authentication_token_to_users.rb
deleted file mode 100644
index 84433656d6..0000000000
--- a/db/migrate/20111115063954_add_authentication_token_to_users.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAuthenticationTokenToUsers < ActiveRecord::Migration
- def change
- add_column :users, :authentication_token, :string
- end
-end
diff --git a/db/migrate/20111124115339_add_extra_field_to_issue.rb b/db/migrate/20111124115339_add_extra_field_to_issue.rb
deleted file mode 100644
index 4946c6fb0b..0000000000
--- a/db/migrate/20111124115339_add_extra_field_to_issue.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddExtraFieldToIssue < ActiveRecord::Migration
- def change
- add_column :issues, :branch_name, :string, :null => true
- end
-end
diff --git a/db/migrate/20111127155345_create_merge_requests.rb b/db/migrate/20111127155345_create_merge_requests.rb
deleted file mode 100644
index 1555ae8404..0000000000
--- a/db/migrate/20111127155345_create_merge_requests.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CreateMergeRequests < ActiveRecord::Migration
- def change
- create_table :merge_requests do |t|
- t.string :target_branch, :null => false
- t.string :source_branch, :null => false
- t.integer :project_id, :null => false
- t.integer :author_id
- t.integer :assignee_id
- t.string :title
- t.boolean :closed, :default => false, :null => false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20111206213842_add_advanced_rights_to_team_member.rb b/db/migrate/20111206213842_add_advanced_rights_to_team_member.rb
deleted file mode 100644
index e2695fdafa..0000000000
--- a/db/migrate/20111206213842_add_advanced_rights_to_team_member.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddAdvancedRightsToTeamMember < ActiveRecord::Migration
- def change
- add_column :users_projects, :repo_access, :integer, :default => 0, :null => false
- add_column :users_projects, :project_access, :integer, :default => 0, :null => false
- end
-end
diff --git a/db/migrate/20111206222316_migrate_to_new_rights.rb b/db/migrate/20111206222316_migrate_to_new_rights.rb
deleted file mode 100644
index 22e0c1ce99..0000000000
--- a/db/migrate/20111206222316_migrate_to_new_rights.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class MigrateToNewRights < ActiveRecord::Migration
- def up
- # Repository access
- UsersProject.update_all("repo_access = 2", :write => true)
- UsersProject.update_all("repo_access = 1", :read => true, :write => false)
-
- # Project access
- UsersProject.update_all("project_access = 1", :read => true, :write => false, :admin => false)
- UsersProject.update_all("project_access = 2", :read => true, :write => true, :admin => false)
- UsersProject.update_all("project_access = 3", :read => true, :write => true, :admin => true)
-
- # Remove old fields
- remove_column :users_projects, :read
- remove_column :users_projects, :write
- remove_column :users_projects, :admin
- end
-
- def down
- end
-end
diff --git a/db/migrate/20111207211728_add_default_branch_to_project.rb b/db/migrate/20111207211728_add_default_branch_to_project.rb
deleted file mode 100644
index 5c2107f7aa..0000000000
--- a/db/migrate/20111207211728_add_default_branch_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddDefaultBranchToProject < ActiveRecord::Migration
- def change
- add_column :projects, :default_branch, :string, :null => false, :default => "master"
- end
-end
diff --git a/db/migrate/20111214091851_create_web_hooks.rb b/db/migrate/20111214091851_create_web_hooks.rb
deleted file mode 100644
index c6ba89c10e..0000000000
--- a/db/migrate/20111214091851_create_web_hooks.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class CreateWebHooks < ActiveRecord::Migration
- def change
- create_table :web_hooks do |t|
- t.string :url
- t.integer :project_id
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20111220190817_add_coloscheme_option_to_user.rb b/db/migrate/20111220190817_add_coloscheme_option_to_user.rb
deleted file mode 100644
index fe06c3aa34..0000000000
--- a/db/migrate/20111220190817_add_coloscheme_option_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddColoschemeOptionToUser < ActiveRecord::Migration
- def change
- add_column :users, :dark_scheme, :boolean, :default => false, :null => false
- end
-end
diff --git a/db/migrate/20111231111825_add_project_id_to_key.rb b/db/migrate/20111231111825_add_project_id_to_key.rb
deleted file mode 100644
index dc80cbdb71..0000000000
--- a/db/migrate/20111231111825_add_project_id_to_key.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddProjectIdToKey < ActiveRecord::Migration
- def change
- add_column :keys, :project_id, :integer, :null => true
- change_column :keys, :user_id, :integer, :null => true
- end
-end
diff --git a/db/migrate/20120110180749_add_line_number_to_note.rb b/db/migrate/20120110180749_add_line_number_to_note.rb
deleted file mode 100644
index 9bdcce3c47..0000000000
--- a/db/migrate/20120110180749_add_line_number_to_note.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddLineNumberToNote < ActiveRecord::Migration
- def change
- add_column :notes, :line_code, :string, :null => true
- end
-end
diff --git a/db/migrate/20120119202326_add_indexes.rb b/db/migrate/20120119202326_add_indexes.rb
deleted file mode 100644
index ee07176a26..0000000000
--- a/db/migrate/20120119202326_add_indexes.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddIndexes < ActiveRecord::Migration
- def change
- add_index :issues, :project_id
- add_index :merge_requests, :project_id
- add_index :notes, :noteable_id
- add_index :notes, :noteable_type
- end
-
-end
diff --git a/db/migrate/20120121122616_fix_noteable_id.rb b/db/migrate/20120121122616_fix_noteable_id.rb
deleted file mode 100644
index d110e8cd63..0000000000
--- a/db/migrate/20120121122616_fix_noteable_id.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class FixNoteableId < ActiveRecord::Migration
- def up
- change_column :notes, :noteable_id, :string, :limit => 255
- end
-
- def down
- end
-end
diff --git a/db/migrate/20120206170141_add_modularity_fields_to_project.rb b/db/migrate/20120206170141_add_modularity_fields_to_project.rb
deleted file mode 100644
index d63de0c2be..0000000000
--- a/db/migrate/20120206170141_add_modularity_fields_to_project.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddModularityFieldsToProject < ActiveRecord::Migration
- def change
- add_column :projects, :issues_enabled, :boolean, :null => false, :default => true
- add_column :projects, :wall_enabled, :boolean, :null => false, :default => true
- add_column :projects, :merge_requests_enabled, :boolean, :null => false, :default => true
- end
-end
diff --git a/db/migrate/20120215182305_create_protected_branches.rb b/db/migrate/20120215182305_create_protected_branches.rb
deleted file mode 100644
index 841d08c33d..0000000000
--- a/db/migrate/20120215182305_create_protected_branches.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class CreateProtectedBranches < ActiveRecord::Migration
- def change
- create_table :protected_branches do |t|
- t.integer :project_id, :null => false
- t.string :name, :null => false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20120216085842_move_to_roles_permissions.rb b/db/migrate/20120216085842_move_to_roles_permissions.rb
deleted file mode 100644
index 36d02cf972..0000000000
--- a/db/migrate/20120216085842_move_to_roles_permissions.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class MoveToRolesPermissions < ActiveRecord::Migration
- def up
- repo_n = 0
- repo_r = 1
- repo_rw = 2
- project_rwa = 3
-
-
- # Build masters and reset repo_access
- UsersProject.update_all({:project_access => UsersProject::MASTER, :repo_access => 99 }, ["project_access = ?", project_rwa])
-
- # Build other roles based on repo access
- UsersProject.update_all ["project_access = ?", UsersProject::DEVELOPER], ["repo_access = ?", repo_rw]
- UsersProject.update_all ["project_access = ?", UsersProject::REPORTER], ["repo_access = ?", repo_r]
- UsersProject.update_all ["project_access = ?", UsersProject::GUEST], ["repo_access = ?", repo_n]
-
- remove_column :users_projects, :repo_access
- end
-
- def down
- end
-end
diff --git a/db/migrate/20120216215008_create_wikis.rb b/db/migrate/20120216215008_create_wikis.rb
deleted file mode 100644
index 38947df389..0000000000
--- a/db/migrate/20120216215008_create_wikis.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreateWikis < ActiveRecord::Migration
- def change
- create_table :wikis do |t|
- t.string :title
- t.text :content
- t.integer :project_id
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20120219130957_add_slug_to_wiki.rb b/db/migrate/20120219130957_add_slug_to_wiki.rb
deleted file mode 100644
index 5f2d5970a8..0000000000
--- a/db/migrate/20120219130957_add_slug_to_wiki.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddSlugToWiki < ActiveRecord::Migration
- def change
- add_column :wikis, :slug, :string
-
- end
-end
diff --git a/db/migrate/20120219140810_add_wiki_enabled_to_project.rb b/db/migrate/20120219140810_add_wiki_enabled_to_project.rb
deleted file mode 100644
index ebd71bea84..0000000000
--- a/db/migrate/20120219140810_add_wiki_enabled_to_project.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddWikiEnabledToProject < ActiveRecord::Migration
- def change
- add_column :projects, :wiki_enabled, :boolean, :default => true, :null => false
-
- end
-end
diff --git a/db/migrate/20120219193300_add_user_to_wiki.rb b/db/migrate/20120219193300_add_user_to_wiki.rb
deleted file mode 100644
index 8a6c0a06ef..0000000000
--- a/db/migrate/20120219193300_add_user_to_wiki.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddUserToWiki < ActiveRecord::Migration
- def change
- add_column :wikis, :user_id, :integer
-
- end
-end
diff --git a/db/migrate/20120228130210_create_events.rb b/db/migrate/20120228130210_create_events.rb
deleted file mode 100644
index c01f557aaa..0000000000
--- a/db/migrate/20120228130210_create_events.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class CreateEvents < ActiveRecord::Migration
- def change
- create_table :events do |t|
- t.string :target_type, :null => true
- t.integer :target_id, :null => true
-
- t.string :title, :null => true
- t.text :data, :null => true
- t.integer :project_id, :null => true
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20120228134252_add_action_to_event.rb b/db/migrate/20120228134252_add_action_to_event.rb
deleted file mode 100644
index aade3d90a8..0000000000
--- a/db/migrate/20120228134252_add_action_to_event.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddActionToEvent < ActiveRecord::Migration
- def change
- add_column :events, :action, :integer, :null => true
- end
-end
diff --git a/db/migrate/20120301185805_add_theme_to_user.rb b/db/migrate/20120301185805_add_theme_to_user.rb
deleted file mode 100644
index 7c2e55692b..0000000000
--- a/db/migrate/20120301185805_add_theme_to_user.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddThemeToUser < ActiveRecord::Migration
- def change
- add_column :users, :theme_id, :integer, :null => false, :default => 1
-
- end
-end
diff --git a/db/migrate/20120307095918_add_author_id_to_event.rb b/db/migrate/20120307095918_add_author_id_to_event.rb
deleted file mode 100644
index 1d24d41e42..0000000000
--- a/db/migrate/20120307095918_add_author_id_to_event.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAuthorIdToEvent < ActiveRecord::Migration
- def change
- add_column :events, :author_id, :integer, :null => true
- end
-end
diff --git a/db/migrate/20120315111711_add_commits_diff_store_to_merge_request.rb b/db/migrate/20120315111711_add_commits_diff_store_to_merge_request.rb
deleted file mode 100644
index 2dc1dfb4b6..0000000000
--- a/db/migrate/20120315111711_add_commits_diff_store_to_merge_request.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddCommitsDiffStoreToMergeRequest < ActiveRecord::Migration
- def change
- add_column :merge_requests, :st_commits, :text, :null => true
- add_column :merge_requests, :st_diffs, :text, :null => true
- end
-end
diff --git a/db/migrate/20120315132931_add_merged_to_merge_request.rb b/db/migrate/20120315132931_add_merged_to_merge_request.rb
deleted file mode 100644
index 2deb59e442..0000000000
--- a/db/migrate/20120315132931_add_merged_to_merge_request.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMergedToMergeRequest < ActiveRecord::Migration
- def change
- add_column :merge_requests, :merged, :boolean, :null => false, :default => false
- end
-end
diff --git a/db/migrate/20120317095543_add_description_to_issues.rb b/db/migrate/20120317095543_add_description_to_issues.rb
deleted file mode 100644
index e47e3f8e89..0000000000
--- a/db/migrate/20120317095543_add_description_to_issues.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddDescriptionToIssues < ActiveRecord::Migration
- def change
- add_column :issues, :description, :text
- end
-end
diff --git a/db/migrate/20120323221339_add_bio_field_to_user.rb b/db/migrate/20120323221339_add_bio_field_to_user.rb
deleted file mode 100644
index 80a4dec597..0000000000
--- a/db/migrate/20120323221339_add_bio_field_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddBioFieldToUser < ActiveRecord::Migration
- def change
- add_column :users, :bio, :string, :null => true
- end
-end
diff --git a/db/migrate/20120329170745_add_automerge_to_merge_request.rb b/db/migrate/20120329170745_add_automerge_to_merge_request.rb
deleted file mode 100644
index de7c68ee1c..0000000000
--- a/db/migrate/20120329170745_add_automerge_to_merge_request.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAutomergeToMergeRequest < ActiveRecord::Migration
- def change
- add_column :merge_requests, :state, :integer, :null => false, :default => 1
- end
-end
diff --git a/db/migrate/20120405211750_increase_mr_text_column_size.rb b/db/migrate/20120405211750_increase_mr_text_column_size.rb
deleted file mode 100644
index 4fbef622da..0000000000
--- a/db/migrate/20120405211750_increase_mr_text_column_size.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class IncreaseMrTextColumnSize < ActiveRecord::Migration
- def up
- # MYSQL LARGETEXT for merge request
- change_column :merge_requests, :st_diffs, :text, :limit => 4294967295
- change_column :merge_requests, :st_commits, :text, :limit => 4294967295
- end
-
- def down
- end
-end
diff --git a/db/migrate/20120408180246_create_milestones.rb b/db/migrate/20120408180246_create_milestones.rb
deleted file mode 100644
index ed3a510d66..0000000000
--- a/db/migrate/20120408180246_create_milestones.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateMilestones < ActiveRecord::Migration
- def change
- create_table :milestones do |t|
- t.string :title, :null => false
- t.integer :project_id, :null => false
- t.text :description
- t.date :due_date
- t.boolean :closed, :default => false, :null => false
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20120408181910_add_milestone_id_to_issue.rb b/db/migrate/20120408181910_add_milestone_id_to_issue.rb
deleted file mode 100644
index a6b44090c1..0000000000
--- a/db/migrate/20120408181910_add_milestone_id_to_issue.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMilestoneIdToIssue < ActiveRecord::Migration
- def change
- add_column :issues, :milestone_id, :integer, :null => true
- end
-end
diff --git a/db/migrate/20120413135904_add_blocked_field_to_user.rb b/db/migrate/20120413135904_add_blocked_field_to_user.rb
deleted file mode 100644
index 050450bf03..0000000000
--- a/db/migrate/20120413135904_add_blocked_field_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddBlockedFieldToUser < ActiveRecord::Migration
- def change
- add_column :users, :blocked, :boolean, :null => false, :default => false
- end
-end
diff --git a/db/migrate/20120627145613_remove_critical_from_issue.rb b/db/migrate/20120627145613_remove_critical_from_issue.rb
deleted file mode 100644
index f8d0797197..0000000000
--- a/db/migrate/20120627145613_remove_critical_from_issue.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveCriticalFromIssue < ActiveRecord::Migration
- def up
- remove_column :issues, :critical
- end
-
- def down
- add_column :issues, :critical, :boolean, :null => true, :default => false
- end
-end
diff --git a/db/migrate/20120706065612_add_lockable_to_users.rb b/db/migrate/20120706065612_add_lockable_to_users.rb
deleted file mode 100644
index cf86e66087..0000000000
--- a/db/migrate/20120706065612_add_lockable_to_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddLockableToUsers < ActiveRecord::Migration
- def change
- add_column :users, :failed_attempts, :integer, :default => 0
- add_column :users, :locked_at, :datetime
- end
-end
diff --git a/db/migrate/20120712080407_add_type_to_web_hook.rb b/db/migrate/20120712080407_add_type_to_web_hook.rb
deleted file mode 100644
index 18ab024c81..0000000000
--- a/db/migrate/20120712080407_add_type_to_web_hook.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddTypeToWebHook < ActiveRecord::Migration
- def change
- add_column :web_hooks, :type, :string, :default => "ProjectHook"
- end
-end
diff --git a/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb b/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb
deleted file mode 100644
index d5e66ba4d3..0000000000
--- a/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddExternAuthProviderToUsers < ActiveRecord::Migration
- def change
- add_column :users, :extern_uid, :string
- add_column :users, :provider, :string
-
- add_index :users, [:extern_uid, :provider], :unique => true
- end
-end
diff --git a/db/migrate/20120905043334_set_default_branch_default_to_nil.rb b/db/migrate/20120905043334_set_default_branch_default_to_nil.rb
deleted file mode 100644
index f5956fe875..0000000000
--- a/db/migrate/20120905043334_set_default_branch_default_to_nil.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class SetDefaultBranchDefaultToNil < ActiveRecord::Migration
- def up
- # Set the default_branch to allow nil, and default it to nil
- change_column_null(:projects, :default_branch, true)
- change_column_default(:projects, :default_branch, nil)
- end
-
- def down
- change_column_null(:projects, :default_branch, false)
- change_column_default(:projects, :default_branch, 'master')
- end
-end
diff --git a/db/migrate/20121002150926_create_groups.rb b/db/migrate/20121002150926_create_groups.rb
deleted file mode 100644
index ac178294c0..0000000000
--- a/db/migrate/20121002150926_create_groups.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreateGroups < ActiveRecord::Migration
- def change
- create_table :groups do |t|
- t.string :name, null: false
- t.string :code, null: false
- t.integer :owner_id, null: false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20121002151033_add_group_id_to_project.rb b/db/migrate/20121002151033_add_group_id_to_project.rb
deleted file mode 100644
index 683fbfec51..0000000000
--- a/db/migrate/20121002151033_add_group_id_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddGroupIdToProject < ActiveRecord::Migration
- def change
- add_column :projects, :group_id, :integer
- end
-end
diff --git a/db/migrate/20121009205010_postgres_create_integer_cast.rb b/db/migrate/20121009205010_postgres_create_integer_cast.rb
deleted file mode 100644
index b9a971387d..0000000000
--- a/db/migrate/20121009205010_postgres_create_integer_cast.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class PostgresCreateIntegerCast < ActiveRecord::Migration
- def up
- execute <<-SQL
- CREATE CAST (integer AS text) WITH INOUT AS IMPLICIT;
- SQL
- rescue ActiveRecord::StatementInvalid
- end
-
- def down
- execute <<-SQL
- DROP CAST (integer AS text);
- SQL
- rescue ActiveRecord::StatementInvalid
- end
-end
diff --git a/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb b/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb
deleted file mode 100644
index b516772434..0000000000
--- a/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMilestoneIdToMergeRequests < ActiveRecord::Migration
- def change
- add_column :merge_requests, :milestone_id, :integer, :null => true
- end
-end
diff --git a/db/migrate/20121119170638_create_services.rb b/db/migrate/20121119170638_create_services.rb
deleted file mode 100644
index f7cac1445a..0000000000
--- a/db/migrate/20121119170638_create_services.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateServices < ActiveRecord::Migration
- def change
- create_table :services do |t|
- t.string :type
- t.string :title
- t.string :token
- t.integer :project_id, null: false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20121120051432_add_service_id_to_web_hook.rb b/db/migrate/20121120051432_add_service_id_to_web_hook.rb
deleted file mode 100644
index 77adf92578..0000000000
--- a/db/migrate/20121120051432_add_service_id_to_web_hook.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddServiceIdToWebHook < ActiveRecord::Migration
- def change
- add_column :web_hooks, :service_id, :integer, null: true
- end
-end
diff --git a/db/migrate/20121120103700_add_active_to_service.rb b/db/migrate/20121120103700_add_active_to_service.rb
deleted file mode 100644
index f45ef52e6f..0000000000
--- a/db/migrate/20121120103700_add_active_to_service.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddActiveToService < ActiveRecord::Migration
- def change
- add_column :services, :active, :boolean, default: false, null: false
- end
-end
diff --git a/db/migrate/20121120113838_add_project_url_to_service.rb b/db/migrate/20121120113838_add_project_url_to_service.rb
deleted file mode 100644
index 13ffbdb192..0000000000
--- a/db/migrate/20121120113838_add_project_url_to_service.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddProjectUrlToService < ActiveRecord::Migration
- def change
- add_column :services, :project_url, :string, null: true
- end
-end
diff --git a/db/migrate/20121122145155_convert_group_to_namespace.rb b/db/migrate/20121122145155_convert_group_to_namespace.rb
deleted file mode 100644
index fc8b023d81..0000000000
--- a/db/migrate/20121122145155_convert_group_to_namespace.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644
index 904f3aa32b..0000000000
--- a/db/migrate/20121122150932_add_namespace_id_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-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
deleted file mode 100644
index 04232a119d..0000000000
--- a/db/migrate/20121123104937_add_username_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-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
deleted file mode 100644
index fb10baf58c..0000000000
--- a/db/migrate/20121123164910_rename_code_to_path.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-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/migrate/20121203154450_add_events_indices.rb b/db/migrate/20121203154450_add_events_indices.rb
deleted file mode 100644
index 502a2ccbcd..0000000000
--- a/db/migrate/20121203154450_add_events_indices.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddEventsIndices < ActiveRecord::Migration
- def change
- add_index :events, :project_id
- add_index :events, :author_id
- add_index :events, :action
- add_index :events, :target_type
- end
-end
diff --git a/db/migrate/20121203160507_more_indices.rb b/db/migrate/20121203160507_more_indices.rb
deleted file mode 100644
index 52170a7c59..0000000000
--- a/db/migrate/20121203160507_more_indices.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class MoreIndices < ActiveRecord::Migration
- def change
- add_index :notes, :project_id
- add_index :namespaces, :owner_id
- add_index :keys, :user_id
-
- add_index :projects, :namespace_id
- add_index :projects, :owner_id
-
- add_index :services, :project_id
- add_index :snippets, :project_id
-
- add_index :users_projects, :project_id
-
- # Issues
- add_index :issues, :assignee_id
- add_index :issues, :milestone_id
- add_index :issues, :author_id
-
- # Merge Requests
- add_index :merge_requests, :assignee_id
- add_index :merge_requests, :milestone_id
- add_index :merge_requests, :author_id
-
- end
-end
diff --git a/db/migrate/20121205201726_add_more_indexes.rb b/db/migrate/20121205201726_add_more_indexes.rb
deleted file mode 100644
index a2b36f7fdf..0000000000
--- a/db/migrate/20121205201726_add_more_indexes.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class AddMoreIndexes < ActiveRecord::Migration
- def change
- add_index :events, :created_at
- add_index :events, :target_id
-
- add_index :issues, :closed
- add_index :issues, :created_at
- add_index :issues, :title
-
- add_index :keys, :identifier
- # FIXME: MySQL can't index text columns
- #add_index :keys, :key
- add_index :keys, :project_id
-
- add_index :merge_requests, :closed
- add_index :merge_requests, :created_at
- add_index :merge_requests, :source_branch
- add_index :merge_requests, :target_branch
- add_index :merge_requests, :title
-
- add_index :milestones, :due_date
- add_index :milestones, :project_id
-
- add_index :namespaces, :name
- add_index :namespaces, :path
- add_index :namespaces, :type
-
- add_index :notes, :created_at
-
- add_index :snippets, :created_at
- add_index :snippets, :expires_at
-
- add_index :users, :admin
- add_index :users, :blocked
- add_index :users, :name
- add_index :users, :username
-
- add_index :users_projects, :project_access
- add_index :users_projects, :user_id
-
- add_index :wikis, :project_id
- add_index :wikis, :slug
- end
-end
diff --git a/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb b/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb
deleted file mode 100644
index 6f2da4136a..0000000000
--- a/db/migrate/20121218164840_move_noteable_commit_to_own_field.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class MoveNoteableCommitToOwnField < ActiveRecord::Migration
- def up
- add_column :notes, :commit_id, :string, null: true
- add_column :notes, :new_noteable_id, :integer, null: true
- Note.where(noteable_type: 'Commit').update_all('commit_id = noteable_id')
-
- if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
- Note.where("noteable_type != 'Commit'").update_all('new_noteable_id = CAST (noteable_id AS INTEGER)')
- else
- Note.where("noteable_type != 'Commit'").update_all('new_noteable_id = noteable_id')
- end
-
- remove_column :notes, :noteable_id
- rename_column :notes, :new_noteable_id, :noteable_id
- end
-
- def down
- raise ActiveRecord::IrreversibleMigration
- end
-end
diff --git a/db/migrate/20121219095402_indices_for_notes.rb b/db/migrate/20121219095402_indices_for_notes.rb
deleted file mode 100644
index 4c5d041ce8..0000000000
--- a/db/migrate/20121219095402_indices_for_notes.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class IndicesForNotes < ActiveRecord::Migration
- def change
- add_index :notes, :commit_id
- add_index :notes, [:project_id, :noteable_type]
- end
-end
diff --git a/db/migrate/20121219183753_create_user_teams.rb b/db/migrate/20121219183753_create_user_teams.rb
deleted file mode 100644
index 65c4d05398..0000000000
--- a/db/migrate/20121219183753_create_user_teams.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreateUserTeams < ActiveRecord::Migration
- def change
- create_table :user_teams do |t|
- t.string :name
- t.string :path
- t.integer :owner_id
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20121220064104_create_user_team_project_relationships.rb b/db/migrate/20121220064104_create_user_team_project_relationships.rb
deleted file mode 100644
index 8eb654c872..0000000000
--- a/db/migrate/20121220064104_create_user_team_project_relationships.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class CreateUserTeamProjectRelationships < ActiveRecord::Migration
- def change
- create_table :user_team_project_relationships do |t|
- t.integer :project_id
- t.integer :user_team_id
- t.integer :greatest_access
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20121220064453_create_user_team_user_relationships.rb b/db/migrate/20121220064453_create_user_team_user_relationships.rb
deleted file mode 100644
index 7783b0ae43..0000000000
--- a/db/migrate/20121220064453_create_user_team_user_relationships.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class CreateUserTeamUserRelationships < ActiveRecord::Migration
- def change
- create_table :user_team_user_relationships do |t|
- t.integer :user_id
- t.integer :user_team_id
- t.boolean :group_admin
- t.integer :permission
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20121220064453_init_schema.rb b/db/migrate/20121220064453_init_schema.rb
new file mode 100644
index 0000000000..90f5eb08e8
--- /dev/null
+++ b/db/migrate/20121220064453_init_schema.rb
@@ -0,0 +1,306 @@
+class InitSchema < ActiveRecord::Migration
+ def up
+
+ create_table "events", force: true do |t|
+ t.string "target_type"
+ t.integer "target_id"
+ t.string "title"
+ t.text "data"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "action"
+ t.integer "author_id"
+ end
+
+ add_index "events", ["action"], name: "index_events_on_action", using: :btree
+ add_index "events", ["author_id"], name: "index_events_on_author_id", using: :btree
+ add_index "events", ["created_at"], name: "index_events_on_created_at", using: :btree
+ add_index "events", ["project_id"], name: "index_events_on_project_id", using: :btree
+ add_index "events", ["target_id"], name: "index_events_on_target_id", using: :btree
+ add_index "events", ["target_type"], name: "index_events_on_target_type", using: :btree
+
+ create_table "issues", force: true do |t|
+ t.string "title"
+ t.integer "assignee_id"
+ t.integer "author_id"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "closed", default: false, null: false
+ t.integer "position", default: 0
+ t.string "branch_name"
+ t.text "description"
+ t.integer "milestone_id"
+ end
+
+ add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
+ add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
+ add_index "issues", ["closed"], name: "index_issues_on_closed", using: :btree
+ add_index "issues", ["created_at"], name: "index_issues_on_created_at", using: :btree
+ add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
+ add_index "issues", ["project_id"], name: "index_issues_on_project_id", using: :btree
+ add_index "issues", ["title"], name: "index_issues_on_title", using: :btree
+
+ create_table "keys", force: true do |t|
+ t.integer "user_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "key"
+ t.string "title"
+ t.string "identifier"
+ t.integer "project_id"
+ end
+
+ add_index "keys", ["identifier"], name: "index_keys_on_identifier", using: :btree
+ add_index "keys", ["project_id"], name: "index_keys_on_project_id", using: :btree
+ add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree
+
+ create_table "merge_requests", force: true do |t|
+ t.string "target_branch", null: false
+ t.string "source_branch", null: false
+ t.integer "project_id", null: false
+ t.integer "author_id"
+ t.integer "assignee_id"
+ t.string "title"
+ t.boolean "closed", default: false, null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "st_commits", limit: 2147483647
+ t.text "st_diffs", limit: 2147483647
+ t.boolean "merged", default: false, null: false
+ t.integer "state", default: 1, null: false
+ t.integer "milestone_id"
+ end
+
+ add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
+ add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
+ add_index "merge_requests", ["closed"], name: "index_merge_requests_on_closed", using: :btree
+ add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
+ add_index "merge_requests", ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree
+ add_index "merge_requests", ["project_id"], name: "index_merge_requests_on_project_id", using: :btree
+ add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree
+ add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
+ add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree
+
+ create_table "milestones", force: true do |t|
+ t.string "title", null: false
+ t.integer "project_id", null: false
+ t.text "description"
+ t.date "due_date"
+ t.boolean "closed", default: false, null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree
+ add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
+
+ 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"
+ t.datetime "updated_at"
+ t.string "type"
+ end
+
+ add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree
+ add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
+ add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree
+ add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
+
+ create_table "notes", force: true do |t|
+ t.text "note"
+ t.string "noteable_type"
+ t.integer "author_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_id"
+ t.string "attachment"
+ t.string "line_code"
+ t.string "commit_id"
+ t.integer "noteable_id"
+ end
+
+ add_index "notes", ["commit_id"], name: "index_notes_on_commit_id", using: :btree
+ add_index "notes", ["created_at"], name: "index_notes_on_created_at", using: :btree
+ add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
+ add_index "notes", ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree
+ add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree
+
+ create_table "projects", force: true do |t|
+ t.string "name"
+ t.string "path"
+ t.text "description"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "private_flag", default: true, null: false
+ 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 "namespace_id"
+ end
+
+ add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree
+ add_index "projects", ["owner_id"], name: "index_projects_on_owner_id", using: :btree
+
+ create_table "protected_branches", force: true do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "services", force: true do |t|
+ t.string "type"
+ t.string "title"
+ t.string "token"
+ t.integer "project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "active", default: false, null: false
+ t.string "project_url"
+ end
+
+ add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
+
+ create_table "snippets", force: true do |t|
+ t.string "title"
+ t.text "content"
+ t.integer "author_id", null: false
+ t.integer "project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "file_name"
+ t.datetime "expires_at"
+ end
+
+ add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
+ add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
+ add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
+
+ create_table "taggings", force: true do |t|
+ t.integer "tag_id"
+ t.integer "taggable_id"
+ t.string "taggable_type"
+ t.integer "tagger_id"
+ t.string "tagger_type"
+ t.string "context"
+ t.datetime "created_at"
+ end
+
+ add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+
+ create_table "tags", force: true do |t|
+ t.string "name"
+ end
+
+ create_table "user_team_project_relationships", force: true do |t|
+ t.integer "project_id"
+ t.integer "user_team_id"
+ t.integer "greatest_access"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "user_team_user_relationships", force: true do |t|
+ t.integer "user_id"
+ t.integer "user_team_id"
+ t.boolean "group_admin"
+ t.integer "permission"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "user_teams", force: true do |t|
+ t.string "name"
+ t.string "path"
+ t.integer "owner_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "users", force: true do |t|
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
+ t.string "reset_password_token"
+ t.datetime "reset_password_sent_at"
+ t.datetime "remember_created_at"
+ t.integer "sign_in_count", default: 0
+ t.datetime "current_sign_in_at"
+ t.datetime "last_sign_in_at"
+ t.string "current_sign_in_ip"
+ t.string "last_sign_in_ip"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "name"
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", default: 10
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
+ t.string "authentication_token"
+ t.boolean "dark_scheme", default: false, null: false
+ t.integer "theme_id", default: 1, null: false
+ t.string "bio"
+ t.boolean "blocked", default: false, null: false
+ t.integer "failed_attempts", default: 0
+ t.datetime "locked_at"
+ t.string "extern_uid"
+ t.string "provider"
+ t.string "username"
+ end
+
+ add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
+ add_index "users", ["blocked"], name: "index_users_on_blocked", using: :btree
+ add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
+ add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
+ add_index "users", ["name"], name: "index_users_on_name", using: :btree
+ add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
+ add_index "users", ["username"], name: "index_users_on_username", using: :btree
+
+ create_table "users_projects", force: true do |t|
+ t.integer "user_id", null: false
+ t.integer "project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_access", default: 0, null: false
+ end
+
+ add_index "users_projects", ["project_access"], name: "index_users_projects_on_project_access", using: :btree
+ add_index "users_projects", ["project_id"], name: "index_users_projects_on_project_id", using: :btree
+ add_index "users_projects", ["user_id"], name: "index_users_projects_on_user_id", using: :btree
+
+ create_table "web_hooks", force: true do |t|
+ t.string "url"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "type", default: "ProjectHook"
+ t.integer "service_id"
+ end
+
+ create_table "wikis", force: true do |t|
+ t.string "title"
+ t.text "content"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "slug"
+ t.integer "user_id"
+ end
+
+ add_index "wikis", ["project_id"], name: "index_wikis_on_project_id", using: :btree
+ add_index "wikis", ["slug"], name: "index_wikis_on_slug", using: :btree
+
+ end
+
+ def down
+ raise "Can not revert initial migration"
+ end
+end
diff --git a/db/migrate/20140122114406_migrate_mr_diffs.rb b/db/migrate/20140122114406_migrate_mr_diffs.rb
index 2cc5faaa85..1595e2b647 100644
--- a/db/migrate/20140122114406_migrate_mr_diffs.rb
+++ b/db/migrate/20140122114406_migrate_mr_diffs.rb
@@ -1,8 +1,6 @@
class MigrateMrDiffs < ActiveRecord::Migration
def self.up
- execute "INSERT INTO merge_request_diffs ( merge_request_id ) SELECT id FROM merge_requests"
- execute "UPDATE merge_requests mr, merge_request_diffs md SET md.st_commits = mr.st_commits WHERE md.merge_request_id = mr.id"
- execute "UPDATE merge_requests mr, merge_request_diffs md SET md.st_diffs = mr.st_diffs WHERE md.merge_request_id = mr.id"
+ execute "INSERT INTO merge_request_diffs ( merge_request_id, st_commits, st_diffs ) SELECT id, st_commits, st_diffs FROM merge_requests"
end
def self.down
diff --git a/db/migrate/20140122122549_remove_m_rdiff_fields.rb b/db/migrate/20140122122549_remove_m_rdiff_fields.rb
index c27e649e9a..8f863d85a6 100644
--- a/db/migrate/20140122122549_remove_m_rdiff_fields.rb
+++ b/db/migrate/20140122122549_remove_m_rdiff_fields.rb
@@ -7,7 +7,15 @@ class RemoveMRdiffFields < ActiveRecord::Migration
def down
add_column :merge_requests, :st_commits, :text, null: true, limit: 2147483647
add_column :merge_requests, :st_diffs, :text, null: true, limit: 2147483647
- execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_commits = md.st_commits WHERE md.merge_request_id = mr.id"
- execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_diffs = md.st_diffs WHERE md.merge_request_id = mr.id"
+
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
+ execute "UPDATE merge_requests mr
+ SET (st_commits, st_diffs) = (md.st_commits, md.st_diffs)
+ FROM merge_request_diffs md
+ WHERE md.merge_request_id = mr.id"
+ else
+ execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_commits = md.st_commits WHERE md.merge_request_id = mr.id"
+ execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_diffs = md.st_diffs WHERE md.merge_request_id = mr.id"
+ end
end
end
diff --git a/db/migrate/20140127170938_add_group_avatars.rb b/db/migrate/20140127170938_add_group_avatars.rb
new file mode 100644
index 0000000000..2911096dd5
--- /dev/null
+++ b/db/migrate/20140127170938_add_group_avatars.rb
@@ -0,0 +1,5 @@
+class AddGroupAvatars < ActiveRecord::Migration
+ def change
+ add_column :namespaces, :avatar, :string
+ end
+end
diff --git a/db/migrate/20140209025651_create_emails.rb b/db/migrate/20140209025651_create_emails.rb
new file mode 100644
index 0000000000..cb78c4af11
--- /dev/null
+++ b/db/migrate/20140209025651_create_emails.rb
@@ -0,0 +1,13 @@
+class CreateEmails < ActiveRecord::Migration
+ def change
+ create_table :emails do |t|
+ t.integer :user_id, null: false
+ t.string :email, null: false
+
+ t.timestamps
+ end
+
+ add_index :emails, :user_id
+ add_index :emails, :email, unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 75a44d9aa0..65f79fb7e0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140122122549) do
+ActiveRecord::Schema.define(version: 20140209025651) do
create_table "broadcast_messages", force: true do |t|
t.text "message", null: false
@@ -33,6 +33,16 @@ ActiveRecord::Schema.define(version: 20140122122549) do
add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree
+ create_table "emails", force: true do |t|
+ t.integer "user_id", null: false
+ t.string "email", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "emails", ["email"], name: "index_emails_on_email", unique: true, using: :btree
+ add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree
+
create_table "events", force: true do |t|
t.string "target_type"
t.integer "target_id"
@@ -66,8 +76,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.integer "assignee_id"
t.integer "author_id"
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "position", default: 0
t.string "branch_name"
t.text "description"
@@ -85,8 +95,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
create_table "keys", force: true do |t|
t.integer "user_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.text "key"
t.string "title"
t.string "type"
@@ -111,8 +121,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.integer "author_id"
t.integer "assignee_id"
t.string "title"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "milestone_id"
t.string "state"
t.string "merge_status"
@@ -152,6 +162,7 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.datetime "updated_at", null: false
t.string "type"
t.string "description", default: "", null: false
+ t.string "avatar"
end
add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree
@@ -163,8 +174,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.text "note"
t.string "noteable_type"
t.integer "author_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "project_id"
t.string "attachment"
t.string "line_code"
@@ -186,8 +197,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.string "name"
t.string "path"
t.text "description"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "creator_id"
t.boolean "issues_enabled", default: true, null: false
t.boolean "wall_enabled", default: true, null: false
@@ -238,8 +249,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.text "content", limit: 2147483647
t.integer "author_id", null: false
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "file_name"
t.datetime "expires_at"
t.boolean "private", default: true, null: false
@@ -261,42 +272,45 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.datetime "created_at"
end
+ add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+
create_table "tags", force: true do |t|
t.string "name"
end
create_table "users", force: true do |t|
- t.string "email", default: "", null: false
- t.string "encrypted_password", limit: 128, default: "", null: false
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
+ t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "name"
- t.boolean "admin", default: false, null: false
- t.integer "projects_limit", default: 10
- t.string "skype", default: "", null: false
- t.string "linkedin", default: "", null: false
- t.string "twitter", default: "", null: false
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", default: 10
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
t.string "authentication_token"
- t.integer "theme_id", default: 1, null: false
+ t.integer "theme_id", default: 1, null: false
t.string "bio"
- t.integer "failed_attempts", default: 0
+ t.integer "failed_attempts", default: 0
t.datetime "locked_at"
t.string "extern_uid"
t.string "provider"
t.string "username"
- t.boolean "can_create_group", default: true, null: false
- t.boolean "can_create_team", default: true, null: false
+ t.boolean "can_create_group", default: true, null: false
+ t.boolean "can_create_team", default: true, null: false
t.string "state"
- t.integer "color_scheme_id", default: 1, null: false
- t.integer "notification_level", default: 1, null: false
+ t.integer "color_scheme_id", default: 1, null: false
+ t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
t.string "avatar"
@@ -304,14 +318,15 @@ ActiveRecord::Schema.define(version: 20140122122549) do
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
- t.boolean "hide_no_ssh_key", default: false
- t.string "website_url", default: "", null: false
+ t.boolean "hide_no_ssh_key", default: false
+ t.string "website_url", default: "", null: false
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
+ add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
add_index "users", ["name"], name: "index_users_on_name", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_index "users", ["username"], name: "index_users_on_username", using: :btree
@@ -330,8 +345,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
create_table "users_projects", force: true do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "project_access", default: 0, null: false
t.integer "notification_level", default: 3, null: false
end
@@ -343,8 +358,8 @@ ActiveRecord::Schema.define(version: 20140122122549) do
create_table "web_hooks", force: true do |t|
t.string "url"
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "type", default: "ProjectHook"
t.integer "service_id"
t.boolean "push_events", default: true, null: false
diff --git a/doc/api/README.md b/doc/api/README.md
index 517a9fae6f..850666953a 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -127,6 +127,8 @@ But when you want to create a link to web page - use `http:://host/project/issu
+ [Projects](projects.md)
+ [Project Snippets](project_snippets.md)
+ [Repositories](repositories.md)
++ [Repository Files](repository_files.md)
++ [Commits](commits.md)
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
diff --git a/doc/api/commits.md b/doc/api/commits.md
new file mode 100644
index 0000000000..69b44a2e83
--- /dev/null
+++ b/doc/api/commits.md
@@ -0,0 +1,95 @@
+# Commits API
+
+## List repository commits
+
+Get a list of repository commits in a project.
+
+```
+GET /projects/:id/repository/commits
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
+
+```json
+[
+ {
+ "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+ "short_id": "ed899a2f4b5",
+ "title": "Replace sanitize with escape once",
+ "author_name": "Dmitriy Zaporozhets",
+ "author_email": "dzaporozhets@sphereconsultinginc.com",
+ "created_at": "2012-09-20T11:50:22+03:00"
+ },
+ {
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "randx",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "created_at": "2012-09-20T09:06:12+03:00"
+ }
+]
+```
+
+## Get a single commit
+
+Get a specific commit identified by the commit hash or name of a branch or tag.
+
+```
+GET /projects/:id/repository/commits/:sha
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `sha` (required) - The commit hash or name of a repository branch or tag
+
+```json
+{
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "randx",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "created_at": "2012-09-20T09:06:12+03:00",
+ "committed_date": "2012-09-20T09:06:12+03:00",
+ "authored_date": "2012-09-20T09:06:12+03:00",
+ "parent_ids" : [
+ "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
+ ]
+}
+```
+
+
+## Get the diff of a commit
+
+Get the diff of a commit in a project.
+
+```
+GET /projects/:id/repository/commits/:sha/diff
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `sha` (required) - The name of a repository branch or tag or if not given the default branch
+
+```json
+[
+ {
+ "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
+ "new_path": "doc/update/5.4-to-6.0.md",
+ "old_path": "doc/update/5.4-to-6.0.md",
+ "a_mode": null,
+ "b_mode": "100644",
+ "new_file": false,
+ "renamed_file": false,
+ "deleted_file": false
+ }
+]
+```
+
+
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 559553a110..e795298c67 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -162,7 +162,7 @@ GET /projects/:id/events
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
@@ -231,6 +231,7 @@ POST /projects
Parameters:
+ `name` (required) - new project name
++ `namespace_id` (optional) - namespace for the new project (defaults to user)
+ `description` (optional) - short project description
+ `issues_enabled` (optional)
+ `wall_enabled` (optional)
@@ -290,7 +291,7 @@ GET /projects/:id/members
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `query` (optional) - Query string to search for members
@@ -304,7 +305,7 @@ GET /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `user_id` (required) - The ID of a user
```json
@@ -332,7 +333,7 @@ POST /projects/:id/members
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `user_id` (required) - The ID of a user to add
+ `access_level` (required) - Project access level
@@ -347,7 +348,7 @@ PUT /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `user_id` (required) - The ID of a team member
+ `access_level` (required) - Project access level
@@ -362,7 +363,7 @@ DELETE /projects/:id/members/:user_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `user_id` (required) - The ID of a team member
This method is idempotent and can be called multiple times with the same parameters.
@@ -383,7 +384,7 @@ GET /projects/:id/hooks
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
### Get project hook
@@ -396,7 +397,7 @@ GET /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `hook_id` (required) - The ID of a project hook
```json
@@ -422,7 +423,7 @@ POST /projects/:id/hooks
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `url` (required) - The hook URL
+ `push_events` - Trigger hook on push events
+ `issues_events` - Trigger hook on issues events
@@ -439,7 +440,7 @@ PUT /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `hook_id` (required) - The ID of a project hook
+ `url` (required) - The hook URL
+ `push_events` - Trigger hook on push events
@@ -458,7 +459,7 @@ DELETE /projects/:id/hooks/:hook_id
Parameters:
-+ `id` (required) - The ID or NAME of a project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `hook_id` (required) - The ID of hook to delete
Note the JSON response differs if the hook is available or not. If the project hook
@@ -477,7 +478,7 @@ GET /projects/:id/repository/branches
Parameters:
-+ `id` (required) - The ID of the project
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
[
@@ -539,7 +540,7 @@ GET /projects/:id/repository/branches/:branch
Parameters:
-+ `id` (required) - The ID of the project.
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `branch` (required) - The name of the branch.
@@ -553,7 +554,7 @@ PUT /projects/:id/repository/branches/:branch/protect
Parameters:
-+ `id` (required) - The ID of the project.
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `branch` (required) - The name of the branch.
@@ -567,7 +568,7 @@ PUT /projects/:id/repository/branches/:branch/unprotect
Parameters:
-+ `id` (required) - The ID of the project.
++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
+ `branch` (required) - The name of the branch.
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 0160726300..65ea361535 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -204,99 +204,6 @@ Parameters:
]
```
-
-## List repository commits
-
-Get a list of repository commits in a project.
-
-```
-GET /projects/:id/repository/commits
-```
-
-Parameters:
-
-+ `id` (required) - The ID of a project
-+ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
-
-```json
-[
- {
- "id": "ed899a2f4b50b4370feeea94676502b42383c746",
- "short_id": "ed899a2f4b5",
- "title": "Replace sanitize with escape once",
- "author_name": "Dmitriy Zaporozhets",
- "author_email": "dzaporozhets@sphereconsultinginc.com",
- "created_at": "2012-09-20T11:50:22+03:00"
- },
- {
- "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
- "short_id": "6104942438c",
- "title": "Sanitize for network graph",
- "author_name": "randx",
- "author_email": "dmitriy.zaporozhets@gmail.com",
- "created_at": "2012-09-20T09:06:12+03:00"
- }
-]
-```
-
-## Get a single commit
-
-Get a specific commit identified by the commit hash or name of a branch or tag.
-
-```
-GET /projects/:id/repository/commits/:sha
-```
-
-Parameters:
-
-+ `id` (required) - The ID of a project
-+ `sha` (required) - The commit hash or name of a repository branch or tag
-
-```json
-{
- "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
- "short_id": "6104942438c",
- "title": "Sanitize for network graph",
- "author_name": "randx",
- "author_email": "dmitriy.zaporozhets@gmail.com",
- "created_at": "2012-09-20T09:06:12+03:00",
- "committed_date": "2012-09-20T09:06:12+03:00",
- "authored_date": "2012-09-20T09:06:12+03:00",
- "parent_ids" : [
- "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
- ]
-}
-```
-
-
-## Get the diff of a commit
-
-Get the diff of a commit in a project.
-
-```
-GET /projects/:id/repository/commits/:sha/diff
-```
-
-Parameters:
-
-+ `id` (required) - The ID of a project
-+ `sha` (required) - The name of a repository branch or tag or if not given the default branch
-
-```json
-[
- {
- "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
- "new_path": "doc/update/5.4-to-6.0.md",
- "old_path": "doc/update/5.4-to-6.0.md",
- "a_mode": null,
- "b_mode": "100644",
- "new_file": false,
- "renamed_file": false,
- "deleted_file": false
- }
-]
-```
-
## List repository tree
Get a list of repository files and directories in a project.
@@ -388,44 +295,3 @@ GET /projects/:id/repository/archive
Parameters:
+ `id` (required) - The ID of a project
+ `sha` (optional) - The commit sha to download defaults to the tip of the default branch
-
-
-## Create new file in repository
-
-```
-POST /projects/:id/repository/files
-```
-
-Parameters:
-
-+ `file_path` (optional) - Full path to new file. Ex. lib/class.rb
-+ `branch_name` (required) - The name of branch
-+ `encoding` (optional) - 'text' or 'base64'. Text is default.
-+ `content` (required) - File content
-+ `commit_message` (required) - Commit message
-
-## Update existing file in repository
-
-```
-PUT /projects/:id/repository/files
-```
-
-Parameters:
-
-+ `file_path` (required) - Full path to file. Ex. lib/class.rb
-+ `branch_name` (required) - The name of branch
-+ `encoding` (optional) - 'text' or 'base64'. Text is default.
-+ `content` (required) - New file content
-+ `commit_message` (required) - Commit message
-
-## Delete existing file in repository
-
-```
-DELETE /projects/:id/repository/files
-```
-
-Parameters:
-
-+ `file_path` (required) - Full path to file. Ex. lib/class.rb
-+ `branch_name` (required) - The name of branch
-+ `commit_message` (required) - Commit message
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
new file mode 100644
index 0000000000..cafab8c828
--- /dev/null
+++ b/doc/api/repository_files.md
@@ -0,0 +1,102 @@
+# CRUD for repository files
+
+## Create, read, update and delete repository files using this API
+
+- - -
+
+## Get file from repository
+
+Allows you to receive information about file in repository like name, size, content.
+Note that file content is Base64 encoded.
+
+```
+GET /projects/:id/repository/files
+```
+
+Example response:
+
+```json
+{
+ "file_name": "key.rb",
+ "file_path": "app/models/key.rb",
+ "size": 1476,
+ "encoding": "base64",
+ "content": "IyA9PSBTY2hlbWEgSW5mb3...",
+ "ref": "master",
+ "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
+ "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50"
+}
+```
+
+Parameters:
+
++ `file_path` (required) - Full path to new file. Ex. lib/class.rb
++ `ref` (required) - The name of branch, tag or commit
+
+## Create new file in repository
+
+```
+POST /projects/:id/repository/files
+```
+
+Example response:
+
+```json
+{
+ "file_name": "app/project.rb",
+ "branch_name": "master",
+}
+```
+
+Parameters:
+
++ `file_path` (required) - Full path to new file. Ex. lib/class.rb
++ `branch_name` (required) - The name of branch
++ `encoding` (optional) - 'text' or 'base64'. Text is default.
++ `content` (required) - File content
++ `commit_message` (required) - Commit message
+
+## Update existing file in repository
+
+```
+PUT /projects/:id/repository/files
+```
+
+Example response:
+
+```json
+{
+ "file_name": "app/project.rb",
+ "branch_name": "master",
+}
+```
+
+Parameters:
+
++ `file_path` (required) - Full path to file. Ex. lib/class.rb
++ `branch_name` (required) - The name of branch
++ `encoding` (optional) - 'text' or 'base64'. Text is default.
++ `content` (required) - New file content
++ `commit_message` (required) - Commit message
+
+## Delete existing file in repository
+
+```
+DELETE /projects/:id/repository/files
+```
+
+Example response:
+
+```json
+{
+ "file_name": "app/project.rb",
+ "branch_name": "master",
+}
+```
+
+Parameters:
+
++ `file_path` (required) - Full path to file. Ex. lib/class.rb
++ `branch_name` (required) - The name of branch
++ `commit_message` (required) - Commit message
+
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index db22f0bda8..8a772344b7 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -1,23 +1,183 @@
-# GitLab project architecture
+# GitLab Architecture Overview
+---
-GitLab project consists of two parts: GitLab and GitLab shell.
+# Software delivery
-## GitLab
+There are two editions of GitLab: [Enterprise Edition](https://www.gitlab.com/features/) (EE) and [Community Edition](http://gitlab.org/gitlab-ce/) (CE).
+GitLab CE is delivered via git from the [gitlabhq repository](https://gitlab.com/gitlab-org/gitlab-ce/tree/master).
+New versions of GitLab are released in stable branches and the master branch is for bleeding edge development.
-Web application with background jobs workers.
-Provides you with UI and most of functionality.
-For some operations like repo creation - uses GitLab shell.
+EE releases are available not long after CE releases.
+To obtain the GitLab EE there is a [repository at gitlab.com](https://gitlab.com/subscribers/gitlab-ee).
+For more information about the release process see the section 'New versions and upgrading' in the readme.
-Uses:
- * Ruby as main language for application code and most libraries.
- * [Rails](http://rubyonrails.org/) web framework as main framework for application.
- * Mysql or postgres as main databases. Used for persistent data storage(users, project, issues etc).
- * Redis database. Used for cache and exchange data between some components.
- * Python2 because of [pygments](http://pygments.org/) as code syntax highlighter.
+Both EE and CE require an add-on component called gitlab-shell.
+It is obtained from the [gitlab-shell repository](https://gitlab.com/gitlab-org/gitlab-shell/tree/master).
+New versions are usually tags but staying on the master branch will give you the latest stable version.
+New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical.
-## GitLab shell
+# System Layout
-Command line ruby application. Used by GitLab through shell commands.
-It provides interface to all kind of manipulations with repositories and ssh keys.
-Full list of commands you can find in README of GitLab shell repo.
-Works on pure ruby and do not require any additional software.
+When referring to ~git in the picures it means the home directory of the git user which is typically /home/git.
+
+GitLab is primarily installed within the `/home/git` user home directory as `git` user.
+Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable).
+The bare repositories are located in `/home/git/repositories`.
+GitLab is a ruby on rails application so the particulars of the inner workings can be learned by studying how a ruby on rails application works.
+To serve repositories over SSH there's an add-on application called gitlab-shell which is installed in `/home/git/gitlab-shell`.
+
+## Components
+
+
+
+A typical install of GitLab will be on Ubuntu Linux or RHEL/CentOS.
+It uses Nginx or Apache as a web front end to proxypass the Unicorn web server.
+By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported.
+The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets.
+GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server.
+It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incomming jobs.
+The GitLab web app uses MySQL or PostgreSQL for persistent database information (e.g. users, permissions, issues, other meta data).
+GitLab stores the bare git repositories it serves in `/home/git/repositories` by default.
+It also keeps default branch and hook information with the bare repository.
+`/home/git/gitlab-satellites` keeps checked out repositories when performing actions such as a merge request, editing files in the web interface, etc.
+The satellite repository is used by the web interface for editing repositories and the wiki which is also a git repository.
+When serving repositories over HTTP/HTTPS GitLab utilizes the GitLab API to resolve authorization and access as well as serving git objects.
+
+The add-on component gitlab-shell serves repositories over SSH.
+It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited.
+gitlab-shell accesses the bare repositories directly to serve git objects and communicates with redis to submit jobs to Sidekiq for GitLab to process.
+ gitlab-shell queries the GitLab API to determine authorization and access.
+
+## Installation Folder Summary
+
+To summarize here's the [directory structure of the `git` user home directory](../install/structure.md).
+
+
+## Processes
+
+ ps aux | grep '^git'
+
+GitLab has several components to operate.
+As a system user (i.e. any user that is not the `git` user) it requires a persistent database (MySQL/PostreSQL) and redis database.
+It also uses Apache httpd or nginx to proxypass Unicorn.
+As the `git` user it starts Sidekiq and Unicorn (a simple ruby HTTP server running on port `8080` by default).
+Under the gitlab user there are normally 4 processes: `unicorn_rails master` (1 process), `unicorn_rails worker` (2 processes), `sidekiq` (1 process).
+
+## Repository access
+
+Repositories get accessed via HTTP or SSH.
+HTTP cloning/push/pull utilizes the GitLab API and SSH cloning is handled by gitlab-shell (previously explained).
+
+# Troubleshooting
+
+See the README for more information.
+
+## Init scripts of the services
+
+The GitLab init script starts and stops Unicorn and Sidekiq.
+
+```
+/etc/init.d/gitlab
+Usage: service gitlab {start|stop|restart|reload|status}
+```
+
+Redis (key-value store/non-persistent database)
+
+```
+/etc/init.d/redis
+Usage: /etc/init.d/redis {start|stop|status|restart|condrestart|try-restart}
+```
+
+SSH daemon
+
+```
+/etc/init.d/sshd
+Usage: /etc/init.d/sshd {start|stop|restart|reload|force-reload|condrestart|try-restart|status}
+```
+
+Web server (one of the following)
+
+```
+/etc/init.d/httpd
+Usage: httpd {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}
+
+$ /etc/init.d/nginx
+Usage: nginx {start|stop|restart|reload|force-reload|status|configtest}
+```
+
+Persistent database (one of the following)
+
+```
+/etc/init.d/mysqld
+Usage: /etc/init.d/mysqld {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
+
+$ /etc/init.d/postgresql
+Usage: /etc/init.d/postgresql {start|stop|restart|reload|force-reload|status} [version ..]
+```
+
+## Log locations of the services
+
+Note: `/home/git/` is shorthand for `/home/git`.
+
+gitlabhq (includes Unicorn and Sidekiq logs)
+
+* `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `githost.log`, `satellites.log`, and `unicorn.stderr.log` normally.
+
+gitlab-shell
+
+* `/home/git/gitlab-shell/gitlab-shell.log`
+
+ssh
+
+* `/var/log/auth.log` auth log (on Ubuntu).
+* `/var/log/secure` auth log (on RHEL).
+
+nginx
+
+* `/var/log/nginx/` contains error and access logs.
+
+Apache httpd
+
+* [Explanation of apache logs](http://httpd.apache.org/docs/2.2/logs.html).
+* `/var/log/apache2/` contains error and output logs (on Ubuntu).
+* `/var/log/httpd/` contains error and output logs (on RHEL).
+
+redis
+
+* `/var/log/redis/redis.log` there are also logrotated logs there.
+
+PostgreSQL
+
+* `/var/log/postgresql/*`
+
+MySQL
+
+* `/var/log/mysql/*`
+* `/var/log/mysql.*`
+
+## GitLab specific config files
+
+GitLab has configuration files located in `/home/git/gitlab/config/*`.
+Commonly referenced config files include:
+
+* `gitlab.yml` - GitLab configuration.
+* `unicorn.rb` - Unicorn web server settings.
+* `database.yml` - Database connection settings.
+
+gitlab-shell has a configuration file at `/home/git/gitlab-shell/config.yml`.
+
+## Maintenance Tasks
+
+[GitLab](https://gitlab.com/gitlab-org/gitlab-ce/tree/master) provides rake tasks with which you see version information and run a quick check on your configuration to ensure it is configured properly within the application.
+See [maintenance rake tasks](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/raketasks/maintenance.md).
+In a nutshell, do the following:
+
+```
+sudo -i -u git
+cd gitlab
+bundle exec rake gitlab:env:info RAILS_ENV=production
+bundle exec rake gitlab:check RAILS_ENV=production
+```
+
+Note: It is recommended to log into the `git` user using `sudo -i -u git` or `sudo su - git`.
+While the sudo commands provided by gitlabhq work in Ubuntu they do not always work in RHEL.
diff --git a/doc/development/resources/gitlab_diagram_overview.odg b/doc/development/resources/gitlab_diagram_overview.odg
new file mode 100644
index 0000000000..b7e02f8fa7
Binary files /dev/null and b/doc/development/resources/gitlab_diagram_overview.odg differ
diff --git a/doc/development/resources/gitlab_diagram_overview.png b/doc/development/resources/gitlab_diagram_overview.png
new file mode 100644
index 0000000000..b5831cf0a4
Binary files /dev/null and b/doc/development/resources/gitlab_diagram_overview.png differ
diff --git a/doc/install/databases.md b/doc/install/database_mysql.md
similarity index 67%
rename from doc/install/databases.md
rename to doc/install/database_mysql.md
index 1d9405dfa9..4cf9b94c1a 100644
--- a/doc/install/databases.md
+++ b/doc/install/database_mysql.md
@@ -1,10 +1,6 @@
-# Setup Database
-
-GitLab supports the following databases:
-
-* MySQL (preferred)
-* PostgreSQL
+## Note
+We do not recommend using MySQL due to various issues. For example, case [(in)sensitivity](https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html) and [problems](http://bugs.mysql.com/bug.php?id=65830) that [suggested](http://bugs.mysql.com/bug.php?id=50909) [fixes](http://bugs.mysql.com/bug.php?id=65830) [have](http://bugs.mysql.com/bug.php?id=63164).
## MySQL
@@ -16,7 +12,7 @@ GitLab supports the following databases:
# Secure your installation.
sudo mysql_secure_installation
-
+
# Login to MySQL
mysql -u root -p
@@ -47,25 +43,3 @@ GitLab supports the following databases:
mysql> \q
# You are done installing the database and can go back to the rest of the installation.
-
-
-## PostgreSQL
-
- # Install the database packages
- sudo apt-get install -y postgresql-9.1 postgresql-client libpq-dev
-
- # Login to PostgreSQL
- sudo -u postgres psql -d template1
-
- # Create a user for GitLab. (change $password to a real password)
- template1=# CREATE USER git;
-
- # Create the GitLab production database & grant all privileges on database
- template1=# CREATE DATABASE gitlabhq_production OWNER git;
-
- # Quit the database session
- template1=# \q
-
- # Try connecting to the new database with the new user
- sudo -u git -H psql -d gitlabhq_production
-
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 575f776de5..3145f64b9e 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -10,9 +10,9 @@ If this is unclear check the [GitLab Blog](http://blog.gitlab.org/) for installa
This guide is long because it covers many cases and includes all commands you need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
-This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements.
+This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements. An unofficial guide for RHEL/CentOS can be found in the [GitLab recipes repository](https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/install/centos).
-This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please consult [the installation section in the readme](https://github.com/gitlabhq/gitlabhq#installation).
+This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
The following steps have been known to work. Please **use caution when you deviate** from this guide. Make sure you don't violate any assumptions GitLab makes about its environment. For example many people run into permission problems because they changed the location of directories or run services as the wrong user.
@@ -56,26 +56,6 @@ Install the required packages:
sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate
-Make sure you have the right version of Python installed.
-
- # Install Python
- sudo apt-get install -y python
-
- # Make sure that Python is 2.5+ (3.x is not supported at the moment)
- python --version
-
- # If it's Python 3 you might need to install Python 2 separately
- sudo apt-get install -y python2.7
-
- # Make sure you can access Python via python2
- python2 --version
-
- # If you get a "command not found" error create a link to the python binary
- sudo ln -s /usr/bin/python /usr/bin/python2
-
- # For reStructuredText markup language support install required package:
- sudo apt-get install -y python-docutils
-
Make sure you have the right version of Git installed
# Install Git
@@ -164,7 +144,25 @@ GitLab Shell is an ssh access and repository management software developed speci
# 5. Database
-To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md).
+We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](doc/install/database_mysql.md).
+
+ # Install the database packages
+ sudo apt-get install -y postgresql-9.1 postgresql-client libpq-dev
+
+ # Login to PostgreSQL
+ sudo -u postgres psql -d template1
+
+ # Create a user for GitLab.
+ template1=# CREATE USER git;
+
+ # Create the GitLab production database & grant all privileges on database
+ template1=# CREATE DATABASE gitlabhq_production OWNER git;
+
+ # Quit the database session
+ template1=# \q
+
+ # Try connecting to the new database with the new user
+ sudo -u git -H psql -d gitlabhq_production
# 6. GitLab
@@ -236,8 +234,8 @@ Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
## Configure GitLab DB settings
- # Mysql
- sudo -u git cp config/database.yml.mysql config/database.yml
+ # PostgreSQL
+ sudo -u git cp config/database.yml.postgresql config/database.yml
# Make sure to update username/password in config/database.yml.
# You only need to adapt the production settings (first part).
@@ -247,10 +245,8 @@ Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
sudo -u git -H editor config/database.yml
or
-
- # PostgreSQL
- sudo -u git cp config/database.yml.postgresql config/database.yml
-
+ # Mysql
+ sudo -u git cp config/database.yml.mysql config/database.yml
# Make config/database.yml readable to git only
sudo -u git -H chmod o-rwx config/database.yml
@@ -259,12 +255,12 @@ Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup.
cd /home/git/gitlab
- # For MySQL (note, the option says "without ... postgres")
- sudo -u git -H bundle install --deployment --without development test postgres aws
-
- # Or for PostgreSQL (note, the option says "without ... mysql")
+ # For PostgreSQL (note, the option says "without ... mysql")
sudo -u git -H bundle install --deployment --without development test mysql aws
+ # Or if you use MySQL (note, the option says "without ... postgres")
+ sudo -u git -H bundle install --deployment --without development test postgres aws
+
## Initialize Database and Activate Advanced Features
@@ -370,6 +366,15 @@ nobody can access your GitLab by using this login information later on.
# Advanced Setup Tips
+## Additional markup styles
+
+Apart from the always supported markdown style there are other rich text files that GitLab can display.
+But you might have to install a depency to do so.
+Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
+For example, reStructuredText markup language support requires python-docutils:
+
+ sudo apt-get install -y python-docutils
+
## Custom Redis Connection
If you'd like Resque to connect to a Redis server on a non-standard port or on
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index a263e9361e..ea172733b1 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -1,6 +1,6 @@
# Operating Systems
-GitLab is developed for the Linux operating system.
+GitLab is developed for the Linux operating system. For the installations options and instructions please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
## GitLab officially supports
@@ -13,13 +13,13 @@ GitLab is developed for the Linux operating system.
- CentOS
- Oracle Linux
-## Not officially supported
+## Not officially supported are
- Arch Linux
- Fedora
- Gentoo
-On the above distributions it is pretty easy to install GitLab yourself.
+But on the above distributions it is pretty easy to install GitLab yourself.
## Unsupported Unix Systems
@@ -47,7 +47,7 @@ We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) but GitLab
- 1 core works for under 100 users but the responsiveness might suffer
- **2 cores** is the **recommended** number of cores and supports up to 100 users
-- 4 cores supports about 1,000 users
+- 4 cores supports up to 1,000 users
- 8 cores supports up to 10,000 users
## Memory
@@ -70,11 +70,6 @@ Apart from a local hard drive you can also mount a volume that supports the netw
If you have enough RAM memory and a recent CPU the speed of GitLab is mainly limited by hard drive seek times. Having a fast drive (7200 RPM and up) or a solid state drive (SSD) will improve the responsiveness of GitLab.
-# Installation troubles and reporting success or failure
-
-If you have troubles installing GitLab following the [official installation guide](installation.md)
-or want to share your experience installing GitLab on a not officially supported
-platform, please follow the the [contribution guide](/CONTRIBUTING.md).
# Supported webbrowsers
diff --git a/doc/install/structure.md b/doc/install/structure.md
index f580ea159a..67ca189537 100644
--- a/doc/install/structure.md
+++ b/doc/install/structure.md
@@ -10,18 +10,12 @@ This is the directory structure you will end up with following the instructions
| |-- gitlab-shell
| |-- repositories
+* `/home/git/.ssh` - contains openssh settings. Specifically the `authorized_keys` file managed by gitlab-shell.
+* `/home/git/gitlab` - GitLab core software.
+* `/home/git/gitlab-satellites` - checked out repositories for merge requests and file editing from web UI. This can be treated as a temporary files directory.
+* `/home/git/gitlab-shell` - Core add-on component of gitlab. Maintains SSH cloning and other functionality.
+* `/home/git/repositories` - bare repositories for all projects organized by namespace. This is where the git repositories which are pushed/pulled are maintained for all projects. **This area is critical data for projects. [Keep a backup](../raketasks/backup_restore.md)**
-**/home/git/.ssh**
+*Note: the default locations for gitlab-satellites and repositories can be configured in `config/gitlab.yml` of gitlab and `config.yml` of gitlab-shell.*
-**/home/git/gitlab**
- This is where GitLab lives.
-
-**/home/git/gitlab-satellites**
- Contains a copy of all repositories with a working tree.
- It's used for merge requests, editing files, etc.
-
-**/home/git/repositories**
- Holds all your repositories in bare format.
- This is the place Git uses when you pull/push to your projects.
-
-You can change them in your `config/gitlab.yml` file.
+To see a more in-depth overview see the [GitLab architecture doc](../development/architecture.md).
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 6b5308afc4..f49f09756a 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -1,41 +1,37 @@
----------------------------------------------
-Table of Contents
+Table of Contents
=================
----------------------------------------------
-[GitLab Flavored Markdown](#toc_3)
--------------------------------
-[Newlines](#toc_4)
-[Multiple underscores in words](#toc_5)
-[URL autolinking](#toc_6)
-[Code and Syntax Highlighting](#toc_7)
-[Emoji](#toc_8)
-[Special GitLab references](#toc_9)
+**[GitLab Flavored Markdown](#gitlab-flavored-markdown-gfm)**
+[Newlines](#newlines)
+[Multiple underscores in words](#multiple-underscores-in-words)
+[URL autolinking](#url-autolinking)
+[Code and Syntax Highlighting](#code-and-syntax-highlighting)
+[Emoji](#emoji)
+[Special GitLab references](#special-gitlab-references)
+**[Standard Markdown](#standard-markdown)**
-[Standard Markdown](#toc_10)
-------------------------------
-[Headers](#toc_11)
-[Emphasis](#toc_20)
-[Lists](#toc_21)
-[Links](#toc_22)
-[Images](#toc_23)
-[Blockquotes](#toc_24)
-[Inline HTML](#toc_25)
-[Horizontal Rule](#toc_26)
-[Line Breaks](#toc_27)
-[Tables](#toc_28)
+[Headers](#headers)
+[Emphasis](#emphasis)
+[Lists](#lists)
+[Links](#links)
+[Images](#images)
+[Blockquotes](#blockquotes)
+[Inline HTML](#inline-html)
+[Horizontal Rule](#horizontal-rule)
+[Line Breaks](#line-breaks)
+[Tables](#tables)
-[References](#toc_29)
----------------------
+**[References](#references)**
----------------------------------------------
-
-GitLab Flavored Markdown (GFM)
+GitLab Flavored Markdown (GFM)
==============================
For GitLab we developed something we call "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few significant ways to add some useful functionality.
@@ -49,7 +45,10 @@ You can use GFM in
* milestones
* wiki pages
-
+You can also use other rich text files in GitLab.
+You might have to install a depency to do so.
+Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
+
Newlines
--------
The biggest difference that GFM introduces is in the handling of linebreaks. With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors. GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended.
@@ -61,8 +60,7 @@ The next paragraph contains two phrases separated by a single newline character:
Roses are red
Violets are blue
-
-
+
Multiple underscores in words
-----------------------------
It is not reasonable to italicize just _part_ of a word, especially when you're dealing with code and names that often appear with multiple underscores. Therefore, GFM ignores multiple underscores in words.
@@ -73,7 +71,6 @@ It is not reasonable to italicize just _part_ of a word, especially when you're
perform_complicated_task
do_this_and_do_that_and_another_thing
-
URL autolinking
---------------
GFM will autolink standard URLs you copy and paste into your text.
@@ -83,12 +80,10 @@ So if you want to link to a URL (instead of a textural link), you can simply put
http://www.google.com
-
## Code and Syntax Highlighting
Blocks of code are either fenced by lines with three back-ticks ```, or are indented with four spaces. Only the fenced code blocks support syntax highlighting.
-
```no-highlight
Inline `code` has `back-ticks around` it.
```
@@ -101,14 +96,14 @@ Example:
var s = "JavaScript syntax highlighting";
alert(s);
```
-
+
```python
def function():
#indenting works just fine in the fenced code block
s = "Python syntax highlighting"
print s
```
-
+
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
@@ -116,7 +111,7 @@ Example:
```
```
- No language indicated, so no syntax highlighting.
+ No language indicated, so no syntax highlighting.
s = "There is no highlighting for this."
But let's throw in a tag.
```
@@ -147,7 +142,6 @@ s = "There is no highlighting for this."
But let's throw in a tag.
```
-
Emoji
-----
@@ -159,7 +153,7 @@ Emoji
If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes.
- Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup:
+ Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup:
Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you:
@@ -169,9 +163,8 @@ You can use it to point out a :bug: or warn about :monkey:patches. And if someon
If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes.
-Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup:
+Consult the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) for a list of all supported emoji codes. :thumbsup:
-
Special GitLab References
-----
@@ -179,7 +172,6 @@ GFM recognized special references.
You can easily reference e.g. a team member, an issue, or a commit within a project.
GFM will turn that reference into a link so you can navigate between them easily.
-
GFM will recognize the following:
* @foo : for team members
@@ -189,13 +181,10 @@ GFM will recognize the following:
* 1234567 : for commits
* \[file\](path/to/file) : for file references
-
-
----------------------------------
# Standard Markdown
----------------------------------
-
## Headers
```no-highlight
@@ -230,7 +219,54 @@ Alt-H1
Alt-H2
------
-
+### Header IDs and links
+
+All markdown rendered headers automatically get IDs, except for comments.
+
+On hover a link to those IDs becomes visible to make it easier to copy the link to the header to give it to someone else.
+
+The IDs are generated from the content of the header according to the following rules:
+
+1) remove the heading hashes `#` and process the rest of the line as it would be processed if it were not a header
+2) from the result, remove all HTML tags, but keep their inner content
+3) convert all characters to lowercase
+4) convert all characters except `[a-z0-9_-]` into hyphens `-`
+5) transform multiple adjacent hyphens into a single hyphen
+6) remove trailing and heading hyphens
+
+For example:
+
+```
+###### ..Ab_c-d. e [anchor](url) ..
+```
+
+which renders as:
+
+###### ..Ab_c-d. e [anchor](url) ..
+
+will first be converted by step 1) into a string like:
+
+```
+..Ab_c-d. e <a href="url">anchor</a> <img src="url" alt="alt text"/>..
+```
+
+After removing the tags in step 2) we get:
+
+```
+..Ab_c-d. e anchor ..
+```
+
+And applying all the other steps gives the id:
+
+```
+ab_c-d-e-anchor
+```
+
+Note in particular how:
+
+- for markdown anchors `[text](url)`, only the `text` is used
+- markdown images `` are completely ignored
+
## Emphasis
```no-highlight
@@ -251,18 +287,16 @@ Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
-
-
## Lists
```no-highlight
1. First ordered list item
2. Another item
- * Unordered sub-list.
+ * Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
1. Ordered sub-list
-4. And another item.
-
+4. And another item.
+
Some text that should be aligned with the above item.
* Unordered list can use asterisks
@@ -272,18 +306,17 @@ Strikethrough uses two tildes. ~~Scratch this.~~
1. First ordered list item
2. Another item
- * Unordered sub-list.
+ * Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
1. Ordered sub-list
-4. And another item.
-
+4. And another item.
+
Some text that should be aligned with the above item.
* Unordered list can use asterisks
- Or minuses
+ Or pluses
-
## Links
There are two ways to create links.
@@ -320,30 +353,28 @@ Some text to show that the reference links can follow later.
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
-
## Images
Here's our logo (hover to see the title text):
- Inline-style:
- 
+ Inline-style:
+ 
- Reference-style:
- ![alt text][logo]
+ Reference-style:
+ ![alt text1][logo]
- [logo]: /assets/logo-white.png "Logo Title Text 2"
+ [logo]: assets/logo-white.png
Here's our logo (hover to see the title text):
-Inline-style:
+Inline-style:

-Reference-style:
+Reference-style:
![alt text][logo]
[logo]: /assets/logo-white.png "Logo Title Text 2"
-
## Blockquotes
```no-highlight
@@ -352,7 +383,7 @@ Reference-style:
Quote break.
-> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
+> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
```
> Blockquotes are very handy in email to emulate reply text.
@@ -360,12 +391,11 @@ Quote break.
Quote break.
-> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
+> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
-
## Inline HTML
-You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
+You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
```no-highlight
@@ -385,7 +415,6 @@ You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
- Does *not* work **very** well. Use HTML tags.
-
## Horizontal Rule
```
@@ -418,10 +447,9 @@ ___
Underscores
-
## Line Breaks
-My basic recommendation for learning how line breaks work is to experiment and discover -- hit <Enter> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. "Markdown Toggle" is your friend.
+My basic recommendation for learning how line breaks work is to experiment and discover -- hit <Enter> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. "Markdown Toggle" is your friend.
Here are some things to try out:
@@ -438,11 +466,9 @@ Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
-This line is also begins a separate paragraph, but...
+This line is also begins a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
-
-
## Tables
Tables aren't part of the core Markdown spec, but they are part of GFM and Markdown Here supports them.
@@ -461,10 +487,8 @@ Code above produces next output:
| cell 1 | cell 2 |
| cell 3 | cell 4 |
-
------------
-
## References
* This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index d2da64f3d3..bdff6ad5da 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -78,3 +78,18 @@ Restoring repositories:
- Restoring repository abcd... [DONE]
Deleting tmp directories...[DONE]
```
+
+### Configure cron to make daily backups
+
+```
+cd /home/git/gitlab
+sudo -u git -H editor config/gitlab.yml # Enable keep_time in the backup section to automatically delete old backups
+sudo -u git crontab -e # Edit the crontab for the git user
+```
+
+Add the following lines at the bottom:
+
+```
+# Create a full backup of the GitLab repositories and SQL database every day at 2am
+0 2 * * * cd /home/git/gitlab && PATH=/usr/local/bin:/usr/bin:/bin bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index 8fa2ed1311..3847410485 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -1,6 +1,6 @@
### Add user as a developer to all projects
-```
+```bash
bundle exec rake gitlab:import:user_to_projects[username@domain.tld]
```
@@ -11,6 +11,22 @@ Notes:
* admin users are added as masters
-```
+```bash
bundle exec rake gitlab:import:all_users_to_all_projects
```
+
+### Add user as a developer to all projects
+
+```
+bundle exec rake gitlab:import:user_to_groups[username@domain.tld]
+```
+
+### Add all users to all groups
+
+Notes:
+
+* admin users are added as owners so they can add additional users to the group
+
+```
+bundle exec rake gitlab:import:all_users_to_all_groups
+```
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 17f69915d1..28fc260b33 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -61,13 +61,16 @@ After making the release branch new commits are cherry-picked from master. When
* 17th: feature freeze (stop merging new features in master)
* 18th: UI freeze (stop merging changes to the user interface)
* 19th: code freeze (stop merging non-essential code improvements)
-* 20th: release candidate 1 (VERSION x.x.0.pre, tag and tweet about x.x.0.rc1)
+* 20th: release candidate 1 (VERSION x.x.0.rc1, tag and tweet about x.x.0.rc1)
* 21st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems)
* 22nd: release (VERSION x.x.0, create x-x-stable branch, tag, blog and tweet)
* 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems)
+* 24-end of month: release Enterprise Edition and upgrade GitLab Cloud
+* 1-7th: official merge window (see contributing guide)
+* 8-16th: bugfixes and sponsored features
# Write a blog post
* Mention what GitLab is on the second line: GitLab is open source software to collaborate on code.
* Select and thank the the Most Valuable Person (MVP) of this release.
-* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
+* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
\ No newline at end of file
diff --git a/doc/update/5.4-to-6.0.md b/doc/update/5.4-to-6.0.md
index bcba3ee4d0..312e9a4608 100644
--- a/doc/update/5.4-to-6.0.md
+++ b/doc/update/5.4-to-6.0.md
@@ -87,14 +87,14 @@ sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
Note: We switched from Puma in GitLab 5.4 to unicorn in GitLab 6.0.
-* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/masterconfig/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/masterconfig/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/unicorn.rb.example but with your settings.
### 7. Update Init script
```bash
sudo rm /etc/init.d/gitlab
-sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-0-stable/lib/support/init.d/gitlab
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
sudo chmod +x /etc/init.d/gitlab
```
diff --git a/doc/update/6.0-to-6.1.md b/doc/update/6.0-to-6.1.md
index ac8f0a77ef..b7fd763485 100644
--- a/doc/update/6.0-to-6.1.md
+++ b/doc/update/6.0-to-6.1.md
@@ -71,7 +71,7 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
```bash
sudo rm /etc/init.d/gitlab
-sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-1-stable/lib/support/init.d/gitlab
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
sudo chmod +x /etc/init.d/gitlab
```
diff --git a/doc/update/6.1-to-6.2.md b/doc/update/6.1-to-6.2.md
index 7342a9117c..3c453a5ab4 100644
--- a/doc/update/6.1-to-6.2.md
+++ b/doc/update/6.1-to-6.2.md
@@ -87,7 +87,7 @@ sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
```bash
sudo rm /etc/init.d/gitlab
-sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-2-stable/lib/support/init.d/gitlab
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
sudo chmod +x /etc/init.d/gitlab
```
diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md
index 6874056498..cfe75a6f14 100644
--- a/doc/update/6.3-to-6.4.md
+++ b/doc/update/6.3-to-6.4.md
@@ -9,7 +9,9 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
### 1. Stop server
- sudo service gitlab stop
+```bash
+sudo service gitlab stop
+````
### 2. Get latest code
@@ -52,18 +54,24 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
### 5. Start application
- sudo service gitlab start
- sudo service nginx restart
+```bash
+sudo service gitlab start
+sudo service nginx restart
+```
-### 8. Check application status
+### 6. Check application status
Check if GitLab and its environment are configured correctly:
- sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```bash
+sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```
To make sure you didn't miss anything run a more thorough check with:
- sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```bash
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
If all items are green, then congratulations upgrade complete!
diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md
index 2b1fa2744f..c88be3582c 100644
--- a/doc/update/6.4-to-6.5.md
+++ b/doc/update/6.4-to-6.5.md
@@ -16,8 +16,20 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```bash
cd /home/git/gitlab
sudo -u git -H git fetch --all
+```
+
+For Gitlab Community Edition:
+
+```bash
sudo -u git -H git checkout 6-5-stable
-# For GitLab Enterprise Edition: sudo -u git -H git checkout 6-5-stable-ee
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 6-5-stable-ee
```
### 3. Update gitlab-shell (and its config)
@@ -65,7 +77,7 @@ To make sure you didn't miss anything run a more thorough check with:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
-If all items are green, then congratulations upgrade complete!
+If all items are green, then congratulations upgrade is complete!
## Things went south? Revert to previous version (6.4)
@@ -79,3 +91,4 @@ Follow the [`upgrade guide from 6.3 to 6.4`](6.3-to-6.4.md), except for the data
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 1eec5a8f39..305ef961be 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -21,10 +21,22 @@ __GitLab Upgrader is available only for GitLab version 6.4.2 or higher__
cd /home/git/gitlab
sudo -u git -H ruby script/upgrade.rb
- # it also supports -y option to avoid waiting for user input
+ # to perform a non-interactive install (no user input required) you can add -y
# sudo -u git -H ruby script/upgrade.rb -y
### 3. Start application
sudo service gitlab start
sudo service nginx restart
+
+### 4. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
diff --git a/features/admin/groups.feature b/features/admin/groups.feature
index 6fed9a3486..352c1b3803 100644
--- a/features/admin/groups.feature
+++ b/features/admin/groups.feature
@@ -2,7 +2,7 @@ Feature: Admin Groups
Background:
Given I sign in as an admin
And I have group with projects
- And Create gitlab user "John"
+ And User "John Doe" exists
And I visit admin groups page
Scenario: See group list
@@ -17,5 +17,5 @@ Feature: Admin Groups
@javascript
Scenario: Add user into projects in group
When I visit admin group page
- When I select user "John" from user list as "Reporter"
- Then I should see "John" in team list in every project as "Reporter"
+ When I select user "John Doe" from user list as "Reporter"
+ Then I should see "John Doe" in team list in every project as "Reporter"
diff --git a/features/dashboard/help.feature b/features/dashboard/help.feature
new file mode 100644
index 0000000000..02ec688f80
--- /dev/null
+++ b/features/dashboard/help.feature
@@ -0,0 +1,8 @@
+Feature: Help
+ Background:
+ Given I sign in as a user
+ And I visit the "Rake Tasks" help page
+
+ Scenario: The markdown should be rendered correctly
+ Then I should see "Rake Tasks" page markdown rendered
+ And Header "Rebuild project satellites" should have correct ids and links
diff --git a/features/group.feature b/features/group.feature
new file mode 100644
index 0000000000..aa49056fee
--- /dev/null
+++ b/features/group.feature
@@ -0,0 +1,116 @@
+Feature: Groups
+ Background:
+ Given I sign in as "John Doe"
+ And "John Doe" is owner of group "Owned"
+ And "John Doe" is guest of group "Guest"
+
+ @javascript
+ Scenario: I should see group "Owned" dashboard list
+ When I visit group "Owned" page
+ Then I should see group "Owned" projects list
+ And I should see projects activity feed
+
+ Scenario: Create a group from dasboard
+ When I visit group "Owned" page
+ And I visit dashboard page
+ And I click new group link
+ And submit form with new group "Samurai" info
+ Then I should be redirected to group "Samurai" page
+ And I should see newly created group "Samurai"
+
+ Scenario: I should see group "Owned" issues list
+ Given project from group "Owned" has issues assigned to me
+ When I visit group "Owned" issues page
+ Then I should see issues from group "Owned" assigned to me
+
+ Scenario: I should see group "Owned" merge requests list
+ Given project from group "Owned" has merge requests assigned to me
+ When I visit group "Owned" merge requests page
+ Then I should see merge requests from group "Owned" assigned to me
+
+ @javascript
+ Scenario: I should add user to projects in group "Owned"
+ Given User "Mary Jane" exists
+ When I visit group "Owned" members page
+ And I select user "Mary Jane" from list with role "Reporter"
+ Then I should see user "Mary Jane" in team list
+
+ Scenario: I should see edit group "Owned" page
+ When I visit group "Owned" settings page
+ And I change group "Owned" name to "new-name"
+ Then I should see new group "Owned" name
+
+ Scenario: I edit group "Owned" avatar
+ When I visit group "Owned" settings page
+ And I change group "Owned" avatar
+ And I visit group "Owned" settings page
+ Then I should see new group "Owned" avatar
+ And I should see the "Remove avatar" button
+
+ Scenario: I remove group "Owned" avatar
+ When I visit group "Owned" settings page
+ And I have group "Owned" avatar
+ And I visit group "Owned" settings page
+ And I remove group "Owned" avatar
+ Then I should not see group "Owned" avatar
+ And I should not see the "Remove avatar" button
+
+ # Leave
+
+ @javascript
+ Scenario: Owner should be able to remove himself from group if he is not the last owner
+ Given "Mary Jane" is owner of group "Owned"
+ When I visit group "Owned" members page
+ Then I should see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+ When I click on the "Remove User From Group" button for "John Doe"
+ And I visit group "Owned" members page
+ Then I should not see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+
+ @javascript
+ Scenario: Owner should not be able to remove himself from group if he is the last owner
+ Given "Mary Jane" is guest of group "Owned"
+ When I visit group "Owned" members page
+ Then I should see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+ Then I should not see the "Remove User From Group" button for "Mary Jane"
+
+ @javascript
+ Scenario: Guest should be able to remove himself from group
+ Given "Mary Jane" is guest of group "Guest"
+ When I visit group "Guest" members page
+ Then I should see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+ When I click on the "Remove User From Group" button for "John Doe"
+ When I visit group "Guest" members page
+ Then I should not see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+
+ @javascript
+ Scenario: Guest should be able to remove himself from group even if he is the only user in the group
+ When I visit group "Guest" members page
+ Then I should see user "John Doe" in team list
+ When I click on the "Remove User From Group" button for "John Doe"
+ When I visit group "Guest" members page
+ Then I should not see user "John Doe" in team list
+
+ # Remove others
+
+ @javascript
+ Scenario: Owner should be able to remove other users from group
+ Given "Mary Jane" is owner of group "Owned"
+ When I visit group "Owned" members page
+ Then I should see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+ When I click on the "Remove User From Group" button for "Mary Jane"
+ When I visit group "Owned" members page
+ Then I should see user "John Doe" in team list
+ Then I should not see user "Mary Jane" in team list
+
+ Scenario: Guest should not be able to remove other users from group
+ Given "Mary Jane" is guest of group "Guest"
+ When I visit group "Guest" members page
+ Then I should see user "John Doe" in team list
+ Then I should see user "Mary Jane" in team list
+ Then I should not see the "Remove User From Group" button for "Mary Jane"
diff --git a/features/group/create_group.feature b/features/group/create_group.feature
deleted file mode 100644
index b77f3599e6..0000000000
--- a/features/group/create_group.feature
+++ /dev/null
@@ -1,11 +0,0 @@
-Feature: Groups
- Background:
- Given I sign in as a user
-
- Scenario: Create a group from dasboard
- Given I have group with projects
- And I visit dashboard page
- When I click new group link
- And submit form with new group info
- Then I should be redirected to group page
- And I should see newly created group
diff --git a/features/group/group.feature b/features/group/group.feature
deleted file mode 100644
index 9fec19a4dc..0000000000
--- a/features/group/group.feature
+++ /dev/null
@@ -1,33 +0,0 @@
-Feature: Groups
- Background:
- Given I sign in as a user
- And I have group with projects
-
- @javascript
- Scenario: I should see group dashboard list
- When I visit group page
- Then I should see projects list
- And I should see projects activity feed
-
- Scenario: I should see group issues list
- Given project from group has issues assigned to me
- When I visit group issues page
- Then I should see issues from this group assigned to me
-
- Scenario: I should see group merge requests list
- Given project from group has merge requests assigned to me
- When I visit group merge requests page
- Then I should see merge requests from this group assigned to me
-
- @javascript
- Scenario: I should add user to projects in Group
- Given I have new user "John"
- When I visit group members page
- And I select user "John" from list with role "Reporter"
- Then I should see user "John" in team list
-
- Scenario: I should see edit group page
- When I visit group settings page
- And I change group name
- Then I should see new group name
-
diff --git a/features/profile/emails.feature b/features/profile/emails.feature
new file mode 100644
index 0000000000..148fc76608
--- /dev/null
+++ b/features/profile/emails.feature
@@ -0,0 +1,25 @@
+Feature: Profile Emails
+ Background:
+ Given I sign in as a user
+ And I visit profile emails page
+
+ Scenario: I should see emails
+ Then I should see my emails
+
+ Scenario: Add new email
+ Given I submit new email "my@email.com"
+ Then I should see new email "my@email.com"
+ And I should see my emails
+
+ Scenario: Add duplicate email
+ Given I submit duplicate email @user.email
+ Then I should not have @user.email added
+ And I should see my emails
+
+ Scenario: Remove email
+ Given I submit new email "my@email.com"
+ Then I should see new email "my@email.com"
+ And I should see my emails
+ Then I click link "Remove" for "my@email.com"
+ Then I should not see email "my@email.com"
+ And I should see my emails
diff --git a/features/profile/group.feature b/features/profile/group.feature
new file mode 100644
index 0000000000..70b682e291
--- /dev/null
+++ b/features/profile/group.feature
@@ -0,0 +1,47 @@
+Feature: Profile Group
+ Background:
+ Given I sign in as "John Doe"
+ And "John Doe" is owner of group "Owned"
+ And "John Doe" is guest of group "Guest"
+
+ # Leave groups
+
+ @javascript
+ Scenario: Owner should be able to leave from group if he is not the last owner
+ Given "Mary Jane" is owner of group "Owned"
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should see group "Guest" in group list
+ When I click on the "Leave" button for group "Owned"
+ And I visit profile groups page
+ Then I should not see group "Owned" in group list
+ Then I should see group "Guest" in group list
+
+ @javascript
+ Scenario: Owner should not be able to leave from group if he is the last owner
+ Given "Mary Jane" is guest of group "Owned"
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should see group "Guest" in group list
+ Then I should not see the "Leave" button for group "Owned"
+
+ @javascript
+ Scenario: Guest should be able to leave from group
+ Given "Mary Jane" is guest of group "Guest"
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should see group "Guest" in group list
+ When I click on the "Leave" button for group "Guest"
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should not see group "Guest" in group list
+
+ @javascript
+ Scenario: Guest should be able to leave from group even if he is the only user in the group
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should see group "Guest" in group list
+ When I click on the "Leave" button for group "Guest"
+ When I visit profile groups page
+ Then I should see group "Owned" in group list
+ Then I should not see group "Guest" in group list
diff --git a/features/profile/profile.feature b/features/profile/profile.feature
index 8b6ee6fd67..44bb190f62 100644
--- a/features/profile/profile.feature
+++ b/features/profile/profile.feature
@@ -6,6 +6,13 @@ Feature: Profile
Given I visit profile page
Then I should see my profile info
+ Scenario: I can see groups I belong to
+ Given I have group with projects
+ When I visit profile page
+ And I click on my profile picture
+ Then I should see my user page
+ And I should see groups I belong to
+
Scenario: I edit profile
Given I visit profile page
Then I change my profile info
diff --git a/features/project/commits/commits_user_lookup.feature b/features/project/commits/commits_user_lookup.feature
new file mode 100644
index 0000000000..f3864c0ab3
--- /dev/null
+++ b/features/project/commits/commits_user_lookup.feature
@@ -0,0 +1,14 @@
+Feature: Project Browse Commits User Lookup
+ Background:
+ Given I sign in as a user
+ And I own a project
+ And I have the user that authored the commits
+ And I visit my project's commits page
+
+ Scenario: I browse commit from list
+ Given I click on commit link
+ Then I see commit info
+
+ Scenario: I browse another commit from list
+ Given I click on another commit link
+ Then I see other commit info
\ No newline at end of file
diff --git a/features/project/issues/filter_labels.feature b/features/project/issues/filter_labels.feature
new file mode 100644
index 0000000000..8df7a119e8
--- /dev/null
+++ b/features/project/issues/filter_labels.feature
@@ -0,0 +1,26 @@
+Feature: Project Filter Labels
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And project "Shop" has issue "Bugfix1" with tags: "bug", "feature"
+ And project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement"
+ And project "Shop" has issue "Feature1" with tags: "feature"
+ Given I visit project "Shop" issues page
+
+ Scenario: I should see project issues
+ Then I should see "bug" in labels filter
+ And I should see "feature" in labels filter
+ And I should see "enhancement" in labels filter
+
+ Scenario: I filter by one label
+ Given I click link "bug"
+ Then I should see "Bugfix1" in issues list
+ And I should see "Bugfix2" in issues list
+ And I should not see "Feature1" in issues list
+
+ Scenario: I filter by two labels
+ Given I click link "bug"
+ And I click link "feature"
+ Then I should see "Bugfix1" in issues list
+ And I should not see "Bugfix2" in issues list
+ And I should not see "Feature1" in issues list
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index 67986784bc..033051991e 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -55,3 +55,15 @@ Feature: Project Issues
And I fill in issue search with ".3"
Then I should see "Release 0.3" in issues
And I should not see "Release 0.4" in issues
+
+ # Markdown
+
+ Scenario: Headers inside the description should have ids generated for them.
+ Given I visit issue page "Release 0.4"
+ Then Header "Description header" should have correct id and link
+
+ @javascript
+ Scenario: Headers inside comments should not have ids generated for them.
+ Given I visit issue page "Release 0.4"
+ And I leave a comment with a header containing "Comment with a header"
+ Then The comment with the header should not have an ID
diff --git a/features/project/issues/milestones.feature b/features/project/issues/milestones.feature
index 2f38acf14d..e67b5d2d86 100644
--- a/features/project/issues/milestones.feature
+++ b/features/project/issues/milestones.feature
@@ -22,3 +22,9 @@ Feature: Project Milestones
Given the milestone has open and closed issues
And I click link "v2.2"
Then I should see 3 issues
+
+ # Markdown
+
+ Scenario: Headers inside the description should have ids generated for them.
+ Given I click link "v2.2"
+ Then Header "Description header" should have correct id and link
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 946f676012..556b96338d 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -29,7 +29,6 @@ Feature: Project Merge Requests
And I click link "Close"
Then I should see closed merge request "Bug NS-04"
- @javascript
Scenario: I submit new unassigned merge request
Given I click link "New Merge Request"
And I submit new merge request "Wiki Feature"
@@ -77,3 +76,15 @@ Feature: Project Merge Requests
Then I modify merge commit message
And I accept this merge request
Then I should see merged request
+
+ # Markdown
+
+ Scenario: Headers inside the description should have ids generated for them.
+ When I visit merge request page "Bug NS-04"
+ Then Header "Description header" should have correct id and link
+
+ @javascript
+ Scenario: Headers inside comments should not have ids generated for them.
+ Given I visit merge request page "Bug NS-04"
+ And I leave a comment with a header containing "Comment with a header"
+ Then The comment with the header should not have an ID
diff --git a/features/project/source/markdown_render.feature b/features/project/source/markdown_render.feature
index 04467b6664..42d6ebcb1c 100644
--- a/features/project/source/markdown_render.feature
+++ b/features/project/source/markdown_render.feature
@@ -4,6 +4,15 @@ Feature: Project markdown render
And I own project "Delta"
Given I visit project source page
+ # -------------------------------------------
+ # README
+ # -------------------------------------------
+
+ Scenario: Tree view should have correct links in README
+ Given I go directory which contains README file
+ And I click on a relative link in README
+ Then I should see the correct markdown
+
Scenario: I browse files from master branch
Then I should see files from repository in master
And I should see rendered README which contains correct links
@@ -28,6 +37,14 @@ Feature: Project markdown render
And I click on Maintenance in README
Then I should see correct maintenance file rendered
+ Scenario: README headers should have header links
+ Then I should see rendered README which contains correct links
+ And Header "Application details" should have correct id and link
+
+ # -------------------------------------------
+ # File content
+ # -------------------------------------------
+
Scenario: I navigate to doc directory to view documentation in master
And I navigate to the doc/api/README
And I see correct file rendered
@@ -40,6 +57,14 @@ Feature: Project markdown render
And I click on raketasks in doc/api/README
Then I should see correct directory rendered
+ Scenario: I navigate to doc directory to view user doc in master
+ And I navigate to the doc/api/README
+ And Header "GitLab API" should have correct id and link
+
+ # -------------------------------------------
+ # Markdown branch README
+ # -------------------------------------------
+
Scenario: I browse files from markdown branch
When I visit markdown branch
Then I should see files from repository in markdown branch
@@ -68,6 +93,10 @@ Feature: Project markdown render
And I click on raketasks in doc/api/README
Then I should see correct directory rendered for markdown branch
+ # -------------------------------------------
+ # Wiki
+ # -------------------------------------------
+
Scenario: I create a wiki page with different links
Given I go to wiki page
And I add various links to the wiki page
@@ -81,12 +110,7 @@ Feature: Project markdown render
And I click on Rake tasks link
Then I see Rake tasks directory
- Scenario: I visit the help page with markdown
- Given I visit to the help page
- And I select a page with markdown
- Then I should see a help page with markdown
-
- Scenario: Tree view should have correct links in README
- Given I go directory which contains README file
- And I click on a relative link in README
- Then I should see the correct markdown
+ Scenario: Wiki headers should have should have ids generated for them.
+ Given I go to wiki page
+ And I add a header to the wiki page
+ Then Wiki header should have correct id and link
diff --git a/features/public/public_projects.feature b/features/public/public_projects.feature
index d6574ca900..57fe834b4b 100644
--- a/features/public/public_projects.feature
+++ b/features/public/public_projects.feature
@@ -62,3 +62,40 @@ Feature: Public Projects Feature
Given public empty project "Empty Public Project"
When I visit empty project page
Then I should see empty public project details
+
+ Scenario: I visit public project issues page as a non authorized user
+ Given I visit project "Community" page
+ And I visit "Community" issues page
+ Then I should see list of issues for "Community" project
+
+ Scenario: I visit public project issues page as authorized user
+ Given I sign in as a user
+ Given I visit project "Community" page
+ And I visit "Community" issues page
+ Then I should see list of issues for "Community" project
+
+ Scenario: I visit internal project issues page as authorized user
+ Given I sign in as a user
+ Given I visit project "Internal" page
+ And I visit "Internal" issues page
+ Then I should see list of issues for "Internal" project
+
+ Scenario: I visit public project merge requests page as an authorized user
+ Given I sign in as a user
+ Given I visit project "Community" page
+ And I visit "Community" merge requests page
+ And project "Community" has "Bug fix" open merge request
+ Then I should see list of merge requests for "Community" project
+
+ Scenario: I visit public project merge requests page as a non authorized user
+ Given I visit project "Community" page
+ And I visit "Community" merge requests page
+ And project "Community" has "Bug fix" open merge request
+ Then I should see list of merge requests for "Community" project
+
+ Scenario: I visit internal project merge requests page as an authorized user
+ Given I sign in as a user
+ Given I visit project "Internal" page
+ And I visit "Internal" merge requests page
+ And project "Internal" has "Feature implemented" open merge request
+ Then I should see list of merge requests for "Internal" project
diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb
index 013fa6da8b..9c1bcfefb9 100644
--- a/features/steps/admin/admin_groups.rb
+++ b/features/steps/admin/admin_groups.rb
@@ -1,6 +1,7 @@
class AdminGroups < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
+ include SharedUser
include SharedActiveTab
include Select2Helper
@@ -20,10 +21,6 @@ class AdminGroups < Spinach::FeatureSteps
@project.team << [current_user, :master]
end
- And 'Create gitlab user "John"' do
- create(:user, name: "John")
- end
-
And 'submit form with new group info' do
fill_in 'group_name', with: 'gitlab'
fill_in 'group_description', with: 'Group description'
@@ -39,8 +36,8 @@ class AdminGroups < Spinach::FeatureSteps
current_path.should == admin_group_path(Group.last)
end
- When 'I select user "John" from user list as "Reporter"' do
- user = User.find_by(name: "John")
+ When 'I select user "John Doe" from user list as "Reporter"' do
+ user = User.find_by(name: "John Doe")
select2(user.id, from: "#user_ids", multiple: true)
within "#new_team_member" do
select "Reporter", from: "group_access"
@@ -48,9 +45,9 @@ class AdminGroups < Spinach::FeatureSteps
click_button "Add users into group"
end
- Then 'I should see "John" in team list in every project as "Reporter"' do
+ Then 'I should see "John Doe" in team list in every project as "Reporter"' do
within ".group-users-list" do
- page.should have_content "John"
+ page.should have_content "John Doe"
page.should have_content "Reporter"
end
end
diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb
index 15d7c46c69..81472d1ca3 100644
--- a/features/steps/group/group.rb
+++ b/features/steps/group/group.rb
@@ -1,45 +1,35 @@
class Groups < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
+ include SharedGroup
+ include SharedUser
include Select2Helper
- Then 'I should see projects list' do
- current_user.authorized_projects.each do |project|
+ Then 'I should see group "Owned" projects list' do
+ Group.find_by(name: "Owned").projects.each do |project|
page.should have_link project.name
end
end
- And 'I have group with projects' do
- @group = create(:group)
- @group.add_owner(current_user)
- @project = create(:project, namespace: @group)
- @event = create(:closed_issue_event, project: @project)
-
- @project.team << [current_user, :master]
- end
-
And 'I should see projects activity feed' do
page.should have_content 'closed issue'
end
- Then 'I should see issues from this group assigned to me' do
+ Then 'I should see issues from group "Owned" assigned to me' do
assigned_to_me(:issues).each do |issue|
page.should have_content issue.title
end
end
- Then 'I should see merge requests from this group assigned to me' do
+ Then 'I should see merge requests from group "Owned" assigned to me' do
assigned_to_me(:merge_requests).each do |issue|
page.should have_content issue.title[0..80]
end
end
- Given 'I have new user "John"' do
- create(:user, name: "John")
- end
-
- And 'I select user "John" from list with role "Reporter"' do
- user = User.find_by(name: "John")
+ And 'I select user "Mary Jane" from list with role "Reporter"' do
+ user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane")
+ click_link 'Add members'
within ".users-group-form" do
select2(user.id, from: "#user_ids", multiple: true)
select "Reporter", from: "group_access"
@@ -47,19 +37,34 @@ class Groups < Spinach::FeatureSteps
click_button "Add users into group"
end
- Then 'I should see user "John" in team list' do
+ Then 'I should see user "John Doe" in team list' do
projects_with_access = find(".ui-box .well-list")
- projects_with_access.should have_content("John")
+ projects_with_access.should have_content("John Doe")
end
- Given 'project from group has issues assigned to me' do
+ Then 'I should not see user "John Doe" in team list' do
+ projects_with_access = find(".ui-box .well-list")
+ projects_with_access.should_not have_content("John Doe")
+ end
+
+ Then 'I should see user "Mary Jane" in team list' do
+ projects_with_access = find(".ui-box .well-list")
+ projects_with_access.should have_content("Mary Jane")
+ end
+
+ Then 'I should not see user "Mary Jane" in team list' do
+ projects_with_access = find(".ui-box .well-list")
+ projects_with_access.should_not have_content("Mary Jane")
+ end
+
+ Given 'project from group "Owned" has issues assigned to me' do
create :issue,
project: project,
assignee: current_user,
author: current_user
end
- Given 'project from group has merge requests assigned to me' do
+ Given 'project from group "Owned" has merge requests assigned to me' do
create :merge_request,
source_project: project,
target_project: project,
@@ -71,44 +76,94 @@ class Groups < Spinach::FeatureSteps
click_link "New group"
end
- And 'submit form with new group info' do
+ And 'submit form with new group "Samurai" info' do
fill_in 'group_name', with: 'Samurai'
fill_in 'group_description', with: 'Tokugawa Shogunate'
click_button "Create group"
end
- Then 'I should see newly created group' do
+ Then 'I should be redirected to group "Samurai" page' do
+ current_path.should == group_path(Group.last)
+ end
+
+ Then 'I should see newly created group "Samurai"' do
page.should have_content "Samurai"
page.should have_content "Tokugawa Shogunate"
page.should have_content "You will only see events from projects in this group"
end
- Then 'I should be redirected to group page' do
- current_path.should == group_path(Group.last)
- end
-
- And 'I change group name' do
+ And 'I change group "Owned" name to "new-name"' do
fill_in 'group_name', with: 'new-name'
click_button "Save group"
end
- Then 'I should see new group name' do
+ Then 'I should see new group "Owned" name' do
within ".navbar-gitlab" do
page.should have_content "group: new-name"
end
end
+ step 'I change group "Owned" avatar' do
+ attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png'))
+ click_button "Save group"
+ Group.find_by(name: "Owned").reload
+ end
+
+ step 'I should see new group "Owned" avatar' do
+ Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader
+ Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png"
+ end
+
+ step 'I should see the "Remove avatar" button' do
+ page.should have_link("Remove avatar")
+ end
+
+ step 'I have group "Owned" avatar' do
+ attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png'))
+ click_button "Save group"
+ Group.find_by(name: "Owned").reload
+ end
+
+ step 'I remove group "Owned" avatar' do
+ click_link "Remove avatar"
+ Group.find_by(name: "Owned").reload
+ end
+
+ step 'I should not see group "Owned" avatar' do
+ Group.find_by(name: "Owned").avatar?.should be_false
+ end
+
+ step 'I should not see the "Remove avatar" button' do
+ page.should_not have_link("Remove avatar")
+ end
+
+ step 'I click on the "Remove User From Group" button for "John Doe"' do
+ find(:css, 'li', text: "John Doe").find(:css, 'a.btn-remove').click
+ # poltergeist always confirms popups.
+ end
+
+ step 'I click on the "Remove User From Group" button for "Mary Jane"' do
+ find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click
+ # poltergeist always confirms popups.
+ end
+
+ step 'I should not see the "Remove User From Group" button for "John Doe"' do
+ find(:css, 'li', text: "John Doe").should_not have_selector(:css, 'a.btn-remove')
+ # poltergeist always confirms popups.
+ end
+
+ step 'I should not see the "Remove User From Group" button for "Mary Jane"' do
+ find(:css, 'li', text: "Mary Jane").should_not have_selector(:css, 'a.btn-remove')
+ # poltergeist always confirms popups.
+ end
+
protected
- def current_group
- @group ||= Group.first
- end
-
- def project
- current_group.projects.first
- end
-
def assigned_to_me key
project.send(key).where(assignee_id: current_user.id)
end
+
+ def project
+ Group.find_by(name: "Owned").projects.first
+ end
end
diff --git a/features/steps/help.rb b/features/steps/help.rb
new file mode 100644
index 0000000000..aa147fd65c
--- /dev/null
+++ b/features/steps/help.rb
@@ -0,0 +1,21 @@
+class Spinach::Features::Help < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedMarkdown
+
+ step 'I visit the help page' do
+ visit help_path
+ end
+
+ step 'I visit the "Rake Tasks" help page' do
+ visit help_raketasks_path
+ end
+
+ step 'I should see "Rake Tasks" page markdown rendered' do
+ page.should have_content "GitLab provides some specific rake tasks to enable special features or perform maintenance tasks"
+ end
+
+ step 'Header "Rebuild project satellites" should have correct ids and links' do
+ header_should_have_correct_id_and_link(3, 'Rebuild project satellites', 'rebuild-project-satellites')
+ end
+end
diff --git a/features/steps/profile/group.rb b/features/steps/profile/group.rb
new file mode 100644
index 0000000000..03144104c7
--- /dev/null
+++ b/features/steps/profile/group.rb
@@ -0,0 +1,44 @@
+class ProfileGroup < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedGroup
+ include SharedPaths
+ include SharedUser
+
+ # Leave
+
+ step 'I click on the "Leave" button for group "Owned"' do
+ find(:css, 'li', text: "Owner").find(:css, 'i.icon-signout').click
+ # poltergeist always confirms popups.
+ end
+
+ step 'I click on the "Leave" button for group "Guest"' do
+ find(:css, 'li', text: "Guest").find(:css, 'i.icon-signout').click
+ # poltergeist always confirms popups.
+ end
+
+ step 'I should not see the "Leave" button for group "Owned"' do
+ find(:css, 'li', text: "Owner").should_not have_selector(:css, 'i.icon-signout')
+ # poltergeist always confirms popups.
+ end
+
+ step 'I should not see the "Leave" button for groupr "Guest"' do
+ find(:css, 'li', text: "Guest").should_not have_selector(:css, 'i.icon-signout')
+ # poltergeist always confirms popups.
+ end
+
+ step 'I should see group "Owned" in group list' do
+ page.should have_content("Owned")
+ end
+
+ step 'I should not see group "Owned" in group list' do
+ page.should_not have_content("Owned")
+ end
+
+ step 'I should see group "Guest" in group list' do
+ page.should have_content("Guest")
+ end
+
+ step 'I should not see group "Guest" in group list' do
+ page.should_not have_content("Guest")
+ end
+end
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 33ae6c7299..879bcf41b4 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -173,4 +173,17 @@ class Profile < Spinach::FeatureSteps
page.should have_content current_user.name
end
end
+
+ step 'I have group with projects' do
+ @group = create(:group)
+ @group.add_owner(current_user)
+ @project = create(:project, namespace: @group)
+ @event = create(:closed_issue_event, project: @project)
+
+ @project.team << [current_user, :master]
+ end
+
+ step 'I should see groups I belong to' do
+ page.should have_css('.profile-groups-avatars', visible: true)
+ end
end
diff --git a/features/steps/profile/profile_emails.rb b/features/steps/profile/profile_emails.rb
new file mode 100644
index 0000000000..99588c8599
--- /dev/null
+++ b/features/steps/profile/profile_emails.rb
@@ -0,0 +1,48 @@
+class ProfileEmails < Spinach::FeatureSteps
+ include SharedAuthentication
+
+ Then 'I visit profile emails page' do
+ visit profile_emails_path
+ end
+
+ Then 'I should see my emails' do
+ page.should have_content(@user.email)
+ @user.emails.each do |email|
+ page.should have_content(email.email)
+ end
+ end
+
+ And 'I submit new email "my@email.com"' do
+ fill_in "email_email", with: "my@email.com"
+ click_button "Add"
+ end
+
+ Then 'I should see new email "my@email.com"' do
+ email = @user.emails.find_by(email: "my@email.com")
+ email.should_not be_nil
+ page.should have_content("my@email.com")
+ end
+
+ Then 'I should not see email "my@email.com"' do
+ email = @user.emails.find_by(email: "my@email.com")
+ email.should be_nil
+ page.should_not have_content("my@email.com")
+ end
+
+ Then 'I click link "Remove" for "my@email.com"' do
+ # there should only be one remove button at this time
+ click_link "Remove"
+ # force these to reload as they have been cached
+ @user.emails.reload
+ end
+
+ And 'I submit duplicate email @user.email' do
+ fill_in "email_email", with: @user.email
+ click_button "Add"
+ end
+
+ Then 'I should not have @user.email added' do
+ email = @user.emails.find_by(email: @user.email)
+ email.should be_nil
+ end
+end
diff --git a/features/steps/profile/profile_notifications.rb b/features/steps/profile/profile_notifications.rb
index 7a41687dfd..e884df3098 100644
--- a/features/steps/profile/profile_notifications.rb
+++ b/features/steps/profile/profile_notifications.rb
@@ -8,6 +8,5 @@ class ProfileNotifications < Spinach::FeatureSteps
step 'I should see global notifications settings' do
page.should have_content "Notifications settings"
- page.should have_content "Global setting"
end
end
diff --git a/features/steps/project/project_active_tab.rb b/features/steps/project/project_active_tab.rb
index e04a17168b..dcc252f476 100644
--- a/features/steps/project/project_active_tab.rb
+++ b/features/steps/project/project_active_tab.rb
@@ -57,7 +57,9 @@ class ProjectActiveTab < Spinach::FeatureSteps
end
Given 'I click the "Edit" tab' do
- click_link('Edit')
+ within '.project-settings-nav' do
+ click_link('Project')
+ end
end
Given 'I click the "Hooks" tab' do
@@ -73,7 +75,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
end
Then 'the active sub nav should be Edit' do
- ensure_active_sub_nav('Edit Project')
+ ensure_active_sub_nav('Project')
end
Then 'the active sub nav should be Hooks' do
diff --git a/features/steps/project/project_browse_commits_user_lookup.rb b/features/steps/project/project_browse_commits_user_lookup.rb
new file mode 100644
index 0000000000..328be37355
--- /dev/null
+++ b/features/steps/project/project_browse_commits_user_lookup.rb
@@ -0,0 +1,35 @@
+class ProjectBrowseCommitsUserLookup < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Given 'I have the user that authored the commits' do
+ @user = create(:user, email: 'dmitriy.zaporozhets@gmail.com')
+ create(:email, { user: @user, email: 'dzaporozhets@sphereconsultinginc.com' })
+ end
+
+ Given 'I click on commit link' do
+ visit project_commit_path(@project, ValidCommit::ID)
+ end
+
+ Given 'I click on another commit link' do
+ visit project_commit_path(@project, ValidCommitWithAltEmail::ID)
+ end
+
+ Then 'I see commit info' do
+ page.should have_content ValidCommit::MESSAGE
+ check_author_link(ValidCommit::AUTHOR_EMAIL)
+ end
+
+ Then 'I see other commit info' do
+ page.should have_content ValidCommitWithAltEmail::MESSAGE
+ check_author_link(ValidCommitWithAltEmail::AUTHOR_EMAIL)
+ end
+
+ def check_author_link(email)
+ author_link = find('.commit-author-link')
+ author_link['href'].should == user_path(@user)
+ author_link['data-original-title'].should == email
+ find('.commit-author-name').text.should == @user.name
+ end
+end
diff --git a/features/steps/project/project_filter_labels.rb b/features/steps/project/project_filter_labels.rb
new file mode 100644
index 0000000000..5926d69d6c
--- /dev/null
+++ b/features/steps/project/project_filter_labels.rb
@@ -0,0 +1,70 @@
+class ProjectFilterLabels < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Then 'I should see "bug" in labels filter' do
+ within ".labels-filter" do
+ page.should have_content "bug"
+ end
+ end
+
+ And 'I should see "feature" in labels filter' do
+ within ".labels-filter" do
+ page.should have_content "feature"
+ end
+ end
+
+ And 'I should see "enhancement" in labels filter' do
+ within ".labels-filter" do
+ page.should have_content "enhancement"
+ end
+ end
+
+ Then 'I should see "Bugfix1" in issues list' do
+ within ".issues-list" do
+ page.should have_content "Bugfix1"
+ end
+ end
+
+ And 'I should see "Bugfix2" in issues list' do
+ within ".issues-list" do
+ page.should have_content "Bugfix2"
+ end
+ end
+
+ And 'I should not see "Bugfix2" in issues list' do
+ within ".issues-list" do
+ page.should_not have_content "Bugfix2"
+ end
+ end
+
+ And 'I should not see "Feature1" in issues list' do
+ within ".issues-list" do
+ page.should_not have_content "Feature1"
+ end
+ end
+
+ Given 'I click link "bug"' do
+ click_link "bug"
+ end
+
+ Given 'I click link "feature"' do
+ click_link "feature"
+ end
+
+ And 'project "Shop" has issue "Bugfix1" with tags: "bug", "feature"' do
+ project = Project.find_by(name: "Shop")
+ create(:issue, title: "Bugfix1", project: project, label_list: ['bug', 'feature'])
+ end
+
+ And 'project "Shop" has issue "Bugfix2" with tags: "bug", "enhancement"' do
+ project = Project.find_by(name: "Shop")
+ create(:issue, title: "Bugfix2", project: project, label_list: ['bug', 'enhancement'])
+ end
+
+ And 'project "Shop" has issue "Feature1" with tags: "feature"' do
+ project = Project.find_by(name: "Shop")
+ create(:issue, title: "Feature1", project: project, label_list: 'feature')
+ end
+end
diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb
index 4a503dfaf4..a92fd50584 100644
--- a/features/steps/project/project_issues.rb
+++ b/features/steps/project/project_issues.rb
@@ -3,6 +3,7 @@ class ProjectIssues < Spinach::FeatureSteps
include SharedProject
include SharedNote
include SharedPaths
+ include SharedMarkdown
Given 'I should see "Release 0.4" in issues' do
page.should have_content "Release 0.4"
@@ -121,7 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps
create(:issue,
title: "Release 0.4",
project: project,
- author: project.users.first)
+ author: project.users.first,
+ description: "# Description header"
+ )
end
And 'project "Shop" have "Tweet control" open issue' do
diff --git a/features/steps/project/project_markdown_render.rb b/features/steps/project/project_markdown_render.rb
index 1209aae643..89fbb7408c 100644
--- a/features/steps/project/project_markdown_render.rb
+++ b/features/steps/project/project_markdown_render.rb
@@ -1,6 +1,7 @@
class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
+ include SharedMarkdown
And 'I own project "Delta"' do
@project = Project.find_by(name: "Delta")
@@ -44,7 +45,6 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps
page.should have_content "maintenance.md"
end
-
And 'I click on GitLab API doc directory in README' do
click_link "GitLab API doc directory"
end
@@ -140,6 +140,16 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps
page.should have_content "test GitLab API doc Rake tasks"
end
+ step 'I add a header to the wiki page' do
+ fill_in "wiki[content]", with: "# Wiki header\n"
+ fill_in "wiki[message]", with: "Add header to wiki"
+ click_button "Create page"
+ end
+
+ step 'Wiki header should have correct id and link' do
+ header_should_have_correct_id_and_link(1, 'Wiki header', 'wiki-header')
+ end
+
And 'I click on test link' do
click_link "test"
end
@@ -173,18 +183,6 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps
page.should have_content "maintenance.md"
end
- Given 'I visit to the help page' do
- visit help_path
- end
-
- And 'I select a page with markdown' do
- click_link "Rake Tasks"
- end
-
- Then 'I should see a help page with markdown' do
- page.should have_content "GitLab provides some specific rake tasks to enable special features or perform maintenance tasks"
- end
-
Given 'I go directory which contains README file' do
visit project_tree_path(@project, "master/doc/api")
current_path.should == project_tree_path(@project, "master/doc/api")
@@ -198,4 +196,12 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps
current_path.should == project_blob_path(@project, "master/doc/api/users.md")
page.should have_content "List users"
end
+
+ step 'Header "Application details" should have correct id and link' do
+ header_should_have_correct_id_and_link(2, 'Application details', 'application-details')
+ end
+
+ step 'Header "GitLab API" should have correct id and link' do
+ header_should_have_correct_id_and_link(1, 'GitLab API', 'gitlab-api')
+ end
end
diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb
index 0c5f05a0a6..adf9e77e13 100644
--- a/features/steps/project/project_merge_requests.rb
+++ b/features/steps/project/project_merge_requests.rb
@@ -3,6 +3,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
include SharedProject
include SharedNote
include SharedPaths
+ include SharedMarkdown
step 'I click link "New Merge Request"' do
click_link "New Merge Request"
@@ -54,25 +55,15 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I click link "Close"' do
- click_link "Close"
+ within '.page-title' do
+ click_link "Close"
+ end
end
step 'I submit new merge request "Wiki Feature"' do
fill_in "merge_request_title", with: "Wiki Feature"
-
- # this must come first, so that the target branch is set
- # by the time the "select" for "notes_refactoring" is executed
- select project.path_with_namespace, from: "merge_request_target_project_id"
select "master", from: "merge_request_source_branch"
-
- find(:select, "merge_request_target_project_id", {}).value.should == project.id.to_s
- find(:select, "merge_request_source_project_id", {}).value.should == project.id.to_s
-
- # using "notes_refactoring" because "Bug NS-04" uses master/stable,
- # this will fail merge_request validation if the branches are the same
- find(:select, "merge_request_target_branch", {}).find(:option, "notes_refactoring", {}).value.should == "notes_refactoring"
select "notes_refactoring", from: "merge_request_target_branch"
-
click_button "Submit merge request"
end
@@ -83,7 +74,9 @@ class ProjectMergeRequests < Spinach::FeatureSteps
target_project: project,
source_branch: 'stable',
target_branch: 'master',
- author: project.users.first)
+ author: project.users.first,
+ description: "# Description header"
+ )
end
step 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do
@@ -172,7 +165,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see merged request' do
- within '.page-title' do
+ within '.issue-box' do
page.should have_content "Merged"
end
end
diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb
index 85962221c0..9ce18fbaab 100644
--- a/features/steps/project/project_milestones.rb
+++ b/features/steps/project/project_milestones.rb
@@ -2,6 +2,7 @@ class ProjectMilestones < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
+ include SharedMarkdown
Then 'I should see milestone "v2.2"' do
milestone = @project.milestones.find_by(title: "v2.2")
@@ -32,8 +33,11 @@ class ProjectMilestones < Spinach::FeatureSteps
And 'project "Shop" has milestone "v2.2"' do
project = Project.find_by(name: "Shop")
- milestone = create(:milestone, title: "v2.2", project: project)
-
+ milestone = create(:milestone,
+ title: "v2.2",
+ project: project,
+ description: "# Description header"
+ )
3.times { create(:issue, project: project, milestone: milestone) }
end
diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb
index c7d9ece6fe..1c5cfcc6c6 100644
--- a/features/steps/project/project_network_graph.rb
+++ b/features/steps/project/project_network_graph.rb
@@ -1,5 +1,6 @@
class ProjectNetworkGraph < Spinach::FeatureSteps
include SharedAuthentication
+ include SharedPaths
include SharedProject
Then 'page should have network graph' do
diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb
index c3ec10b87d..eb1d235f43 100644
--- a/features/steps/public/projects_feature.rb
+++ b/features/steps/public/projects_feature.rb
@@ -3,12 +3,8 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
include SharedPaths
include SharedProject
- step 'I should see project "Community"' do
- page.should have_content "Community"
- end
-
- step 'I should not see project "Enterprise"' do
- page.should_not have_content "Enterprise"
+ step 'public empty project "Empty Public Project"' do
+ create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC
end
step 'I should see project "Empty Public Project"' do
@@ -24,14 +20,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
page.should have_content 'README.md'
end
- step 'public project "Community"' do
- create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC
- end
-
- step 'public empty project "Empty Public Project"' do
- create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC
- end
-
step 'I visit empty project page' do
project = Project.find_by(name: 'Empty Public Project')
visit project_path(project)
@@ -60,10 +48,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
end
end
- step 'private project "Enterprise"' do
- create :project, name: 'Enterprise'
- end
-
step 'I visit project "Enterprise" page' do
project = Project.find_by(name: 'Enterprise')
visit project_path(project)
@@ -75,18 +59,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
end
end
- step 'internal project "Internal"' do
- create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL
- end
-
- step 'I should see project "Internal"' do
- page.should have_content "Internal"
- end
-
- step 'I should not see project "Internal"' do
- page.should_not have_content "Internal"
- end
-
step 'I visit project "Internal" page' do
project = Project.find_by(name: 'Internal')
visit project_path(project)
@@ -107,5 +79,94 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
project = Project.find_by(name: 'Community')
page.should have_field('project_clone', with: project.url_to_repo)
end
+
+ step 'I visit "Community" issues page' do
+ create(:issue,
+ title: "Bug",
+ project: public_project
+ )
+ create(:issue,
+ title: "New feature",
+ project: public_project
+ )
+ visit project_issues_path(public_project)
+ end
+
+
+ step 'I should see list of issues for "Community" project' do
+ page.should have_content "Bug"
+ page.should have_content public_project.name
+ page.should have_content "New feature"
+ end
+
+ step 'I visit "Internal" issues page' do
+ create(:issue,
+ title: "Internal Bug",
+ project: internal_project
+ )
+ create(:issue,
+ title: "New internal feature",
+ project: internal_project
+ )
+ visit project_issues_path(internal_project)
+ end
+
+
+ step 'I should see list of issues for "Internal" project' do
+ page.should have_content "Internal Bug"
+ page.should have_content internal_project.name
+ page.should have_content "New internal feature"
+ end
+
+ step 'I visit "Community" merge requests page' do
+ visit project_merge_requests_path(public_project)
+ end
+
+ step 'project "Community" has "Bug fix" open merge request' do
+ create(:merge_request,
+ title: "Bug fix for public project",
+ source_project: public_project,
+ target_project: public_project,
+ )
+ end
+
+ step 'I should see list of merge requests for "Community" project' do
+ page.should have_content public_project.name
+ page.should have_content public_merge_request.source_project.name
+ end
+
+ step 'I visit "Internal" merge requests page' do
+ visit project_merge_requests_path(internal_project)
+ end
+
+ step 'project "Internal" has "Feature implemented" open merge request' do
+ create(:merge_request,
+ title: "Feature implemented",
+ source_project: internal_project,
+ target_project: internal_project
+ )
+ end
+
+ step 'I should see list of merge requests for "Internal" project' do
+ page.should have_content internal_project.name
+ page.should have_content internal_merge_request.source_project.name
+ end
+
+ def internal_project
+ @internal_project ||= Project.find_by!(name: 'Internal')
+ end
+
+ def public_project
+ @public_project ||= Project.find_by!(name: 'Community')
+ end
+
+
+ def internal_merge_request
+ @internal_merge_request ||= MergeRequest.find_by!(title: 'Feature implemented')
+ end
+
+ def public_merge_request
+ @public_merge_request ||= MergeRequest.find_by!(title: 'Bug fix for public project')
+ end
end
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
index df05754c28..b8c11ce0a2 100644
--- a/features/steps/shared/authentication.rb
+++ b/features/steps/shared/authentication.rb
@@ -12,6 +12,14 @@ module SharedAuthentication
login_as :admin
end
+ step 'I sign in as "John Doe"' do
+ login_with(user_exists("John Doe"))
+ end
+
+ step 'I sign in as "Mary Jane"' do
+ login_with(user_exists("Mary Jane"))
+ end
+
step 'I should be redirected to sign in page' do
current_path.should == new_user_session_path
end
diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb
new file mode 100644
index 0000000000..6b4c47312a
--- /dev/null
+++ b/features/steps/shared/group.rb
@@ -0,0 +1,36 @@
+module SharedGroup
+ include Spinach::DSL
+
+ step '"John Doe" is owner of group "Owned"' do
+ is_member_of("John Doe", "Owned", Gitlab::Access::OWNER)
+ end
+
+ step '"John Doe" is guest of group "Guest"' do
+ is_member_of("John Doe", "Guest", Gitlab::Access::GUEST)
+ end
+
+ step '"Mary Jane" is owner of group "Owned"' do
+ is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER)
+ end
+
+ step '"Mary Jane" is guest of group "Owned"' do
+ is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST)
+ end
+
+ step '"Mary Jane" is guest of group "Guest"' do
+ is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST)
+ end
+
+ protected
+
+ def is_member_of(username, groupname, role)
+ @project_count ||= 0
+ user = User.find_by(name: username) || create(:user, name: username)
+ group = Group.find_by(name: groupname) || create(:group, name: groupname)
+ group.add_user(user, role)
+ project ||= create(:project, namespace: group, path: "project#{@project_count}")
+ event ||= create(:closed_issue_event, project: project)
+ project.team << [user, :master]
+ @project_count += 1
+ end
+end
diff --git a/features/steps/shared/markdown.rb b/features/steps/shared/markdown.rb
new file mode 100644
index 0000000000..782f3f0920
--- /dev/null
+++ b/features/steps/shared/markdown.rb
@@ -0,0 +1,12 @@
+module SharedMarkdown
+ include Spinach::DSL
+
+ def header_should_have_correct_id_and_link(level, text, id, parent = ".wiki")
+ page.find(:css, "#{parent} h#{level}##{id}").text.should == text
+ page.find(:css, "#{parent} h#{level}##{id} > :last-child")[:href].should =~ /##{id}$/
+ end
+
+ step 'Header "Description header" should have correct id and link' do
+ header_should_have_correct_id_and_link(1, 'Description header', 'description-header')
+ end
+end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index da08da9420..36b81b7418 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -102,4 +102,21 @@ module SharedNote
page.should have_content("XML attached")
end
end
+
+ # Markdown
+
+ step 'I leave a comment with a header containing "Comment with a header"' do
+ within(".js-main-target-form") do
+ fill_in "note[note]", with: "# Comment with a header"
+ click_button "Add Comment"
+ sleep 0.05
+ end
+ end
+
+ step 'The comment with the header should not have an ID' do
+ within(".note-text") do
+ page.should have_content("Comment with a header")
+ page.should_not have_css("#comment-with-a-header")
+ end
+ end
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index d287121bb8..a0213815a7 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -5,28 +5,56 @@ module SharedPaths
visit new_project_path
end
+ # ----------------------------------------
+ # User
+ # ----------------------------------------
+
+ step 'I visit user "John Doe" page' do
+ visit user_path("john_doe")
+ end
+
# ----------------------------------------
# Group
# ----------------------------------------
- step 'I visit group page' do
- visit group_path(current_group)
+ step 'I visit group "Owned" page' do
+ visit group_path(Group.find_by(name:"Owned"))
end
- step 'I visit group issues page' do
- visit issues_group_path(current_group)
+ step 'I visit group "Owned" issues page' do
+ visit issues_group_path(Group.find_by(name:"Owned"))
end
- step 'I visit group merge requests page' do
- visit merge_requests_group_path(current_group)
+ step 'I visit group "Owned" merge requests page' do
+ visit merge_requests_group_path(Group.find_by(name:"Owned"))
end
- step 'I visit group members page' do
- visit members_group_path(current_group)
+ step 'I visit group "Owned" members page' do
+ visit members_group_path(Group.find_by(name:"Owned"))
end
- step 'I visit group settings page' do
- visit edit_group_path(current_group)
+ step 'I visit group "Owned" settings page' do
+ visit edit_group_path(Group.find_by(name:"Owned"))
+ end
+
+ step 'I visit group "Guest" page' do
+ visit group_path(Group.find_by(name:"Guest"))
+ end
+
+ step 'I visit group "Guest" issues page' do
+ visit issues_group_path(Group.find_by(name:"Guest"))
+ end
+
+ step 'I visit group "Guest" merge requests page' do
+ visit merge_requests_group_path(Group.find_by(name:"Guest"))
+ end
+
+ step 'I visit group "Guest" members page' do
+ visit members_group_path(Group.find_by(name:"Guest"))
+ end
+
+ step 'I visit group "Guest" settings page' do
+ visit edit_group_path(Group.find_by(name:"Guest"))
end
# ----------------------------------------
@@ -85,6 +113,14 @@ module SharedPaths
visit history_profile_path
end
+ step 'I visit profile groups page' do
+ visit profile_groups_path
+ end
+
+ step 'I should be redirected to the profile groups page' do
+ current_path.should == profile_groups_path
+ end
+
# ----------------------------------------
# Admin
# ----------------------------------------
@@ -318,4 +354,12 @@ module SharedPaths
def project
project = Project.find_by!(name: "Shop")
end
+
+ # ----------------------------------------
+ # Errors
+ # ----------------------------------------
+
+ Then 'page status code should be 404' do
+ page.status_code.should == 404
+ end
end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index 7360482d73..f35beab8af 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -58,11 +58,68 @@ module SharedProject
page.should have_content("Features:")
end
- Then 'page status code should be 404' do
- page.status_code.should == 404
- end
-
def current_project
@project ||= Project.first
end
+
+ # ----------------------------------------
+ # Visibility level
+ # ----------------------------------------
+
+ step 'private project "Enterprise"' do
+ create :project, name: 'Enterprise'
+ end
+
+ step 'I should see project "Enterprise"' do
+ page.should have_content "Enterprise"
+ end
+
+ step 'I should not see project "Enterprise"' do
+ page.should_not have_content "Enterprise"
+ end
+
+ step 'internal project "Internal"' do
+ create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL
+ end
+
+ step 'I should see project "Internal"' do
+ page.should have_content "Internal"
+ end
+
+ step 'I should not see project "Internal"' do
+ page.should_not have_content "Internal"
+ end
+
+ step 'public project "Community"' do
+ create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC
+ end
+
+ step 'I should see project "Community"' do
+ page.should have_content "Community"
+ end
+
+ step 'I should not see project "Community"' do
+ page.should_not have_content "Community"
+ end
+
+ step '"John Doe" is authorized to private project "Enterprise"' do
+ user = user_exists("John Doe", username: "john_doe")
+ project = Project.find_by(name: "Enterprise")
+ project ||= create(:project, name: "Enterprise", namespace: user.namespace)
+ project.team << [user, :master]
+ end
+
+ step '"John Doe" is authorized to internal project "Internal"' do
+ user = user_exists("John Doe", username: "john_doe")
+ project = Project.find_by(name: "Internal")
+ project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL
+ project.team << [user, :master]
+ end
+
+ step '"John Doe" is authorized to public project "Community"' do
+ user = user_exists("John Doe", username: "john_doe")
+ project = Project.find_by(name: "Community")
+ project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC
+ project.team << [user, :master]
+ end
end
diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb
new file mode 100644
index 0000000000..209d77c7ac
--- /dev/null
+++ b/features/steps/shared/user.rb
@@ -0,0 +1,17 @@
+module SharedUser
+ include Spinach::DSL
+
+ step 'User "John Doe" exists' do
+ user_exists("John Doe", {username: "john_doe"})
+ end
+
+ step 'User "Mary Jane" exists' do
+ user_exists("Mary Jane", {username: "mary_jane"})
+ end
+
+ protected
+
+ def user_exists(name, options = {})
+ User.find_by(name: name) || create(:user, {name: name, admin: false}.merge(options))
+ end
+end
diff --git a/features/steps/user.rb b/features/steps/user.rb
new file mode 100644
index 0000000000..5fb248ffcb
--- /dev/null
+++ b/features/steps/user.rb
@@ -0,0 +1,10 @@
+class Spinach::Features::User < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedUser
+ include SharedProject
+
+ step 'I should see user "John Doe" page' do
+ expect(page.title).to match(/^\s*John Doe/)
+ end
+end
diff --git a/features/support/env.rb b/features/support/env.rb
index 0186002c55..7b11f5a7c6 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -15,7 +15,7 @@ require 'spinach/capybara'
require 'sidekiq/testing/inline'
-%w(valid_commit big_commits select2_helper test_env).each do |f|
+%w(valid_commit valid_commit_with_alt_email big_commits select2_helper test_env).each do |f|
require Rails.root.join('spec', 'support', f)
end
diff --git a/features/user.feature b/features/user.feature
new file mode 100644
index 0000000000..d4198c08de
--- /dev/null
+++ b/features/user.feature
@@ -0,0 +1,69 @@
+Feature: User
+ Background:
+ Given User "John Doe" exists
+ And "John Doe" is authorized to private project "Enterprise"
+
+ # Signed out
+
+ Scenario: I visit user "John Doe" page while not signed in when he is authorized to a public project
+ Given "John Doe" is authorized to internal project "Internal"
+ And "John Doe" is authorized to public project "Community"
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should not see project "Enterprise"
+ And I should not see project "Internal"
+ And I should see project "Community"
+
+ Scenario: I visit user "John Doe" page while not signed in when he is not authorized to a public project
+ Given "John Doe" is authorized to internal project "Internal"
+ When I visit user "John Doe" page
+ Then I should be redirected to sign in page
+
+ # Signed in as someone else
+
+ Scenario: I visit user "John Doe" page while signed in as someone else when he is authorized to a public project
+ Given "John Doe" is authorized to public project "Community"
+ And "John Doe" is authorized to internal project "Internal"
+ And I sign in as a user
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should not see project "Enterprise"
+ And I should see project "Internal"
+ And I should see project "Community"
+
+ Scenario: I visit user "John Doe" page while signed in as someone else when he is not authorized to a public project
+ Given "John Doe" is authorized to internal project "Internal"
+ And I sign in as a user
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should not see project "Enterprise"
+ And I should see project "Internal"
+ And I should not see project "Community"
+
+ Scenario: I visit user "John Doe" page while signed in as someone else when he is not authorized to a project I can see
+ Given I sign in as a user
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should not see project "Enterprise"
+ And I should not see project "Internal"
+ And I should not see project "Community"
+
+ # Signed in as the user himself
+
+ Scenario: I visit user "John Doe" page while signed in as "John Doe" when he has a public project
+ Given "John Doe" is authorized to internal project "Internal"
+ And "John Doe" is authorized to public project "Community"
+ And I sign in as "John Doe"
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should see project "Enterprise"
+ And I should see project "Internal"
+ And I should see project "Community"
+
+ Scenario: I visit user "John Doe" page while signed in as "John Doe" when he has no public project
+ Given I sign in as "John Doe"
+ When I visit user "John Doe" page
+ Then I should see user "John Doe" page
+ And I should see project "Enterprise"
+ And I should not see project "Internal"
+ And I should not see project "Community"
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 283f7642f6..6bec8368b1 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -22,6 +22,8 @@ module API
end
format :json
+ content_type :txt, "text/plain"
+
helpers APIHelpers
mount Groups
@@ -40,6 +42,7 @@ module API
mount ProjectHooks
mount Services
mount Files
+ mount Commits
mount Namespaces
end
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
new file mode 100644
index 0000000000..33b8b3d224
--- /dev/null
+++ b/lib/api/commits.rb
@@ -0,0 +1,64 @@
+require 'mime/types'
+
+module API
+ # Projects API
+ class Commits < Grape::API
+ before { authenticate! }
+ before { authorize! :download_code, user_project }
+
+ resource :projects do
+ helpers do
+ def handle_project_member_errors(errors)
+ if errors[:project_access].any?
+ error!(errors[:project_access], 422)
+ end
+ not_found!
+ end
+ end
+
+ # Get a project repository commits
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
+ # Example Request:
+ # GET /projects/:id/repository/commits
+ get ":id/repository/commits" do
+ page = (params[:page] || 0).to_i
+ per_page = (params[:per_page] || 20).to_i
+ ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
+
+ commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
+ present commits, with: Entities::RepoCommit
+ end
+
+ # Get a specific commit of a project
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # sha (required) - The commit hash or name of a repository branch or tag
+ # Example Request:
+ # GET /projects/:id/repository/commits/:sha
+ get ":id/repository/commits/:sha" do
+ sha = params[:sha]
+ commit = user_project.repository.commit(sha)
+ not_found! "Commit" unless commit
+ present commit, with: Entities::RepoCommitDetail
+ end
+
+ # Get the diff for a specific commit of a project
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # sha (required) - The commit or branch name
+ # Example Request:
+ # GET /projects/:id/repository/commits/:sha/diff
+ get ":id/repository/commits/:sha/diff" do
+ sha = params[:sha]
+ commit = user_project.repository.commit(sha)
+ not_found! "Commit" unless commit
+ commit.diffs
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4f636fc54a..8557fa074d 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -6,6 +6,12 @@ module API
expose :is_admin?, as: :is_admin
expose :can_create_group?, as: :can_create_group
expose :can_create_project?, as: :can_create_project
+
+ expose :avatar_url do |user, options|
+ if user.avatar.present?
+ user.avatar.url
+ end
+ end
end
class UserSafe < Grape::Entity
@@ -79,7 +85,16 @@ module API
end
class RepoObject < Grape::Entity
- expose :name, :commit
+ expose :name
+
+ expose :commit do |repo_obj, options|
+ if repo_obj.respond_to?(:commit)
+ repo_obj.commit
+ elsif options[:project]
+ options[:project].repository.commit(repo_obj.target)
+ end
+ end
+
expose :protected do |repo, options|
if options[:project]
options[:project].protected_branch? repo.name
@@ -87,6 +102,16 @@ module API
end
end
+ class RepoTreeObject < Grape::Entity
+ expose :id, :name, :type
+
+ expose :mode do |obj, options|
+ filemode = obj.mode.to_s(8)
+ filemode = "0" + filemode if filemode.length < 6
+ filemode
+ end
+ end
+
class RepoCommit < Grape::Entity
expose :id, :short_id, :title, :author_name, :author_email, :created_at
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 213604915a..e0c46f92b8 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -5,10 +5,61 @@ module API
before { authorize! :push_code, user_project }
resource :projects do
+ # Get file from repository
+ # File content is Base64 encoded
+ #
+ # Parameters:
+ # file_path (required) - The path to the file. Ex. lib/class.rb
+ # ref (required) - The name of branch, tag or commit
+ #
+ # Example Request:
+ # GET /projects/:id/repository/files
+ #
+ # Example response:
+ # {
+ # "file_name": "key.rb",
+ # "file_path": "app/models/key.rb",
+ # "size": 1476,
+ # "encoding": "base64",
+ # "content": "IyA9PSBTY2hlbWEgSW5mb3...",
+ # "ref": "master",
+ # "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
+ # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50"
+ # }
+ #
+ get ":id/repository/files" do
+ required_attributes! [:file_path, :ref]
+ attrs = attributes_for_keys [:file_path, :ref]
+ ref = attrs.delete(:ref)
+ file_path = attrs.delete(:file_path)
+
+ commit = user_project.repository.commit(ref)
+ not_found! "Commit" unless commit
+
+ blob = user_project.repository.blob_at(commit.sha, file_path)
+
+ if blob
+ status(200)
+
+ {
+ file_name: blob.name,
+ file_path: blob.path,
+ size: blob.size,
+ encoding: "base64",
+ content: Base64.encode64(blob.data),
+ ref: ref,
+ blob_id: blob.id,
+ commit_id: commit.id,
+ }
+ else
+ render_api_error!('File not found', 404)
+ end
+ end
+
# Create new file in repository
#
# Parameters:
- # file_path (optional) - The path to new file. Ex. lib/class.rb
+ # file_path (required) - The path to new file. Ex. lib/class.rb
# branch_name (required) - The name of branch
# content (required) - File content
# commit_message (required) - Commit message
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index ed6b50c3a6..ebc9fef07b 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -35,7 +35,9 @@ module API
user = key.user
return false if user.blocked?
- return false if user.ldap_user? && Gitlab::LDAP::User.blocked?(user.extern_uid)
+ if Gitlab.config.ldap.enabled
+ return false if user.ldap_user? && Gitlab::LDAP::User.blocked?(user.extern_uid)
+ end
action = case git_cmd
when *DOWNLOAD_COMMANDS
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 0f62cac9a0..58d2f79faf 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -116,8 +116,6 @@ module API
authorize! :modify_merge_request, merge_request
if merge_request.update_attributes attrs
- merge_request.reload_code
- merge_request.mark_as_unchecked
present merge_request, with: Entities::MergeRequest
else
handle_merge_request_errors! merge_request.errors
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 888aa7e77d..bcca69ff49 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -11,7 +11,7 @@ module API
end
not_found!
end
-
+
def map_public_to_visibility_level(attrs)
publik = attrs.delete(:public)
publik = [ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(publik)
@@ -308,6 +308,18 @@ module API
projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%")
present paginate(projects), with: Entities::Project
end
+
+
+ # Get a users list
+ #
+ # Example Request:
+ # GET /users
+ get ':id/users' do
+ @users = User.where(id: user_project.team.users.map(&:id))
+ @users = @users.search(params[:search]) if params[:search].present?
+ @users = paginate @users
+ present @users, with: Entities::User
+ end
end
end
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 878929b803..ba53bf9baa 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -82,51 +82,7 @@ module API
# Example Request:
# GET /projects/:id/repository/tags
get ":id/repository/tags" do
- present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject
- end
-
- # Get a project repository commits
- #
- # Parameters:
- # id (required) - The ID of a project
- # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
- # Example Request:
- # GET /projects/:id/repository/commits
- get ":id/repository/commits" do
- page = (params[:page] || 0).to_i
- per_page = (params[:per_page] || 20).to_i
- ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
-
- commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
- present commits, with: Entities::RepoCommit
- end
-
- # Get a specific commit of a project
- #
- # Parameters:
- # id (required) - The ID of a project
- # sha (required) - The commit hash or name of a repository branch or tag
- # Example Request:
- # GET /projects/:id/repository/commits/:sha
- get ":id/repository/commits/:sha" do
- sha = params[:sha]
- commit = user_project.repository.commit(sha)
- not_found! "Commit" unless commit
- present commit, with: Entities::RepoCommitDetail
- end
-
- # Get the diff for a specific commit of a project
- #
- # Parameters:
- # id (required) - The ID of a project
- # sha (required) - The commit or branch name
- # Example Request:
- # GET /projects/:id/repository/commits/:sha/diff
- get ":id/repository/commits/:sha/diff" do
- sha = params[:sha]
- commit = user_project.repository.commit(sha)
- not_found! "Commit" unless commit
- commit.diffs
+ present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject, project: user_project
end
# Get a project repository tree
@@ -141,15 +97,9 @@ module API
path = params[:path] || nil
commit = user_project.repository.commit(ref)
- tree = Tree.new(user_project.repository, commit.id, path)
+ tree = user_project.repository.tree(commit.id, path)
- trees = []
-
- %w(trees blobs submodules).each do |type|
- trees += tree.send(type).map { |t| {name: t.name, type: type.singularize, mode: t.mode, id: t.id} }
- end
-
- trees
+ present tree.sorted_entries, with: Entities::RepoTreeObject
end
# Get a raw file contents
@@ -173,9 +123,7 @@ module API
blob = Gitlab::Git::Blob.find(repo, commit.id, params[:filepath])
not_found! "File" unless blob
- env['api.format'] = :txt
-
- content_type blob.mime_type
+ content_type 'text/plain'
present blob.data
end
@@ -233,4 +181,3 @@ module API
end
end
end
-
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index 6e7872dcd0..e51cb30bdd 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -117,7 +117,7 @@ module ExtractsPath
end
def tree
- @tree ||= Tree.new(@repo, @commit.id, @path)
+ @tree ||= @repo.tree(@commit.id, @path)
end
private
diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb
index 2f30fde207..5283cf0b82 100644
--- a/lib/gitlab/popen.rb
+++ b/lib/gitlab/popen.rb
@@ -1,9 +1,15 @@
+require 'fileutils'
+
module Gitlab
module Popen
def popen(cmd, path)
vars = { "PWD" => path }
options = { chdir: path }
+ unless File.directory?(path)
+ FileUtils.mkdir_p(path)
+ end
+
@cmd_output = ""
@cmd_status = 0
Open3.popen3(vars, cmd, options) do |stdin, stdout, stderr, wait_thr|
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 2d1e0aec5e..42f6316910 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -8,14 +8,11 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
@project = @template.instance_variable_get("@project")
@ref = @template.instance_variable_get("@ref")
@request_path = @template.instance_variable_get("@path")
+ @options = options.dup
super options
end
def block_code(code, language)
- options = { options: {encoding: 'utf-8'} }
- lexer = Pygments::Lexer.find(language) # language can be an alias
- options.merge!(lexer: lexer.aliases[0].downcase) if lexer # downcase is required
-
# New lines are placed to fix an rendering issue
# with code wrapped inside tag for next case:
#
@@ -25,7 +22,11 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
#
<<-HTML
-
#{Pygments.highlight(code, options)}
+
HTML
end
@@ -34,6 +35,16 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
h.link_to_gfm(content, link, title: title)
end
+ def header(text, level)
+ if @options[:no_header_anchors]
+ "#{text}"
+ else
+ id = ActionController::Base.helpers.strip_tags(h.gfm(text)).downcase() \
+ .gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-/, '').gsub(/-$/, '')
+ "#{text}"
+ end
+ end
+
def preprocess(full_document)
if @project
h.create_relative_links(full_document, @project, @ref, @request_path, is_wiki?)
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 0860d2a869..882f038604 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -53,5 +53,7 @@ server {
proxy_pass http://gitlab;
}
+
+ error_page 502 /502.html;
}
diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake
index 612a9ba93a..0e1a3d071e 100644
--- a/lib/tasks/gitlab/bulk_add_permission.rake
+++ b/lib/tasks/gitlab/bulk_add_permission.rake
@@ -20,5 +20,29 @@ namespace :gitlab do
puts "Importing #{user.email} users into #{project_ids.size} projects"
UsersProject.add_users_into_projects(project_ids, Array.wrap(user.id), UsersProject::DEVELOPER)
end
+
+ desc "GITLAB | Add all users to all groups (admin users are added as owners)"
+ task all_users_to_all_groups: :environment do |t, args|
+ user_ids = User.where(admin: false).pluck(:id)
+ admin_ids = User.where(admin: true).pluck(:id)
+ groups = Group.all
+
+ puts "Importing #{user_ids.size} users into #{groups.size} groups"
+ puts "Importing #{admin_ids.size} admins into #{groups.size} groups"
+ groups.each do |group|
+ group.add_users(user_ids, UsersGroup::DEVELOPER)
+ group.add_users(admin_ids, UsersGroup::OWNER)
+ end
+ end
+
+ desc "GITLAB | Add a specific user to all groups (as a developer)"
+ task :user_to_groups, [:email] => :environment do |t, args|
+ user = User.find_by_email args.email
+ groups = Group.all
+ puts "Importing #{user.email} users into #{groups.size} groups"
+ groups.each do |group|
+ group.add_users(Array.wrap(user.id), UsersGroup::DEVELOPER)
+ end
+ end
end
end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index f48d26433c..c91dedf74c 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -279,8 +279,6 @@ namespace :gitlab do
start_checking "Environment"
check_gitlab_git_config
- check_python2_exists
- check_python2_version
finished_checking "Environment"
end
@@ -314,52 +312,6 @@ namespace :gitlab do
fix_and_rerun
end
end
-
- def check_python2_exists
- print "Has python2? ... "
-
- # Python prints its version to STDERR
- # so we can't just use run("python2 --version")
- if run_and_match("which python2", /python2$/)
- puts "yes".green
- else
- puts "no".red
- try_fixing_it(
- "Make sure you have Python 2.5+ installed",
- "Link it to python2"
- )
- for_more_information(
- see_installation_guide_section "Packages / Dependencies"
- )
- fix_and_rerun
- end
- end
-
- def check_python2_version
- print "python2 is supported version? ... "
-
- # Python prints its version to STDERR
- # so we can't just use run("python2 --version")
-
- unless run_and_match("which python2", /python2$/)
- puts "can't check because of previous errors".magenta
- return
- end
-
- if `python2 --version 2>&1` =~ /2\.[567]\.\d/
- puts "yes".green
- else
- puts "no".red
- try_fixing_it(
- "Make sure you have Python 2.5+ installed",
- "Link it to python2"
- )
- for_more_information(
- see_installation_guide_section "Packages / Dependencies"
- )
- fix_and_rerun
- end
- end
end
diff --git a/public/500.html b/public/500.html
index 5b78e3e38c..c84b9e90e4 100644
--- a/public/500.html
+++ b/public/500.html
@@ -8,6 +8,6 @@
500
We're sorry, but something went wrong.
- We've been notified about this issue and we'll take a look at it shortly.
+ Please contact your GitLab administrator if this problem persists.