Commit e6edaa3b authored by Jeremy Anderson's avatar Jeremy Anderson

Merge remote-tracking branch 'upstream/master'

parents 0301ba33 3caf0aa8
......@@ -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"
......
......@@ -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)
......
......@@ -33,7 +33,7 @@ init:
})
$("#note_note").live("focus", function(){
$(this).css("height", "100px");
$(this).css("height", "80px");
$('.note_advanced_opts').show();
});
......
......@@ -8,7 +8,6 @@ var Pager = {
this.limit=limit;
this.offset=limit;
this.initLoadMore();
$('.loading').show();
},
getOld:
......
......@@ -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 {
......
......@@ -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;
}
......@@ -517,6 +513,7 @@ form {
font-weight:bold;
color:#444;
&:hover {
color:#444;
text-decoration:underline;
}
}
......
......@@ -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;
}
}
}
}
}
......
......@@ -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;
}
}
......@@ -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;
}
}
}
......@@ -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
......
......@@ -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
......
......@@ -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
......@@ -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 ||= exception.message if exception.respond_to?(:message)
error ||= env["omniauth.error.type"].to_s
end
error.to_s.humanize if error
end
......
......@@ -51,6 +51,7 @@ 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
......
......@@ -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
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
......
......@@ -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} ")
......
......@@ -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
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
......
......@@ -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
......
......@@ -2,13 +2,12 @@
.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]
= 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
%span.row_title= truncate(commit.safe_message, :length => 50)
= 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)
......
.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
......
......@@ -24,7 +24,8 @@
- unless @commits.empty?
%h4 Commits (#{@commits.count})
%div.ui-box
%h5.small Commits (#{@commits.count})
%ul.unstyled= render @commits
- unless @diffs.empty?
......
......@@ -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
%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
......
.alert-message.block-message.error
%h3 Gitolite Error
%hr
%h4 Application cant get access to your gitolite system.
%ol
%h4 Tips for Administrator:
%ul
%li
%p
Check 'config/gitlab.yml' for correct settings.
Check git logs in admin area
%li
%p
Make sure web server user has access to gitolite.
%a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial
Check config/gitlab.yml for correct settings.
%li
%p
Try:
Diagnostic tool:
%pre
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
- 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
= 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
%span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding"
= truncate(commit.title, :length => 50) rescue "--broken encoding"
......@@ -11,6 +11,8 @@
%a{:href => "#projects"} Projects
%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"))
......@@ -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
......
......@@ -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}"
......
......@@ -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|
......
......@@ -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}"
......
......@@ -6,9 +6,8 @@
= 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)
%h4
= link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title"
%small
= milestone.expires_at
%br
......
......@@ -51,7 +51,7 @@
= link_to [@project, issue] do
%span.badge.badge-info ##{issue.id}
&ndash;
= truncate issue.title, :length => 60
= link_to truncate(issue.title, :length => 60), [@project, issue]
%br
= paginate @issues, :theme => "gitlab"
......
= 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|
......
......@@ -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,8 +13,13 @@
= f.hidden_field :noteable_type
= f.hidden_field :line_code
= f.text_area :note, :size => 255
%h5 Notify via email:
.clearfix
.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
......@@ -23,9 +28,6 @@
= 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"
:javascript
$(function(){
......
%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"}
......@@ -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
- 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"
......@@ -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
......
- 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
......
- 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)
......
......@@ -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)
......
......@@ -6,19 +6,21 @@
- @wiki.errors.full_messages.each do |msg|
%li= msg
.alert-message.block-message.warning
%p
.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"}.
%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
.bottom_box_content
= f.label :content
.input= f.text_area :content, :class => :xxlarge
.input= f.text_area :content, :class => 'span8'
.actions
= f.submit 'Save', :class => "primary btn"
= link_to "Cancel", project_wiki_path(@project, :index), :class => "btn"
%h3 Editing page
%h3.page_title Editing page
%hr
= render 'form'
%h3.page_title Empty page
%hr
.alert-message.block-message.warning
%span You are not allowed to create wiki pages
%h3 Versions
%table
%h3.page_title Versions
%br
%table.admin-table
%thead
%tr
%th #
......
......@@ -5,9 +5,11 @@
= 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
%br
.file_holder
.file_content.wiki
= preserve do
= markdown @wiki.content
......@@ -15,3 +17,6 @@
- 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"
......@@ -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)
## 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.
## 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.
......@@ -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
......
......@@ -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
......
......@@ -15,5 +15,6 @@ module Gitlab
mount Users
mount Projects
mount Issues
end
end
......@@ -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
......@@ -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
......
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
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
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
......@@ -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
......
......@@ -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
......
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment