Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jeremy Anderson 2012-07-27 22:18:04 -04:00
commit e6edaa3b50
64 changed files with 763 additions and 198 deletions

View file

@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0"
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0" 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 "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 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
gem 'grack', :git => "https://github.com/gitlabhq/grack.git" gem 'grack', :git => "https://github.com/gitlabhq/grack.git"
gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git"

View file

@ -42,8 +42,8 @@ GIT
GIT GIT
remote: https://github.com/gitlabhq/omniauth-ldap.git remote: https://github.com/gitlabhq/omniauth-ldap.git
revision: 7edf27d0281e09561838122982c16b7e62181f44 revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
ref: 7edf27d0281e09561838122982c16b7e62181f44 ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
specs: specs:
omniauth-ldap (1.0.2) omniauth-ldap (1.0.2)
net-ldap (~> 0.2.2) net-ldap (~> 0.2.2)

View file

@ -33,7 +33,7 @@ init:
}) })
$("#note_note").live("focus", function(){ $("#note_note").live("focus", function(){
$(this).css("height", "100px"); $(this).css("height", "80px");
$('.note_advanced_opts').show(); $('.note_advanced_opts').show();
}); });

View file

@ -8,7 +8,6 @@ var Pager = {
this.limit=limit; this.limit=limit;
this.offset=limit; this.offset=limit;
this.initLoadMore(); this.initLoadMore();
$('.loading').show();
}, },
getOld: getOld:

View file

@ -337,6 +337,15 @@ p.time {
padding: 15px 5px; padding: 15px 5px;
&:last-child { border:none } &:last-child { border:none }
.wll:hover { background:none } .wll:hover { background:none }
.event_commits {
margin-top: 5px;
li.commit {
padding:5px;
border:none;
}
}
} }
.ico { .ico {

View file

@ -18,7 +18,8 @@ a {
} }
&.lined { &.lined {
text-decoration:underlined; text-decoration:underline;
&:hover { text-decoration:underline; }
} }
&.gray { &.gray {
@ -74,10 +75,6 @@ h5 {
font-size:14px; font-size:14px;
} }
code {
background:#FCEEC1;
color:$style_color;
}
table { table {
width:100%; width:100%;
@ -381,7 +378,6 @@ form {
min-height: 20px; min-height: 20px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
cursor:pointer;
&.smoke { &.smoke {
background-color:#f5f5f5; background-color:#f5f5f5;
} }
@ -516,7 +512,8 @@ form {
.row_title { .row_title {
font-weight:bold; font-weight:bold;
color:#444; color:#444;
&:hover { &:hover {
color:#444;
text-decoration:underline; text-decoration:underline;
} }
} }

View file

@ -14,7 +14,8 @@
border-bottom:1px solid #aaa; border-bottom:1px solid #aaa;
} }
.issue_notes { .issue_notes,
.wiki_notes {
.note_content { .note_content {
float:left; float:left;
width:400px; width:400px;
@ -23,8 +24,8 @@
/* Note textare */ /* Note textare */
#note_note { #note_note {
height:100px; height:80px;
width:97%; width:99%;
font-size:14px; font-size:14px;
} }
@ -99,8 +100,25 @@ tr.line_notes_row {
td { td {
border-bottom:1px solid #ddd; border-bottom:1px solid #ddd;
} }
.actions { .note_actions {
margin:0; 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;
}
}
}
} }
} }

View file

@ -194,4 +194,16 @@
float:right; float:right;
@extend .cgray; @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;
}
} }

View file

@ -30,13 +30,14 @@
.issue { .issue {
padding:7px 10px; padding:7px 10px;
p {
padding-top:0;
padding-bottom:2px;
}
img.avatar { img.avatar {
width:32px; width:32px;
margin-top:4px; margin-top:4px;
} }
p.row_title {
padding:0px;
padding-bottom:2px;
}
} }
} }

View file

@ -17,6 +17,8 @@ class NotesLoad < BaseContext
then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
when "merge_request" when "merge_request"
then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) 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 end
@notes = if last_id @notes = if last_id

View file

@ -17,6 +17,7 @@ class CommitsController < ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @project.commits(@ref, params[:path], @limit, @offset) @commits = @project.commits(@ref, params[:path], @limit, @offset)
@commits = CommitDecorator.decorate(@commits)
respond_to do |format| respond_to do |format|
format.html # index.html.erb format.html # index.html.erb
@ -51,6 +52,8 @@ class CommitsController < ApplicationController
@commit = result[:commit] @commit = result[:commit]
@diffs = result[:diffs] @diffs = result[:diffs]
@line_notes = [] @line_notes = []
@commits = CommitDecorator.decorate(@commits)
end end
def patch def patch

View file

@ -143,5 +143,6 @@ class MergeRequestsController < ApplicationController
# Get commits from repository # Get commits from repository
# or from cache if already merged # or from cache if already merged
@commits = @merge_request.commits @commits = @merge_request.commits
@commits = CommitDecorator.decorate(@commits)
end end
end end

View file

@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Extend the standard message generation to accept our custom exception # Extend the standard message generation to accept our custom exception
def failure_message def failure_message
exception = env["omniauth.error"] exception = env["omniauth.error"]
if exception.class == OmniAuth::Error error = exception.error_reason if exception.respond_to?(:error_reason)
error = exception.message error ||= exception.error if exception.respond_to?(:error)
else error ||= exception.message if exception.respond_to?(:message)
error = exception.error_reason if exception.respond_to?(:error_reason) error ||= env["omniauth.error.type"].to_s
error ||= exception.error if exception.respond_to?(:error)
error ||= env["omniauth.error.type"].to_s
end
error.to_s.humanize if error error.to_s.humanize if error
end end

View file

@ -51,7 +51,8 @@ class RefsController < ApplicationController
@logs = contents.map do |content| @logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name file = params[:path] ? File.join(params[:path], content.name) : content.name
last_commit = @project.commits(@commit.id, file, 1).last last_commit = @project.commits(@commit.id, file, 1).last
{ last_commit = CommitDecorator.decorate(last_commit)
{
:file_name => content.name, :file_name => content.name,
:commit => last_commit :commit => last_commit
} }

View file

@ -13,16 +13,16 @@ class WikisController < ApplicationController
@wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last
end end
unless @wiki @note = @project.notes.new(:noteable => @wiki)
return render_404 unless can?(current_user, :write_wiki, @project)
end
respond_to do |format| if @wiki
if @wiki render 'show'
format.html else
else if can?(current_user, :write_wiki, @project)
@wiki = @project.wikis.new(:slug => params[:id]) @wiki = @project.wikis.new(:slug => params[:id])
format.html { render "edit" } render 'edit'
else
render 'empty'
end end
end end
end end

View file

@ -46,6 +46,13 @@ class Notify < ActionMailer::Base
mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ") mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ")
end 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) def new_merge_request_email(merge_request_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ") mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ")

View file

@ -114,6 +114,10 @@ class Commit
@head = head @head = head
end end
def short_id(length = 10)
id.to_s[0..length]
end
def safe_message def safe_message
utf8 message utf8 message
end end
@ -150,4 +154,8 @@ class Commit
def prev_commit_id def prev_commit_id
prev_commit.try :id prev_commit.try :id
end end
def parents_count
parents && parents.count || 0
end
end end

View file

@ -1,6 +1,7 @@
class Wiki < ActiveRecord::Base class Wiki < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :user belongs_to :user
has_many :notes, :as => :noteable, :dependent => :destroy
validates :content, :title, :user_id, :presence => true validates :content, :title, :user_id, :presence => true
validates :title, :length => 1..250 validates :title, :length => 1..250

View file

@ -34,6 +34,7 @@ class MailerObserver < ActiveRecord::Observer
case note.noteable_type case note.noteable_type
when "Commit"; Notify.note_commit_email(u.id, note.id).deliver when "Commit"; Notify.note_commit_email(u.id, note.id).deliver
when "Issue"; Notify.note_issue_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 "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver
when "Snippet"; true when "Snippet"; true
else else

View file

@ -2,16 +2,15 @@
.browse_code_link_holder .browse_code_link_holder
%p %p
%strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right" %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
%p = link_to commit.short_id(8), project_commit_path(@project, :id => commit.id), :class => "commit_short_id"
%code.left= commit.id.to_s[0..10] %strong.cgray= commit.author_name
%strong.cgray= commit.author_name &ndash;
&ndash; = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
= 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.row_title= truncate(commit.safe_message, :length => 50)
%span.committed_ago %span.committed_ago
= time_ago_in_words(commit.committed_date) = time_ago_in_words(commit.committed_date)
ago ago
&nbsp; &nbsp;

