Commit e6edaa3b502090f461b58c439ea476da2d37f039

Authored by Jeremy Anderson
2 parents 0301ba33 3caf0aa8

Merge remote-tracking branch 'upstream/master'

Showing 64 changed files with 763 additions and 198 deletions   Show diff stats
@@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0" @@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0"
14 gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" 14 gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
15 gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0" 15 gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0"
16 gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188" 16 gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188"
17 -gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44" 17 +gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e"
18 gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" 18 gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
19 gem 'grack', :git => "https://github.com/gitlabhq/grack.git" 19 gem 'grack', :git => "https://github.com/gitlabhq/grack.git"
20 gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" 20 gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git"
@@ -42,8 +42,8 @@ GIT @@ -42,8 +42,8 @@ GIT
42 42
43 GIT 43 GIT
44 remote: https://github.com/gitlabhq/omniauth-ldap.git 44 remote: https://github.com/gitlabhq/omniauth-ldap.git
45 - revision: 7edf27d0281e09561838122982c16b7e62181f44  
46 - ref: 7edf27d0281e09561838122982c16b7e62181f44 45 + revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
  46 + ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
47 specs: 47 specs:
48 omniauth-ldap (1.0.2) 48 omniauth-ldap (1.0.2)
49 net-ldap (~> 0.2.2) 49 net-ldap (~> 0.2.2)
app/assets/javascripts/note.js
@@ -33,7 +33,7 @@ init: @@ -33,7 +33,7 @@ init:
33 }) 33 })
34 34
35 $("#note_note").live("focus", function(){ 35 $("#note_note").live("focus", function(){
36 - $(this).css("height", "100px"); 36 + $(this).css("height", "80px");
37 $('.note_advanced_opts').show(); 37 $('.note_advanced_opts').show();
38 }); 38 });
39 39
app/assets/javascripts/pager.js
@@ -8,7 +8,6 @@ var Pager = { @@ -8,7 +8,6 @@ var Pager = {
8 this.limit=limit; 8 this.limit=limit;
9 this.offset=limit; 9 this.offset=limit;
10 this.initLoadMore(); 10 this.initLoadMore();
11 - $('.loading').show();  
12 }, 11 },
13 12
14 getOld: 13 getOld:
app/assets/stylesheets/common.scss
@@ -337,6 +337,15 @@ p.time { @@ -337,6 +337,15 @@ p.time {
337 padding: 15px 5px; 337 padding: 15px 5px;
338 &:last-child { border:none } 338 &:last-child { border:none }
339 .wll:hover { background:none } 339 .wll:hover { background:none }
  340 +
  341 + .event_commits {
  342 + margin-top: 5px;
  343 +
  344 + li.commit {
  345 + padding:5px;
  346 + border:none;
  347 + }
  348 + }
340 } 349 }
341 350
342 .ico { 351 .ico {
app/assets/stylesheets/gitlab_bootstrap.scss
@@ -18,7 +18,8 @@ a { @@ -18,7 +18,8 @@ a {
18 } 18 }
19 19
20 &.lined { 20 &.lined {
21 - text-decoration:underlined; 21 + text-decoration:underline;
  22 + &:hover { text-decoration:underline; }
22 } 23 }
23 24
24 &.gray { 25 &.gray {
@@ -74,10 +75,6 @@ h5 { @@ -74,10 +75,6 @@ h5 {
74 font-size:14px; 75 font-size:14px;
75 } 76 }
76 77
77 -code {  
78 - background:#FCEEC1;  
79 - color:$style_color;  
80 -}  
81 78
82 table { 79 table {
83 width:100%; 80 width:100%;
@@ -381,7 +378,6 @@ form { @@ -381,7 +378,6 @@ form {
381 min-height: 20px; 378 min-height: 20px;
382 border-bottom: 1px solid #eee; 379 border-bottom: 1px solid #eee;
383 border-bottom: 1px solid rgba(0, 0, 0, 0.05); 380 border-bottom: 1px solid rgba(0, 0, 0, 0.05);
384 - cursor:pointer;  
385 &.smoke { 381 &.smoke {
386 background-color:#f5f5f5; 382 background-color:#f5f5f5;
387 } 383 }
@@ -516,7 +512,8 @@ form { @@ -516,7 +512,8 @@ form {
516 .row_title { 512 .row_title {
517 font-weight:bold; 513 font-weight:bold;
518 color:#444; 514 color:#444;
519 - &:hover { 515 + &:hover {
  516 + color:#444;
520 text-decoration:underline; 517 text-decoration:underline;
521 } 518 }
522 } 519 }
app/assets/stylesheets/notes.scss
@@ -14,7 +14,8 @@ @@ -14,7 +14,8 @@
14 border-bottom:1px solid #aaa; 14 border-bottom:1px solid #aaa;
15 } 15 }
16 16
17 -.issue_notes { 17 +.issue_notes,
  18 +.wiki_notes {
18 .note_content { 19 .note_content {
19 float:left; 20 float:left;
20 width:400px; 21 width:400px;
@@ -23,8 +24,8 @@ @@ -23,8 +24,8 @@
23 24
24 /* Note textare */ 25 /* Note textare */
25 #note_note { 26 #note_note {
26 - height:100px;  
27 - width:97%; 27 + height:80px;
  28 + width:99%;
28 font-size:14px; 29 font-size:14px;
29 } 30 }
30 31
@@ -99,8 +100,25 @@ tr.line_notes_row { @@ -99,8 +100,25 @@ tr.line_notes_row {
99 td { 100 td {
100 border-bottom:1px solid #ddd; 101 border-bottom:1px solid #ddd;
101 } 102 }
102 - .actions { 103 + .note_actions {
103 margin:0; 104 margin:0;
  105 + padding-top: 10px;
  106 +
  107 + .buttons {
  108 + float:left;
  109 + width:300px;
  110 + }
  111 + .options {
  112 + .labels {
  113 + float:left;
  114 + padding-left:10px;
  115 + label {
  116 + padding: 6px 0;
  117 + margin: 0;
  118 + width:120px;
  119 + }
  120 + }
  121 + }
104 } 122 }
105 } 123 }
106 124
app/assets/stylesheets/sections/commits.scss
@@ -194,4 +194,16 @@ @@ -194,4 +194,16 @@
194 float:right; 194 float:right;
195 @extend .cgray; 195 @extend .cgray;
196 } 196 }
  197 +
  198 + code {
  199 + background:#FCEEC1;
  200 + color:$style_color;
  201 + }
  202 +
  203 + .commit_short_id {
  204 + float:left;
  205 + @extend .lined;
  206 + min-width:65px;
  207 + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
  208 + }
197 } 209 }
app/assets/stylesheets/sections/issues.scss
@@ -30,13 +30,14 @@ @@ -30,13 +30,14 @@
30 .issue { 30 .issue {
31 padding:7px 10px; 31 padding:7px 10px;
32 32
  33 + p {
  34 + padding-top:0;
  35 + padding-bottom:2px;
  36 + }
  37 +
33 img.avatar { 38 img.avatar {
34 width:32px; 39 width:32px;
35 margin-top:4px; 40 margin-top:4px;
36 } 41 }
37 - p.row_title {  
38 - padding:0px;  
39 - padding-bottom:2px;  
40 - }  
41 } 42 }
42 } 43 }
app/contexts/notes_load.rb
@@ -17,6 +17,8 @@ class NotesLoad < BaseContext @@ -17,6 +17,8 @@ class NotesLoad < BaseContext
17 then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) 17 then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
18 when "merge_request" 18 when "merge_request"
19 then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) 19 then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
  20 + when "wiki"
  21 + then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20]
20 end 22 end
21 23
22 @notes = if last_id 24 @notes = if last_id
app/controllers/commits_controller.rb
@@ -17,6 +17,7 @@ class CommitsController < ApplicationController @@ -17,6 +17,7 @@ class CommitsController < ApplicationController
17 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) 17 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
18 18
19 @commits = @project.commits(@ref, params[:path], @limit, @offset) 19 @commits = @project.commits(@ref, params[:path], @limit, @offset)
  20 + @commits = CommitDecorator.decorate(@commits)
20 21
21 respond_to do |format| 22 respond_to do |format|
22 format.html # index.html.erb 23 format.html # index.html.erb
@@ -51,6 +52,8 @@ class CommitsController < ApplicationController @@ -51,6 +52,8 @@ class CommitsController < ApplicationController
51 @commit = result[:commit] 52 @commit = result[:commit]
52 @diffs = result[:diffs] 53 @diffs = result[:diffs]
53 @line_notes = [] 54 @line_notes = []
  55 +
  56 + @commits = CommitDecorator.decorate(@commits)
54 end 57 end
55 58
56 def patch 59 def patch
app/controllers/merge_requests_controller.rb
@@ -143,5 +143,6 @@ class MergeRequestsController < ApplicationController @@ -143,5 +143,6 @@ class MergeRequestsController < ApplicationController
143 # Get commits from repository 143 # Get commits from repository
144 # or from cache if already merged 144 # or from cache if already merged
145 @commits = @merge_request.commits 145 @commits = @merge_request.commits
  146 + @commits = CommitDecorator.decorate(@commits)
146 end 147 end
147 end 148 end
app/controllers/omniauth_callbacks_controller.rb
@@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController @@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
3 # Extend the standard message generation to accept our custom exception 3 # Extend the standard message generation to accept our custom exception
4 def failure_message 4 def failure_message
5 exception = env["omniauth.error"] 5 exception = env["omniauth.error"]
6 - if exception.class == OmniAuth::Error  
7 - error = exception.message  
8 - else  
9 - error = exception.error_reason if exception.respond_to?(:error_reason)  
10 - error ||= exception.error if exception.respond_to?(:error)  
11 - error ||= env["omniauth.error.type"].to_s  
12 - end 6 + error = exception.error_reason if exception.respond_to?(:error_reason)
  7 + error ||= exception.error if exception.respond_to?(:error)
  8 + error ||= exception.message if exception.respond_to?(:message)
  9 + error ||= env["omniauth.error.type"].to_s
13 error.to_s.humanize if error 10 error.to_s.humanize if error
14 end 11 end
15 12
app/controllers/refs_controller.rb
@@ -51,7 +51,8 @@ class RefsController < ApplicationController @@ -51,7 +51,8 @@ class RefsController < ApplicationController
51 @logs = contents.map do |content| 51 @logs = contents.map do |content|
52 file = params[:path] ? File.join(params[:path], content.name) : content.name 52 file = params[:path] ? File.join(params[:path], content.name) : content.name
53 last_commit = @project.commits(@commit.id, file, 1).last 53 last_commit = @project.commits(@commit.id, file, 1).last
54 - { 54 + last_commit = CommitDecorator.decorate(last_commit)
  55 + {
55 :file_name => content.name, 56 :file_name => content.name,
56 :commit => last_commit 57 :commit => last_commit
57 } 58 }
app/controllers/wikis_controller.rb
@@ -13,16 +13,16 @@ class WikisController < ApplicationController @@ -13,16 +13,16 @@ class WikisController < ApplicationController
13 @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last 13 @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last
14 end 14 end
15 15
16 - unless @wiki  
17 - return render_404 unless can?(current_user, :write_wiki, @project)  
18 - end 16 + @note = @project.notes.new(:noteable => @wiki)
19 17
20 - respond_to do |format|  
21 - if @wiki  
22 - format.html  
23 - else 18 + if @wiki
  19 + render 'show'
  20 + else
  21 + if can?(current_user, :write_wiki, @project)
24 @wiki = @project.wikis.new(:slug => params[:id]) 22 @wiki = @project.wikis.new(:slug => params[:id])
25 - format.html { render "edit" } 23 + render 'edit'
  24 + else
  25 + render 'empty'
26 end 26 end
27 end 27 end
28 end 28 end
app/mailers/notify.rb
@@ -46,6 +46,13 @@ class Notify < ActionMailer::Base @@ -46,6 +46,13 @@ class Notify < ActionMailer::Base
46 mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ") 46 mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ")
47 end 47 end
48 48
  49 + def note_wiki_email(recipient_id, note_id)
  50 + recipient = User.find(recipient_id)
  51 + @note = Note.find(note_id)
  52 + @wiki = @note.noteable
  53 + mail(:to => recipient.email, :subject => "gitlab | note for wiki | #{@note.project_name}")
  54 + end
  55 +
49 def new_merge_request_email(merge_request_id) 56 def new_merge_request_email(merge_request_id)
50 @merge_request = MergeRequest.find(merge_request_id) 57 @merge_request = MergeRequest.find(merge_request_id)
51 mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ") 58 mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ")
app/models/commit.rb
@@ -114,6 +114,10 @@ class Commit @@ -114,6 +114,10 @@ class Commit
114 @head = head 114 @head = head
115 end 115 end
116 116
  117 + def short_id(length = 10)
  118 + id.to_s[0..length]
  119 + end
  120 +
117 def safe_message 121 def safe_message
118 utf8 message 122 utf8 message
119 end 123 end
@@ -150,4 +154,8 @@ class Commit @@ -150,4 +154,8 @@ class Commit
150 def prev_commit_id 154 def prev_commit_id
151 prev_commit.try :id 155 prev_commit.try :id
152 end 156 end
  157 +
  158 + def parents_count
  159 + parents && parents.count || 0
  160 + end
153 end 161 end
app/models/wiki.rb
1 class Wiki < ActiveRecord::Base 1 class Wiki < ActiveRecord::Base
2 belongs_to :project 2 belongs_to :project
3 belongs_to :user 3 belongs_to :user
  4 + has_many :notes, :as => :noteable, :dependent => :destroy
4 5
5 validates :content, :title, :user_id, :presence => true 6 validates :content, :title, :user_id, :presence => true
6 validates :title, :length => 1..250 7 validates :title, :length => 1..250
app/observers/mailer_observer.rb
@@ -34,6 +34,7 @@ class MailerObserver &lt; ActiveRecord::Observer @@ -34,6 +34,7 @@ class MailerObserver &lt; ActiveRecord::Observer
34 case note.noteable_type 34 case note.noteable_type
35 when "Commit"; Notify.note_commit_email(u.id, note.id).deliver 35 when "Commit"; Notify.note_commit_email(u.id, note.id).deliver
36 when "Issue"; Notify.note_issue_email(u.id, note.id).deliver 36 when "Issue"; Notify.note_issue_email(u.id, note.id).deliver
  37 + when "Wiki"; Notify.note_wiki_email(u.id, note.id).deliver
37 when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver 38 when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver
38 when "Snippet"; true 39 when "Snippet"; true
39 else 40 else
app/views/commits/_commit.html.haml
@@ -2,16 +2,15 @@ @@ -2,16 +2,15 @@
2 .browse_code_link_holder 2 .browse_code_link_holder
3 %p 3 %p
4 %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right" 4 %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right"
5 - = link_to project_commit_path(@project, :id => commit.id) do  
6 - %p  
7 - %code.left= commit.id.to_s[0..10]  
8 - %strong.cgray= commit.author_name  
9 - &ndash;  
10 - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16  
11 - %span.row_title= truncate(commit.safe_message, :length => 50) 5 + %p
  6 + = link_to commit.short_id(8), project_commit_path(@project, :id => commit.id), :class => "commit_short_id"
  7 + %strong.cgray= commit.author_name
  8 + &ndash;
  9 + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
  10 + = link_to truncate(commit.title, :length => 50), project_commit_path(@project, :id => commit.id), :class => "row_title"
12 11
13 - %span.committed_ago  
14 - = time_ago_in_words(commit.committed_date)  
15 - ago  
16 - &nbsp; 12 + %span.committed_ago
  13 + = time_ago_in_words(commit.committed_date)
  14 + ago
  15 + &nbsp;
17 16
app/views/commits/_commit_box.html.haml
1 -.commit-box{class: @commit.parents.count > 1 ? "merge-commit" : ""} 1 +.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""}
2 .commit-head 2 .commit-head
3 .right 3 .right
4 - if @notes_count > 0 4 - if @notes_count > 0
app/views/commits/compare.html.haml
@@ -24,8 +24,9 @@ @@ -24,8 +24,9 @@
24 24
25 25
26 - unless @commits.empty? 26 - unless @commits.empty?
27 - %h4 Commits (#{@commits.count})  
28 - %ul.unstyled= render @commits 27 + %div.ui-box
  28 + %h5.small Commits (#{@commits.count})
  29 + %ul.unstyled= render @commits
29 30
30 - unless @diffs.empty? 31 - unless @diffs.empty?
31 %h4 Diff 32 %h4 Diff
app/views/commits/index.atom.builder
@@ -10,14 +10,14 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -10,14 +10,14 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
10 xml.entry do 10 xml.entry do
11 xml.id project_commit_url(@project, :id => commit.id) 11 xml.id project_commit_url(@project, :id => commit.id)
12 xml.link :href => project_commit_url(@project, :id => commit.id) 12 xml.link :href => project_commit_url(@project, :id => commit.id)
13 - xml.title truncate(commit.safe_message, :length => 80) 13 + xml.title truncate(commit.title, :length => 80)
14 xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") 14 xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
15 xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email) 15 xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email)
16 xml.author do |author| 16 xml.author do |author|
17 xml.name commit.author_name 17 xml.name commit.author_name
18 xml.email commit.author_email 18 xml.email commit.author_email
19 end 19 end
20 - xml.summary commit.safe_message 20 + xml.summary commit.description
21 end 21 end
22 end 22 end
23 end 23 end
app/views/dashboard/merge_requests.html.haml
1 %h3.page_title 1 %h3.page_title
2 Merge Requests 2 Merge Requests
3 - %small (authored or assigned to you) 3 + %small (authored by or assigned to you)
4 %small.right #{@merge_requests.total_count} merge requests 4 %small.right #{@merge_requests.total_count} merge requests
5 5
6 %br 6 %br
app/views/errors/gitolite.html.haml
1 .alert-message.block-message.error 1 .alert-message.block-message.error
2 %h3 Gitolite Error 2 %h3 Gitolite Error
3 - %hr  
4 %h4 Application cant get access to your gitolite system. 3 %h4 Application cant get access to your gitolite system.
5 - %ol  
6 - %li  
7 - %p  
8 - Check 'config/gitlab.yml' for correct settings.  
9 - %li  
10 - %p  
11 - Make sure web server user has access to gitolite.  
12 - %a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial  
13 - %li  
14 - %p  
15 - Try: 4 +
  5 +
  6 +
  7 +
  8 +%h4 Tips for Administrator:
  9 +
  10 +%ul
  11 + %li
  12 + %p
  13 + Check git logs in admin area
  14 + %li
  15 + %p
  16 + Check config/gitlab.yml for correct settings.
  17 + %li
  18 + %p
  19 + Diagnostic tool:
16 %pre 20 %pre
17 - = preserve do  
18 - sudo chmod -R 770 /home/git/repositories/  
19 - sudo chown -R git:git /home/git/repositories/ 21 + bundle exec rake gitlab:app:status RAILS_ENV=production
  22 + %li
  23 + %p
  24 + Permissions:
  25 + %pre
  26 + = preserve do
  27 + sudo chmod -R 770 /home/git/repositories/
  28 + sudo chown -R git:git /home/git/repositories/
  29 + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
  30 +
app/views/events/_commit.html.haml
  1 +- commit = CommitDecorator.decorate(commit)
1 %li.wll.commit 2 %li.wll.commit
2 - = link_to project_commit_path(project, :id => commit.id) do  
3 - %p  
4 - %code.left= commit.id.to_s[0..10]  
5 - %strong.cgray= commit.author_name  
6 - &ndash;  
7 - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16  
8 - %span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding" 3 + %p
  4 + = link_to commit.short_id(8), project_commit_path(project, :id => commit.id), :class => "commit_short_id"
  5 + %strong.cdark= commit.author_name
  6 + &ndash;
  7 + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
  8 + = truncate(commit.title, :length => 50) rescue "--broken encoding"
9 9
app/views/help/api.html.haml
1 %h3 API 1 %h3 API
2 .back_link 2 .back_link
3 - = link_to help_path do 3 + = link_to help_path do
4 &larr; to index 4 &larr; to index
5 %hr 5 %hr
6 6
7 %ol 7 %ol
8 - %li 8 + %li
9 %a{:href => "#README"} README 9 %a{:href => "#README"} README
10 - %li 10 + %li
11 %a{:href => "#projects"} Projects 11 %a{:href => "#projects"} Projects
12 - %li 12 + %li
13 %a{:href => "#users"} Users 13 %a{:href => "#users"} Users
  14 + %li
  15 + %a{:href => "#issues"} Issues
14 16
15 .file_holder#README 17 .file_holder#README
16 .file_title 18 .file_title
@@ -39,3 +41,13 @@ @@ -39,3 +41,13 @@
39 .file_content.wiki 41 .file_content.wiki
40 = preserve do 42 = preserve do
41 = markdown File.read(Rails.root.join("doc", "api", "users.md")) 43 = markdown File.read(Rails.root.join("doc", "api", "users.md"))
  44 +
  45 +%br
  46 +
  47 +.file_holder#issues
  48 + .file_title
  49 + %i.icon-file
  50 + Issues
  51 + .file_content.wiki
  52 + = preserve do
  53 + = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
app/views/help/permissions.html.haml
@@ -38,7 +38,6 @@ @@ -38,7 +38,6 @@
38 %li Push to non-protected branches 38 %li Push to non-protected branches
39 %li Remove non-protected branches 39 %li Remove non-protected branches
40 %li Add tags 40 %li Add tags
41 - %li Create new merge request  
42 %li Write a wiki 41 %li Write a wiki
43 42
44 .ui-box.span3 43 .ui-box.span3
@@ -55,7 +54,6 @@ @@ -55,7 +54,6 @@
55 %li Push to non-protected branches 54 %li Push to non-protected branches
56 %li Remove non-protected branches 55 %li Remove non-protected branches
57 %li Add tags 56 %li Add tags
58 - %li Create new merge request  
59 %li Write a wiki 57 %li Write a wiki
60 %li Add new team members 58 %li Add new team members
61 %li Push to protected branches 59 %li Push to protected branches
app/views/issues/_show.html.haml
@@ -24,8 +24,7 @@ @@ -24,8 +24,7 @@
24 - else 24 - else
25 = image_tag "no_avatar.png", :class => "avatar" 25 = image_tag "no_avatar.png", :class => "avatar"
26 26
27 - = link_to project_issue_path(issue.project, issue) do  
28 - %p.row_title= truncate(issue.title, :length => 100) 27 + %p= link_to truncate(issue.title, :length => 100), project_issue_path(issue.project, issue), :class => "row_title"
29 28
30 %span.update-author 29 %span.update-author
31 %small.cdark= "##{issue.id}" 30 %small.cdark= "##{issue.id}"
app/views/issues/show.html.haml
@@ -46,9 +46,7 @@ @@ -46,9 +46,7 @@
46 - if @issue.milestone 46 - if @issue.milestone
47 - milestone = @issue.milestone 47 - milestone = @issue.milestone
48 %cite.cgray and attached to milestone 48 %cite.cgray and attached to milestone
49 - = link_to project_milestone_path(milestone.project, milestone) do  
50 - %strong  
51 - = truncate(milestone.title, :length => 20) 49 + %strong= link_to truncate(milestone.title, :length => 20), project_milestone_path(milestone.project, milestone)
52 50
53 .right 51 .right
54 - @issue.labels.each do |label| 52 - @issue.labels.each do |label|
app/views/merge_requests/_merge_request.html.haml
@@ -16,8 +16,7 @@ @@ -16,8 +16,7 @@
16 = merge_request.target_branch 16 = merge_request.target_branch
17 = image_tag gravatar_icon(merge_request.author_email), :class => "avatar" 17 = image_tag gravatar_icon(merge_request.author_email), :class => "avatar"
18 18
19 - = link_to project_merge_request_path(merge_request.project, merge_request) do  
20 - %p.row_title= truncate(merge_request.title, :length => 80) 19 + %p= link_to truncate(merge_request.title, :length => 80), project_merge_request_path(merge_request.project, merge_request), :class => "row_title"
21 20
22 %span.update-author 21 %span.update-author
23 %small.cdark= "##{merge_request.id}" 22 %small.cdark= "##{merge_request.id}"
app/views/milestones/_milestone.html.haml
@@ -6,14 +6,13 @@ @@ -6,14 +6,13 @@
6 = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped" 6 = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped"
7 - if can? current_user, :admin_milestone, milestone.project 7 - if can? current_user, :admin_milestone, milestone.project
8 = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped" 8 = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped"
9 - = link_to project_milestone_path(milestone.project, milestone) do  
10 - %h4.row_title  
11 - = truncate(milestone.title, :length => 100)  
12 - %small  
13 - = milestone.expires_at  
14 - %br  
15 - .progress.progress-success.span3  
16 - .bar{:style => "width: #{milestone.percent_complete}%;"} 9 + %h4
  10 + = link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title"
  11 + %small
  12 + = milestone.expires_at
  13 + %br
  14 + .progress.progress-success.span3
  15 + .bar{:style => "width: #{milestone.percent_complete}%;"}
17 16
18 17
19 &nbsp; 18 &nbsp;
app/views/milestones/show.html.haml
@@ -50,8 +50,8 @@ @@ -50,8 +50,8 @@
50 %td 50 %td
51 = link_to [@project, issue] do 51 = link_to [@project, issue] do
52 %span.badge.badge-info ##{issue.id} 52 %span.badge.badge-info ##{issue.id}
53 - &ndash;  
54 - = truncate issue.title, :length => 60 53 + &ndash;
  54 + = link_to truncate(issue.title, :length => 60), [@project, issue]
55 %br 55 %br
56 = paginate @issues, :theme => "gitlab" 56 = paginate @issues, :theme => "gitlab"
57 57
app/views/notes/_form.html.haml
1 = form_for [@project, @note], :remote => "true", :multipart => true do |f| 1 = form_for [@project, @note], :remote => "true", :multipart => true do |f|
2 - %h3 Leave a comment 2 + %h3.page_title Leave a comment
3 -if @note.errors.any? 3 -if @note.errors.any?
4 .alert-message.block-message.error 4 .alert-message.block-message.error
5 - @note.errors.full_messages.each do |msg| 5 - @note.errors.full_messages.each do |msg|
app/views/notes/_per_line_form.html.haml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 %tr.per_line_form 2 %tr.per_line_form
3 %td{:colspan => 3 } 3 %td{:colspan => 3 }
4 = form_for [@project, @note], :remote => "true", :multipart => true do |f| 4 = form_for [@project, @note], :remote => "true", :multipart => true do |f|
5 - %h3 Leave a note 5 + %h3.page_title Leave a note
6 %div.span10 6 %div.span10
7 -if @note.errors.any? 7 -if @note.errors.any?
8 .alert-message.block-message.error 8 .alert-message.block-message.error
@@ -13,19 +13,21 @@ @@ -13,19 +13,21 @@
13 = f.hidden_field :noteable_type 13 = f.hidden_field :noteable_type
14 = f.hidden_field :line_code 14 = f.hidden_field :line_code
15 = f.text_area :note, :size => 255 15 = f.text_area :note, :size => 255
16 - %h5 Notify via email:  
17 - .clearfix  
18 - = label_tag :notify do  
19 - = check_box_tag :notify, 1, @note.noteable_type != "Commit"  
20 - %span Project team 16 + .note_actions
  17 + .buttons
  18 + = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
  19 + = link_to "Cancel", "#", :class => "btn hide-button"
  20 + .options
  21 + %h6.left Notify via email:
  22 + .labels
  23 + = label_tag :notify do
  24 + = check_box_tag :notify, 1, @note.noteable_type != "Commit"
  25 + %span Project team
