Commit 48443d20 authored by Florian Unglaub's avatar Florian Unglaub

Merge branch 'master' of git://github.com/gitlabhq/gitlabhq

parents c5ae1549 6d4ae75f
#this code temporarily disables notes for all controllers
# Footnotes::Filter.notes = []
v 2.8.1
- ability to disable gravatars
- improved MR diff logic
- ssh key help page
v 2.8.0 v 2.8.0
- Gitlab Flavored Markdown - Gitlab Flavored Markdown
- Bulk issues update - Bulk issues update
- Issues API - Issues API
- Cucumber coverage increased - Cucumber coverage increased
- Post-receive files fixed
- UI improved
- Application cleanup
- more cucumber
- capybara-webkit + headless
v 2.7.0 v 2.7.0
- Issue Labels - Issue Labels
......
...@@ -58,7 +58,7 @@ gem "unicorn" ...@@ -58,7 +58,7 @@ gem "unicorn"
gem "acts-as-taggable-on", "2.3.1" gem "acts-as-taggable-on", "2.3.1"
# Decorators # Decorators
gem "drapper" gem "draper"
# Background jobs # Background jobs
gem "resque", "~> 1.20.0" gem "resque", "~> 1.20.0"
...@@ -80,10 +80,6 @@ gem 'settingslogic' ...@@ -80,10 +80,6 @@ gem 'settingslogic'
gem "foreman" gem "foreman"
gem "git" gem "git"
# Unused
gem 'tabs_on_rails'
gem "acts_as_list"
group :assets do group :assets do
gem "sass-rails", "3.2.5" gem "sass-rails", "3.2.5"
gem "coffee-rails", "3.2.2" gem "coffee-rails", "3.2.2"
...@@ -95,12 +91,11 @@ group :assets do ...@@ -95,12 +91,11 @@ group :assets do
gem "jquery-ui-rails", "0.5.0" gem "jquery-ui-rails", "0.5.0"
gem "modernizr", "2.5.3" gem "modernizr", "2.5.3"
gem "raphael-rails", "1.5.2" gem "raphael-rails", "1.5.2"
gem 'bootstrap-sass', "2.0.3.1" gem 'bootstrap-sass', "2.0.4"
end end
group :development do group :development do
gem "letter_opener" gem "letter_opener"
gem "rails-footnotes"
gem "annotate", :git => "https://github.com/ctran/annotate_models.git" gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
gem 'rack-mini-profiler' gem 'rack-mini-profiler'
end end
...@@ -109,6 +104,7 @@ group :development, :test do ...@@ -109,6 +104,7 @@ group :development, :test do
gem "rspec-rails" gem "rspec-rails"
gem "capybara" gem "capybara"
gem "capybara-webkit" gem "capybara-webkit"
gem "headless"
gem "autotest" gem "autotest"
gem "autotest-rails" gem "autotest-rails"
gem "pry" gem "pry"
...@@ -119,11 +115,13 @@ end ...@@ -119,11 +115,13 @@ end
group :test do group :test do
gem 'cucumber-rails', :require => false gem 'cucumber-rails', :require => false
gem 'minitest', ">= 2.10"
gem "turn", :require => false
gem "simplecov", :require => false gem "simplecov", :require => false
gem "shoulda-matchers" gem "shoulda-matchers"
gem 'email_spec' gem 'email_spec'
gem 'resque_spec' gem 'resque_spec'
gem "webmock" gem "webmock"
end end
group :production do
gem "gitlab_meta", '2.8'
end
...@@ -98,9 +98,7 @@ GEM ...@@ -98,9 +98,7 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
acts-as-taggable-on (2.3.1) acts-as-taggable-on (2.3.1)
rails (~> 3.0) rails (~> 3.0)
acts_as_list (0.1.6)
addressable (2.2.8) addressable (2.2.8)
ansi (1.4.2)
arel (3.0.2) arel (3.0.2)
autotest (4.4.6) autotest (4.4.6)
ZenTest (>= 4.4.1) ZenTest (>= 4.4.1)
...@@ -109,7 +107,7 @@ GEM ...@@ -109,7 +107,7 @@ GEM
awesome_print (1.0.2) awesome_print (1.0.2)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
blankslate (2.1.2.4) blankslate (2.1.2.4)
bootstrap-sass (2.0.3.1) bootstrap-sass (2.0.4.0)
builder (3.0.0) builder (3.0.0)
capybara (1.1.2) capybara (1.1.2)
mime-types (>= 1.16) mime-types (>= 1.16)
...@@ -157,7 +155,9 @@ GEM ...@@ -157,7 +155,9 @@ GEM
railties (~> 3.1) railties (~> 3.1)
warden (~> 1.2.1) warden (~> 1.2.1)
diff-lcs (1.1.3) diff-lcs (1.1.3)
drapper (0.8.4) draper (0.17.0)
actionpack (~> 3.2)
activesupport (~> 3.2)
email_spec (1.2.1) email_spec (1.2.1)
mail (~> 2.2) mail (~> 2.2)
rspec (~> 2.0) rspec (~> 2.0)
...@@ -175,6 +175,7 @@ GEM ...@@ -175,6 +175,7 @@ GEM
gherkin (2.11.0) gherkin (2.11.0)
json (>= 1.4.6) json (>= 1.4.6)
git (1.2.5) git (1.2.5)
gitlab_meta (2.8)
grape (0.2.1) grape (0.2.1)
hashie (~> 1.2) hashie (~> 1.2)
multi_json multi_json
...@@ -189,6 +190,7 @@ GEM ...@@ -189,6 +190,7 @@ GEM
railties (~> 3.0) railties (~> 3.0)
hashery (1.4.0) hashery (1.4.0)
hashie (1.2.0) hashie (1.2.0)
headless (0.3.1)
hike (1.2.1) hike (1.2.1)
httparty (0.8.3) httparty (0.8.3)
multi_json (~> 1.0) multi_json (~> 1.0)
...@@ -223,7 +225,6 @@ GEM ...@@ -223,7 +225,6 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
method_source (0.7.1) method_source (0.7.1)
mime-types (1.19) mime-types (1.19)
minitest (3.1.0)
modernizr (2.5.3) modernizr (2.5.3)
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.3.6) multi_json (1.3.6)
...@@ -286,8 +287,6 @@ GEM ...@@ -286,8 +287,6 @@ GEM
activesupport (= 3.2.8) activesupport (= 3.2.8)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.2.8) railties (= 3.2.8)
rails-footnotes (3.7.8)
rails (>= 3.0.0)
railties (3.2.8) railties (3.2.8)
actionpack (= 3.2.8) actionpack (= 3.2.8)
activesupport (= 3.2.8) activesupport (= 3.2.8)
...@@ -366,7 +365,6 @@ GEM ...@@ -366,7 +365,6 @@ GEM
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.6) sqlite3 (1.3.6)
stamp (0.1.6) stamp (0.1.6)
tabs_on_rails (2.1.1)
therubyracer (0.10.1) therubyracer (0.10.1)
libv8 (~> 3.3.10) libv8 (~> 3.3.10)
thin (1.3.1) thin (1.3.1)
...@@ -378,8 +376,6 @@ GEM ...@@ -378,8 +376,6 @@ GEM
treetop (1.4.10) treetop (1.4.10)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
turn (0.9.5)
ansi
tzinfo (0.3.33) tzinfo (0.3.33)
uglifier (1.0.3) uglifier (1.0.3)
execjs (>= 0.3.0) execjs (>= 0.3.0)
...@@ -403,12 +399,11 @@ PLATFORMS ...@@ -403,12 +399,11 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
acts-as-taggable-on (= 2.3.1) acts-as-taggable-on (= 2.3.1)
acts_as_list
annotate! annotate!
autotest autotest
autotest-rails autotest-rails
awesome_print awesome_print
bootstrap-sass (= 2.0.3.1) bootstrap-sass (= 2.0.4)
capybara capybara
capybara-webkit capybara-webkit
carrierwave carrierwave
...@@ -419,16 +414,18 @@ DEPENDENCIES ...@@ -419,16 +414,18 @@ DEPENDENCIES
cucumber-rails cucumber-rails
database_cleaner database_cleaner
devise (~> 2.1.0) devise (~> 2.1.0)
drapper draper
email_spec email_spec
ffaker ffaker
foreman foreman
git git
gitlab_meta (= 2.8)
gitolite! gitolite!
grack! grack!
grape (~> 0.2.1) grape (~> 0.2.1)
grit! grit!
haml-rails haml-rails
headless
httparty httparty
jquery-rails (= 2.0.2) jquery-rails (= 2.0.2)
jquery-ui-rails (= 0.5.0) jquery-ui-rails (= 0.5.0)
...@@ -436,7 +433,6 @@ DEPENDENCIES ...@@ -436,7 +433,6 @@ DEPENDENCIES
launchy launchy
letter_opener letter_opener
linguist (~> 1.0.0)! linguist (~> 1.0.0)!
minitest (>= 2.10)
modernizr (= 2.5.3) modernizr (= 2.5.3)
mysql2 mysql2
omniauth omniauth
...@@ -448,7 +444,6 @@ DEPENDENCIES ...@@ -448,7 +444,6 @@ DEPENDENCIES
pygments.rb! pygments.rb!
rack-mini-profiler rack-mini-profiler
rails (= 3.2.8) rails (= 3.2.8)
rails-footnotes
raphael-rails (= 1.5.2) raphael-rails (= 1.5.2)
redcarpet (~> 2.1.1) redcarpet (~> 2.1.1)
resque (~> 1.20.0) resque (~> 1.20.0)
...@@ -463,10 +458,8 @@ DEPENDENCIES ...@@ -463,10 +458,8 @@ DEPENDENCIES
six six
sqlite3 sqlite3
stamp stamp
tabs_on_rails
therubyracer therubyracer
thin thin
turn
uglifier (= 1.0.3) uglifier (= 1.0.3)
unicorn unicorn
webmock webmock
......
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
//= require jquery //= require jquery
//= require jquery.ui.all //= require jquery.ui.all
//= require jquery_ujs //= require jquery_ujs
//= require jquery.ui.selectmenu
//= require jquery.tagify
//= require jquery.cookie //= require jquery.cookie
//= require jquery.endless-scroll //= require jquery.endless-scroll
//= require jquery.highlight //= require jquery.highlight
...@@ -74,7 +72,7 @@ $(document).ready(function(){ ...@@ -74,7 +72,7 @@ $(document).ready(function(){
* Note markdown preview * Note markdown preview
* *
*/ */
$('#preview-link').on('click', function(e) { $(document).on('click', '#preview-link', function(e) {
$('#preview-note').text('Loading...'); $('#preview-note').text('Loading...');
var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
......
...@@ -112,6 +112,7 @@ var MergeRequest = { ...@@ -112,6 +112,7 @@ var MergeRequest = {
already_cannot_be_merged: already_cannot_be_merged:
function(){ function(){
$(".automerge_widget").hide(); $(".automerge_widget").hide();
$(".merge_in_progress").hide();
$(".automerge_widget.already_cannot_be_merged").show(); $(".automerge_widget.already_cannot_be_merged").show();
} }
} }
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope. * the top of the compiled file, but it's generally better to create a new file per style scope.
*= require jquery.ui.all *= require jquery.ui.all
*= require jquery-ui/jquery.ui.selectmenu *= require jquery.ui.aristo
*= require jquery-ui/jquery.tagify
*= require chosen *= require chosen
*= require_self *= require_self
*= require main *= require main
......
...@@ -735,3 +735,11 @@ li.note { ...@@ -735,3 +735,11 @@ li.note {
font-size: 12px; font-size: 12px;
} }
} }
.error_message {
@extend .cred;
border-bottom: 1px solid #D21;
padding-bottom:20px;
text-align:center;
margin-bottom:10px;
}
body { body {
margin-bottom:20px; margin-bottom:20px;
} }
pre {
font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
&.dark {
background: #333;
color:#f5f5f5;
}
}
a { a {
outline: none; outline: none;
color: $link_color; color: $link_color;
...@@ -325,16 +335,20 @@ img.avatar { ...@@ -325,16 +335,20 @@ img.avatar {
float:left; float:left;
margin-right:15px; margin-right:15px;
width:40px; width:40px;
border:2px solid #ddd; border:1px solid #ddd;
padding:1px;
&.s16 { &.s16 {
width:16px; width:16px;
height:16px;
} }
&.s24 { &.s24 {
width:24px; width:24px;
height:24px;
} }
&.s32 { &.s32 {
width:32px; width:32px;
height:32px;
} }
} }
......
/**
* JQUERY UI datepicker
*
*/
.ui-datepicker {
border-color:#eee;
padding:20px;
.ui-state-default {
background:#f1f1f1;
padding:5px;
}
.ui-state-active {
background:#fff;
}
}
/**
* JQUERY UI progressbar
*
*/
.ui-progressbar {
border:1px solid #ddd;
height:6px;
margin:0;
padding:0;
.ui-progressbar-value {
background-color: #62C462;//$blue_link;
margin:0;
}
}
...@@ -23,6 +23,8 @@ $blue_link: #2fa0bb; ...@@ -23,6 +23,8 @@ $blue_link: #2fa0bb;
$style_color: #474D57; $style_color: #474D57;
$hover: #FDF5D9; $hover: #FDF5D9;
/** GITLAB Fonts **/
@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
/** MIXINS **/ /** MIXINS **/
@mixin shade { @mixin shade {
...@@ -165,9 +167,3 @@ $hover: #FDF5D9; ...@@ -165,9 +167,3 @@ $hover: #FDF5D9;
* *
*/ */
@import "highlight/dark.scss"; @import "highlight/dark.scss";
/**
* JQUERY UI ext
*
*/
@import "jquery_ui.scss";
...@@ -26,23 +26,25 @@ header { ...@@ -26,23 +26,25 @@ header {
float:left; float:left;
position:relative; position:relative;
top:-5px; top:-5px;
a { a {
float:left; float:left;
h1 { h1 {
text-indent:-9999px; padding-top: 5px;
width:102px; width:102px;
background: url('logo_text.png') no-repeat 0px -3px; background: url('logo_dark.png') no-repeat 0px -3px;
float:left; float:left;
margin-left:5px; margin-left:5px;
font-size:20px; font-size:36px;
line-height:36px; line-height:36px;
font-weight:bold; font-weight:normal;
color:#aaa; color:$style_color;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
padding-left:50px; padding-left:50px;
height:40px;
font-family: 'Korolev', sans-serif;
} }
} }
.separator { .separator {
margin-left:20px; margin-left:20px;
...@@ -68,14 +70,16 @@ header { ...@@ -68,14 +70,16 @@ header {
* *
*/ */
.project_name { .project_name {
position:relative;
float:left; float:left;
margin:0; margin:0;
margin-right:30px; margin-right:30px;
font-size:24px; font-size:36px;
line-height:36px; line-height:36px;
font-weight:500; font-weight:normal;
color:$style_color; color:$style_color;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
font-family: 'Korolev', sans-serif;
} }
.fbtn { .fbtn {
......
...@@ -27,6 +27,7 @@ body.login-page{ ...@@ -27,6 +27,7 @@ body.login-page{
-moz-border-radius-topright: 5px; -moz-border-radius-topright: 5px;
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-top-right-radius: 5px; border-top-right-radius: 5px;
margin-bottom:0px;
} }
.login-box input.text.bottom{ .login-box input.text.bottom{
......
...@@ -94,3 +94,8 @@ li.merge_request { ...@@ -94,3 +94,8 @@ li.merge_request {
padding-bottom: 2px; padding-bottom: 2px;
} }
} }
.merge_in_progress {
@extend .padded;
@extend .append-bottom-10;
}
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
p { color:$style_color; } p { color:$style_color; }
.note-author { color: $style_color;} .note-author { color: $style_color;}
.note-title { margin-left:50px; padding-top: 5px;} .note-title { margin-left:45px; padding-top: 5px;}
.avatar { .avatar {
margin-top:3px; margin-top:3px;
} }
......
.projects { .projects {
@extend .row; @extend .row;
.activities { .activities {
} }
.side { .side {
@extend .span4; @extend .span4;
@extend .right; @extend .right;
.projects_box { .projects_box {
h5 { h5 {
color:$style_color; color:$style_color;
font-size:16px; font-size:16px;
text-shadow: 0 1px 1px #fff; text-shadow: 0 1px 1px #fff;
padding: 2px 10px;
} }
@extend .leftbar; @extend .leftbar;
@extend .ui-box; @extend .ui-box;
...@@ -19,21 +20,22 @@ ...@@ -19,21 +20,22 @@
} }
} }
.new_project, .new_project,
.edit_project { .edit_project {
.project_name_holder { .project_name_holder {
input, input,
label { label {
font-size:16px; font-size:16px;
line-height:20px; line-height:20px;
padding:8px; padding:8px;
} }
label { label {
color:#888; color:#888;
} }
.btn { .btn {
padding:6px; padding:6px;
margin-left:10px; margin-left:10px;
margin-bottom:8px;
} }
} }
} }
...@@ -15,4 +15,36 @@ ...@@ -15,4 +15,36 @@
color: $blue_link; color: $blue_link;
} }
} }
header {
.fbtn {
.btn {
background-color: #F8F8F8;
background-image: -webkit-gradient(linear,left top,left bottom,from(#F8F8F8),to(#ECECEC));
background-image: -webkit-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -moz-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -ms-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: -o-linear-gradient(top,#F8F8F8,#ECECEC);
background-image: linear-gradient(top,#F8F8F8,#ECECEC);
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');
border-color: #C6C6C6;
margin-left:7px;
@include border-radius(3px);
box-shadow:none;
color:#666;
}
}
.search {
.search-input {
@include border-radius(3px);
border-color: #C6C6C6;
box-shadow:none;
}
}
.pic {
img {
@include border-radius(3px);
}
}
}
} }
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
.fbtn { .fbtn {
.btn { .btn {
i {
position: relative;
top: 1px;
}
margin-left:8px; margin-left:8px;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E)); background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E); background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
...@@ -32,6 +36,10 @@ ...@@ -32,6 +36,10 @@
background-image: -moz-linear-gradient(#595D63 6.6%, #202227); background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
background-image: -o-linear-gradient(#595D63 6.6%, #202227); background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0; background-position:0 0;
color:#fff;
i {
@extend .icon-white;
}
} }
border: 1px solid #31363E; border: 1px solid #31363E;
...@@ -59,14 +67,9 @@ ...@@ -59,14 +67,9 @@
.app_logo { .app_logo {
a { a {
h1 { h1 {
background: url('images.png') no-repeat -3px -6px; background: url('logo_white.png') no-repeat 0px -3px;
width: 65px; color:#fff;
height: 26px; text-shadow: 0 1px 1px #111;
margin: 6px 0;
padding: 0;
float: left;
text-indent: -1000em;
float:left;
} }
} }
.separator { .separator {
...@@ -75,7 +78,6 @@ ...@@ -75,7 +78,6 @@
} }
.project_name { .project_name {
line-height:38px;
color:#fff; color:#fff;
text-shadow: 0 1px 1px #111; text-shadow: 0 1px 1px #111;
} }
......
...@@ -37,26 +37,20 @@ ...@@ -37,26 +37,20 @@
* *
*/ */
.app_logo { .app_logo {
width:160px;
a { a {
h1 { h1 {
opacity: 0.7; background: none;
background: url('images.png') no-repeat -3px -6px; color:#DDD;
width: 65px; font-size:30px;
height: 26px; text-shadow: 0 1px 1px #111;
margin: 6px 0; padding-left: 0;
padding: 0;
float: left;
text-indent: -1000em;
float:left;
&:hover {
opacity: 1.0;
}
} }
} }
.separator { .separator {
width: 1px; width: 1px;
height: 40px; height: 40px;
margin: 0 9px; margin: 0 10px;
overflow: hidden; overflow: hidden;
background: #222; background: #222;
border-left: 1px solid #333; border-left: 1px solid #333;
...@@ -66,7 +60,6 @@ ...@@ -66,7 +60,6 @@
.fbtn { .fbtn {
.btn { .btn {
i { i {
@extend .icon-white;
position: relative; position: relative;
top: 2px; top: 2px;
} }
...@@ -77,10 +70,14 @@ ...@@ -77,10 +70,14 @@
color:#ccc; color:#ccc;
&:hover { &:hover {
color:#fff; color:#fff;
i {
@extend .icon-white;
}
} }
border: none; border: none;
box-shadow:none; box-shadow:none;
text-shadow: 0 -1px 0 #000000; text-shadow: 0 -1px 0 #000000;
border-left: 1px solid #333;
} }
} }
...@@ -113,9 +110,9 @@ ...@@ -113,9 +110,9 @@
* *
*/ */
.project_name { .project_name {
line-height:34px; line-height:36px;
font-size:22px; font-size:30px;
color:#fff; color:#DDD;
text-shadow: 0 1px 1px #111; text-shadow: 0 1px 1px #111;
} }
......
class LabelsController < ApplicationController
before_filter :authenticate_user!
before_filter :project
before_filter :module_enabled
layout "project"
# Authorize
before_filter :add_project_abilities
# Allow read any issue
before_filter :authorize_read_issue!
respond_to :js, :html
def index
@labels = Issue.tag_counts_on(:labels)
end
protected
def module_enabled
return render_404 unless @project.issues_enabled
end
end
...@@ -12,8 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -12,8 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def ldap def ldap
# We only find ourselves here if the authentication to LDAP was successful. # We only find ourselves here if the authentication to LDAP was successful.
info = request.env["omniauth.auth"]["info"] @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
@user = User.find_for_ldap_auth(info)
if @user.persisted? if @user.persisted?
@user.remember_me = true @user.remember_me = true
end end
...@@ -39,7 +38,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -39,7 +38,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
current_user.save current_user.save
redirect_to profile_path redirect_to profile_path
else else
@user = User.find_by_provider_and_uid(provider, uid) @user = User.find_by_provider_and_extern_uid(provider, uid)
if @user if @user
sign_in_and_redirect @user sign_in_and_redirect @user
......
require File.join(Rails.root, 'lib', 'graph_commit') require Rails.root.join('lib', 'gitlab', 'graph_commit')
class ProjectsController < ApplicationController class ProjectsController < ApplicationController
before_filter :project, except: [:index, :new, :create] before_filter :project, except: [:index, :new, :create]
...@@ -78,7 +78,7 @@ class ProjectsController < ApplicationController ...@@ -78,7 +78,7 @@ class ProjectsController < ApplicationController
end end
def graph def graph
@days_json, @commits_json = GraphCommit.to_graph(project) @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project)
end end
def destroy def destroy
......
...@@ -9,6 +9,7 @@ class TeamMembersController < ApplicationController ...@@ -9,6 +9,7 @@ class TeamMembersController < ApplicationController
def show def show
@team_member = project.users_projects.find(params[:id]) @team_member = project.users_projects.find(params[:id])
@events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
end end
def new def new
......
class ApplicationDecorator < Drapper::Base class ApplicationDecorator < Draper::Base
# Lazy Helpers # Lazy Helpers
# PRO: Call Rails helpers without the h. proxy # PRO: Call Rails helpers without the h. proxy
# ex: number_to_currency(model.price) # ex: number_to_currency(model.price)
......
...@@ -2,10 +2,13 @@ require 'digest/md5' ...@@ -2,10 +2,13 @@ require 'digest/md5'
module ApplicationHelper module ApplicationHelper
def gravatar_icon(user_email = '', size = 40) def gravatar_icon(user_email = '', size = 40)
return unless user_email if Gitlab.config.disable_gravatar? || user_email.blank?
gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" 'no_avatar.png'
user_email.strip! else
"#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
user_email.strip!
"#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
end
end end
def request_protocol def request_protocol
......
module GitlabMarkdownHelper module GitlabMarkdownHelper
# Replaces references (i.e. @abc, #123, !456, ...) in the text with links to
# the appropriate items in Gitlab.
#
# text - the source text
# html_options - extra options for the reference links as given to link_to
#
# note: reference links will only be generated if @project is set
#
# see Gitlab::Markdown for details on the supported syntax
def gfm(text, html_options = {}) def gfm(text, html_options = {})
return text if text.nil? return text if text.nil?
return text if @project.nil? return text if @project.nil?
# Extract pre blocks # Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/ # from http://github.github.com/github-flavored-markdown/
extractions = {} extractions = {}
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
...@@ -25,7 +34,15 @@ module GitlabMarkdownHelper ...@@ -25,7 +34,15 @@ module GitlabMarkdownHelper
text.html_safe text.html_safe
end end
# circumvents nesting links, which will behave bad in browsers # Use this in places where you would normally use link_to(gfm(...), ...).
#
# It solves a problem occurring with nested links (i.e.
# "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
# interpreted as intended. Browsers will parse something like
# "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
# not linked any more). link_to_gfm corrects that. It wraps all parts to
# explicitly produce the correct linking behavior (i.e.
# "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
def link_to_gfm(body, url, html_options = {}) def link_to_gfm(body, url, html_options = {})
gfm_body = gfm(body, html_options) gfm_body = gfm(body, html_options)
......
...@@ -12,74 +12,102 @@ class Notify < ActionMailer::Base ...@@ -12,74 +12,102 @@ class Notify < ActionMailer::Base
def new_user_email(user_id, password) def new_user_email(user_id, password)
@user = User.find(user_id) @user = User.find(user_id)
@password = password @password = password
mail(to: @user.email, subject: "gitlab | Account was created for you") mail(to: @user.email, subject: subject("Account was created for you"))
end end
def new_issue_email(issue_id) def new_issue_email(issue_id)
@issue = Issue.find(issue_id) @issue = Issue.find(issue_id)
@project = @issue.project @project = @issue.project
mail(to: @issue.assignee_email, subject: "gitlab | new issue ##{@issue.id} | #{@issue.title} | #{@project.name}") mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
end end
def note_wall_email(recipient_id, note_id) def note_wall_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | #{@project.name}") mail(to: recipient(recipient_id), subject: subject)
end end
def note_commit_email(recipient_id, note_id) def note_commit_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@commit = @note.target @commit = @note.target
@commit = CommitDecorator.decorate(@commit) @commit = CommitDecorator.decorate(@commit)
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for commit #{@commit.short_id} | #{@commit.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
end end
def note_merge_request_email(recipient_id, note_id) def note_merge_request_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@merge_request = @note.noteable @merge_request = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for merge request !#{@merge_request.id} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}"))
end end
def note_issue_email(recipient_id, note_id) def note_issue_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@issue = @note.noteable @issue = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for issue ##{@issue.id} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}"))
end end
def note_wiki_email(recipient_id, note_id) def note_wiki_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@wiki = @note.noteable @wiki = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for wiki | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for wiki"))
end end
def new_merge_request_email(merge_request_id) def new_merge_request_email(merge_request_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project @project = @merge_request.project
mail(to: @merge_request.assignee_email, subject: "gitlab | new merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
end end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
recipient = User.find(recipient_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
@previous_assignee ||= User.find(previous_assignee_id) @previous_assignee ||= User.find(previous_assignee_id)
@project = @merge_request.project @project = @merge_request.project
mail(to: recipient.email, subject: "gitlab | changed merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
recipient = User.find(recipient_id)
@issue = Issue.find(issue_id) @issue = Issue.find(issue_id)
@previous_assignee ||= User.find(previous_assignee_id) @previous_assignee ||= User.find(previous_assignee_id)
@project = @issue.project @project = @issue.project
mail(to: recipient.email, subject: "gitlab | changed issue ##{@issue.id} | #{@issue.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
end
private
# Look up a User by their ID and return their email address
#
# recipient_id - User ID
#
# Returns a String containing the User's email address.
def recipient(recipient_id)
if recipient = User.find(recipient_id)
recipient.email
end
end
# Formats arguments into a String suitable for use as an email subject
#
# extra - Extra Strings to be inserted into the subject
#
# Examples
#
# >> subject('Lorem ipsum')
# => "gitlab | Lorem ipsum"
#
# # Automatically inserts Project name when @project is set
# >> @project = Project.last
# => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# >> subject('Lorem ipsum')
# => "gitlab | Lorem ipsum | Ruby on Rails"
#
# # Accepts multiple arguments
# >> subject('Lorem ipsum', 'Dolor sit amet')
# => "gitlab | Lorem ipsum | Dolor sit amet"
def subject(*extra)
"gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "")
end end
end end
...@@ -9,8 +9,6 @@ class Issue < ActiveRecord::Base ...@@ -9,8 +9,6 @@ class Issue < ActiveRecord::Base
validates :description, validates :description,
length: { within: 0..2000 } length: { within: 0..2000 }
acts_as_list
def self.open_for(user) def self.open_for(user)
opened.assigned(user) opened.assigned(user)
end end
......
...@@ -88,8 +88,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -88,8 +88,11 @@ class MergeRequest < ActiveRecord::Base
end end
def unmerged_diffs def unmerged_diffs
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} # Only show what is new in the source branch compared to the target branch, not the other way around.
diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
# From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
diffs = project.repo.diff(common_commit, source_branch)
end end
def last_commit def last_commit
......
...@@ -2,7 +2,7 @@ require "grit" ...@@ -2,7 +2,7 @@ require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Repository include Repository
include ProjectPush include PushObserver
include Authority include Authority
include Team include Team
......
...@@ -7,7 +7,7 @@ class User < ActiveRecord::Base ...@@ -7,7 +7,7 @@ class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
:name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme,
:theme_id, :force_random_password :theme_id, :force_random_password, :extern_uid, :provider
attr_accessor :force_random_password attr_accessor :force_random_password
...@@ -54,6 +54,8 @@ class User < ActiveRecord::Base ...@@ -54,6 +54,8 @@ class User < ActiveRecord::Base
validates :bio, length: { within: 0..255 } validates :bio, length: { within: 0..255 }
validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
before_save :ensure_authentication_token before_save :ensure_authentication_token
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
...@@ -84,21 +86,31 @@ class User < ActiveRecord::Base ...@@ -84,21 +86,31 @@ class User < ActiveRecord::Base
where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
end end
def self.find_for_ldap_auth(omniauth_info) def self.find_for_ldap_auth(auth, signed_in_resource=nil)
name = omniauth_info.name.force_encoding("utf-8") uid = auth.info.uid
email = omniauth_info.email.downcase unless omniauth_info.email.nil? provider = auth.provider
raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil? name = auth.info.name.force_encoding("utf-8")
email = auth.info.email.downcase unless auth.info.email.nil?
raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
if @user = User.find_by_email(email) if @user = User.find_by_extern_uid_and_provider(uid, provider)
@user
# workaround for backward compatibility
elsif @user = User.find_by_email(email)
logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
@user.update_attributes(:extern_uid => uid, :provider => provider)
@user @user
else else
logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
password = Devise.friendly_token[0, 8].downcase password = Devise.friendly_token[0, 8].downcase
@user = User.create( @user = User.create(
name: name, :extern_uid => uid,
email: email, :provider => provider,
password: password, :name => name,
password_confirmation: password, :email => email,
projects_limit: Gitlab.config.default_projects_limit :password => password,
:password_confirmation => password,
:projects_limit => Gitlab.config.default_projects_limit
) )
end end
end end
......
module ProjectPush module PushObserver
def observe_push(oldrev, newrev, ref, user) def observe_push(oldrev, newrev, ref, user)
data = post_receive_data(oldrev, newrev, ref, user) data = post_receive_data(oldrev, newrev, ref, user)
......
...@@ -30,26 +30,10 @@ module Repository ...@@ -30,26 +30,10 @@ module Repository
Commit.commits_between(repo, from, to) Commit.commits_between(repo, from, to)
end end
def write_hooks
%w(post-receive).each do |hook|
write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
end
end
def satellite def satellite
@satellite ||= Gitlab::Satellite.new(self) @satellite ||= Gitlab::Satellite.new(self)
end end
def write_hook(name, content)
hook_file = File.join(path_to_repo, 'hooks', name)
File.open(hook_file, 'w') do |f|
f.write(content)
end
File.chmod(0775, hook_file)
end
def has_post_receive_file? def has_post_receive_file?
hook_file = File.join(path_to_repo, 'hooks', 'post-receive') hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
File.exists?(hook_file) File.exists?(hook_file)
...@@ -73,8 +57,6 @@ module Repository ...@@ -73,8 +57,6 @@ module Repository
def update_repository def update_repository
Gitlab::GitHost.system.update_project(path, self) Gitlab::GitHost.system.update_project(path, self)
write_hooks if File.exists?(path_to_repo)
end end
def destroy_repository def destroy_repository
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
Read more about system hooks Read more about system hooks
%strong #{link_to "here", help_system_hooks_path, class: "vlink"} %strong #{link_to "here", help_system_hooks_path, class: "vlink"}
= form_for @hook, as: :hook, url: admin_hooks_path do |f| = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
- @hook.errors.full_messages.each do |msg| - @hook.errors.full_messages.each do |msg|
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Projects Projects
= link_to 'New Project', new_admin_project_path, class: "btn small right" = link_to 'New Project', new_admin_project_path, class: "btn small right"
%br %br
= form_tag admin_projects_path, method: :get do = form_tag admin_projects_path, method: :get, class: 'form-inline' do
= text_field_tag :name, params[:name], class: "xlarge" = text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary" = submit_tag "Search", class: "btn submit primary"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= link_to 'New User', new_admin_user_path, class: "btn small right" = link_to 'New User', new_admin_user_path, class: "btn small right"
%br %br
= form_tag admin_users_path, method: :get do = form_tag admin_users_path, method: :get, class: 'form-inline' do
= text_field_tag :name, params[:name], class: "xlarge" = text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary" = submit_tag "Search", class: "btn submit primary"
%ul.nav.nav-pills %ul.nav.nav-pills
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
%span.btn.disabled.grouped %span.btn.disabled.grouped
%i.icon-comment %i.icon-comment
= @notes_count = @notes_count
= link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do = link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do
%i.icon-download-alt %i.icon-download-alt
Get Patch Get Patch
= link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do
%strong Browse Code » %strong Browse Code »
%h3.commit-title.page_title %h3.commit-title.page_title
= gfm @commit.title = gfm @commit.title
......
- if @projects.any? - if @projects.any?
.projects .projects
.activities.span8 .activities.span8
- if current_user.require_ssh_key? = render 'shared/no_ssh'
.alert.alert-error.padded
%span
You wont be able to pull/push project code unless you
%strong
= link_to new_key_path, class: "vlink" do
add new key
to your profile
- if @events.any? - if @events.any?
.content_list= render @events .content_list= render @events
- else - else
...@@ -57,5 +50,5 @@ ...@@ -57,5 +50,5 @@
If you will be added to project - it will be displayed here If you will be added to project - it will be displayed here
:javascript :javascript
$(function(){ Pager.init(20); }); $(function(){ Pager.init(20); });
...@@ -23,5 +23,3 @@ ...@@ -23,5 +23,3 @@
= preserve do = preserve do
sudo chmod -R 770 /home/git/repositories/ sudo chmod -R 770 /home/git/repositories/
sudo chown -R git:git /home/git/repositories/ sudo chown -R git:git /home/git/repositories/
sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
...@@ -31,3 +31,6 @@ ...@@ -31,3 +31,6 @@
%li %li
%h5= link_to "Gitlab Markdown", help_markdown_path %h5= link_to "Gitlab Markdown", help_markdown_path
%li
%h5= link_to "SSH keys", help_ssh_path
%h3 Permissions %h3.page_title Permissions
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
......
%h3.page_title SSH Keys
.back_link
= link_to help_path do
&larr; to index
%hr
%p.slead
SSH key allows you to establish a secure connection between your computer and Gitlab
%p.slead
To generate a new SSH key just open your terminal and use code below.
%pre.dark
ssh-keygen -t rsa -C "#{current_user.email}"
\# Creates a new ssh key using the provided email
\# Generating public/private rsa key pair...
%p.slead
Next just use code below to dump your public key and add to GITLAB SSH Keys
%pre.dark
cat ~/.ssh/id_rsa.pub
\# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....
%h3 System hooks %h3 System hooks
.back_link .back_link
= link_to :back do = link_to :back do
&larr; back &larr; back
%hr %hr
%p.slead %p.slead
Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
%br %br
System Hooks can be used for logging or change information in LDAP server. System Hooks can be used for logging or change information in LDAP server.
......
%h3 Web hooks %h3.page_title Web hooks
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
%p.slead %p.slead
Every Gitlab project can trigger a web server whenever the repo is pushed to. Every Gitlab project can trigger a web server whenever the repo is pushed to.
%br %br
Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
%br %br
......
- bash_lexer = Pygments::Lexer[:bash] %h3.page_title Workflow
%h3 Workflow
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
...@@ -9,25 +8,25 @@ ...@@ -9,25 +8,25 @@
%li %li
%p Clone project %p Clone project
.bash .bash
%pre %pre.dark
git clone git@example.com:project-name.git git clone git@example.com:project-name.git
%li %li
%p Create branch with your feature %p Create branch with your feature
.bash .bash
%pre %pre.dark
git checkout -b $feature_name git checkout -b $feature_name
%li %li
%p Write code. Commit changes %p Write code. Commit changes
.bash .bash
%pre %pre.dark
git commit -am "My feature is ready" git commit -am "My feature is ready"
%li %li
%p Push your branch to gitlabhq %p Push your branch to gitlabhq
.bash .bash
%pre %pre.dark
git push origin $feature_name git push origin $feature_name
%li %li
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
Read more about web hooks Read more about web hooks
%strong #{link_to "here", help_web_hooks_path, class: "vlink"} %strong #{link_to "here", help_web_hooks_path, class: "vlink"}
= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project) do |f| = form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
- @hook.errors.full_messages.each do |msg| - @hook.errors.full_messages.each do |msg|
......
%div.issue-form-holder %div.issue-form-holder
%h3= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" %h3.page_title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}"
= form_for [@project, @issue], remote: request.xhr? do |f| = form_for [@project, @issue], remote: request.xhr? do |f|
-if @issue.errors.any? -if @issue.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
...@@ -9,26 +9,26 @@ ...@@ -9,26 +9,26 @@
.issue_form_box .issue_form_box
.issue_title .issue_title
.clearfix .clearfix
= f.label :title do = f.label :title do
%strong= "Subject *" %strong= "Subject *"
.input .input
= f.text_field :title, maxlength: 255, class: "xxlarge" = f.text_field :title, maxlength: 255, class: "xxlarge"
.issue_middle_block .issue_middle_block
.issue_assignee .issue_assignee
= f.label :assignee_id do = f.label :assignee_id do
%i.icon-user %i.icon-user
Assign to Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }) .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" })
.issue_milestone .issue_milestone
= f.label :milestone_id do = f.label :milestone_id do
%i.icon-time %i.icon-time
Milestone Milestone
.input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }) .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" })
.issue_description .issue_description
.clearfix .clearfix
= f.label :label_list do = f.label :label_list do
%i.icon-tag %i.icon-tag
Labels Labels
.input .input
= f.text_field :label_list, maxlength: 2000, class: "xxlarge" = f.text_field :label_list, maxlength: 2000, class: "xxlarge"
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
%li{class: "#{'active' if current_page?(project_milestones_path(@project))}"} %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
= link_to project_milestones_path(@project), class: "tab" do = link_to project_milestones_path(@project), class: "tab" do
Milestones Milestones
%li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
= link_to project_labels_path(@project), class: "tab" do
Labels
%li.right %li.right
%span.rss-icon %span.rss-icon
= link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
.span5 .span5
- if can? current_user, :write_issue, @project - if can? current_user, :write_issue, @project
= link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do
%i.icon-plus
New Issue New Issue
= form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
= hidden_field_tag :project_id, @project.id, { id: 'project_id' } = hidden_field_tag :project_id, @project.id, { id: 'project_id' }
...@@ -21,7 +22,7 @@ ...@@ -21,7 +22,7 @@
.issues_bulk_update.hide .issues_bulk_update.hide
= form_tag bulk_update_project_issues_path(@project), method: :post do = form_tag bulk_update_project_issues_path(@project), method: :post do
%span.update_issues_text Update selected issues with &nbsp; %span.update_issues_text Update selected issues with &nbsp;
.left .left
= select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
...@@ -53,7 +54,7 @@ ...@@ -53,7 +54,7 @@
= select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone")
= hidden_field_tag :f, params[:f] = hidden_field_tag :f, params[:f]
.clearfix .clearfix
%ul#issues-table.unstyled.issues_table %ul#issues-table.unstyled.issues_table
= render "issues" = render "issues"
......
...@@ -11,7 +11,13 @@ ...@@ -11,7 +11,13 @@
.input= f.text_field :title .input= f.text_field :title
.clearfix .clearfix
= f.label :key = f.label :key
.input= f.text_area :key, class: [:xxlarge, :thin_area] .input
= f.text_area :key, class: [:xxlarge, :thin_area]
%p.hint
Paste your public key here. Read more about how generate it
= link_to "here", help_ssh_path
.actions .actions
= f.submit 'Save', class: "primary btn" = f.submit 'Save', class: "primary btn"
= link_to "Cancel", keys_path, class: "btn" = link_to "Cancel", keys_path, class: "btn"
......
%h3.page_title New key %h3.page_title Add an SSH Key
%hr %hr
= render 'form' = render 'form'
......
%li.wll
%strong= label.name
.right
%span= pluralize label.count, 'issue'
= render "issues/head"
%h3.page_title
Labels
%br
%div.ui-box
%ul.unstyled.labels-table
- @labels.each do |label|
= render 'label', label: label
- unless @labels.present?
%li
%h3.nothing_here_message Nothing to show here
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
= favicon_link_tag 'favicon.ico' = favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
-# Atom feed -# Atom feed
- if controller_name == 'projects' && action_name == 'index' - if controller_name == 'projects' && action_name == 'index'
= auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
......
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
}); });
$(".edit_merge_request").live("ajax:beforeSend", function() { $(".edit_merge_request").live("ajax:beforeSend", function() {
$(this).replaceWith('#{image_tag "ajax_loader.gif"}'); $('.can_be_merged').hide();
$('.merge_in_progress').show();
}) })
}) })
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
%a.close{href: "#"} × %a.close{href: "#"} ×
%h3 How To Merge %h3 How To Merge
.modal-body .modal-body
%pre %pre.dark
= preserve do = preserve do
:erb git checkout #{@merge_request.target_branch}
git checkout <%= @merge_request.target_branch %> git fetch origin
git fetch origin git merge origin/#{@merge_request.source_branch}
git merge origin/<%= @merge_request.source_branch %> git push origin #{@merge_request.target_branch}
git push origin <%= @merge_request.target_branch %>
:javascript :javascript
......
...@@ -40,3 +40,6 @@ ...@@ -40,3 +40,6 @@
.alert.alert-info .alert.alert-info
%strong This merge request already can not be merged. Try to reload page. %strong This merge request already can not be merged. Try to reload page.
.merge_in_progress.hide
%span.cgray Merge is in progress. Please wait. Page will be automatically reloaded. &nbsp;
= image_tag "ajax_loader.gif"
%h3= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}" %h3.page_title= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}"
.back_link .back_link
= link_to project_milestones_path(@project) do = link_to project_milestones_path(@project) do
&larr; To milestones &larr; To milestones
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
= f.label :title, "Title", class: "control-label" = f.label :title, "Title", class: "control-label"
.controls .controls
= f.text_field :title, maxlength: 255, class: "input-xlarge" = f.text_field :title, maxlength: 255, class: "input-xlarge"
%p.help-block Required %p.hint Required
.control-group .control-group
= f.label :description, "Description", class: "control-label" = f.label :description, "Description", class: "control-label"
.controls .controls
= f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10
%p.help-block Markdown is enabled. %p.hint Markdown is enabled.
.span6 .span6
.control-group .control-group
= f.label :due_date, "Due Date", class: "control-label" = f.label :due_date, "Due Date", class: "control-label"
......
- if note.valid? - if note.valid?
:plain :plain
$("#new_note .errors").remove(); $("#new_note .error").remove();
$('#new_note textarea').val(""); $('#new_note textarea').val("");
$('#preview-link').text('Preview');
$('#preview-note').hide(); $('#note_note').show();
NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}");
- else - else
:plain :plain
......
%li{id: dom_id(note), class: "note"} %li{id: dom_id(note), class: "note"}
= image_tag gravatar_icon(note.author.email), class: "avatar" = image_tag gravatar_icon(note.author.email), class: "avatar s32"
%div.note-author %div.note-author
%strong= note.author_name %strong= note.author_name
= link_to "##{dom_id(note)}", name: dom_id(note) do = link_to "##{dom_id(note)}", name: dom_id(note) do
......
- if current_user.require_ssh_key? = render 'shared/no_ssh'
.alert-message.block-message.error
%ul
%li You have no ssh keys added to your profile.
%li You wont be able to pull/push repository.
%li Visit profile &rarr; keys and add public key of every machine you want to use for work with gitlabhq.
.alert-message.block-message.error
%ul.unstyled.alert_holder
%li You should push repository to proceed.
%li After push you will be able to browse code, commits etc.
- bash_lexer = Pygments::Lexer[:bash]
%div.git-empty %div.git-empty
%h3 Git global setup: %h4 Git global setup:
- setup_str = ["git config --global user.name \"#{current_user.name}\"", %pre.dark
"git config --global user.email \"#{current_user.email}\""].join("\n") = preserve do
= preserve do git config --global user.name "#{current_user.name}"
= raw bash_lexer.highlight(setup_str, lexer: 'bash', options: {encoding: 'utf-8'}) git config --global user.email "#{current_user.email}"
%br
%br
%h3 Create Repository
- repo_setup_str = ["mkdir #{@project.path}",
"cd #{@project.path}",
"git init",
"touch README",
"git add README",
"git commit -m 'first commit'",
"git remote add origin #{@project.url_to_repo}",
"git push -u origin master"].join("\n")
= preserve do %h4.prepend-top-20 Create Repository
= raw bash_lexer.highlight(repo_setup_str) %pre.dark
= preserve do
mkdir #{@project.path}
cd #{@project.path}
git init
touch README
git add README
git commit -m 'first commit'
git remote add origin #{@project.url_to_repo}
git push -u origin master
%br %h4.prepend-top-20 Existing Git Repo?
%br %pre.dark
%h3 Existing Git Repo? = preserve do
- exist_repo_setup_str = ["cd existing_git_repo", cd existing_git_repo
"git remote add origin #{@project.url_to_repo}", git remote add origin #{@project.url_to_repo}
"git push -u origin master"].join("\n") git push -u origin master
= preserve do
= raw bash_lexer.highlight(exist_repo_setup_str)
- if can? current_user, :admin_project, @project - if can? current_user, :admin_project, @project
.alert-message.block-message.error.prepend-top-20 .prepend-top-20
= link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger" = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger right"
...@@ -51,8 +51,6 @@ ...@@ -51,8 +51,6 @@
:javascript :javascript
$(function(){ $(function(){
$('select#branch').selectmenu({style:'popup', width:200});
$('select#tag').selectmenu({style:'popup', width:200});
$('.project-refs-select').chosen(); $('.project-refs-select').chosen();
history.pushState({ path: this.path }, '', "#{@history_path}"); history.pushState({ path: this.path }, '', "#{@history_path}");
......
- if tm - if tm
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) = link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
= link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link" = link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link"
= form_tag search_path, method: :get do |f| = form_tag search_path, method: :get, class: 'form-inline' do |f|
.padded .padded
= label_tag :search do = label_tag :search do
%strong Looking for %strong Looking for
......
- if current_user.require_ssh_key?
%h6.error_message
%span
You wont be able to pull/push project code unless you
%strong
= link_to new_key_path, class: "vlink" do
add SSH key
to your profile
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%span.label Blocked %span.label Blocked
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
= image_tag gravatar_icon(user.email, 40), class: "avatar" = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
%strong= truncate(user.name, lenght: 40) %strong= truncate(user.name, lenght: 40)
%br %br
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
= form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f|
= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin
%hr %hr
= render user.recent_events.limit(5) = render @events
:javascript :javascript
$(function(){ $(function(){
$('.repo-access-select, .project-access-select').live("change", function() { $('.repo-access-select, .project-access-select').live("change", function() {
......
...@@ -44,5 +44,8 @@ module Gitlab ...@@ -44,5 +44,8 @@ module Gitlab
# Version of your assets, change this if you want to expire all your assets # Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0' config.assets.version = '1.0'
# Add fonts
config.assets.paths << "#{Rails.root}/app/assets/fonts"
end end
end end
...@@ -23,7 +23,7 @@ app: ...@@ -23,7 +23,7 @@ app:
default_projects_limit: 10 default_projects_limit: 10
# backup_path: "/vol/backups" # default: Rails.root + backups/ # backup_path: "/vol/backups" # default: Rails.root + backups/
# backup_keep_time: 604800 # default: 0 (forever) (in seconds) # backup_keep_time: 604800 # default: 0 (forever) (in seconds)
# disable_gravatar: true # default: false - Disable user avatars from Gravatar.com
# #
# 2. Advanced settings: # 2. Advanced settings:
...@@ -39,7 +39,6 @@ git_host: ...@@ -39,7 +39,6 @@ git_host:
receive_pack: true receive_pack: true
# port: 22 # port: 22
# Git settings # Git settings
# Use default values unless you understand it # Use default values unless you understand it
git: git:
......
...@@ -120,5 +120,8 @@ class Settings < Settingslogic ...@@ -120,5 +120,8 @@ class Settings < Settingslogic
omniauth['providers'] || [] omniauth['providers'] || []
end end
def disable_gravatar?
app['disable_gravatar'] || false
end
end end
end end
#if defined?(Footnotes) && Rails.env.development?
#Footnotes.run! # first of all
#end
...@@ -30,6 +30,7 @@ Gitlab::Application.routes.draw do ...@@ -30,6 +30,7 @@ Gitlab::Application.routes.draw do
get 'help/web_hooks' => 'help#web_hooks' get 'help/web_hooks' => 'help#web_hooks'
get 'help/system_hooks' => 'help#system_hooks' get 'help/system_hooks' => 'help#system_hooks'
get 'help/markdown' => 'help#markdown' get 'help/markdown' => 'help#markdown'
get 'help/ssh' => 'help#ssh'
# #
# Admin Area # Admin Area
...@@ -196,7 +197,9 @@ Gitlab::Application.routes.draw do ...@@ -196,7 +197,9 @@ Gitlab::Application.routes.draw do
end end
resources :team_members resources :team_members
resources :milestones resources :milestones
resources :labels, :only => [:index]
resources :issues do resources :issues do
collection do collection do
post :sort post :sort
post :bulk_update post :bulk_update
......
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
class AddProviderAndUidToUsers < ActiveRecord::Migration
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
end
end
...@@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version => 20120803152018) do ...@@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version => 20120803152018) do
t.boolean "blocked", :default => false, :null => false t.boolean "blocked", :default => false, :null => false
t.integer "failed_attempts", :default => 0 t.integer "failed_attempts", :default => 0
t.datetime "locked_at" t.datetime "locked_at"
t.string "extern_uid"
t.string "provider" t.string "provider"
t.string "uid"
end end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
create_table "users_projects", :force => true do |t| create_table "users_projects", :force => true do |t|
......
...@@ -119,7 +119,6 @@ Permissions: ...@@ -119,7 +119,6 @@ Permissions:
sudo chmod -R g+rwX /home/git/repositories/ sudo chmod -R g+rwX /home/git/repositories/
sudo chown -R git:git /home/git/repositories/ sudo chown -R git:git /home/git/repositories/
sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
#### CHECK: Logout & login again to apply git group to your user #### CHECK: Logout & login again to apply git group to your user
...@@ -134,7 +133,7 @@ Permissions: ...@@ -134,7 +133,7 @@ Permissions:
# 4. Install gitlab and configuration. Check status configuration. # 4. Install gitlab and configuration. Check status configuration.
sudo gem install charlock_holmes sudo gem install charlock_holmes --version '0.6.8'
sudo pip install pygments sudo pip install pygments
sudo gem install bundler sudo gem install bundler
cd /home/gitlab cd /home/gitlab
...@@ -177,6 +176,11 @@ Permissions: ...@@ -177,6 +176,11 @@ Permissions:
#### Setup DB #### Setup DB
sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production
#### Setup gitlab hooks
sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive
sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive
Checking status: Checking status:
...@@ -196,6 +200,7 @@ Checking status: ...@@ -196,6 +200,7 @@ Checking status:
Resolving deltas: 100% (174/174), done. Resolving deltas: 100% (174/174), done.
Can clone gitolite-admin?............YES Can clone gitolite-admin?............YES
UMASK for .gitolite.rc is 0007? ............YES UMASK for .gitolite.rc is 0007? ............YES
/home/git/share/gitolite/hooks/common/post-receive exists? ............YES
If you got all YES - congrats! You can go to next step. If you got all YES - congrats! You can go to next step.
......
Feature: Labels
Background:
Given I signin as a user
And I own project "Shop"
And project "Shop" have issues tags:
| name |
| bug |
| feature |
Given I visit project "Shop" labels page
Scenario: I should see active milestones
Then I should see label "bug"
And I should see label "feature"
...@@ -4,9 +4,7 @@ Feature: Project Network Graph ...@@ -4,9 +4,7 @@ Feature: Project Network Graph
Background: Background:
Given I signin as a user Given I signin as a user
And I own project "Shop" And I own project "Shop"
And I visit project "Shop" network page And I visit project "Shop" network page
Scenario: I should see project network Scenario: I should see project network
Then page should have network graph Then page should have network graph
...@@ -91,36 +91,28 @@ Then /^I should see my merge requests$/ do ...@@ -91,36 +91,28 @@ Then /^I should see my merge requests$/ do
end end
Given /^I have assigned issues$/ do Given /^I have assigned issues$/ do
project1 = Factory :project, project = Factory :project
:path => "project1", project.add_access(@user, :read, :write)
:code => "TEST1"
project2 = Factory :project,
:path => "project2",
:code => "TEST2"
project1.add_access(@user, :read, :write)
project2.add_access(@user, :read, :write)
issue1 = Factory :issue, issue1 = Factory :issue,
:author => @user, :author => @user,
:assignee => @user, :assignee => @user,
:project => project1 :project => project
issue2 = Factory :issue, issue2 = Factory :issue,
:author => @user, :author => @user,
:assignee => @user, :assignee => @user,
:project => project2 :project => project
end end
Given /^I have authored merge requests$/ do Given /^I have authored merge requests$/ do
project1 = Factory :project, project1 = Factory :project,
:path => "project1", :path => "gitlabhq_1",
:code => "TEST1" :code => "gitlabhq_1"
project2 = Factory :project, project2 = Factory :project,
:path => "project2", :path => "gitlabhq_2",
:code => "TEST2" :code => "gitlabhq_2"
project1.add_access(@user, :read, :write) project1.add_access(@user, :read, :write)
project2.add_access(@user, :read, :write) project2.add_access(@user, :read, :write)
......
...@@ -33,6 +33,25 @@ Given /^I visit issue page "(.*?)"$/ do |arg1| ...@@ -33,6 +33,25 @@ Given /^I visit issue page "(.*?)"$/ do |arg1|
end end
Given /^I submit new issue "(.*?)"$/ do |arg1| Given /^I submit new issue "(.*?)"$/ do |arg1|
fill_in "issue_title", :with => arg1 fill_in "issue_title", with: arg1
click_button "Submit new issue" click_button "Submit new issue"
end end
Given /^project "(.*?)" have issues tags:$/ do |arg1, table|
project = Project.find_by_name(arg1)
table.hashes.each do |hash|
Factory :issue,
project: project,
label_list: [hash[:name]]
end
end
Given /^I visit project "(.*?)" labels page$/ do |arg1|
visit project_labels_path(Project.find_by_name(arg1))
end
Then /^I should see label "(.*?)"$/ do |arg1|
within ".labels-table" do
page.should have_content arg1
end
end
...@@ -57,6 +57,11 @@ end ...@@ -57,6 +57,11 @@ end
Given /^I visit project "(.*?)" network page$/ do |arg1| Given /^I visit project "(.*?)" network page$/ do |arg1|
project = Project.find_by_name(arg1) project = Project.find_by_name(arg1)
# Stub out find_all to speed this up (10 commits vs. 650)
commits = Grit::Commit.find_all(project.repo, nil, {max_count: 10})
Grit::Commit.stub(:find_all).and_return(commits)
visit graph_project_path(project) visit graph_project_path(project)
end end
...@@ -67,8 +72,8 @@ end ...@@ -67,8 +72,8 @@ end
Given /^page should have network graph$/ do Given /^page should have network graph$/ do
page.should have_content "Project Network Graph" page.should have_content "Project Network Graph"
within ".graph" do within ".graph" do
page.should have_content "stable" page.should have_content "master"
page.should have_content "notes_refacto..." page.should have_content "scss_refactor..."
end end
end end
......
require 'simplecov' unless ENV['CI']
SimpleCov.start 'rails' require 'simplecov'
SimpleCov.start 'rails'
end
require 'cucumber/rails' require 'cucumber/rails'
require 'webmock/cucumber' require 'webmock/cucumber'
...@@ -39,3 +41,10 @@ rescue NameError ...@@ -39,3 +41,10 @@ rescue NameError
end end
Cucumber::Rails::Database.javascript_strategy = :truncation Cucumber::Rails::Database.javascript_strategy = :truncation
require 'headless'
headless = Headless.new
headless.start
require 'cucumber/rspec/doubles'
module Color
extend self
def colorize(text, color_code)
"\033[#{color_code}#{text}\033[0m"
end
def red(text)
colorize(text, "31m")
end
def green(text)
colorize(text, "32m")
end
def yellow(text)
colorize(text, "93m")
end
def command(string)
`#{string}`
if $?.to_i > 0
puts red " == #{string} - FAIL"
puts red " == Error during configure"
exit
else
puts green " == #{string} - OK"
end
end
end
require "grit"
module Gitlab
class GraphCommit
attr_accessor :time, :space
attr_accessor :refs
def self.to_graph(project)
@repo = project.repo
commits = Grit::Commit.find_all(@repo, nil, {max_count: 650})
ref_cache = {}
commits.map! {|c| GraphCommit.new(Commit.new(c))}
commits.each { |commit| commit.add_refs(ref_cache, @repo) }
days = GraphCommit.index_commits(commits)
@days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json
@commits_json = commits.map(&:to_graph_hash).to_json
return @days_json, @commits_json
end
# Method is adding time and space on the
# list of commits. As well as returns date list
# corelated with time set on commits.
#
# @param [Array<GraphCommit>] comits to index
#
# @return [Array<TimeDate>] list of commit dates corelated with time on commits
def self.index_commits(commits)
days, heads = [], []
map = {}
commits.reverse.each_with_index do |c,i|
c.time = i
days[i] = c.committed_date
map[c.id] = c
heads += c.refs unless c.refs.nil?
end
heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}
# sort heads so the master is top and current branches are closer
heads.sort! do |a,b|
if a.name == "master"
-1
elsif b.name == "master"
1
else
b.commit.committed_date <=> a.commit.committed_date
end
end
@_reserved = {}
days.each_index do |i|
@_reserved[i] = []
end
heads.each do |h|
if map.include? h.commit.id then
place_chain(map[h.commit.id], map)
end
end
days
end
# Add space mark on commit and its parents
#
# @param [GraphCommit] the commit object.
# @param [Hash<String,GraphCommit>] map of commits
def self.place_chain(commit, map, parent_time = nil)
leaves = take_left_leaves(commit, map)
if leaves.empty? then
return
end
space = find_free_space(leaves.last.time..leaves.first.time)
leaves.each{|l| l.space = space}
# and mark it as reserved
min_time = leaves.last.time
parents = leaves.last.parents.collect
parents.each do |p|
if map.include? p.id then
parent = map[p.id]
if parent.time < min_time then
min_time = parent.time
end
end
end
if parent_time.nil? then
max_time = leaves.first.time
else
max_time = parent_time - 1
end
mark_reserved(min_time..max_time, space)
# Visit branching chains
leaves.each do |l|
parents = l.parents.collect
.select{|p| map.include? p.id and map[p.id].space == 0}
for p in parents
place_chain(map[p.id], map, l.time)
end
end
end
def self.mark_reserved(time_range, space)
for day in time_range
@_reserved[day].push(space)
end
end
def self.find_free_space(time_range)
reserved = []
for day in time_range
reserved += @_reserved[day]
end
space = 1
while reserved.include? space do
space += 1
end
space
end
# Takes most left subtree branch of commits
# which don't have space mark yet.
#
# @param [GraphCommit] the commit object.
# @param [Hash<String,GraphCommit>] map of commits
#
# @return [Array<GraphCommit>] list of branch commits
def self.take_left_leaves(commit, map)
leaves = []
leaves.push(commit) if commit.space == 0
while true
parent = commit.parents.collect
.select{|p| map.include? p.id and map[p.id].space == 0}
if parent.count == 0 then
return leaves
else
commit = map[parent.first.id]
leaves.push(commit)
end
end
end
def initialize(commit)
@_commit = commit
@time = -1
@space = 0
end
def method_missing(m, *args, &block)
@_commit.send(m, *args, &block)
end
def to_graph_hash
h = {}
h[:parents] = self.parents.collect do |p|
[p.id,0,0]
end
h[:author] = Gitlab::Encode.utf8(author.name)
h[:time] = time
h[:space] = space
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
h[:message] = Gitlab::Encode.utf8(message)
h[:login] = author.email
h
end
def add_refs(ref_cache, repo)
if ref_cache.empty?
repo.refs.each do |ref|
ref_cache[ref.commit.id] ||= []
ref_cache[ref.commit.id] << ref
end
end
@refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
@refs ||= []
end
end
end
module Gitlab module Gitlab
# Custom parsing for Gitlab-flavored Markdown # Custom parser for Gitlab-flavored Markdown
#
# It replaces references in the text with links to the appropriate items in Gitlab.
#
# Supported reference formats are:
# * @foo for team members
# * #123 for issues
# * !123 for merge requests
# * $123 for snippets
# * 123456 for commits
# #
# Examples # Examples
# #
...@@ -67,25 +76,25 @@ module Gitlab ...@@ -67,25 +76,25 @@ module Gitlab
def reference_user(identifier) def reference_user(identifier)
if user = @project.users.where(name: identifier).first if user = @project.users.where(name: identifier).first
member = @project.users_projects.where(user_id: user).first member = @project.users_projects.where(user_id: user).first
link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
end end
end end
def reference_issue(identifier) def reference_issue(identifier)
if issue = @project.issues.where(id: identifier).first if issue = @project.issues.where(id: identifier).first
link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) link_to("##{identifier}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}"))
end end
end end
def reference_merge_request(identifier) def reference_merge_request(identifier)
if merge_request = @project.merge_requests.where(id: identifier).first if merge_request = @project.merge_requests.where(id: identifier).first
link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) link_to("!#{identifier}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}"))
end end
end end
def reference_snippet(identifier) def reference_snippet(identifier)
if snippet = @project.snippets.where(id: identifier).first if snippet = @project.snippets.where(id: identifier).first
link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) link_to("$#{identifier}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}"))
end end
end end
......
require "grit"
class GraphCommit
attr_accessor :time, :space
attr_accessor :refs
def self.to_graph(project)
@repo = project.repo
commits = Grit::Commit.find_all(@repo, nil, {max_count: 650})
ref_cache = {}
commits.map! {|c| GraphCommit.new(Commit.new(c))}
commits.each { |commit| commit.add_refs(ref_cache, @repo) }
days = GraphCommit.index_commits(commits)
@days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json
@commits_json = commits.map(&:to_graph_hash).to_json
return @days_json, @commits_json
end
# Method is adding time and space on the
# list of commits. As well as returns date list
# corelated with time set on commits.
#
# @param [Array<GraphCommit>] comits to index
#
# @return [Array<TimeDate>] list of commit dates corelated with time on commits
def self.index_commits(commits)
days, heads = [], []
map = {}
commits.reverse.each_with_index do |c,i|
c.time = i
days[i] = c.committed_date
map[c.id] = c
heads += c.refs unless c.refs.nil?
end
heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}
# sort heads so the master is top and current branches are closer
heads.sort! do |a,b|
if a.name == "master"
-1
elsif b.name == "master"
1
else
b.commit.committed_date <=> a.commit.committed_date
end
end
@_reserved = {}
days.each_index do |i|
@_reserved[i] = []
end
heads.each do |h|
if map.include? h.commit.id then
place_chain(map[h.commit.id], map)
end
end
days
end
# Add space mark on commit and its parents
#
# @param [GraphCommit] the commit object.
# @param [Hash<String,GraphCommit>] map of commits
def self.place_chain(commit, map, parent_time = nil)
leaves = take_left_leaves(commit, map)
if leaves.empty? then
return
end
space = find_free_space(leaves.last.time..leaves.first.time)
leaves.each{|l| l.space = space}
# and mark it as reserved
min_time = leaves.last.time
parents = leaves.last.parents.collect
parents.each do |p|
if map.include? p.id then
parent = map[p.id]
if parent.time < min_time then
min_time = parent.time
end
end
end
if parent_time.nil? then
max_time = leaves.first.time
else
max_time = parent_time - 1
end
mark_reserved(min_time..max_time, space)
# Visit branching chains
leaves.each do |l|
parents = l.parents.collect
.select{|p| map.include? p.id and map[p.id].space == 0}
for p in parents
place_chain(map[p.id], map, l.time)
end
end
end
def self.mark_reserved(time_range, space)
for day in time_range
@_reserved[day].push(space)
end
end
def self.find_free_space(time_range)
reserved = []
for day in time_range
reserved += @_reserved[day]
end
space = 1
while reserved.include? space do
space += 1
end
space
end
# Takes most left subtree branch of commits
# which don't have space mark yet.
#
# @param [GraphCommit] the commit object.
# @param [Hash<String,GraphCommit>] map of commits
#
# @return [Array<GraphCommit>] list of branch commits
def self.take_left_leaves(commit, map)
leaves = []
leaves.push(commit) if commit.space == 0
while true
parent = commit.parents.collect
.select{|p| map.include? p.id and map[p.id].space == 0}
if parent.count == 0 then
return leaves
else
commit = map[parent.first.id]
leaves.push(commit)
end
end
end
def initialize(commit)
@_commit = commit
@time = -1
@space = 0
end
def method_missing(m, *args, &block)
@_commit.send(m, *args, &block)
end
def to_graph_hash
h = {}
h[:parents] = self.parents.collect do |p|
[p.id,0,0]
end
h[:author] = Gitlab::Encode.utf8(author.name)
h[:time] = time
h[:space] = space
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
h[:message] = Gitlab::Encode.utf8(message)
h[:login] = author.email
h
end
def add_refs(ref_cache, repo)
if ref_cache.empty?
repo.refs.each do |ref|
ref_cache[ref.commit.id] ||= []
ref_cache[ref.commit.id] << ref
end
end
@refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
@refs ||= []
end
end
namespace :dev do
desc "Prepare for development (run dev_user.sh first)"
task :repos => :environment do
key = `sudo -u gitlabdev -H cat /home/gitlabdev/.ssh/id_rsa.pub`
raise "\n *** Run ./lib/tasks/dev/user.sh first *** \n" if key.empty?
Key.create(:user_id => User.first, :key => key, :title => "gitlabdev")
puts "\n *** Clone diaspora from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/diaspora/diaspora.git /home/gitlabdev/diaspora"`
puts "\n *** Push diaspora source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/diaspora; git remote add local git@localhost:diaspora.git; git push local master; git push local --tags; git checkout -b api origin/api; git push local api; git checkout -b heroku origin/heroku; git push local heroku"`
puts "\n *** Clone rails from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rails/rails.git /home/gitlabdev/rails"`
puts "\n *** Push rails source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rails; git remote add local git@localhost:ruby_on_rails.git; git push local master; git push local --tags"`
puts "\n *** Clone rubinius from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rubinius/rubinius.git /home/gitlabdev/rubinius"`
puts "\n *** Push rubinius source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rubinius; git remote add local git@localhost:rubinius.git; git push local master; git push local --tags"`
end
end
namespace :dev do
desc "DEV | Run cucumber and rspec"
task :tests do
["cucumber", "rspec spec"].each do |cmd|
puts "Starting to run #{cmd}..."
system("bundle exec #{cmd}")
raise "#{cmd} failed!" unless $?.exitstatus == 0
end
end
end
sudo adduser \
--gecos 'gitlab dev user' \
--disabled-password \
--home /home/gitlabdev \
gitlabdev
sudo -i -u gitlabdev -H sh -c "ssh-keygen -t rsa"
namespace :gitlab do namespace :gitlab do
namespace :app do namespace :app do
desc "GITLAB | Setup production application" desc "GITLAB | Setup production application"
task :setup => ['db:setup', 'db:seed_fu', 'gitlab:app:enable_automerge'] task :setup => [
'db:setup',
'db:seed_fu',
'gitlab:app:enable_automerge'
]
end end
end end
...@@ -56,6 +56,20 @@ namespace :gitlab do ...@@ -56,6 +56,20 @@ namespace :gitlab do
return return
end end
gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
gitlab_hook_files = ['post-receive']
gitlab_hook_files.each do |file_name|
dest = File.join(gitolite_hooks_path, file_name)
print "#{dest} exists? ............"
if File.exists?(dest)
puts "YES".green
else
puts "NO".red
return
end
end
if Project.count > 0 if Project.count > 0
puts "Validating projects repositories:".yellow puts "Validating projects repositories:".yellow
Project.find_each(:batch_size => 100) do |project| Project.find_each(:batch_size => 100) do |project|
...@@ -67,12 +81,6 @@ namespace :gitlab do ...@@ -67,12 +81,6 @@ namespace :gitlab do
next next
end end
unless File.owned?(hook_file)
puts "post-receive file is not owner by gitlab".red
next
end
puts "post-reveice file ok".green puts "post-reveice file ok".green
end end
end end
......
namespace :gitlab do
namespace :gitolite do
desc "GITLAB | Rewrite hooks for repos"
task :update_hooks => :environment do
puts "Starting Projects"
Project.find_each(:batch_size => 100) do |project|
begin
if project.commit
project.write_hooks
print ".".green
end
rescue Exception => e
print e.message.red
end
end
puts "\nDone with projects"
end
end
end
namespace :gitlab do
namespace :gitolite do
desc "GITLAB | Write GITLAB hook for gitolite"
task :write_hooks => :environment do
gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
gitlab_hooks_path = Rails.root.join("lib", "hooks")
gitlab_hook_files = ['post-receive']
gitlab_hook_files.each do |file_name|
source = File.join(gitlab_hooks_path, file_name)
dest = File.join(gitolite_hooks_path, file_name)
puts "sudo -u root cp #{source} #{dest}".yellow
`sudo -u root cp #{source} #{dest}`
puts "sudo -u root chown git:git #{dest}".yellow
`sudo -u root chown git:git #{dest}`
end
end
end
end
require 'spec_helper'
describe ApplicationHelper do
describe "gravatar_icon" do
let(:user_email) { 'user@email.com' }
it "should return a generic avatar path when Gravatar is disabled" do
Gitlab.config.stub(:disable_gravatar?).and_return(true)
gravatar_icon(user_email).should == 'no_avatar.png'
end
it "should return a generic avatar path when email is blank" do
gravatar_icon('').should == 'no_avatar.png'
end
it "should use SSL when appropriate" do
stub!(:request).and_return(double(:ssl? => true))
gravatar_icon(user_email).should match('https://secure.gravatar.com')
end
it "should accept a custom size" do
stub!(:request).and_return(double(:ssl? => false))
gravatar_icon(user_email, 64).should match(/\?s=64/)
end
end
end
...@@ -24,7 +24,7 @@ describe Notify do ...@@ -24,7 +24,7 @@ describe Notify do
end end
it 'has the correct subject' do it 'has the correct subject' do
should have_subject /Account was created for you/ should have_subject /^gitlab \| Account was created for you$/
end end
it 'contains the new user\'s login name' do it 'contains the new user\'s login name' do
...@@ -60,7 +60,7 @@ describe Notify do ...@@ -60,7 +60,7 @@ describe Notify do
it_behaves_like 'an assignee email' it_behaves_like 'an assignee email'
it 'has the correct subject' do it 'has the correct subject' do
should have_subject /new issue ##{issue.id}/ should have_subject /new issue ##{issue.id} \| #{issue.title} \| #{project.name}/
end end
it 'contains a link to the new issue' do it 'contains a link to the new issue' do
...@@ -76,7 +76,7 @@ describe Notify do ...@@ -76,7 +76,7 @@ describe Notify do
it_behaves_like 'a multiple recipients email' it_behaves_like 'a multiple recipients email'
it 'has the correct subject' do it 'has the correct subject' do
should have_subject /changed issue/ should have_subject /changed issue ##{issue.id} \| #{issue.title}/
end end
it 'contains the name of the previous assignee' do it 'contains the name of the previous assignee' do
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment