summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/note.js2
-rw-r--r--app/assets/javascripts/pager.js1
-rw-r--r--app/assets/stylesheets/common.scss9
-rw-r--r--app/assets/stylesheets/gitlab_bootstrap.scss11
-rw-r--r--app/assets/stylesheets/notes.scss26
-rw-r--r--app/assets/stylesheets/sections/commits.scss12
-rw-r--r--app/assets/stylesheets/sections/issues.scss9
-rw-r--r--app/contexts/notes_load.rb2
-rw-r--r--app/controllers/commits_controller.rb3
-rw-r--r--app/controllers/merge_requests_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb11
-rw-r--r--app/controllers/refs_controller.rb3
-rw-r--r--app/controllers/wikis_controller.rb16
-rw-r--r--app/mailers/notify.rb7
-rw-r--r--app/models/commit.rb8
-rw-r--r--app/models/wiki.rb1
-rw-r--r--app/observers/mailer_observer.rb1
-rw-r--r--app/views/commits/_commit.html.haml21
-rw-r--r--app/views/commits/_commit_box.html.haml2
-rw-r--r--app/views/commits/compare.html.haml5
-rw-r--r--app/views/commits/index.atom.builder4
-rw-r--r--app/views/dashboard/merge_requests.html.haml2
-rw-r--r--app/views/errors/gitolite.html.haml41
-rw-r--r--app/views/events/_commit.html.haml14
-rw-r--r--app/views/help/api.html.haml20
-rw-r--r--app/views/help/permissions.html.haml2
-rw-r--r--app/views/issues/_show.html.haml3
-rw-r--r--app/views/issues/show.html.haml4
-rw-r--r--app/views/merge_requests/_merge_request.html.haml3
-rw-r--r--app/views/milestones/_milestone.html.haml15
-rw-r--r--app/views/milestones/show.html.haml4
-rw-r--r--app/views/notes/_form.html.haml2
-rw-r--r--app/views/notes/_per_line_form.html.haml28
-rw-r--r--app/views/notify/note_wiki_email.html.haml24
-rw-r--r--app/views/projects/files.html.haml2
-rw-r--r--app/views/refs/_tree_commit.html.haml2
-rw-r--r--app/views/refs/blame.html.haml6
-rw-r--r--app/views/repositories/_branch.html.haml12
-rw-r--r--app/views/repositories/_feed.html.haml5
-rw-r--r--app/views/repositories/tags.html.haml5
-rw-r--r--app/views/wikis/_form.html.haml28
-rw-r--r--app/views/wikis/edit.html.haml2
-rw-r--r--app/views/wikis/empty.html.haml4
-rw-r--r--app/views/wikis/history.html.haml5
-rw-r--r--app/views/wikis/show.html.haml13
-rw-r--r--doc/api/README.md1
-rw-r--r--doc/api/issues.md184
-rw-r--r--doc/api/projects.md22
-rw-r--r--doc/installation.md1
-rw-r--r--features/step_definitions/project_commits_steps.rb4
-rw-r--r--lib/api.rb1
-rw-r--r--lib/api/entities.rb20
-rw-r--r--lib/api/helpers.rb10
-rw-r--r--lib/api/issues.rb111
-rw-r--r--lib/api/projects.rb40
-rw-r--r--lib/gitlab/logger.rb1
-rw-r--r--lib/tasks/gitlab/backup.rake10
-rw-r--r--lib/tasks/gitlab/status.rake25
-rw-r--r--spec/api/issues_spec.rb71
-rw-r--r--spec/api/projects_spec.rb14
-rw-r--r--spec/requests/commits_spec.rb10
-rw-r--r--spec/requests/wikis_notes_spec.rb29
64 files changed, 763 insertions, 198 deletions
diff --git a/Gemfile b/Gemfile
index 5b076176568..ef2076e528b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0"
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0"
gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188"
-gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44"
+gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e"
gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
gem 'grack', :git => "https://github.com/gitlabhq/grack.git"
gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git"
diff --git a/Gemfile.lock b/Gemfile.lock
index 5c57bf6c1b2..cede1547f37 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -42,8 +42,8 @@ GIT
GIT
remote: https://github.com/gitlabhq/omniauth-ldap.git
- revision: 7edf27d0281e09561838122982c16b7e62181f44
- ref: 7edf27d0281e09561838122982c16b7e62181f44
+ revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
+ ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
specs:
omniauth-ldap (1.0.2)
net-ldap (~> 0.2.2)
diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js
index c45a45d2fcb..d9ae45d93c7 100644
--- a/app/assets/javascripts/note.js
+++ b/app/assets/javascripts/note.js
@@ -33,7 +33,7 @@ init:
})
$("#note_note").live("focus", function(){
- $(this).css("height", "100px");
+ $(this).css("height", "80px");
$('.note_advanced_opts').show();
});
diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js
index d42ae1e05d1..769e8a62343 100644
--- a/app/assets/javascripts/pager.js
+++ b/app/assets/javascripts/pager.js
@@ -8,7 +8,6 @@ var Pager = {
this.limit=limit;
this.offset=limit;
this.initLoadMore();
- $('.loading').show();
},
getOld:
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
index 0db803aae23..9d9bfb7db72 100644
--- a/app/assets/stylesheets/common.scss
+++ b/app/assets/stylesheets/common.scss
@@ -337,6 +337,15 @@ p.time {
padding: 15px 5px;
&:last-child { border:none }
.wll:hover { background:none }
+
+ .event_commits {
+ margin-top: 5px;
+
+ li.commit {
+ padding:5px;
+ border:none;
+ }
+ }
}
.ico {
diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss
index 39e5998305a..b01f1274407 100644
--- a/app/assets/stylesheets/gitlab_bootstrap.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap.scss
@@ -18,7 +18,8 @@ a {
}
&.lined {
- text-decoration:underlined;
+ text-decoration:underline;
+ &:hover { text-decoration:underline; }
}
&.gray {
@@ -74,10 +75,6 @@ h5 {
font-size:14px;
}
-code {
- background:#FCEEC1;
- color:$style_color;
-}
table {
width:100%;
@@ -381,7 +378,6 @@ form {
min-height: 20px;
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- cursor:pointer;
&.smoke {
background-color:#f5f5f5;
}
@@ -516,7 +512,8 @@ form {
.row_title {
font-weight:bold;
color:#444;
- &:hover {
+ &:hover {
+ color:#444;
text-decoration:underline;
}
}
diff --git a/app/assets/stylesheets/notes.scss b/app/assets/stylesheets/notes.scss
index 39db704b1a9..abce4c6893f 100644
--- a/app/assets/stylesheets/notes.scss
+++ b/app/assets/stylesheets/notes.scss
@@ -14,7 +14,8 @@
border-bottom:1px solid #aaa;
}
-.issue_notes {
+.issue_notes,
+.wiki_notes {
.note_content {
float:left;
width:400px;
@@ -23,8 +24,8 @@
/* Note textare */
#note_note {
- height:100px;
- width:97%;
+ height:80px;
+ width:99%;
font-size:14px;
}
@@ -99,8 +100,25 @@ tr.line_notes_row {
td {
border-bottom:1px solid #ddd;
}
- .actions {
+ .note_actions {
margin:0;
+ padding-top: 10px;
+
+ .buttons {
+ float:left;
+ width:300px;
+ }
+ .options {
+ .labels {
+ float:left;
+ padding-left:10px;
+ label {
+ padding: 6px 0;
+ margin: 0;
+ width:120px;
+ }
+ }
+ }
}
}
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index 6052ec3fabb..e2db701db71 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -194,4 +194,16 @@
float:right;
@extend .cgray;
}
+
+ code {
+ background:#FCEEC1;
+ color:$style_color;
+ }
+
+ .commit_short_id {
+ float:left;
+ @extend .lined;
+ min-width:65px;
+ font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
+ }
}
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index dd1c22d4e76..12926d3fdb1 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -30,13 +30,14 @@
.issue {
padding:7px 10px;
+ p {
+ padding-top:0;
+ padding-bottom:2px;
+ }
+
img.avatar {
width:32px;
margin-top:4px;
}
- p.row_title {
- padding:0px;
- padding-bottom:2px;
- }
}
}
diff --git a/app/contexts/notes_load.rb b/app/contexts/notes_load.rb
index d1f8da9ce12..cbb9f67fa05 100644
--- a/app/contexts/notes_load.rb
+++ b/app/contexts/notes_load.rb
@@ -17,6 +17,8 @@ class NotesLoad < BaseContext
then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
when "merge_request"
then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
+ when "wiki"
+ then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20]
end
@notes = if last_id
diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb
index cb1f74527a1..05f29da3ddd 100644
--- a/app/controllers/commits_controller.rb
+++ b/app/controllers/commits_controller.rb
@@ -17,6 +17,7 @@ class CommitsController < ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @project.commits(@ref, params[:path], @limit, @offset)
+ @commits = CommitDecorator.decorate(@commits)
respond_to do |format|
format.html # index.html.erb
@@ -51,6 +52,8 @@ class CommitsController < ApplicationController
@commit = result[:commit]
@diffs = result[:diffs]
@line_notes = []
+
+ @commits = CommitDecorator.decorate(@commits)
end
def patch
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index 1cb1d388465..f9a1c1dd67d 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -143,5 +143,6 @@ class MergeRequestsController < ApplicationController
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
+ @commits = CommitDecorator.decorate(@commits)
end
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index fb759c371c4..d19931e93d7 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Extend the standard message generation to accept our custom exception
def failure_message
exception = env["omniauth.error"]
- if exception.class == OmniAuth::Error
- error = exception.message
- else
- error = exception.error_reason if exception.respond_to?(:error_reason)
- error ||= exception.error if exception.respond_to?(:error)
- error ||= env["omniauth.error.type"].to_s
- end
+ error = exception.error_reason if exception.respond_to?(:error_reason)
+ error ||= exception.error if exception.respond_to?(:error)
+ error ||= exception.message if exception.respond_to?(:message)
+ error ||= env["omniauth.error.type"].to_s
error.to_s.humanize if error
end
diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb
index b610c9f34d4..d180e708882 100644
--- a/app/controllers/refs_controller.rb
+++ b/app/controllers/refs_controller.rb
@@ -51,7 +51,8 @@ class RefsController < ApplicationController
@logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name
last_commit = @project.commits(@commit.id, file, 1).last
- {
+ last_commit = CommitDecorator.decorate(last_commit)
+ {
:file_name => content.name,
:commit => last_commit
}
diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb
index 9bcd20c3187..1fa38034c66 100644
--- a/app/controllers/wikis_controller.rb
+++ b/app/controllers/wikis_controller.rb
@@ -13,16 +13,16 @@ class WikisController < ApplicationController
@wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last
end
- unless @wiki
- return render_404 unless can?(current_user, :write_wiki, @project)
- end
+ @note = @project.notes.new(:noteable => @wiki)
- respond_to do |format|
- if @wiki
- format.html
- else
+ if @wiki
+ render 'show'
+ else
+ if can?(current_user, :write_wiki, @project)
@wiki = @project.wikis.new(:slug => params[:id])
- format.html { render "edit" }
+ render 'edit'
+ else
+ render 'empty'
end
end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index c673eb3d161..2ce940c35cc 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -46,6 +46,13 @@ class Notify < ActionMailer::Base
mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ")
end
+ def note_wiki_email(recipient_id, note_id)
+ recipient = User.find(recipient_id)
+ @note = Note.find(note_id)
+ @wiki = @note.noteable
+ mail(:to => recipient.email, :subject => "gitlab | note for wiki | #{@note.project_name}")
+ end
+
def new_merge_request_email(merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ")
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 859bee29fa5..71c41350c95 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -114,6 +114,10 @@ class Commit
@head = head
end
+ def short_id(length = 10)
+ id.to_s[0..length]
+ end
+
def safe_message
utf8 message
end
@@ -150,4 +154,8 @@ class Commit
def prev_commit_id
prev_commit.try :id
end
+
+ def parents_count
+ parents && parents.count || 0
+ end
end
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index ecc46fb4efb..d9ec069d14b 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -1,6 +1,7 @@
class Wiki < ActiveRecord::Base
belongs_to :project
belongs_to :user
+ has_many :notes, :as => :noteable, :dependent => :destroy
validates :content, :title, :user_id, :presence => true
validates :title, :length => 1..250
diff --git a/app/observers/mailer_observer.rb b/app/observers/mailer_observer.rb
index 451deccd14f..b6f5217847a 100644
--- a/app/observers/mailer_observer.rb
+++ b/app/observers/mailer_observer.rb
@@ -34,6 +34,7 @@ class MailerObserver < ActiveRecord::Observer
case note.noteable_type
when "Commit"; Notify.note_commit_email(u.id, note.id).deliver
when "Issue"; Notify.note_issue_email(u.id, note.id).deliver
+ when "Wiki"; Notify.note_wiki_email(u.id, note.id).deliver
when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver
when "Snippet"; true
else
diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml
index 9f9502e30d4..9824161493d 100644
--- a/app/views/commits/_commit.html.haml
+++ b/app/views/commits/_commit.html.haml
@@ -2,16 +2,15 @@
.browse_code_link_holder
%p
%strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right"
- = link_to project_commit_path(@project, :id => commit.id) do
- %p
- %code.left= commit.id.to_s[0..10]
- %strong.cgray= commit.author_name
- &ndash;
- = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
- %span.row_title= truncate(commit.safe_message, :length => 50)
+ %p
+ = link_to commit.short_id(8), project_commit_path(@project, :id => commit.id), :class => "commit_short_id"
+ %strong.cgray= commit.author_name
+ &ndash;
+ = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
+ = link_to truncate(commit.title, :length => 50), project_commit_path(@project, :id => commit.id), :class => "row_title"
- %span.committed_ago
- = time_ago_in_words(commit.committed_date)
- ago
- &nbsp;
+ %span.committed_ago
+ = time_ago_in_words(commit.committed_date)
+ ago
+ &nbsp;
diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml
index 8ccb3f1b72a..6994de4a134 100644
--- a/app/views/commits/_commit_box.html.haml
+++ b/app/views/commits/_commit_box.html.haml
@@ -1,4 +1,4 @@
-.commit-box{class: @commit.parents.count > 1 ? "merge-commit" : ""}
+.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""}
.commit-head
.right
- if @notes_count > 0
diff --git a/app/views/commits/compare.html.haml b/app/views/commits/compare.html.haml
index 66ed8dad595..04d8af5459d 100644
--- a/app/views/commits/compare.html.haml
+++ b/app/views/commits/compare.html.haml
@@ -24,8 +24,9 @@
- unless @commits.empty?
- %h4 Commits (#{@commits.count})
- %ul.unstyled= render @commits
+ %div.ui-box
+ %h5.small Commits (#{@commits.count})
+ %ul.unstyled= render @commits
- unless @diffs.empty?
%h4 Diff
diff --git a/app/views/commits/index.atom.builder b/app/views/commits/index.atom.builder
index 2a352dac1b7..86c9fc04e51 100644
--- a/app/views/commits/index.atom.builder
+++ b/app/views/commits/index.atom.builder
@@ -10,14 +10,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.entry do
xml.id project_commit_url(@project, :id => commit.id)
xml.link :href => project_commit_url(@project, :id => commit.id)
- xml.title truncate(commit.safe_message, :length => 80)
+ xml.title truncate(commit.title, :length => 80)
xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email)
xml.author do |author|
xml.name commit.author_name
xml.email commit.author_email
end
- xml.summary commit.safe_message
+ xml.summary commit.description
end
end
end
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index ce3cd6b5959..407bf532422 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -1,6 +1,6 @@
%h3.page_title
Merge Requests
- %small (authored or assigned to you)
+ %small (authored by or assigned to you)
%small.right #{@merge_requests.total_count} merge requests
%br
diff --git a/app/views/errors/gitolite.html.haml b/app/views/errors/gitolite.html.haml
index ccee757378d..eb09d2141b9 100644
--- a/app/views/errors/gitolite.html.haml
+++ b/app/views/errors/gitolite.html.haml
@@ -1,19 +1,30 @@
.alert-message.block-message.error
%h3 Gitolite Error
- %hr
%h4 Application cant get access to your gitolite system.
- %ol
- %li
- %p
- Check 'config/gitlab.yml' for correct settings.
- %li
- %p
- Make sure web server user has access to gitolite.
- %a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial
- %li
- %p
- Try:
+
+
+
+
+%h4 Tips for Administrator:
+
+%ul
+ %li
+ %p
+ Check git logs in admin area
+ %li
+ %p
+ Check config/gitlab.yml for correct settings.
+ %li
+ %p
+ Diagnostic tool:
%pre
- = preserve do
- sudo chmod -R 770 /home/git/repositories/
- sudo chown -R git:git /home/git/repositories/
+ bundle exec rake gitlab:app:status RAILS_ENV=production
+ %li
+ %p
+ Permissions:
+ %pre
+ = preserve do
+ sudo chmod -R 770 /home/git/repositories/
+ sudo chown -R git:git /home/git/repositories/
+ sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
+
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 60112b508a8..d6c5546148d 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,9 +1,9 @@
+- commit = CommitDecorator.decorate(commit)
%li.wll.commit
- = link_to project_commit_path(project, :id => commit.id) do
- %p
- %code.left= commit.id.to_s[0..10]
- %strong.cgray= commit.author_name
- &ndash;
- = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
- %span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding"
+ %p
+ = link_to commit.short_id(8), project_commit_path(project, :id => commit.id), :class => "commit_short_id"
+ %strong.cdark= commit.author_name
+ &ndash;
+ = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
+ = truncate(commit.title, :length => 50) rescue "--broken encoding"
diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml
index 4964c1bbd87..e184df549de 100644
--- a/app/views/help/api.html.haml
+++ b/app/views/help/api.html.haml
@@ -1,16 +1,18 @@
%h3 API
.back_link
- = link_to help_path do
+ = link_to help_path do
&larr; to index
%hr
%ol
- %li
+ %li
%a{:href => "#README"} README
- %li
+ %li
%a{:href => "#projects"} Projects
- %li
+ %li
%a{:href => "#users"} Users
+ %li
+ %a{:href => "#issues"} Issues
.file_holder#README
.file_title
@@ -39,3 +41,13 @@
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "users.md"))
+
+%br
+
+.file_holder#issues
+ .file_title
+ %i.icon-file
+ Issues
+ .file_content.wiki
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml
index 860cfc8669c..7511d15d995 100644
--- a/app/views/help/permissions.html.haml
+++ b/app/views/help/permissions.html.haml
@@ -38,7 +38,6 @@
%li Push to non-protected branches
%li Remove non-protected branches
%li Add tags
- %li Create new merge request
%li Write a wiki
.ui-box.span3
@@ -55,7 +54,6 @@
%li Push to non-protected branches
%li Remove non-protected branches
%li Add tags
- %li Create new merge request
%li Write a wiki
%li Add new team members
%li Push to protected branches
diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml
index e12c3c1a99c..18294af40a9 100644
--- a/app/views/issues/_show.html.haml
+++ b/app/views/issues/_show.html.haml
@@ -24,8 +24,7 @@
- else
= image_tag "no_avatar.png", :class => "avatar"
- = link_to project_issue_path(issue.project, issue) do
- %p.row_title= truncate(issue.title, :length => 100)
+ %p= link_to truncate(issue.title, :length => 100), project_issue_path(issue.project, issue), :class => "row_title"
%span.update-author
%small.cdark= "##{issue.id}"
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 8ffc9c2b662..4e8bcb89373 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -46,9 +46,7 @@
- if @issue.milestone
- milestone = @issue.milestone
%cite.cgray and attached to milestone
- = link_to project_milestone_path(milestone.project, milestone) do
- %strong
- = truncate(milestone.title, :length => 20)
+ %strong= link_to truncate(milestone.title, :length => 20), project_milestone_path(milestone.project, milestone)
.right
- @issue.labels.each do |label|
diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml
index b9a005e08be..5cd9b9b2497 100644
--- a/app/views/merge_requests/_merge_request.html.haml
+++ b/app/views/merge_requests/_merge_request.html.haml
@@ -16,8 +16,7 @@
= merge_request.target_branch
= image_tag gravatar_icon(merge_request.author_email), :class => "avatar"
- = link_to project_merge_request_path(merge_request.project, merge_request) do
- %p.row_title= truncate(merge_request.title, :length => 80)
+ %p= link_to truncate(merge_request.title, :length => 80), project_merge_request_path(merge_request.project, merge_request), :class => "row_title"
%span.update-author
%small.cdark= "##{merge_request.id}"
diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml
index 9912cf9ed54..81ec92ef6bc 100644
--- a/app/views/milestones/_milestone.html.haml
+++ b/app/views/milestones/_milestone.html.haml
@@ -6,14 +6,13 @@
= link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped"
- if can? current_user, :admin_milestone, milestone.project
= link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped"
- = link_to project_milestone_path(milestone.project, milestone) do
- %h4.row_title
- = truncate(milestone.title, :length => 100)
- %small
- = milestone.expires_at
- %br
- .progress.progress-success.span3
- .bar{:style => "width: #{milestone.percent_complete}%;"}
+ %h4
+ = link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title"
+ %small
+ = milestone.expires_at
+ %br
+ .progress.progress-success.span3
+ .bar{:style => "width: #{milestone.percent_complete}%;"}
&nbsp;
diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml
index dc3dcd01de8..7ec49b55f47 100644
--- a/app/views/milestones/show.html.haml
+++ b/app/views/milestones/show.html.haml
@@ -50,8 +50,8 @@
%td
= link_to [@project, issue] do
%span.badge.badge-info ##{issue.id}
- &ndash;
- = truncate issue.title, :length => 60
+ &ndash;
+ = link_to truncate(issue.title, :length => 60), [@project, issue]
%br
= paginate @issues, :theme => "gitlab"
diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml
index f5aa1495796..aeaf57e6ddc 100644
--- a/app/views/notes/_form.html.haml
+++ b/app/views/notes/_form.html.haml
@@ -1,5 +1,5 @@
= form_for [@project, @note], :remote => "true", :multipart => true do |f|
- %h3 Leave a comment
+ %h3.page_title Leave a comment
-if @note.errors.any?
.alert-message.block-message.error
- @note.errors.full_messages.each do |msg|
diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml
index 8beaf9b5e0c..a5a70053480 100644
--- a/app/views/notes/_per_line_form.html.haml
+++ b/app/views/notes/_per_line_form.html.haml
@@ -2,7 +2,7 @@
%tr.per_line_form
%td{:colspan => 3 }
= form_for [@project, @note], :remote => "true", :multipart => true do |f|
- %h3 Leave a note
+ %h3.page_title Leave a note
%div.span10
-if @note.errors.any?
.alert-message.block-message.error
@@ -13,19 +13,21 @@
= f.hidden_field :noteable_type
= f.hidden_field :line_code
= f.text_area :note, :size => 255
- %h5 Notify via email:
- .clearfix
- = label_tag :notify do
- = check_box_tag :notify, 1, @note.noteable_type != "Commit"
- %span Project team
+ .note_actions
+ .buttons
+ = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
+ = link_to "Cancel", "#", :class => "btn hide-button"
+ .options
+ %h6.left Notify via email:
+ .labels
+ = label_tag :notify do
+ = check_box_tag :notify, 1, @note.noteable_type != "Commit"
+ %span Project team
- - if @note.notify_only_author?(current_user)
- = label_tag :notify_author do
- = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
- %span Commit author
- .actions
- = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
- = link_to "Close", "#", :class => "btn hide-button"
+ - if @note.notify_only_author?(current_user)
+ = label_tag :notify_author do
+ = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+ %span Commit author
:javascript
$(function(){
diff --git a/app/views/notify/note_wiki_email.html.haml b/app/views/notify/note_wiki_email.html.haml
new file mode 100644
index 00000000000..91270682c6b
--- /dev/null
+++ b/app/views/notify/note_wiki_email.html.haml
@@ -0,0 +1,24 @@
+%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:align => "left", :style => "padding: 20px 0 0;"}
+ %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ New comment -
+ = link_to project_issue_url(@wiki.project, @wiki, :anchor => "note_#{@note.id}") do
+ = "Wiki ##{@wiki.title.to_s}"
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:style => "padding: 15px 0 15px;", :valign => "top"}
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name}
+ commented on Wiki page:
+ %br
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"}
+ %tr
+ %td{:valign => "top"}
+ %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" }
+ = markdown(@note.note)
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+
diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml
index d171b0d09a1..52424ae4353 100644
--- a/app/views/projects/files.html.haml
+++ b/app/views/projects/files.html.haml
@@ -14,6 +14,6 @@
ago
- else
.alert-message.block-message
- %p All files attached to project wall, issues etc will be displayed here
+ %span All files attached to project wall, issues etc will be displayed here
diff --git a/app/views/refs/_tree_commit.html.haml b/app/views/refs/_tree_commit.html.haml
index 1f2524a4c3a..7da8ae1c501 100644
--- a/app/views/refs/_tree_commit.html.haml
+++ b/app/views/refs/_tree_commit.html.haml
@@ -1,3 +1,3 @@
- if tm
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
-= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
+= link_to truncate(content_commit.title, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
diff --git a/app/views/refs/blame.html.haml b/app/views/refs/blame.html.haml
index 6a86b91fe74..0fc08e0c7d7 100644
--- a/app/views/refs/blame.html.haml
+++ b/app/views/refs/blame.html.haml
@@ -25,15 +25,15 @@
%table
- @blame.each do |commit, lines|
- commit = Commit.new(commit)
+ - commit = CommitDecorator.decorate(commit)
%tr
%td.author
= image_tag gravatar_icon(commit.author_email, 16)
= commit.author_name
%td.blame_commit
&nbsp;
- = link_to project_commit_path(@project, :id => commit.id) do
- %code= commit.id.to_s[0..10]
- %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding"
+ %code= link_to commit.short_id, project_commit_path(@project, :id => commit.id)
+ = link_to truncate(commit.title, :length => 30), project_commit_path(@project, :id => commit.id), :class => "row_title" rescue "--broken encoding"
%td.lines
= preserve do
%pre
diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml
index 4742b92bd74..3efe83ec1a0 100644
--- a/app/views/repositories/_branch.html.haml
+++ b/app/views/repositories/_branch.html.haml
@@ -1,3 +1,5 @@
+- commit = Commit.new(branch.commit)
+- commit = CommitDecorator.decorate(commit)
%tr
%td
= link_to project_commits_path(@project, :ref => branch.name) do
@@ -5,14 +7,14 @@
- if branch.name == @project.root_ref
%span.label default
%td
- = link_to project_commit_path(@project, :id => branch.commit.id) do
- %code= branch.commit.id.to_s[0..10]
+ = link_to project_commit_path(@project, :id => commit.id) do
+ %code= commit.short_id
- = image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16
- = truncate(Commit.new(branch.commit).safe_message, :length => 40)
+ = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
+ = truncate(commit.title, :length => 40)
%td
%span.update-author.right
- = time_ago_in_words(branch.commit.committed_date)
+ = time_ago_in_words(commit.committed_date)
ago
%td
- if can? current_user, :download_code, @project
diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml
index 0734327233e..a9a1181974b 100644
--- a/app/views/repositories/_feed.html.haml
+++ b/app/views/repositories/_feed.html.haml
@@ -1,4 +1,5 @@
- commit = update
+- commit = CommitDecorator.new(commit)
%tr
%td
= link_to project_commits_path(@project, :ref => commit.head.name) do
@@ -10,9 +11,9 @@
%td
%div
= link_to project_commits_path(@project, commit.id) do
- %code= commit.id.to_s[0..10]
+ %code= commit.short_id
= image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
- = truncate(commit.safe_message, :length => 40)
+ = truncate(commit.title, :length => 40)
%td
%span.right.cgray
= time_ago_in_words(commit.committed_date)
diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml
index 5e5cca31d8f..d09c40e15a3 100644
--- a/app/views/repositories/tags.html.haml
+++ b/app/views/repositories/tags.html.haml
@@ -9,14 +9,15 @@
%th
- @tags.each do |tag|
- commit = Commit.new(tag.commit)
+ - commit = CommitDecorator.decorate(commit)
%tr
%td
%strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => ""
%td
= link_to project_commit_path(@project, commit.id) do
- %code= commit.id.to_s[0..10]
+ %code= commit.short_id
= image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
- = truncate(commit.safe_message, :length => 40)
+ = truncate(commit.title, :length => 40)
%td
%span.update-author.right
= time_ago_in_words(commit.committed_date)
diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml
index dbb8648d664..20b5b112819 100644
--- a/app/views/wikis/_form.html.haml
+++ b/app/views/wikis/_form.html.haml
@@ -6,19 +6,21 @@
- @wiki.errors.full_messages.each do |msg|
%li= msg
- .alert-message.block-message.warning
- %p
- Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.
- %br
- To add link to new page you can just type
- %code [Link Title](page-slug)
- .clearfix
- = f.label :title
- .input= f.text_field :title, :class => :xxlarge
- = f.hidden_field :slug
- .clearfix
- = f.label :content
- .input= f.text_area :content, :class => :xxlarge
+ .main_box
+ .top_box_content
+ = f.label :title
+ .input= f.text_field :title, :class => 'span8'
+ = f.hidden_field :slug
+ .middle_box_content
+ .input
+ %span.cgray
+ Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.
+ To add link to new page you can just type
+ %code [Link Title](page-slug)
+
+ .bottom_box_content
+ = f.label :content
+ .input= f.text_area :content, :class => 'span8'
.actions
= f.submit 'Save', :class => "primary btn"
= link_to "Cancel", project_wiki_path(@project, :index), :class => "btn"
diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml
index 26cbd52a9a8..27d2a8f915f 100644
--- a/app/views/wikis/edit.html.haml
+++ b/app/views/wikis/edit.html.haml
@@ -1,3 +1,3 @@
-%h3 Editing page
+%h3.page_title Editing page
%hr
= render 'form'
diff --git a/app/views/wikis/empty.html.haml b/app/views/wikis/empty.html.haml
new file mode 100644
index 00000000000..32b1c9258c5
--- /dev/null
+++ b/app/views/wikis/empty.html.haml
@@ -0,0 +1,4 @@
+%h3.page_title Empty page
+%hr
+.alert-message.block-message.warning
+ %span You are not allowed to create wiki pages
diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml
index 6a9b56ae771..2e46a90ef51 100644
--- a/app/views/wikis/history.html.haml
+++ b/app/views/wikis/history.html.haml
@@ -1,5 +1,6 @@
-%h3 Versions
-%table
+%h3.page_title Versions
+%br
+%table.admin-table
%thead
%tr
%th #
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index 9aa287dff07..3e92275102c 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -5,13 +5,18 @@
= link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
History
= link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
+ %i.icon-edit
Edit
-%hr
-.wiki_content
- = preserve do
- = markdown @wiki.content
+%br
+.file_holder
+ .file_content.wiki
+ = preserve do
+ = markdown @wiki.content
%p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago
- if can? current_user, :admin_wiki, @project
= link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do
Delete this page
+
+%hr
+.wiki_notes#notes= render "notes/notes", :tid => @wiki.id, :tt => "wiki"
diff --git a/doc/api/README.md b/doc/api/README.md
index dcf75afda1f..e01119661f0 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -27,3 +27,4 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en
+ [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md)
+ [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md)
++ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md)
diff --git a/doc/api/issues.md b/doc/api/issues.md
new file mode 100644
index 00000000000..aaad3305489
--- /dev/null
+++ b/doc/api/issues.md
@@ -0,0 +1,184 @@
+## List issues
+
+Get all issues created by authenticed user.
+
+```
+GET /issues
+```
+
+```json
+[
+ {
+ "id": 43,
+ "project_id": 8,
+ "title": "4xx/5xx pages",
+ "description": "",
+ "labels": [ ],
+ "milestone": null,
+ "assignee": null,
+ "author": {
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z"
+ },
+ "closed": true,
+ "updated_at": "2012-07-02T17:53:12Z",
+ "created_at": "2012-07-02T17:53:12Z"
+ },
+ {
+ "id": 42,
+ "project_id": 8,
+ "title": "Add user settings",
+ "description": "",
+ "labels": [
+ "feature"
+ ],
+ "milestone": {
+ "id": 1,
+ "title": "v1.0",
+ "description": "",
+ "due_date": "2012-07-20",
+ "closed": false,
+ "updated_at": "2012-07-04T13:42:48Z",
+ "created_at": "2012-07-04T13:42:48Z"
+ },
+ "assignee": {
+ "id": 2,
+ "email": "jack@example.com",
+ "name": "Jack Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:01:01Z"
+ },
+ "author": {
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z"
+ },
+ "closed": false,
+ "updated_at": "2012-07-12T13:43:19Z",
+ "created_at": "2012-06-28T12:58:06Z"
+ }
+]
+```
+
+## List project issues
+
+Get a list of project issues.
+
+```
+GET /projects/:id/issues
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
+
+## Single issue
+
+Get a project issue.
+
+```
+GET /projects/:id/issues/:issue_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of a project issue
+
+```json
+{
+ "id": 42,
+ "project_id": 8,
+ "title": "Add user settings",
+ "description": "",
+ "labels": [
+ "feature"
+ ],
+ "milestone": {
+ "id": 1,
+ "title": "v1.0",
+ "description": "",
+ "due_date": "2012-07-20",
+ "closed": false,
+ "updated_at": "2012-07-04T13:42:48Z",
+ "created_at": "2012-07-04T13:42:48Z"
+ },
+ "assignee": {
+ "id": 2,
+ "email": "jack@example.com",
+ "name": "Jack Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:01:01Z"
+ },
+ "author": {
+ "id": 1,
+ "email": "john@example.com",
+ "name": "John Smith",
+ "blocked": false,
+ "created_at": "2012-05-23T08:00:58Z"
+ },
+ "closed": false,
+ "updated_at": "2012-07-12T13:43:19Z",
+ "created_at": "2012-06-28T12:58:06Z"
+}
+```
+
+## New issue
+
+Create a new project issue.
+
+```
+POST /projects/:id/issues
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `title` (required) - The title of an issue
++ `description` (optional) - The description of an issue
++ `assignee_id` (optional) - The ID of a user to assign issue
++ `milestone_id` (optional) - The ID of a milestone to assign issue
++ `labels` (optional) - Comma-separated label names for an issue
+
+Will return created issue with status `201 Created` on success, or `404 Not found` on fail.
+
+## Edit issue
+
+Update an existing project issue.
+
+```
+PUT /projects/:id/issues/:issue_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of a project's issue
++ `title` (optional) - The title of an issue
++ `description` (optional) - The description of an issue
++ `assignee_id` (optional) - The ID of a user to assign issue
++ `milestone_id` (optional) - The ID of a milestone to assign issue
++ `labels` (optional) - Comma-separated label names for an issue
++ `closed` (optional) - The state of an issue (0 = false, 1 = true)
+
+Will return updated issue with status `200 OK` on success, or `404 Not found` on fail.
+
+## Delete issue
+
+Delete existing project issue.
+
+```
+DELETE /projects/:id/issues/:issue_id
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `issue_id` (required) - The ID of a project's issue
+
+Status code `200` will be returned on success.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index c748745e063..cd94cd42328 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,6 +1,6 @@
## List projects
-Get a list of authenticated users' projects.
+Get a list of authenticated user's projects.
```
GET /projects
@@ -63,7 +63,7 @@ GET /projects/:id
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
```json
{
@@ -91,7 +91,7 @@ Parameters:
## Project repository branches
-Get a list of project repository branches.
+Get a list of project repository branches sorted by name alphabetically.
```
GET /projects/:id/repository/branches
@@ -99,7 +99,7 @@ GET /projects/:id/repository/branches
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
```json
[
@@ -131,7 +131,7 @@ Parameters:
## Project repository tags
-Get a list of project repository tags.
+Get a list of project repository tags sorted by name in reverse alphabetical order.
```
GET /projects/:id/repository/tags
@@ -139,7 +139,7 @@ GET /projects/:id/repository/tags
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
```json
[
@@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
+ `snippet_id` (required) - The ID of a project's snippet
```json
@@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
+ `snippet_id` (required) - The ID of a project's snippet
## New snippet
@@ -227,7 +227,7 @@ POST /projects/:id/snippets
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
+ `title` (required) - The title of a snippet
+ `file_name` (required) - The name of a snippet file
+ `lifetime` (optional) - The expiration date of a snippet
@@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
+ `snippet_id` (required) - The ID of a project's snippet
+ `title` (optional) - The title of a snippet
+ `file_name` (optional) - The name of a snippet file
@@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id
Parameters:
-+ `id` (required) - The code name of a project
++ `id` (required) - The ID or code name of a project
+ `snippet_id` (required) - The ID of a project's snippet
Status code `200` will be returned on success.
diff --git a/doc/installation.md b/doc/installation.md
index 3dfedfe10ad..cb54663e79e 100644
--- a/doc/installation.md
+++ b/doc/installation.md
@@ -119,6 +119,7 @@ Permissions:
sudo chmod -R g+rwX /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
diff --git a/features/step_definitions/project_commits_steps.rb b/features/step_definitions/project_commits_steps.rb
index 9bfccfc06ed..9b3b0aa1f81 100644
--- a/features/step_definitions/project_commits_steps.rb
+++ b/features/step_definitions/project_commits_steps.rb
@@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do
end
Then /^I see commits atom feed$/ do
- commit = @project.commit
+ commit = CommitDecorator.decorate(@project.commit)
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
page.body.should have_selector("author email", :text => commit.author_email)
- page.body.should have_selector("entry summary", :text => commit.message)
+ page.body.should have_selector("entry summary", :text => commit.description)
end
Given /^I click on commit link$/ do
diff --git a/lib/api.rb b/lib/api.rb
index e24e0a78f71..6a8a3d651c0 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -15,5 +15,6 @@ module Gitlab
mount Users
mount Projects
+ mount Issues
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 35ad4d430ad..d86fb79c78b 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -16,11 +16,7 @@ module Gitlab
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
end
- class ProjectRepositoryBranches < Grape::Entity
- expose :name, :commit
- end
-
- class ProjectRepositoryTags < Grape::Entity
+ class RepoObject < Grape::Entity
expose :name, :commit
end
@@ -29,5 +25,19 @@ module Gitlab
expose :author, :using => Entities::UserBasic
expose :expires_at, :updated_at, :created_at
end
+
+ class Milestone < Grape::Entity
+ expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at
+ end
+
+ class Issue < Grape::Entity
+ expose :id
+ expose (:project_id) {|issue| issue.project.id}
+ expose :title, :description
+ expose :label_list, :as => :labels
+ expose :milestone, :using => Entities::Milestone
+ expose :assignee, :author, :using => Entities::UserBasic
+ expose :closed, :updated_at, :created_at
+ end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 424a17b283c..c1ea05667ae 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -4,6 +4,16 @@ module Gitlab
@current_user ||= User.find_by_authentication_token(params[:private_token])
end
+ def user_project
+ if @project ||= current_user.projects.find_by_id(params[:id]) ||
+ current_user.projects.find_by_code(params[:id])
+ else
+ error!({'message' => '404 Not found'}, 404)
+ end
+
+ @project
+ end
+
def authenticate!
error!({'message' => '401 Unauthorized'}, 401) unless current_user
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
new file mode 100644
index 00000000000..dcb6e53588c
--- /dev/null
+++ b/lib/api/issues.rb
@@ -0,0 +1,111 @@
+module Gitlab
+ # Issues API
+ class Issues < Grape::API
+ before { authenticate! }
+
+ resource :issues do
+ # Get currently authenticated user's issues
+ #
+ # Example Request:
+ # GET /issues
+ get do
+ present current_user.issues, :with => Entities::Issue
+ end
+ end
+
+ resource :projects do
+ # Get a list of project issues
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # Example Request:
+ # GET /projects/:id/issues
+ get ":id/issues" do
+ present user_project.issues, :with => Entities::Issue
+ end
+
+ # Get a single project issue
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # issue_id (required) - The ID of a project issue
+ # Example Request:
+ # GET /projects/:id/issues/:issue_id
+ get ":id/issues/:issue_id" do
+ @issue = user_project.issues.find(params[:issue_id])
+ present @issue, :with => Entities::Issue
+ end
+
+ # Create a new project issue
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # title (required) - The title of an issue
+ # description (optional) - The description of an issue
+ # assignee_id (optional) - The ID of a user to assign issue
+ # milestone_id (optional) - The ID of a milestone to assign issue
+ # labels (optional) - The labels of an issue
+ # Example Request:
+ # POST /projects/:id/issues
+ post ":id/issues" do
+ @issue = user_project.issues.new(
+ :title => params[:title],
+ :description => params[:description],
+ :assignee_id => params[:assignee_id],
+ :milestone_id => params[:milestone_id],
+ :label_list => params[:labels]
+ )
+ @issue.author = current_user
+
+ if @issue.save
+ present @issue, :with => Entities::Issue
+ else
+ error!({'message' => '404 Not found'}, 404)
+ end
+ end
+
+ # Update an existing issue
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # issue_id (required) - The ID of a project issue
+ # title (optional) - The title of an issue
+ # description (optional) - The description of an issue
+ # assignee_id (optional) - The ID of a user to assign issue
+ # milestone_id (optional) - The ID of a milestone to assign issue
+ # labels (optional) - The labels of an issue
+ # closed (optional) - The state of an issue (0 = false, 1 = true)
+ # Example Request:
+ # PUT /projects/:id/issues/:issue_id
+ put ":id/issues/:issue_id" do
+ @issue = user_project.issues.find(params[:issue_id])
+ parameters = {
+ :title => (params[:title] || @issue.title),
+ :description => (params[:description] || @issue.description),
+ :assignee_id => (params[:assignee_id] || @issue.assignee_id),
+ :milestone_id => (params[:milestone_id] || @issue.milestone_id),
+ :label_list => (params[:labels] || @issue.label_list),
+ :closed => (params[:closed] || @issue.closed)
+ }
+
+ if @issue.update_attributes(parameters)
+ present @issue, :with => Entities::Issue
+ else
+ error!({'message' => '404 Not found'}, 404)
+ end
+ end
+
+ # Delete a project issue
+ #
+ # Parameters:
+ # id (required) - The ID or code name of a project
+ # issue_id (required) - The ID of a project issue
+ # Example Request:
+ # DELETE /projects/:id/issues/:issue_id
+ delete ":id/issues/:issue_id" do
+ @issue = user_project.issues.find(params[:issue_id])
+ @issue.destroy
+ end
+ end
+ end
+end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 70f8fa2aa62..8edfa481c10 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -16,53 +16,49 @@ module Gitlab
# Get a single project
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id
get ":id" do
- @project = current_user.projects.find_by_code(params[:id])
- present @project, :with => Entities::Project
+ present user_project, :with => Entities::Project
end
# Get a project repository branches
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/repository/branches
get ":id/repository/branches" do
- @project = current_user.projects.find_by_code(params[:id])
- present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches
+ present user_project.repo.heads.sort_by(&:name), :with => Entities::RepoObject
end
# Get a project repository tags
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/repository/tags
get ":id/repository/tags" do
- @project = current_user.projects.find_by_code(params[:id])
- present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags
+ present user_project.repo.tags.sort_by(&:name).reverse, :with => Entities::RepoObject
end
# Get a project snippet
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# Example Request:
# GET /projects/:id/snippets/:snippet_id
get ":id/snippets/:snippet_id" do
- @project = current_user.projects.find_by_code(params[:id])
- @snippet = @project.snippets.find(params[:snippet_id])
+ @snippet = user_project.snippets.find(params[:snippet_id])
present @snippet, :with => Entities::ProjectSnippet
end
# Create a new project snippet
#
# Parameters:
- # id (required) - The code name of a project
+ # id (required) - The ID or code name of a project
# title (required) - The title of a snippet
# file_name (required) - The name of a snippet file
# lifetime (optional) - The expiration date of a snippet
@@ -70,8 +66,7 @@ module Gitlab
# Example Request:
# POST /projects/:id/snippets
post ":id/snippets" do
- @project = current_user.projects.find_by_code(params[:id])
- @snippet = @project.snippets.new(
+ @snippet = user_project.snippets.new(
:title => params[:title],
:file_name => params[:file_name],
:expires_at => params[:lifetime],
@@ -89,7 +84,7 @@ module Gitlab
# Update an existing project snippet
#
# Parameters:
- # id (required) - The code name of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file
@@ -98,8 +93,7 @@ module Gitlab
# Example Request:
# PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do
- @project = current_user.projects.find_by_code(params[:id])
- @snippet = @project.snippets.find(params[:snippet_id])
+ @snippet = user_project.snippets.find(params[:snippet_id])
parameters = {
:title => (params[:title] || @snippet.title),
:file_name => (params[:file_name] || @snippet.file_name),
@@ -117,26 +111,24 @@ module Gitlab
# Delete a project snippet
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# Example Request:
# DELETE /projects/:id/snippets/:snippet_id
delete ":id/snippets/:snippet_id" do
- @project = current_user.projects.find_by_code(params[:id])
- @snippet = @project.snippets.find(params[:snippet_id])
+ @snippet = user_project.snippets.find(params[:snippet_id])
@snippet.destroy
end
# Get a raw project snippet
#
# Parameters:
- # id (required) - The code of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# Example Request:
# GET /projects/:id/snippets/:snippet_id/raw
get ":id/snippets/:snippet_id/raw" do
- @project = current_user.projects.find_by_code(params[:id])
- @snippet = @project.snippets.find(params[:snippet_id])
+ @snippet = user_project.snippets.find(params[:snippet_id])
present @snippet.content
end
end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index aff13baf67b..c3a19e71c10 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -10,6 +10,7 @@ module Gitlab
def self.read_latest
path = Rails.root.join("log/githost.log")
+ self.build unless File.exist?(path)
logs = File.read(path).split("\n")
end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 014483d4e8c..d9053c232cd 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -121,7 +121,7 @@ namespace :gitlab do
backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo)
puts "Dumping repositories:"
- project = Project.all.map { |n| [n.name,n.path_to_repo] }
+ project = Project.all.map { |n| [n.path,n.path_to_repo] }
project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
project.each do |project|
print "- Dumping repository #{project.first}... "
@@ -136,12 +136,18 @@ namespace :gitlab do
task :repo_restore => :environment do
backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
puts "Restoring repositories:"
- project = Project.all.map { |n| [n.name,n.path_to_repo] }
+ project = Project.all.map { |n| [n.path,n.path_to_repo] }
project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
project.each do |project|
print "- Restoring repository #{project.first}... "
FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff
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")
+ permission_commands = [
+ "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}",
+ "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}",
+ "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive"
+ ]
+ permission_commands.each { |command| Kernel.system(command) }
puts "[DONE]".green
else
puts "[FAILED]".red
diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake
index ac712234b27..96b8886fa89 100644
--- a/lib/tasks/gitlab/status.rake
+++ b/lib/tasks/gitlab/status.rake
@@ -2,7 +2,7 @@ namespace :gitlab do
namespace :app do
desc "GITLAB | Check gitlab installation status"
task :status => :environment do
- puts "Starting diagnostic"
+ puts "Starting diagnostic".yellow
git_base_path = Gitlab.config.git_base_path
print "config/database.yml............"
@@ -56,7 +56,28 @@ namespace :gitlab do
return
end
- puts "\nFinished"
+ if Project.count > 0
+ puts "Validating projects repositories:".yellow
+ Project.find_each(:batch_size => 100) do |project|
+ print "#{project.name}....."
+ hook_file = File.join(project.path_to_repo, 'hooks','post-receive')
+
+ unless File.exists?(hook_file)
+ puts "post-receive file missing".red
+ next
+ end
+
+
+ unless File.owned?(hook_file)
+ puts "post-receive file is not owner by gitlab".red
+ next
+ end
+
+ puts "post-reveice file ok".green
+ end
+ end
+
+ puts "\nFinished".blue
end
end
end
diff --git a/spec/api/issues_spec.rb b/spec/api/issues_spec.rb
new file mode 100644
index 00000000000..d81a07e214b
--- /dev/null
+++ b/spec/api/issues_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+ let(:user) { Factory :user }
+ let!(:project) { Factory :project, :owner => user }
+ let!(:issue) { Factory :issue, :author => user, :assignee => user, :project => project }
+ before { project.add_access(user, :read) }
+
+ describe "GET /issues" do
+ it "should return authentication error" do
+ get "#{api_prefix}/issues"
+ response.status.should == 401
+ end
+
+ describe "authenticated GET /issues" do
+ it "should return an array of issues" do
+ get "#{api_prefix}/issues?private_token=#{user.private_token}"
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['title'].should == issue.title
+ end
+ end
+ end
+
+ describe "GET /projects/:id/issues" do
+ it "should return project issues" do
+ get "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}"
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['title'].should == issue.title
+ end
+ end
+
+ describe "GET /projects/:id/issues/:issue_id" do
+ it "should return a project issue by id" do
+ get "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}"
+ response.status.should == 200
+ json_response['title'].should == issue.title
+ end
+ end
+
+ describe "POST /projects/:id/issues" do
+ it "should create a new project issue" do
+ post "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}",
+ :title => 'new issue', :labels => 'label, label2'
+ response.status.should == 201
+ json_response['title'].should == 'new issue'
+ json_response['description'].should be_nil
+ json_response['labels'].should == ['label', 'label2']
+ end
+ end
+
+ describe "PUT /projects/:id/issues/:issue_id" do
+ it "should update a project issue" do
+ put "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}",
+ :title => 'updated title', :labels => 'label2', :closed => 1
+ response.status.should == 200
+ json_response['title'].should == 'updated title'
+ json_response['labels'].should == ['label2']
+ json_response['closed'].should be_true
+ end
+ end
+
+ describe "DELETE /projects/:id/issues/:issue_id" do
+ it "should delete a project issue" do
+ expect {
+ delete "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}"
+ }.to change { Issue.count }.by(-1)
+ end
+ end
+end
diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb
index 9998ee509bf..8852a0d346b 100644
--- a/spec/api/projects_spec.rb
+++ b/spec/api/projects_spec.rb
@@ -25,11 +25,23 @@ describe Gitlab::API do
describe "GET /projects/:id" do
it "should return a project by id" do
- get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}"
+ get "#{api_prefix}/projects/#{project.id}?private_token=#{user.private_token}"
response.status.should == 200
json_response['name'].should == project.name
json_response['owner']['email'].should == user.email
end
+
+ it "should return a project by code name" do
+ get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}"
+ response.status.should == 200
+ json_response['name'].should == project.name
+ end
+
+ it "should return a 404 error if not found" do
+ get "#{api_prefix}/projects/42?private_token=#{user.private_token}"
+ response.status.should == 404
+ json_response['message'].should == '404 Not found'
+ end
end
describe "GET /projects/:id/repository/branches" do
diff --git a/spec/requests/commits_spec.rb b/spec/requests/commits_spec.rb
index 00b69379848..ae36a932ae0 100644
--- a/spec/requests/commits_spec.rb
+++ b/spec/requests/commits_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe "Commits" do
let(:project) { Factory :project }
- let!(:commit) { project.commit }
+ let!(:commit) { CommitDecorator.decorate(project.commit) }
before do
login_as :user
project.add_access(@user, :read)
@@ -22,8 +22,8 @@ describe "Commits" do
end
it "should list commits" do
- page.should have_content(commit.message)
- page.should have_content(commit.id.to_s[0..5])
+ page.should have_content(commit.description)
+ page.should have_content(commit.short_id(8))
end
it "should render atom feed" do
@@ -32,7 +32,7 @@ describe "Commits" do
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "Recent commits to #{project.name}")
page.body.should have_selector("author email", :text => commit.author_email)
- page.body.should have_selector("entry summary", :text => commit.message)
+ page.body.should have_selector("entry summary", :text => commit.description)
end
it "should render atom feed via private token" do
@@ -42,7 +42,7 @@ describe "Commits" do
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "Recent commits to #{project.name}")
page.body.should have_selector("author email", :text => commit.author_email)
- page.body.should have_selector("entry summary", :text => commit.message)
+ page.body.should have_selector("entry summary", :text => commit.description)
end
end
diff --git a/spec/requests/wikis_notes_spec.rb b/spec/requests/wikis_notes_spec.rb
new file mode 100644
index 00000000000..144d0318bea
--- /dev/null
+++ b/spec/requests/wikis_notes_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe "Wikis" do
+ let(:project) { Factory :project }
+
+ before do
+ login_as :user
+ project.add_access(@user, :read, :write)
+ end
+
+ describe "add new note", :js => true do
+ before do
+ visit project_wiki_path(project, :index)
+
+ fill_in "Title", :with => 'Test title'
+ fill_in "Content", :with => '[link test](test)'
+ click_on "Save"
+
+ page.should have_content("Test title")
+
+ fill_in "note_note", :with => "Comment on wiki!"
+ click_button "Add Comment"
+ end
+
+ it "should contain the new note" do
+ page.should have_content("Comment on wiki!")
+ end
+ end
+end