21 26
22 - - if @note.notify_only_author?(current_user)  
23 - = label_tag :notify_author do  
24 - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"  
25 - %span Commit author  
26 - .actions  
27 - = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"  
28 - = link_to "Close", "#", :class => "btn hide-button" 27 + - if @note.notify_only_author?(current_user)
  28 + = label_tag :notify_author do
  29 + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
  30 + %span Commit author
29 31
30 :javascript 32 :javascript
31 $(function(){ 33 $(function(){
app/views/notify/note_wiki_email.html.haml 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
  2 + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
  3 + %tr
  4 + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
  5 + %td{:align => "left", :style => "padding: 20px 0 0;"}
  6 + %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
  7 + New comment -
  8 + = link_to project_issue_url(@wiki.project, @wiki, :anchor => "note_#{@note.id}") do
  9 + = "Wiki ##{@wiki.title.to_s}"
  10 + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
  11 + %tr
  12 + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
  13 + %td{:style => "padding: 15px 0 15px;", :valign => "top"}
  14 + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
  15 + %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name}
  16 + commented on Wiki page:
  17 + %br
  18 + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"}
  19 + %tr
  20 + %td{:valign => "top"}
  21 + %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" }
  22 + = markdown(@note.note)
  23 + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
  24 +
app/views/projects/files.html.haml
@@ -14,6 +14,6 @@ @@ -14,6 +14,6 @@
14 ago 14 ago
15 - else 15 - else
16 .alert-message.block-message 16 .alert-message.block-message
17 - %p All files attached to project wall, issues etc will be displayed here 17 + %span All files attached to project wall, issues etc will be displayed here
18 18
19 19
app/views/refs/_tree_commit.html.haml
1 - if tm 1 - if tm
2 %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) 2 %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
3 -= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" 3 += link_to truncate(content_commit.title, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
app/views/refs/blame.html.haml
@@ -25,15 +25,15 @@ @@ -25,15 +25,15 @@
25 %table 25 %table
26 - @blame.each do |commit, lines| 26 - @blame.each do |commit, lines|
27 - commit = Commit.new(commit) 27 - commit = Commit.new(commit)
  28 + - commit = CommitDecorator.decorate(commit)
28 %tr 29 %tr
29 %td.author 30 %td.author
30 = image_tag gravatar_icon(commit.author_email, 16) 31 = image_tag gravatar_icon(commit.author_email, 16)
31 = commit.author_name 32 = commit.author_name
32 %td.blame_commit 33 %td.blame_commit
33 &nbsp; 34 &nbsp;
34 - = link_to project_commit_path(@project, :id => commit.id) do  
35 - %code= commit.id.to_s[0..10]  
36 - %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding" 35 + %code= link_to commit.short_id, project_commit_path(@project, :id => commit.id)
  36 + = link_to truncate(commit.title, :length => 30), project_commit_path(@project, :id => commit.id), :class => "row_title" rescue "--broken encoding"
37 %td.lines 37 %td.lines
38 = preserve do 38 = preserve do
39 %pre 39 %pre
app/views/repositories/_branch.html.haml
  1 +- commit = Commit.new(branch.commit)
  2 +- commit = CommitDecorator.decorate(commit)
1 %tr 3 %tr
2 %td 4 %td
3 = link_to project_commits_path(@project, :ref => branch.name) do 5 = link_to project_commits_path(@project, :ref => branch.name) do
@@ -5,14 +7,14 @@ @@ -5,14 +7,14 @@
5 - if branch.name == @project.root_ref 7 - if branch.name == @project.root_ref
6 %span.label default 8 %span.label default
7 %td 9 %td
8 - = link_to project_commit_path(@project, :id => branch.commit.id) do  
9 - %code= branch.commit.id.to_s[0..10] 10 + = link_to project_commit_path(@project, :id => commit.id) do
  11 + %code= commit.short_id
10 12
11 - = image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16  
12 - = truncate(Commit.new(branch.commit).safe_message, :length => 40) 13 + = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
  14 + = truncate(commit.title, :length => 40)
13 %td 15 %td
14 %span.update-author.right 16 %span.update-author.right
15 - = time_ago_in_words(branch.commit.committed_date) 17 + = time_ago_in_words(commit.committed_date)
16 ago 18 ago
17 %td 19 %td
18 - if can? current_user, :download_code, @project 20 - if can? current_user, :download_code, @project
app/views/repositories/_feed.html.haml
1 - commit = update 1 - commit = update
  2 +- commit = CommitDecorator.new(commit)
2 %tr 3 %tr
3 %td 4 %td
4 = link_to project_commits_path(@project, :ref => commit.head.name) do 5 = link_to project_commits_path(@project, :ref => commit.head.name) do
@@ -10,9 +11,9 @@ @@ -10,9 +11,9 @@
10 %td 11 %td
11 %div 12 %div
12 = link_to project_commits_path(@project, commit.id) do 13 = link_to project_commits_path(@project, commit.id) do
13 - %code= commit.id.to_s[0..10] 14 + %code= commit.short_id
14 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 15 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
15 - = truncate(commit.safe_message, :length => 40) 16 + = truncate(commit.title, :length => 40)
16 %td 17 %td
17 %span.right.cgray 18 %span.right.cgray
18 = time_ago_in_words(commit.committed_date) 19 = time_ago_in_words(commit.committed_date)
app/views/repositories/tags.html.haml
@@ -9,14 +9,15 @@ @@ -9,14 +9,15 @@
9 %th 9 %th
10 - @tags.each do |tag| 10 - @tags.each do |tag|
11 - commit = Commit.new(tag.commit) 11 - commit = Commit.new(tag.commit)
  12 + - commit = CommitDecorator.decorate(commit)
12 %tr 13 %tr
13 %td 14 %td
14 %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => "" 15 %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => ""
15 %td 16 %td
16 = link_to project_commit_path(@project, commit.id) do 17 = link_to project_commit_path(@project, commit.id) do
17 - %code= commit.id.to_s[0..10] 18 + %code= commit.short_id
18 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 19 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
19 - = truncate(commit.safe_message, :length => 40) 20 + = truncate(commit.title, :length => 40)
20 %td 21 %td
21 %span.update-author.right 22 %span.update-author.right
22 = time_ago_in_words(commit.committed_date) 23 = time_ago_in_words(commit.committed_date)
app/views/wikis/_form.html.haml
@@ -6,19 +6,21 @@ @@ -6,19 +6,21 @@
6 - @wiki.errors.full_messages.each do |msg| 6 - @wiki.errors.full_messages.each do |msg|
7 %li= msg 7 %li= msg
8 8
9 - .alert-message.block-message.warning  
10 - %p  
11 - Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.  
12 - %br  
13 - To add link to new page you can just type  
14 - %code [Link Title](page-slug)  
15 - .clearfix  
16 - = f.label :title  
17 - .input= f.text_field :title, :class => :xxlarge  
18 - = f.hidden_field :slug  
19 - .clearfix  
20 - = f.label :content  
21 - .input= f.text_area :content, :class => :xxlarge 9 + .main_box
  10 + .top_box_content
  11 + = f.label :title
  12 + .input= f.text_field :title, :class => 'span8'
  13 + = f.hidden_field :slug
  14 + .middle_box_content
  15 + .input
  16 + %span.cgray
  17 + Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.
  18 + To add link to new page you can just type
  19 + %code [Link Title](page-slug)
  20 +
  21 + .bottom_box_content
  22 + = f.label :content
  23 + .input= f.text_area :content, :class => 'span8'
22 .actions 24 .actions
23 = f.submit 'Save', :class => "primary btn" 25 = f.submit 'Save', :class => "primary btn"
24 = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn" 26 = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn"
app/views/wikis/edit.html.haml
1 -%h3 Editing page 1 +%h3.page_title Editing page
2 %hr 2 %hr
3 = render 'form' 3 = render 'form'
app/views/wikis/empty.html.haml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +%h3.page_title Empty page
  2 +%hr
  3 +.alert-message.block-message.warning
  4 + %span You are not allowed to create wiki pages
app/views/wikis/history.html.haml
1 -%h3 Versions  
2 -%table 1 +%h3.page_title Versions
  2 +%br
  3 +%table.admin-table
3 %thead 4 %thead
4 %tr 5 %tr
5 %th # 6 %th #
app/views/wikis/show.html.haml
@@ -5,13 +5,18 @@ @@ -5,13 +5,18 @@
5 = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do 5 = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
6 History 6 History
7 = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do 7 = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
  8 + %i.icon-edit
8 Edit 9 Edit
9 -%hr  
10 -.wiki_content  
11 - = preserve do  
12 - = markdown @wiki.content 10 +%br
  11 +.file_holder
  12 + .file_content.wiki
  13 + = preserve do
  14 + = markdown @wiki.content
13 15
14 %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago 16 %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago
15 - if can? current_user, :admin_wiki, @project 17 - if can? current_user, :admin_wiki, @project
16 = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do 18 = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do
17 Delete this page 19 Delete this page
  20 +
  21 +%hr
  22 +.wiki_notes#notes= render "notes/notes", :tid => @wiki.id, :tt => "wiki"
doc/api/README.md
@@ -27,3 +27,4 @@ The API uses JSON to serialize data. You don&#39;t need to specify `.json` at the en @@ -27,3 +27,4 @@ The API uses JSON to serialize data. You don&#39;t need to specify `.json` at the en
27 27
28 + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) 28 + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md)
29 + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) 29 + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md)
  30 ++ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md)
doc/api/issues.md 0 → 100644
@@ -0,0 +1,184 @@ @@ -0,0 +1,184 @@
  1 +## List issues
  2 +
  3 +Get all issues created by authenticed user.
  4 +
  5 +```
  6 +GET /issues
  7 +```
  8 +
  9 +```json
  10 +[
  11 + {
  12 + "id": 43,
  13 + "project_id": 8,
  14 + "title": "4xx/5xx pages",
  15 + "description": "",
  16 + "labels": [ ],
  17 + "milestone": null,
  18 + "assignee": null,
  19 + "author": {
  20 + "id": 1,
  21 + "email": "john@example.com",
  22 + "name": "John Smith",
  23 + "blocked": false,
  24 + "created_at": "2012-05-23T08:00:58Z"
  25 + },
  26 + "closed": true,
  27 + "updated_at": "2012-07-02T17:53:12Z",
  28 + "created_at": "2012-07-02T17:53:12Z"
  29 + },
  30 + {
  31 + "id": 42,
  32 + "project_id": 8,
  33 + "title": "Add user settings",
  34 + "description": "",
  35 + "labels": [
  36 + "feature"
  37 + ],
  38 + "milestone": {
  39 + "id": 1,
  40 + "title": "v1.0",
  41 + "description": "",
  42 + "due_date": "2012-07-20",
  43 + "closed": false,
  44 + "updated_at": "2012-07-04T13:42:48Z",
  45 + "created_at": "2012-07-04T13:42:48Z"
  46 + },
  47 + "assignee": {
  48 + "id": 2,
  49 + "email": "jack@example.com",
  50 + "name": "Jack Smith",
  51 + "blocked": false,
  52 + "created_at": "2012-05-23T08:01:01Z"
  53 + },
  54 + "author": {
  55 + "id": 1,
  56 + "email": "john@example.com",
  57 + "name": "John Smith",
  58 + "blocked": false,
  59 + "created_at": "2012-05-23T08:00:58Z"
  60 + },
  61 + "closed": false,
  62 + "updated_at": "2012-07-12T13:43:19Z",
  63 + "created_at": "2012-06-28T12:58:06Z"
  64 + }
  65 +]
  66 +```
  67 +
  68 +## List project issues
  69 +
  70 +Get a list of project issues.
  71 +
  72 +```
  73 +GET /projects/:id/issues
  74 +```
  75 +
  76 +Parameters:
  77 +
  78 ++ `id` (required) - The ID or code name of a project
  79 +
  80 +## Single issue
  81 +
  82 +Get a project issue.
  83 +
  84 +```
  85 +GET /projects/:id/issues/:issue_id
  86 +```
  87 +
  88 +Parameters:
  89 +
  90 ++ `id` (required) - The ID or code name of a project
  91 ++ `issue_id` (required) - The ID of a project issue
  92 +
  93 +```json
  94 +{
  95 + "id": 42,
  96 + "project_id": 8,
  97 + "title": "Add user settings",
  98 + "description": "",
  99 + "labels": [
  100 + "feature"
  101 + ],
  102 + "milestone": {
  103 + "id": 1,
  104 + "title": "v1.0",
  105 + "description": "",
  106 + "due_date": "2012-07-20",
  107 + "closed": false,
  108 + "updated_at": "2012-07-04T13:42:48Z",
  109 + "created_at": "2012-07-04T13:42:48Z"
  110 + },
  111 + "assignee": {
  112 + "id": 2,
  113 + "email": "jack@example.com",
  114 + "name": "Jack Smith",
  115 + "blocked": false,
  116 + "created_at": "2012-05-23T08:01:01Z"
  117 + },
  118 + "author": {
  119 + "id": 1,
  120 + "email": "john@example.com",
  121 + "name": "John Smith",
  122 + "blocked": false,
  123 + "created_at": "2012-05-23T08:00:58Z"
  124 + },
  125 + "closed": false,
  126 + "updated_at": "2012-07-12T13:43:19Z",
  127 + "created_at": "2012-06-28T12:58:06Z"
  128 +}
  129 +```
  130 +
  131 +## New issue
  132 +
  133 +Create a new project issue.
  134 +
  135 +```
  136 +POST /projects/:id/issues
  137 +```
  138 +
  139 +Parameters:
  140 +
  141 ++ `id` (required) - The ID or code name of a project
  142 ++ `title` (required) - The title of an issue
  143 ++ `description` (optional) - The description of an issue
  144 ++ `assignee_id` (optional) - The ID of a user to assign issue
  145 ++ `milestone_id` (optional) - The ID of a milestone to assign issue
  146 ++ `labels` (optional) - Comma-separated label names for an issue
  147 +
  148 +Will return created issue with status `201 Created` on success, or `404 Not found` on fail.
  149 +
  150 +## Edit issue
  151 +
  152 +Update an existing project issue.
  153 +
  154 +```
  155 +PUT /projects/:id/issues/:issue_id
  156 +```
  157 +
  158 +Parameters:
  159 +
  160 ++ `id` (required) - The ID or code name of a project
  161 ++ `issue_id` (required) - The ID of a project's issue
  162 ++ `title` (optional) - The title of an issue
  163 ++ `description` (optional) - The description of an issue
  164 ++ `assignee_id` (optional) - The ID of a user to assign issue
  165 ++ `milestone_id` (optional) - The ID of a milestone to assign issue
  166 ++ `labels` (optional) - Comma-separated label names for an issue
  167 ++ `closed` (optional) - The state of an issue (0 = false, 1 = true)
  168 +
  169 +Will return updated issue with status `200 OK` on success, or `404 Not found` on fail.
  170 +
  171 +## Delete issue
  172 +
  173 +Delete existing project issue.
  174 +
  175 +```
  176 +DELETE /projects/:id/issues/:issue_id
  177 +```
  178 +
  179 +Parameters:
  180 +
  181 ++ `id` (required) - The ID or code name of a project
  182 ++ `issue_id` (required) - The ID of a project's issue
  183 +
  184 +Status code `200` will be returned on success.
doc/api/projects.md
1 ## List projects 1 ## List projects
2 2
3 -Get a list of authenticated users' projects. 3 +Get a list of authenticated user's projects.
4 4
5 ``` 5 ```
6 GET /projects 6 GET /projects
@@ -63,7 +63,7 @@ GET /projects/:id @@ -63,7 +63,7 @@ GET /projects/:id
63 63
64 Parameters: 64 Parameters:
65 65
66 -+ `id` (required) - The code name of a project 66 ++ `id` (required) - The ID or code name of a project
67 67
68 ```json 68 ```json
69 { 69 {
@@ -91,7 +91,7 @@ Parameters: @@ -91,7 +91,7 @@ Parameters:
91 91
92 ## Project repository branches 92 ## Project repository branches
93 93
94 -Get a list of project repository branches. 94 +Get a list of project repository branches sorted by name alphabetically.
95 95
96 ``` 96 ```
97 GET /projects/:id/repository/branches 97 GET /projects/:id/repository/branches
@@ -99,7 +99,7 @@ GET /projects/:id/repository/branches @@ -99,7 +99,7 @@ GET /projects/:id/repository/branches
99 99
100 Parameters: 100 Parameters:
101 101
102 -+ `id` (required) - The code name of a project 102 ++ `id` (required) - The ID or code name of a project
103 103
104 ```json 104 ```json
105 [ 105 [
@@ -131,7 +131,7 @@ Parameters: @@ -131,7 +131,7 @@ Parameters:
131 131
132 ## Project repository tags 132 ## Project repository tags
133 133
134 -Get a list of project repository tags. 134 +Get a list of project repository tags sorted by name in reverse alphabetical order.
135 135
136 ``` 136 ```
137 GET /projects/:id/repository/tags 137 GET /projects/:id/repository/tags
@@ -139,7 +139,7 @@ GET /projects/:id/repository/tags @@ -139,7 +139,7 @@ GET /projects/:id/repository/tags
139 139
140 Parameters: 140 Parameters:
141 141
142 -+ `id` (required) - The code name of a project 142 ++ `id` (required) - The ID or code name of a project
143 143
144 ```json 144 ```json
145 [ 145 [
@@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id @@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id
183 183
184 Parameters: 184 Parameters:
185 185
186 -+ `id` (required) - The code name of a project 186 ++ `id` (required) - The ID or code name of a project
187 + `snippet_id` (required) - The ID of a project's snippet 187 + `snippet_id` (required) - The ID of a project's snippet
188 188
189 ```json 189 ```json
@@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw @@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw
214 214
215 Parameters: 215 Parameters:
216 216
217 -+ `id` (required) - The code name of a project 217 ++ `id` (required) - The ID or code name of a project
218 + `snippet_id` (required) - The ID of a project's snippet 218 + `snippet_id` (required) - The ID of a project's snippet
219 219
220 ## New snippet 220 ## New snippet
@@ -227,7 +227,7 @@ POST /projects/:id/snippets @@ -227,7 +227,7 @@ POST /projects/:id/snippets
227 227
228 Parameters: 228 Parameters:
229 229
230 -+ `id` (required) - The code name of a project 230 ++ `id` (required) - The ID or code name of a project
231 + `title` (required) - The title of a snippet 231 + `title` (required) - The title of a snippet
232 + `file_name` (required) - The name of a snippet file 232 + `file_name` (required) - The name of a snippet file
233 + `lifetime` (optional) - The expiration date of a snippet 233 + `lifetime` (optional) - The expiration date of a snippet
@@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id @@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id
245 245
246 Parameters: 246 Parameters:
247 247
248 -+ `id` (required) - The code name of a project 248 ++ `id` (required) - The ID or code name of a project
249 + `snippet_id` (required) - The ID of a project's snippet 249 + `snippet_id` (required) - The ID of a project's snippet
250 + `title` (optional) - The title of a snippet 250 + `title` (optional) - The title of a snippet
251 + `file_name` (optional) - The name of a snippet file 251 + `file_name` (optional) - The name of a snippet file
@@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id @@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id
264 264
265 Parameters: 265 Parameters:
266 266
267 -+ `id` (required) - The code name of a project 267 ++ `id` (required) - The ID or code name of a project
268 + `snippet_id` (required) - The ID of a project's snippet 268 + `snippet_id` (required) - The ID of a project's snippet
269 269
270 Status code `200` will be returned on success. 270 Status code `200` will be returned on success.
doc/installation.md
@@ -119,6 +119,7 @@ Permissions: @@ -119,6 +119,7 @@ Permissions:
119 119
120 sudo chmod -R g+rwX /home/git/repositories/ 120 sudo chmod -R g+rwX /home/git/repositories/
121 sudo chown -R git:git /home/git/repositories/ 121 sudo chown -R git:git /home/git/repositories/
  122 + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
122 123
123 #### CHECK: Logout & login again to apply git group to your user 124 #### CHECK: Logout & login again to apply git group to your user
124 125
features/step_definitions/project_commits_steps.rb
@@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do @@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do
16 end 16 end
17 17
18 Then /^I see commits atom feed$/ do 18 Then /^I see commits atom feed$/ do
19 - commit = @project.commit 19 + commit = CommitDecorator.decorate(@project.commit)
20 page.response_headers['Content-Type'].should have_content("application/atom+xml") 20 page.response_headers['Content-Type'].should have_content("application/atom+xml")
21 page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") 21 page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
22 page.body.should have_selector("author email", :text => commit.author_email) 22 page.body.should have_selector("author email", :text => commit.author_email)
23 - page.body.should have_selector("entry summary", :text => commit.message) 23 + page.body.should have_selector("entry summary", :text => commit.description)
24 end 24 end
25 25
26 Given /^I click on commit link$/ do 26 Given /^I click on commit link$/ do
@@ -15,5 +15,6 @@ module Gitlab @@ -15,5 +15,6 @@ module Gitlab
15 15
16 mount Users 16 mount Users
17 mount Projects 17 mount Projects
  18 + mount Issues
18 end 19 end
19 end 20 end
lib/api/entities.rb
@@ -16,11 +16,7 @@ module Gitlab @@ -16,11 +16,7 @@ module Gitlab
16 expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at 16 expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
17 end 17 end
18 18
19 - class ProjectRepositoryBranches < Grape::Entity  
20 - expose :name, :commit  
21 - end  
22 -  
23 - class ProjectRepositoryTags < Grape::Entity 19 + class RepoObject < Grape::Entity
24 expose :name, :commit 20 expose :name, :commit
25 end 21 end
26 22
@@ -29,5 +25,19 @@ module Gitlab @@ -29,5 +25,19 @@ module Gitlab
29 expose :author, :using => Entities::UserBasic 25 expose :author, :using => Entities::UserBasic
30 expose :expires_at, :updated_at, :created_at 26 expose :expires_at, :updated_at, :created_at
31 end 27 end
  28 +
  29 + class Milestone < Grape::Entity
  30 + expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at
  31 + end
  32 +
  33 + class Issue < Grape::Entity
  34 + expose :id
  35 + expose (:project_id) {|issue| issue.project.id}
  36 + expose :title, :description
  37 + expose :label_list, :as => :labels
  38 + expose :milestone, :using => Entities::Milestone
  39 + expose :assignee, :author, :using => Entities::UserBasic
  40 + expose :closed, :updated_at, :created_at
  41 + end
32 end 42 end
33 end 43 end
lib/api/helpers.rb
@@ -4,6 +4,16 @@ module Gitlab @@ -4,6 +4,16 @@ module Gitlab
4 @current_user ||= User.find_by_authentication_token(params[:private_token]) 4 @current_user ||= User.find_by_authentication_token(params[:private_token])
5 end 5 end
6 6
  7 + def user_project
  8 + if @project ||= current_user.projects.find_by_id(params[:id]) ||
  9 + current_user.projects.find_by_code(params[:id])
  10 + else
  11 + error!({'message' => '404 Not found'}, 404)
  12 + end
  13 +
  14 + @project
  15 + end
  16 +
7 def authenticate! 17 def authenticate!
8 error!({'message' => '401 Unauthorized'}, 401) unless current_user 18 error!({'message' => '401 Unauthorized'}, 401) unless current_user
9 end 19 end
lib/api/issues.rb 0 → 100644
@@ -0,0 +1,111 @@ @@ -0,0 +1,111 @@
  1 +module Gitlab
  2 + # Issues API
  3 + class Issues < Grape::API
  4 + before { authenticate! }
  5 +
  6 + resource :issues do
  7 + # Get currently authenticated user's issues
  8 + #
  9 + # Example Request:
  10 + # GET /issues
  11 + get do
  12 + present current_user.issues, :with => Entities::Issue
  13 + end
  14 + end
  15 +
  16 + resource :projects do
  17 + # Get a list of project issues
  18 + #
  19 + # Parameters:
  20 + # id (required) - The ID or code name of a project
  21 + # Example Request:
  22 + # GET /projects/:id/issues
  23 + get ":id/issues" do
  24 + present user_project.issues, :with => Entities::Issue
  25 + end
  26 +
  27 + # Get a single project issue
  28 + #
  29 + # Parameters:
  30 + # id (required) - The ID or code name of a project
  31 + # issue_id (required) - The ID of a project issue
  32 + # Example Request:
  33 + # GET /projects/:id/issues/:issue_id
  34 + get ":id/issues/:issue_id" do
  35 + @issue = user_project.issues.find(params[:issue_id])
  36 + present @issue, :with => Entities::Issue
  37 + end
  38 +
  39 + # Create a new project issue
  40 + #
  41 + # Parameters:
  42 + # id (required) - The ID or code name of a project
  43 + # title (required) - The title of an issue
  44 + # description (optional) - The description of an issue
  45 + # assignee_id (optional) - The ID of a user to assign issue
  46 + # milestone_id (optional) - The ID of a milestone to assign issue
  47 + # labels (optional) - The labels of an issue
  48 + # Example Request:
  49 + # POST /projects/:id/issues
  50 + post ":id/issues" do
  51 + @issue = user_project.issues.new(
  52 + :title => params[:title],
  53 + :description => params[:description],
  54 + :assignee_id => params[:assignee_id],
  55 + :milestone_id => params[:milestone_id],
  56 + :label_list => params[:labels]
  57 + )
  58 + @issue.author = current_user
  59 +
  60 + if @issue.save
  61 + present @issue, :with => Entities::Issue
  62 + else
  63 + error!({'message' => '404 Not found'}, 404)
  64 + end
  65 + end
  66 +
  67 + # Update an existing issue
  68 + #
  69 + # Parameters:
  70 + # id (required) - The ID or code name of a project
  71 + # issue_id (required) - The ID of a project issue
  72 + # title (optional) - The title of an issue
  73 + # description (optional) - The description of an issue
  74 + # assignee_id (optional) - The ID of a user to assign issue
  75 + # milestone_id (optional) - The ID of a milestone to assign issue
  76 + # labels (optional) - The labels of an issue
  77 + # closed (optional) - The state of an issue (0 = false, 1 = true)
  78 + # Example Request:
  79 + # PUT /projects/:id/issues/:issue_id
  80 + put ":id/issues/:issue_id" do
  81 + @issue = user_project.issues.find(params[:issue_id])
  82 + parameters = {
  83 + :title => (params[:title] || @issue.title),
  84 + :description => (params[:description] || @issue.description),
  85 + :assignee_id => (params[:assignee_id] || @issue.assignee_id),
  86 + :milestone_id => (params[:milestone_id] || @issue.milestone_id),
  87 + :label_list => (params[:labels] || @issue.label_list),
  88 + :closed => (params[:closed] || @issue.closed)
  89 + }
  90 +
  91 + if @issue.update_attributes(parameters)
  92 + present @issue, :with => Entities::Issue
  93 + else
  94 + error!({'message' => '404 Not found'}, 404)
  95 + end
  96 + end
  97 +
  98 + # Delete a project issue
  99 + #
  100 + # Parameters:
  101 + # id (required) - The ID or code name of a project
  102 + # issue_id (required) - The ID of a project issue
  103 + # Example Request:
  104 + # DELETE /projects/:id/issues/:issue_id
  105 + delete ":id/issues/:issue_id" do
  106 + @issue = user_project.issues.find(params[:issue_id])
  107 + @issue.destroy
  108 + end
  109 + end
  110 + end
  111 +end
lib/api/projects.rb
@@ -16,53 +16,49 @@ module Gitlab @@ -16,53 +16,49 @@ module Gitlab
16 # Get a single project 16 # Get a single project
17 # 17 #
18 # Parameters: 18 # Parameters:
19 - # id (required) - The code of a project 19 + # id (required) - The ID or code name of a project
20 # Example Request: 20 # Example Request:
21 # GET /projects/:id 21 # GET /projects/:id
22 get ":id" do 22 get ":id" do
23 - @project = current_user.projects.find_by_code(params[:id])  
24 - present @project, :with => Entities::Project 23 + present user_project, :with => Entities::Project
25 end 24 end
26 25
27 # Get a project repository branches 26 # Get a project repository branches
28 # 27 #
29 # Parameters: 28 # Parameters:
30 - # id (required) - The code of a project 29 + # id (required) - The ID or code name of a project
31 # Example Request: 30 # Example Request:
32 # GET /projects/:id/repository/branches 31 # GET /projects/:id/repository/branches
33 get ":id/repository/branches" do 32 get ":id/repository/branches" do
34 - @project = current_user.projects.find_by_code(params[:id])  
35 - present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches 33 + present user_project.repo.heads.sort_by(&:name), :with => Entities::RepoObject
36 end 34 end
37 35
38 # Get a project repository tags 36 # Get a project repository tags
39 # 37 #
40 # Parameters: 38 # Parameters:
41 - # id (required) - The code of a project 39 + # id (required) - The ID or code name of a project
42 # Example Request: 40 # Example Request:
43 # GET /projects/:id/repository/tags 41 # GET /projects/:id/repository/tags
44 get ":id/repository/tags" do 42 get ":id/repository/tags" do
45 - @project = current_user.projects.find_by_code(params[:id])  
46 - present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags 43 + present user_project.repo.tags.sort_by(&:name).reverse, :with => Entities::RepoObject
47 end 44 end
48 45
49 # Get a project snippet 46 # Get a project snippet
50 # 47 #
51 # Parameters: 48 # Parameters:
52 - # id (required) - The code of a project 49 + # id (required) - The ID or code name of a project
53 # snippet_id (required) - The ID of a project snippet 50 # snippet_id (required) - The ID of a project snippet
54 # Example Request: 51 # Example Request:
55 # GET /projects/:id/snippets/:snippet_id 52 # GET /projects/:id/snippets/:snippet_id
56 get ":id/snippets/:snippet_id" do 53 get ":id/snippets/:snippet_id" do
57 - @project = current_user.projects.find_by_code(params[:id])  
58 - @snippet = @project.snippets.find(params[:snippet_id]) 54 + @snippet = user_project.snippets.find(params[:snippet_id])
59 present @snippet, :with => Entities::ProjectSnippet 55 present @snippet, :with => Entities::ProjectSnippet
60 end 56 end
61 57
62 # Create a new project snippet 58 # Create a new project snippet
63 # 59 #
64 # Parameters: 60 # Parameters:
65 - # id (required) - The code name of a project 61 + # id (required) - The ID or code name of a project
66 # title (required) - The title of a snippet 62 # title (required) - The title of a snippet
67 # file_name (required) - The name of a snippet file 63 # file_name (required) - The name of a snippet file
68 # lifetime (optional) - The expiration date of a snippet 64 # lifetime (optional) - The expiration date of a snippet
@@ -70,8 +66,7 @@ module Gitlab @@ -70,8 +66,7 @@ module Gitlab
70 # Example Request: 66 # Example Request:
71 # POST /projects/:id/snippets 67 # POST /projects/:id/snippets
72 post ":id/snippets" do 68 post ":id/snippets" do
73 - @project = current_user.projects.find_by_code(params[:id])  
74 - @snippet = @project.snippets.new( 69 + @snippet = user_project.snippets.new(
75 :title => params[:title], 70 :title => params[:title],
76 :file_name => params[:file_name], 71 :file_name => params[:file_name],
77 :expires_at => params[:lifetime], 72 :expires_at => params[:lifetime],
@@ -89,7 +84,7 @@ module Gitlab @@ -89,7 +84,7 @@ module Gitlab
89 # Update an existing project snippet 84 # Update an existing project snippet
90 # 85 #
91 # Parameters: 86 # Parameters:
92 - # id (required) - The code name of a project 87 + # id (required) - The ID or code name of a project
93 # snippet_id (required) - The ID of a project snippet 88 # snippet_id (required) - The ID of a project snippet
94 # title (optional) - The title of a snippet 89 # title (optional) - The title of a snippet
95 # file_name (optional) - The name of a snippet file 90 # file_name (optional) - The name of a snippet file
@@ -98,8 +93,7 @@ module Gitlab @@ -98,8 +93,7 @@ module Gitlab
98 # Example Request: 93 # Example Request:
99 # PUT /projects/:id/snippets/:snippet_id 94 # PUT /projects/:id/snippets/:snippet_id
100 put ":id/snippets/:snippet_id" do 95 put ":id/snippets/:snippet_id" do
101 - @project = current_user.projects.find_by_code(params[:id])  
102 - @snippet = @project.snippets.find(params[:snippet_id]) 96 + @snippet = user_project.snippets.find(params[:snippet_id])
103 parameters = { 97 parameters = {
104 :title => (params[:title] || @snippet.title), 98 :title => (params[:title] || @snippet.title),
105 :file_name => (params[:file_name] || @snippet.file_name), 99 :file_name => (params[:file_name] || @snippet.file_name),
@@ -117,26 +111,24 @@ module Gitlab @@ -117,26 +111,24 @@ module Gitlab
117 # Delete a project snippet 111 # Delete a project snippet
118 # 112 #
119 # Parameters: 113 # Parameters:
120 - # id (required) - The code of a project 114 + # id (required) - The ID or code name of a project
121 # snippet_id (required) - The ID of a project snippet 115 # snippet_id (required) - The ID of a project snippet
122 # Example Request: 116 # Example Request:
123 # DELETE /projects/:id/snippets/:snippet_id 117 # DELETE /projects/:id/snippets/:snippet_id
124 delete ":id/snippets/:snippet_id" do 118 delete ":id/snippets/:snippet_id" do
125 - @project = current_user.projects.find_by_code(params[:id])  
126 - @snippet = @project.snippets.find(params[:snippet_id]) 119 + @snippet = user_project.snippets.find(params[:snippet_id])
127 @snippet.destroy 120 @snippet.destroy
128 end 121 end
129 122
130 # Get a raw project snippet 123 # Get a raw project snippet
131 # 124 #
132 # Parameters: 125 # Parameters:
133 - # id (required) - The code of a project 126 + # id (required) - The ID or code name of a project
134 # snippet_id (required) - The ID of a project snippet 127 # snippet_id (required) - The ID of a project snippet
135 # Example Request: 128 # Example Request:
136 # GET /projects/:id/snippets/:snippet_id/raw 129 # GET /projects/:id/snippets/:snippet_id/raw
137 get ":id/snippets/:snippet_id/raw" do 130 get ":id/snippets/:snippet_id/raw" do
138 - @project = current_user.projects.find_by_code(params[:id])  
139 - @snippet = @project.snippets.find(params[:snippet_id]) 131 + @snippet = user_project.snippets.find(params[:snippet_id])
140 present @snippet.content 132 present @snippet.content
141 end 133 end
142 end 134 end
lib/gitlab/logger.rb
@@ -10,6 +10,7 @@ module Gitlab @@ -10,6 +10,7 @@ module Gitlab
10 10
11 def self.read_latest 11 def self.read_latest
12 path = Rails.root.join("log/githost.log") 12 path = Rails.root.join("log/githost.log")
  13 + self.build unless File.exist?(path)
13 logs = File.read(path).split("\n") 14 logs = File.read(path).split("\n")
14 end 15 end
15 16
lib/tasks/gitlab/backup.rake
@@ -121,7 +121,7 @@ namespace :gitlab do @@ -121,7 +121,7 @@ namespace :gitlab do
121 backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") 121 backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
122 FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) 122 FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo)
123 puts "Dumping repositories:" 123 puts "Dumping repositories:"
124 - project = Project.all.map { |n| [n.name,n.path_to_repo] } 124 + project = Project.all.map { |n| [n.path,n.path_to_repo] }
125 project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] 125 project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
126 project.each do |project| 126 project.each do |project|
127 print "- Dumping repository #{project.first}... " 127 print "- Dumping repository #{project.first}... "
@@ -136,12 +136,18 @@ namespace :gitlab do @@ -136,12 +136,18 @@ namespace :gitlab do
136 task :repo_restore => :environment do 136 task :repo_restore => :environment do
137 backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") 137 backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
138 puts "Restoring repositories:" 138 puts "Restoring repositories:"
139 - project = Project.all.map { |n| [n.name,n.path_to_repo] } 139 + project = Project.all.map { |n| [n.path,n.path_to_repo] }
140 project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] 140 project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
141 project.each do |project| 141 project.each do |project|
142 print "- Restoring repository #{project.first}... " 142 print "- Restoring repository #{project.first}... "
143 FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff 143 FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff
144 if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") 144 if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1")
  145 + permission_commands = [
  146 + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}",
  147 + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}",
  148 + "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive"
  149 + ]
  150 + permission_commands.each { |command| Kernel.system(command) }
145 puts "[DONE]".green 151 puts "[DONE]".green
146 else 152 else
147 puts "[FAILED]".red 153 puts "[FAILED]".red
lib/tasks/gitlab/status.rake
@@ -2,7 +2,7 @@ namespace :gitlab do @@ -2,7 +2,7 @@ namespace :gitlab do
2 namespace :app do 2 namespace :app do
3 desc "GITLAB | Check gitlab installation status" 3 desc "GITLAB | Check gitlab installation status"
4 task :status => :environment do 4 task :status => :environment do
5 - puts "Starting diagnostic" 5 + puts "Starting diagnostic".yellow
6 git_base_path = Gitlab.config.git_base_path 6 git_base_path = Gitlab.config.git_base_path
7 7
8 print "config/database.yml............" 8 print "config/database.yml............"
@@ -56,7 +56,28 @@ namespace :gitlab do @@ -56,7 +56,28 @@ namespace :gitlab do
56 return 56 return
57 end 57 end
58 58
59 - puts "\nFinished" 59 + if Project.count > 0
  60 + puts "Validating projects repositories:".yellow
  61 + Project.find_each(:batch_size => 100) do |project|
  62 + print "#{project.name}....."
  63 + hook_file = File.join(project.path_to_repo, 'hooks','post-receive')
  64 +
  65 + unless File.exists?(hook_file)
  66 + puts "post-receive file missing".red
  67 + next
  68 + end
  69 +
  70 +
  71 + unless File.owned?(hook_file)
  72 + puts "post-receive file is not owner by gitlab".red
  73 + next
  74 + end
  75 +
  76 + puts "post-reveice file ok".green
  77 + end
  78 + end
  79 +
  80 + puts "\nFinished".blue
60 end 81 end
61 end 82 end
62 end 83 end
spec/api/issues_spec.rb 0 → 100644
@@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Gitlab::API do
  4 + let(:user) { Factory :user }
  5 + let!(:project) { Factory :project, :owner => user }
  6 + let!(:issue) { Factory :issue, :author => user, :assignee => user, :project => project }
  7 + before { project.add_access(user, :read) }
  8 +
  9 + describe "GET /issues" do
  10 + it "should return authentication error" do
  11 + get "#{api_prefix}/issues"
  12 + response.status.should == 401
  13 + end
  14 +
  15 + describe "authenticated GET /issues" do
  16 + it "should return an array of issues" do
  17 + get "#{api_prefix}/issues?private_token=#{user.private_token}"
  18 + response.status.should == 200
  19 + json_response.should be_an Array
  20 + json_response.first['title'].should == issue.title
  21 + end
  22 + end
  23 + end
  24 +
  25 + describe "GET /projects/:id/issues" do
  26 + it "should return project issues" do
  27 + get "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}"
  28 + response.status.should == 200
  29 + json_response.should be_an Array
  30 + json_response.first['title'].should == issue.title
  31 + end
  32 + end
  33 +
  34 + describe "GET /projects/:id/issues/:issue_id" do
  35 + it "should return a project issue by id" do
  36 + get "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}"
  37 + response.status.should == 200
  38 + json_response['title'].should == issue.title
  39 + end
  40 + end
  41 +
  42 + describe "POST /projects/:id/issues" do
  43 + it "should create a new project issue" do
  44 + post "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}",
  45 + :title => 'new issue', :labels => 'label, label2'
  46 + response.status.should == 201
  47 + json_response['title'].should == 'new issue'
  48 + json_response['description'].should be_nil
  49 + json_response['labels'].should == ['label', 'label2']
  50 + end
  51 + end
  52 +
  53 + describe "PUT /projects/:id/issues/:issue_id" do
  54 + it "should update a project issue" do
  55 + put "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}",
  56 + :title => 'updated title', :labels => 'label2', :closed => 1
  57 + response.status.should == 200
  58 + json_response['title'].should == 'updated title'
  59 + json_response['labels'].should == ['label2']
  60 + json_response['closed'].should be_true
  61 + end
  62 + end
  63 +
  64 + describe "DELETE /projects/:id/issues/:issue_id" do
  65 + it "should delete a project issue" do
  66 + expect {
  67 + delete "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}"
  68 + }.to change { Issue.count }.by(-1)
  69 + end
  70 + end
  71 +end
spec/api/projects_spec.rb
@@ -25,11 +25,23 @@ describe Gitlab::API do @@ -25,11 +25,23 @@ describe Gitlab::API do
25 25
26 describe "GET /projects/:id" do 26 describe "GET /projects/:id" do
27 it "should return a project by id" do 27 it "should return a project by id" do
28 - get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" 28 + get "#{api_prefix}/projects/#{project.id}?private_token=#{user.private_token}"
29 response.status.should == 200 29 response.status.should == 200
30 json_response['name'].should == project.name 30 json_response['name'].should == project.name
31 json_response['owner']['email'].should == user.email 31 json_response['owner']['email'].should == user.email
32 end 32 end
  33 +
  34 + it "should return a project by code name" do
  35 + get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}"
  36 + response.status.should == 200
  37 + json_response['name'].should == project.name
  38 + end
  39 +
  40 + it "should return a 404 error if not found" do
  41 + get "#{api_prefix}/projects/42?private_token=#{user.private_token}"
  42 + response.status.should == 404
  43 + json_response['message'].should == '404 Not found'
  44 + end
33 end 45 end
34 46
35 describe "GET /projects/:id/repository/branches" do 47 describe "GET /projects/:id/repository/branches" do
spec/requests/commits_spec.rb
@@ -2,7 +2,7 @@ require &#39;spec_helper&#39; @@ -2,7 +2,7 @@ require &#39;spec_helper&#39;
2 2
3 describe "Commits" do 3 describe "Commits" do
4 let(:project) { Factory :project } 4 let(:project) { Factory :project }
5 - let!(:commit) { project.commit } 5 + let!(:commit) { CommitDecorator.decorate(project.commit) }
6 before do 6 before do
7 login_as :user 7 login_as :user
8 project.add_access(@user, :read) 8 project.add_access(@user, :read)
@@ -22,8 +22,8 @@ describe &quot;Commits&quot; do @@ -22,8 +22,8 @@ describe &quot;Commits&quot; do
22 end 22 end
23 23
24 it "should list commits" do 24 it "should list commits" do
25 - page.should have_content(commit.message)  
26 - page.should have_content(commit.id.to_s[0..5]) 25 + page.should have_content(commit.description)
  26 + page.should have_content(commit.short_id(8))
27 end 27 end
28 28
29 it "should render atom feed" do 29 it "should render atom feed" do
@@ -32,7 +32,7 @@ describe &quot;Commits&quot; do @@ -32,7 +32,7 @@ describe &quot;Commits&quot; do
32 page.response_headers['Content-Type'].should have_content("application/atom+xml") 32 page.response_headers['Content-Type'].should have_content("application/atom+xml")
33 page.body.should have_selector("title", :text => "Recent commits to #{project.name}") 33 page.body.should have_selector("title", :text => "Recent commits to #{project.name}")
34 page.body.should have_selector("author email", :text => commit.author_email) 34 page.body.should have_selector("author email", :text => commit.author_email)
35 - page.body.should have_selector("entry summary", :text => commit.message) 35 + page.body.should have_selector("entry summary", :text => commit.description)
36 end 36 end
37 37
38 it "should render atom feed via private token" do 38 it "should render atom feed via private token" do
@@ -42,7 +42,7 @@ describe &quot;Commits&quot; do @@ -42,7 +42,7 @@ describe &quot;Commits&quot; do
42 page.response_headers['Content-Type'].should have_content("application/atom+xml") 42 page.response_headers['Content-Type'].should have_content("application/atom+xml")
43 page.body.should have_selector("title", :text => "Recent commits to #{project.name}") 43 page.body.should have_selector("title", :text => "Recent commits to #{project.name}")
44 page.body.should have_selector("author email", :text => commit.author_email) 44 page.body.should have_selector("author email", :text => commit.author_email)
45 - page.body.should have_selector("entry summary", :text => commit.message) 45 + page.body.should have_selector("entry summary", :text => commit.description)
46 end 46 end
47 end 47 end
48 48
spec/requests/wikis_notes_spec.rb 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Wikis" do
  4 + let(:project) { Factory :project }
  5 +
  6 + before do
  7 + login_as :user
  8 + project.add_access(@user, :read, :write)
  9 + end
  10 +
  11 + describe "add new note", :js => true do
  12 + before do
  13 + visit project_wiki_path(project, :index)
  14 +
  15 + fill_in "Title", :with => 'Test title'
  16 + fill_in "Content", :with => '[link test](test)'
  17 + click_on "Save"
  18 +
  19 + page.should have_content("Test title")
  20 +
  21 + fill_in "note_note", :with => "Comment on wiki!"
  22 + click_button "Add Comment"
  23 + end
  24 +
  25 + it "should contain the new note" do
  26 + page.should have_content("Comment on wiki!")
  27 + end
  28 + end
  29 +end