View file

@ -1,4 +1,4 @@
.commit-box{class: @commit.parents.count > 1 ? "merge-commit" : ""} .commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""}
.commit-head .commit-head
.right .right
- if @notes_count > 0 - if @notes_count > 0

View file

@ -24,8 +24,9 @@
- unless @commits.empty? - unless @commits.empty?
%h4 Commits (#{@commits.count}) %div.ui-box
%ul.unstyled= render @commits %h5.small Commits (#{@commits.count})
%ul.unstyled= render @commits
- unless @diffs.empty? - unless @diffs.empty?
%h4 Diff %h4 Diff

View file

@ -10,14 +10,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.entry do xml.entry do
xml.id project_commit_url(@project, :id => commit.id) xml.id project_commit_url(@project, :id => commit.id)
xml.link :href => 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.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.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email)
xml.author do |author| xml.author do |author|
xml.name commit.author_name xml.name commit.author_name
xml.email commit.author_email xml.email commit.author_email
end end
xml.summary commit.safe_message xml.summary commit.description
end end
end end
end end

View file

@ -1,6 +1,6 @@
%h3.page_title %h3.page_title
Merge Requests Merge Requests
%small (authored or assigned to you) %small (authored by or assigned to you)
%small.right #{@merge_requests.total_count} merge requests %small.right #{@merge_requests.total_count} merge requests
%br %br

View file

@ -1,19 +1,30 @@
.alert-message.block-message.error .alert-message.block-message.error
%h3 Gitolite Error %h3 Gitolite Error
%hr
%h4 Application cant get access to your gitolite system. %h4 Application cant get access to your gitolite system.
%ol
%li
%p
Check 'config/gitlab.yml' for correct settings.
%li %h4 Tips for Administrator:
%p
Make sure web server user has access to gitolite. %ul
%a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial %li
%li %p
%p Check git logs in admin area
Try: %li
%p
Check config/gitlab.yml for correct settings.
%li
%p
Diagnostic tool:
%pre %pre
= preserve do bundle exec rake gitlab:app:status RAILS_ENV=production
sudo chmod -R 770 /home/git/repositories/ %li
sudo chown -R git:git /home/git/repositories/ %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

View file

@ -1,9 +1,9 @@
- commit = CommitDecorator.decorate(commit)
%li.wll.commit %li.wll.commit
= link_to project_commit_path(project, :id => commit.id) do %p
%p = link_to commit.short_id(8), project_commit_path(project, :id => commit.id), :class => "commit_short_id"
%code.left= commit.id.to_s[0..10] %strong.cdark= commit.author_name
%strong.cgray= commit.author_name &ndash;
&ndash; = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16
= image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 = truncate(commit.title, :length => 50) rescue "--broken encoding"
%span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding"

View file

@ -1,16 +1,18 @@
%h3 API %h3 API
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
%ol %ol
%li %li
%a{:href => "#README"} README %a{:href => "#README"} README
%li %li
%a{:href => "#projects"} Projects %a{:href => "#projects"} Projects
%li %li
%a{:href => "#users"} Users %a{:href => "#users"} Users
%li
%a{:href => "#issues"} Issues
.file_holder#README .file_holder#README
.file_title .file_title
@ -39,3 +41,13 @@
.file_content.wiki .file_content.wiki
= preserve do = preserve do
= markdown File.read(Rails.root.join("doc", "api", "users.md")) = 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"))

View file

@ -38,7 +38,6 @@
%li Push to non-protected branches %li Push to non-protected branches
%li Remove non-protected branches %li Remove non-protected branches
%li Add tags %li Add tags
%li Create new merge request
%li Write a wiki %li Write a wiki
.ui-box.span3 .ui-box.span3
@ -55,7 +54,6 @@
%li Push to non-protected branches %li Push to non-protected branches
%li Remove non-protected branches %li Remove non-protected branches
%li Add tags %li Add tags
%li Create new merge request
%li Write a wiki %li Write a wiki
%li Add new team members %li Add new team members
%li Push to protected branches %li Push to protected branches

View file

@ -24,8 +24,7 @@
- else - else
= image_tag "no_avatar.png", :class => "avatar" = image_tag "no_avatar.png", :class => "avatar"
= link_to project_issue_path(issue.project, issue) do %p= link_to truncate(issue.title, :length => 100), project_issue_path(issue.project, issue), :class => "row_title"
%p.row_title= truncate(issue.title, :length => 100)
%span.update-author %span.update-author
%small.cdark= "##{issue.id}" %small.cdark= "##{issue.id}"

View file

@ -46,9 +46,7 @@
- if @issue.milestone - if @issue.milestone
- milestone = @issue.milestone - milestone = @issue.milestone
%cite.cgray and attached to milestone %cite.cgray and attached to milestone
= link_to project_milestone_path(milestone.project, milestone) do %strong= link_to truncate(milestone.title, :length => 20), project_milestone_path(milestone.project, milestone)
%strong
= truncate(milestone.title, :length => 20)
.right .right
- @issue.labels.each do |label| - @issue.labels.each do |label|

View file

@ -16,8 +16,7 @@
= merge_request.target_branch = merge_request.target_branch
= image_tag gravatar_icon(merge_request.author_email), :class => "avatar" = image_tag gravatar_icon(merge_request.author_email), :class => "avatar"
= link_to project_merge_request_path(merge_request.project, merge_request) do %p= link_to truncate(merge_request.title, :length => 80), project_merge_request_path(merge_request.project, merge_request), :class => "row_title"
%p.row_title= truncate(merge_request.title, :length => 80)
%span.update-author %span.update-author
%small.cdark= "##{merge_request.id}" %small.cdark= "##{merge_request.id}"

View file

@ -6,14 +6,13 @@
= link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped" = 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 - 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 '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
%h4.row_title = link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title"
= truncate(milestone.title, :length => 100) %small
%small = milestone.expires_at
= milestone.expires_at %br
%br .progress.progress-success.span3
.progress.progress-success.span3 .bar{:style => "width: #{milestone.percent_complete}%;"}
.bar{:style => "width: #{milestone.percent_complete}%;"}
&nbsp; &nbsp;

View file

@ -50,8 +50,8 @@
%td %td
= link_to [@project, issue] do = link_to [@project, issue] do
%span.badge.badge-info ##{issue.id} %span.badge.badge-info ##{issue.id}
&ndash; &ndash;
= truncate issue.title, :length => 60 = link_to truncate(issue.title, :length => 60), [@project, issue]
%br %br
= paginate @issues, :theme => "gitlab" = paginate @issues, :theme => "gitlab"

View file

@ -1,5 +1,5 @@
= form_for [@project, @note], :remote => "true", :multipart => true do |f| = form_for [@project, @note], :remote => "true", :multipart => true do |f|
%h3 Leave a comment %h3.page_title Leave a comment
-if @note.errors.any? -if @note.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
- @note.errors.full_messages.each do |msg| - @note.errors.full_messages.each do |msg|

View file

@ -2,7 +2,7 @@
%tr.per_line_form %tr.per_line_form
%td{:colspan => 3 } %td{:colspan => 3 }
= form_for [@project, @note], :remote => "true", :multipart => true do |f| = form_for [@project, @note], :remote => "true", :multipart => true do |f|
%h3 Leave a note %h3.page_title Leave a note
%div.span10 %div.span10
-if @note.errors.any? -if @note.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
@ -13,19 +13,21 @@
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
= f.hidden_field :line_code = f.hidden_field :line_code
= f.text_area :note, :size => 255 = f.text_area :note, :size => 255
%h5 Notify via email: .note_actions
.clearfix .buttons
= label_tag :notify do = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
= check_box_tag :notify, 1, @note.noteable_type != "Commit" = link_to "Cancel", "#", :class => "btn hide-button"
%span Project team .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) - if @note.notify_only_author?(current_user)
= label_tag :notify_author do = label_tag :notify_author do
= check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
%span Commit author %span Commit author
.actions
= f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
= link_to "Close", "#", :class => "btn hide-button"
:javascript :javascript
$(function(){ $(function(){

View file

@ -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"}

View file

@ -14,6 +14,6 @@
ago ago
- else - else
.alert-message.block-message .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

View file

@ -1,3 +1,3 @@
- if tm - if tm
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, 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"

View file

@ -25,15 +25,15 @@
%table %table
- @blame.each do |commit, lines| - @blame.each do |commit, lines|
- commit = Commit.new(commit) - commit = Commit.new(commit)
- commit = CommitDecorator.decorate(commit)
%tr %tr
%td.author %td.author
= image_tag gravatar_icon(commit.author_email, 16) = image_tag gravatar_icon(commit.author_email, 16)
= commit.author_name = commit.author_name
%td.blame_commit %td.blame_commit
&nbsp; &nbsp;
= link_to project_commit_path(@project, :id => commit.id) do %code= link_to commit.short_id, project_commit_path(@project, :id => commit.id)
%code= commit.id.to_s[0..10] = link_to truncate(commit.title, :length => 30), project_commit_path(@project, :id => commit.id), :class => "row_title" rescue "--broken encoding"
%span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding"
%td.lines %td.lines
= preserve do = preserve do
%pre %pre

View file

@ -1,3 +1,5 @@
- commit = Commit.new(branch.commit)
- commit = CommitDecorator.decorate(commit)
%tr %tr
%td %td
= link_to project_commits_path(@project, :ref => branch.name) do = link_to project_commits_path(@project, :ref => branch.name) do
@ -5,14 +7,14 @@
- if branch.name == @project.root_ref - if branch.name == @project.root_ref
%span.label default %span.label default
%td %td
= link_to project_commit_path(@project, :id => branch.commit.id) do = link_to project_commit_path(@project, :id => commit.id) do
%code= branch.commit.id.to_s[0..10] %code= commit.short_id
= image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
= truncate(Commit.new(branch.commit).safe_message, :length => 40) = truncate(commit.title, :length => 40)
%td %td
%span.update-author.right %span.update-author.right
= time_ago_in_words(branch.commit.committed_date) = time_ago_in_words(commit.committed_date)
ago ago
%td %td
- if can? current_user, :download_code, @project - if can? current_user, :download_code, @project

View file

@ -1,4 +1,5 @@
- commit = update - commit = update
- commit = CommitDecorator.new(commit)
%tr %tr
%td %td
= link_to project_commits_path(@project, :ref => commit.head.name) do = link_to project_commits_path(@project, :ref => commit.head.name) do
@ -10,9 +11,9 @@
%td %td
%div %div
= link_to project_commits_path(@project, commit.id) do = 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 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
= truncate(commit.safe_message, :length => 40) = truncate(commit.title, :length => 40)
%td %td
%span.right.cgray %span.right.cgray
= time_ago_in_words(commit.committed_date) = time_ago_in_words(commit.committed_date)

View file

@ -9,14 +9,15 @@
%th %th
- @tags.each do |tag| - @tags.each do |tag|
- commit = Commit.new(tag.commit) - commit = Commit.new(tag.commit)
- commit = CommitDecorator.decorate(commit)
%tr %tr
%td %td
%strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => "" %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => ""
%td %td
= link_to project_commit_path(@project, commit.id) do = 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 = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16
= truncate(commit.safe_message, :length => 40) = truncate(commit.title, :length => 40)
%td %td
%span.update-author.right %span.update-author.right
= time_ago_in_words(commit.committed_date) = time_ago_in_words(commit.committed_date)

View file

@ -6,19 +6,21 @@
- @wiki.errors.full_messages.each do |msg| - @wiki.errors.full_messages.each do |msg|
%li= msg %li= msg
.alert-message.block-message.warning .main_box
%p .top_box_content
Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. = f.label :title
%br .input= f.text_field :title, :class => 'span8'
To add link to new page you can just type = f.hidden_field :slug
%code [Link Title](page-slug) .middle_box_content
.clearfix .input
= f.label :title %span.cgray
.input= f.text_field :title, :class => :xxlarge Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}.
= f.hidden_field :slug To add link to new page you can just type
.clearfix %code [Link Title](page-slug)
= f.label :content
.input= f.text_area :content, :class => :xxlarge .bottom_box_content
= f.label :content
.input= f.text_area :content, :class => 'span8'
.actions .actions
= f.submit 'Save', :class => "primary btn" = f.submit 'Save', :class => "primary btn"
= link_to "Cancel", project_wiki_path(@project, :index), :class => "btn" = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn"

View file

@ -1,3 +1,3 @@
%h3 Editing page %h3.page_title Editing page
%hr %hr
= render 'form' = render 'form'

View file

@ -0,0 +1,4 @@
%h3.page_title Empty page
%hr
.alert-message.block-message.warning
%span You are not allowed to create wiki pages

View file

@ -1,5 +1,6 @@
%h3 Versions %h3.page_title Versions
%table %br
%table.admin-table
%thead %thead
%tr %tr
%th # %th #

View file

@ -5,13 +5,18 @@
= link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
History History
= link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do
%i.icon-edit
Edit Edit
%hr %br
.wiki_content .file_holder
= preserve do .file_content.wiki
= markdown @wiki.content = preserve do
= markdown @wiki.content
%p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago
- if can? current_user, :admin_wiki, @project - 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 = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do
Delete this page Delete this page
%hr
.wiki_notes#notes= render "notes/notes", :tid => @wiki.id, :tt => "wiki"

View file

@ -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) + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md)
+ [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.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)

184
doc/api/issues.md Normal file
View file

@ -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.

View file

@ -1,6 +1,6 @@
## List projects ## List projects
Get a list of authenticated users' projects. Get a list of authenticated user's projects.
``` ```
GET /projects GET /projects
@ -63,7 +63,7 @@ GET /projects/:id
Parameters: Parameters:
+ `id` (required) - The code name of a project + `id` (required) - The ID or code name of a project
```json ```json
{ {
@ -91,7 +91,7 @@ Parameters:
## Project repository branches ## 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 GET /projects/:id/repository/branches
@ -99,7 +99,7 @@ GET /projects/:id/repository/branches
Parameters: Parameters:
+ `id` (required) - The code name of a project + `id` (required) - The ID or code name of a project
```json ```json
[ [
@ -131,7 +131,7 @@ Parameters:
## Project repository tags ## 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 GET /projects/:id/repository/tags
@ -139,7 +139,7 @@ GET /projects/:id/repository/tags
Parameters: Parameters:
+ `id` (required) - The code name of a project + `id` (required) - The ID or code name of a project
```json ```json
[ [
@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id
Parameters: 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 + `snippet_id` (required) - The ID of a project's snippet
```json ```json
@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw
Parameters: 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 + `snippet_id` (required) - The ID of a project's snippet
## New snippet ## New snippet
@ -227,7 +227,7 @@ POST /projects/:id/snippets
Parameters: 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 + `title` (required) - The title of a snippet
+ `file_name` (required) - The name of a snippet file + `file_name` (required) - The name of a snippet file
+ `lifetime` (optional) - The expiration date of a snippet + `lifetime` (optional) - The expiration date of a snippet
@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id
Parameters: 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 + `snippet_id` (required) - The ID of a project's snippet
+ `title` (optional) - The title of a snippet + `title` (optional) - The title of a snippet
+ `file_name` (optional) - The name of a snippet file + `file_name` (optional) - The name of a snippet file
@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id
Parameters: 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 + `snippet_id` (required) - The ID of a project's snippet
Status code `200` will be returned on success. Status code `200` will be returned on success.

View file

@ -119,6 +119,7 @@ Permissions:
sudo chmod -R g+rwX /home/git/repositories/ sudo chmod -R g+rwX /home/git/repositories/
sudo chown -R git:git /home/git/repositories/ sudo chown -R git:git /home/git/repositories/
sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
#### CHECK: Logout & login again to apply git group to your user #### CHECK: Logout & login again to apply git group to your user

View file

@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do
end end
Then /^I see commits atom feed$/ do 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.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("title", :text => "Recent commits to #{@project.name}")
page.body.should have_selector("author email", :text => commit.author_email) 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
Given /^I click on commit link$/ do Given /^I click on commit link$/ do

View file

@ -15,5 +15,6 @@ module Gitlab
mount Users mount Users
mount Projects mount Projects
mount Issues
end end
end end

View file

@ -16,11 +16,7 @@ module Gitlab
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
end end
class ProjectRepositoryBranches < Grape::Entity class RepoObject < Grape::Entity
expose :name, :commit
end
class ProjectRepositoryTags < Grape::Entity
expose :name, :commit expose :name, :commit
end end
@ -29,5 +25,19 @@ module Gitlab
expose :author, :using => Entities::UserBasic expose :author, :using => Entities::UserBasic
expose :expires_at, :updated_at, :created_at expose :expires_at, :updated_at, :created_at
end 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
end end

View file

@ -4,6 +4,16 @@ module Gitlab
@current_user ||= User.find_by_authentication_token(params[:private_token]) @current_user ||= User.find_by_authentication_token(params[:private_token])
end 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! def authenticate!
error!({'message' => '401 Unauthorized'}, 401) unless current_user error!({'message' => '401 Unauthorized'}, 401) unless current_user
end end

111
lib/api/issues.rb Normal file
View file

@ -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

View file

@ -16,53 +16,49 @@ module Gitlab
# Get a single project # Get a single project
# #
# Parameters: # Parameters:
# id (required) - The code of a project # id (required) - The ID or code name of a project
# Example Request: # Example Request:
# GET /projects/:id # GET /projects/:id
get ":id" do get ":id" do
@project = current_user.projects.find_by_code(params[:id]) present user_project, :with => Entities::Project
present @project, :with => Entities::Project
end end
# Get a project repository branches # Get a project repository branches
# #
# Parameters: # Parameters:
# id (required) - The code of a project # id (required) - The ID or code name of a project
# Example Request: # Example Request:
# GET /projects/:id/repository/branches # GET /projects/:id/repository/branches
get ":id/repository/branches" do get ":id/repository/branches" do
@project = current_user.projects.find_by_code(params[:id]) present user_project.repo.heads.sort_by(&:name), :with => Entities::RepoObject
present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches
end end
# Get a project repository tags # Get a project repository tags
# #
# Parameters: # Parameters:
# id (required) - The code of a project # id (required) - The ID or code name of a project
# Example Request: # Example Request:
# GET /projects/:id/repository/tags # GET /projects/:id/repository/tags
get ":id/repository/tags" do get ":id/repository/tags" do
@project = current_user.projects.find_by_code(params[:id]) present user_project.repo.tags.sort_by(&:name).reverse, :with => Entities::RepoObject
present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags
end end
# Get a project snippet # Get a project snippet
# #
# Parameters: # 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 # snippet_id (required) - The ID of a project snippet
# Example Request: # Example Request:
# GET /projects/:id/snippets/:snippet_id # GET /projects/:id/snippets/:snippet_id
get ":id/snippets/:snippet_id" do get ":id/snippets/:snippet_id" do
@project = current_user.projects.find_by_code(params[:id]) @snippet = user_project.snippets.find(params[:snippet_id])
@snippet = @project.snippets.find(params[:snippet_id])
present @snippet, :with => Entities::ProjectSnippet present @snippet, :with => Entities::ProjectSnippet
end end
# Create a new project snippet # Create a new project snippet
# #
# Parameters: # 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 # title (required) - The title of a snippet
# file_name (required) - The name of a snippet file # file_name (required) - The name of a snippet file
# lifetime (optional) - The expiration date of a snippet # lifetime (optional) - The expiration date of a snippet
@ -70,8 +66,7 @@ module Gitlab
# Example Request: # Example Request:
# POST /projects/:id/snippets # POST /projects/:id/snippets
post ":id/snippets" do post ":id/snippets" do
@project = current_user.projects.find_by_code(params[:id]) @snippet = user_project.snippets.new(
@snippet = @project.snippets.new(
:title => params[:title], :title => params[:title],
:file_name => params[:file_name], :file_name => params[:file_name],
:expires_at => params[:lifetime], :expires_at => params[:lifetime],
@ -89,7 +84,7 @@ module Gitlab
# Update an existing project snippet # Update an existing project snippet
# #
# Parameters: # 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 # snippet_id (required) - The ID of a project snippet
# title (optional) - The title of a snippet # title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file # file_name (optional) - The name of a snippet file
@ -98,8 +93,7 @@ module Gitlab
# Example Request: # Example Request:
# PUT /projects/:id/snippets/:snippet_id # PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do put ":id/snippets/:snippet_id" do
@project = current_user.projects.find_by_code(params[:id]) @snippet = user_project.snippets.find(params[:snippet_id])
@snippet = @project.snippets.find(params[:snippet_id])
parameters = { parameters = {
:title => (params[:title] || @snippet.title), :title => (params[:title] || @snippet.title),
:file_name => (params[:file_name] || @snippet.file_name), :file_name => (params[:file_name] || @snippet.file_name),
@ -117,26 +111,24 @@ module Gitlab
# Delete a project snippet # Delete a project snippet
# #
# Parameters: # 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 # snippet_id (required) - The ID of a project snippet
# Example Request: # Example Request:
# DELETE /projects/:id/snippets/:snippet_id # DELETE /projects/:id/snippets/:snippet_id
delete ":id/snippets/:snippet_id" do delete ":id/snippets/:snippet_id" do
@project = current_user.projects.find_by_code(params[:id]) @snippet = user_project.snippets.find(params[:snippet_id])
@snippet = @project.snippets.find(params[:snippet_id])
@snippet.destroy @snippet.destroy
end end
# Get a raw project snippet # Get a raw project snippet
# #
# Parameters: # 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 # snippet_id (required) - The ID of a project snippet
# Example Request: # Example Request:
# GET /projects/:id/snippets/:snippet_id/raw # GET /projects/:id/snippets/:snippet_id/raw
get ":id/snippets/:snippet_id/raw" do get ":id/snippets/:snippet_id/raw" do
@project = current_user.projects.find_by_code(params[:id]) @snippet = user_project.snippets.find(params[:snippet_id])
@snippet = @project.snippets.find(params[:snippet_id])
present @snippet.content present @snippet.content
end end
end end

View file

@ -10,6 +10,7 @@ module Gitlab
def self.read_latest def self.read_latest
path = Rails.root.join("log/githost.log") path = Rails.root.join("log/githost.log")
self.build unless File.exist?(path)
logs = File.read(path).split("\n") logs = File.read(path).split("\n")
end end

View file

@ -121,7 +121,7 @@ namespace :gitlab do
backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo)
puts "Dumping repositories:" 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 << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
project.each do |project| project.each do |project|
print "- Dumping repository #{project.first}... " print "- Dumping repository #{project.first}... "
@ -136,12 +136,18 @@ namespace :gitlab do
task :repo_restore => :environment do task :repo_restore => :environment do
backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") backup_path_repo = File.join(Gitlab.config.backup_path, "repositories")
puts "Restoring 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 << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")]
project.each do |project| project.each do |project|
print "- Restoring repository #{project.first}... " print "- Restoring repository #{project.first}... "
FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff 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") 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 puts "[DONE]".green
else else
puts "[FAILED]".red puts "[FAILED]".red

View file

@ -2,7 +2,7 @@ namespace :gitlab do
namespace :app do namespace :app do
desc "GITLAB | Check gitlab installation status" desc "GITLAB | Check gitlab installation status"
task :status => :environment do task :status => :environment do
puts "Starting diagnostic" puts "Starting diagnostic".yellow
git_base_path = Gitlab.config.git_base_path git_base_path = Gitlab.config.git_base_path
print "config/database.yml............" print "config/database.yml............"
@ -56,7 +56,28 @@ namespace :gitlab do
return return
end 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 end
end end

71
spec/api/issues_spec.rb Normal file
View file

@ -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

View file

@ -25,11 +25,23 @@ describe Gitlab::API do
describe "GET /projects/:id" do describe "GET /projects/:id" do
it "should return a project by 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 response.status.should == 200
json_response['name'].should == project.name json_response['name'].should == project.name
json_response['owner']['email'].should == user.email json_response['owner']['email'].should == user.email
end 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 end
describe "GET /projects/:id/repository/branches" do describe "GET /projects/:id/repository/branches" do

View file

@ -2,7 +2,7 @@ require 'spec_helper'
describe "Commits" do describe "Commits" do
let(:project) { Factory :project } let(:project) { Factory :project }
let!(:commit) { project.commit } let!(:commit) { CommitDecorator.decorate(project.commit) }
before do before do
login_as :user login_as :user
project.add_access(@user, :read) project.add_access(@user, :read)
@ -22,8 +22,8 @@ describe "Commits" do
end end
it "should list commits" do it "should list commits" do
page.should have_content(commit.message) page.should have_content(commit.description)
page.should have_content(commit.id.to_s[0..5]) page.should have_content(commit.short_id(8))
end end
it "should render atom feed" do 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.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("title", :text => "Recent commits to #{project.name}")
page.body.should have_selector("author email", :text => commit.author_email) 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
it "should render atom feed via private token" do 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.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("title", :text => "Recent commits to #{project.name}")
page.body.should have_selector("author email", :text => commit.author_email) 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
end end

View file

@ -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