diff --git a/Gemfile b/Gemfile index 5b076176..ef2076e5 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ gem "devise", "~> 2.1.0" gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0" gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188" -gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44" +gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e" gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" gem 'grack', :git => "https://github.com/gitlabhq/grack.git" gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" diff --git a/Gemfile.lock b/Gemfile.lock index 5c57bf6c..cede1547 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -42,8 +42,8 @@ GIT GIT remote: https://github.com/gitlabhq/omniauth-ldap.git - revision: 7edf27d0281e09561838122982c16b7e62181f44 - ref: 7edf27d0281e09561838122982c16b7e62181f44 + revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e + ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e specs: omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index c45a45d2..d9ae45d9 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -33,7 +33,7 @@ init: }) $("#note_note").live("focus", function(){ - $(this).css("height", "100px"); + $(this).css("height", "80px"); $('.note_advanced_opts').show(); }); diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index d42ae1e0..769e8a62 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -8,7 +8,6 @@ var Pager = { this.limit=limit; this.offset=limit; this.initLoadMore(); - $('.loading').show(); }, getOld: diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 0db803aa..9d9bfb7d 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -337,6 +337,15 @@ p.time { padding: 15px 5px; &:last-child { border:none } .wll:hover { background:none } + + .event_commits { + margin-top: 5px; + + li.commit { + padding:5px; + border:none; + } + } } .ico { diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss index 39e59983..b01f1274 100644 --- a/app/assets/stylesheets/gitlab_bootstrap.scss +++ b/app/assets/stylesheets/gitlab_bootstrap.scss @@ -18,7 +18,8 @@ a { } &.lined { - text-decoration:underlined; + text-decoration:underline; + &:hover { text-decoration:underline; } } &.gray { @@ -74,10 +75,6 @@ h5 { font-size:14px; } -code { - background:#FCEEC1; - color:$style_color; -} table { width:100%; @@ -381,7 +378,6 @@ form { min-height: 20px; border-bottom: 1px solid #eee; border-bottom: 1px solid rgba(0, 0, 0, 0.05); - cursor:pointer; &.smoke { background-color:#f5f5f5; } @@ -516,7 +512,8 @@ form { .row_title { font-weight:bold; color:#444; - &:hover { + &:hover { + color:#444; text-decoration:underline; } } diff --git a/app/assets/stylesheets/notes.scss b/app/assets/stylesheets/notes.scss index 39db704b..abce4c68 100644 --- a/app/assets/stylesheets/notes.scss +++ b/app/assets/stylesheets/notes.scss @@ -14,7 +14,8 @@ border-bottom:1px solid #aaa; } -.issue_notes { +.issue_notes, +.wiki_notes { .note_content { float:left; width:400px; @@ -23,8 +24,8 @@ /* Note textare */ #note_note { - height:100px; - width:97%; + height:80px; + width:99%; font-size:14px; } @@ -99,8 +100,25 @@ tr.line_notes_row { td { border-bottom:1px solid #ddd; } - .actions { + .note_actions { margin:0; + padding-top: 10px; + + .buttons { + float:left; + width:300px; + } + .options { + .labels { + float:left; + padding-left:10px; + label { + padding: 6px 0; + margin: 0; + width:120px; + } + } + } } } diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 6052ec3f..e2db701d 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -194,4 +194,16 @@ float:right; @extend .cgray; } + + code { + background:#FCEEC1; + color:$style_color; + } + + .commit_short_id { + float:left; + @extend .lined; + min-width:65px; + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + } } diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index dd1c22d4..12926d3f 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -30,13 +30,14 @@ .issue { padding:7px 10px; + p { + padding-top:0; + padding-bottom:2px; + } + img.avatar { width:32px; margin-top:4px; } - p.row_title { - padding:0px; - padding-bottom:2px; - } } } diff --git a/app/contexts/notes_load.rb b/app/contexts/notes_load.rb index d1f8da9c..cbb9f67f 100644 --- a/app/contexts/notes_load.rb +++ b/app/contexts/notes_load.rb @@ -17,6 +17,8 @@ class NotesLoad < BaseContext then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) when "merge_request" then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) + when "wiki" + then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] end @notes = if last_id diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index cb1f7452..05f29da3 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -17,6 +17,7 @@ class CommitsController < ApplicationController @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @project.commits(@ref, params[:path], @limit, @offset) + @commits = CommitDecorator.decorate(@commits) respond_to do |format| format.html # index.html.erb @@ -51,6 +52,8 @@ class CommitsController < ApplicationController @commit = result[:commit] @diffs = result[:diffs] @line_notes = [] + + @commits = CommitDecorator.decorate(@commits) end def patch diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 1cb1d388..f9a1c1dd 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -143,5 +143,6 @@ class MergeRequestsController < ApplicationController # Get commits from repository # or from cache if already merged @commits = @merge_request.commits + @commits = CommitDecorator.decorate(@commits) end end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index fb759c37..d19931e9 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -3,13 +3,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Extend the standard message generation to accept our custom exception def failure_message exception = env["omniauth.error"] - if exception.class == OmniAuth::Error - error = exception.message - else - error = exception.error_reason if exception.respond_to?(:error_reason) - error ||= exception.error if exception.respond_to?(:error) - error ||= env["omniauth.error.type"].to_s - end + error = exception.error_reason if exception.respond_to?(:error_reason) + error ||= exception.error if exception.respond_to?(:error) + error ||= exception.message if exception.respond_to?(:message) + error ||= env["omniauth.error.type"].to_s error.to_s.humanize if error end diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index b610c9f3..d180e708 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -51,7 +51,8 @@ class RefsController < ApplicationController @logs = contents.map do |content| file = params[:path] ? File.join(params[:path], content.name) : content.name last_commit = @project.commits(@commit.id, file, 1).last - { + last_commit = CommitDecorator.decorate(last_commit) + { :file_name => content.name, :commit => last_commit } diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb index 9bcd20c3..1fa38034 100644 --- a/app/controllers/wikis_controller.rb +++ b/app/controllers/wikis_controller.rb @@ -13,16 +13,16 @@ class WikisController < ApplicationController @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last end - unless @wiki - return render_404 unless can?(current_user, :write_wiki, @project) - end + @note = @project.notes.new(:noteable => @wiki) - respond_to do |format| - if @wiki - format.html - else + if @wiki + render 'show' + else + if can?(current_user, :write_wiki, @project) @wiki = @project.wikis.new(:slug => params[:id]) - format.html { render "edit" } + render 'edit' + else + render 'empty' end end end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index c673eb3d..2ce940c3 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -46,6 +46,13 @@ class Notify < ActionMailer::Base mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ") end + def note_wiki_email(recipient_id, note_id) + recipient = User.find(recipient_id) + @note = Note.find(note_id) + @wiki = @note.noteable + mail(:to => recipient.email, :subject => "gitlab | note for wiki | #{@note.project_name}") + end + def new_merge_request_email(merge_request_id) @merge_request = MergeRequest.find(merge_request_id) mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ") diff --git a/app/models/commit.rb b/app/models/commit.rb index 859bee29..71c41350 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -114,6 +114,10 @@ class Commit @head = head end + def short_id(length = 10) + id.to_s[0..length] + end + def safe_message utf8 message end @@ -150,4 +154,8 @@ class Commit def prev_commit_id prev_commit.try :id end + + def parents_count + parents && parents.count || 0 + end end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index ecc46fb4..d9ec069d 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -1,6 +1,7 @@ class Wiki < ActiveRecord::Base belongs_to :project belongs_to :user + has_many :notes, :as => :noteable, :dependent => :destroy validates :content, :title, :user_id, :presence => true validates :title, :length => 1..250 diff --git a/app/observers/mailer_observer.rb b/app/observers/mailer_observer.rb index 451deccd..b6f52178 100644 --- a/app/observers/mailer_observer.rb +++ b/app/observers/mailer_observer.rb @@ -34,6 +34,7 @@ class MailerObserver < ActiveRecord::Observer case note.noteable_type when "Commit"; Notify.note_commit_email(u.id, note.id).deliver when "Issue"; Notify.note_issue_email(u.id, note.id).deliver + when "Wiki"; Notify.note_wiki_email(u.id, note.id).deliver when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver when "Snippet"; true else diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 9f9502e3..98241614 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -2,16 +2,15 @@ .browse_code_link_holder %p %strong= link_to "Browse Code ยป", tree_project_ref_path(@project, commit.id), :class => "right" - = link_to project_commit_path(@project, :id => commit.id) do - %p - %code.left= commit.id.to_s[0..10] - %strong.cgray= commit.author_name - – - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 - %span.row_title= truncate(commit.safe_message, :length => 50) + %p + = link_to commit.short_id(8), project_commit_path(@project, :id => commit.id), :class => "commit_short_id" + %strong.cgray= commit.author_name + – + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 + = link_to truncate(commit.title, :length => 50), project_commit_path(@project, :id => commit.id), :class => "row_title" - %span.committed_ago - = time_ago_in_words(commit.committed_date) - ago -   + %span.committed_ago + = time_ago_in_words(commit.committed_date) + ago +   diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 8ccb3f1b..6994de4a 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -1,4 +1,4 @@ -.commit-box{class: @commit.parents.count > 1 ? "merge-commit" : ""} +.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""} .commit-head .right - if @notes_count > 0 diff --git a/app/views/commits/compare.html.haml b/app/views/commits/compare.html.haml index 66ed8dad..04d8af54 100644 --- a/app/views/commits/compare.html.haml +++ b/app/views/commits/compare.html.haml @@ -24,8 +24,9 @@ - unless @commits.empty? - %h4 Commits (#{@commits.count}) - %ul.unstyled= render @commits + %div.ui-box + %h5.small Commits (#{@commits.count}) + %ul.unstyled= render @commits - unless @diffs.empty? %h4 Diff diff --git a/app/views/commits/index.atom.builder b/app/views/commits/index.atom.builder index 2a352dac..86c9fc04 100644 --- a/app/views/commits/index.atom.builder +++ b/app/views/commits/index.atom.builder @@ -10,14 +10,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.entry do xml.id project_commit_url(@project, :id => commit.id) xml.link :href => project_commit_url(@project, :id => commit.id) - xml.title truncate(commit.safe_message, :length => 80) + xml.title truncate(commit.title, :length => 80) xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email) xml.author do |author| xml.name commit.author_name xml.email commit.author_email end - xml.summary commit.safe_message + xml.summary commit.description end end end diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index ce3cd6b5..407bf532 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,6 +1,6 @@ %h3.page_title Merge Requests - %small (authored or assigned to you) + %small (authored by or assigned to you) %small.right #{@merge_requests.total_count} merge requests %br diff --git a/app/views/errors/gitolite.html.haml b/app/views/errors/gitolite.html.haml index ccee7573..eb09d214 100644 --- a/app/views/errors/gitolite.html.haml +++ b/app/views/errors/gitolite.html.haml @@ -1,19 +1,30 @@ .alert-message.block-message.error %h3 Gitolite Error - %hr %h4 Application cant get access to your gitolite system. - %ol - %li - %p - Check 'config/gitlab.yml' for correct settings. - %li - %p - Make sure web server user has access to gitolite. - %a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial - %li - %p - Try: + + + + +%h4 Tips for Administrator: + +%ul + %li + %p + Check git logs in admin area + %li + %p + Check config/gitlab.yml for correct settings. + %li + %p + Diagnostic tool: %pre - = preserve do - sudo chmod -R 770 /home/git/repositories/ - sudo chown -R git:git /home/git/repositories/ + bundle exec rake gitlab:app:status RAILS_ENV=production + %li + %p + Permissions: + %pre + = preserve do + sudo chmod -R 770 /home/git/repositories/ + sudo chown -R git:git /home/git/repositories/ + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive + diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml index 60112b50..d6c55461 100644 --- a/app/views/events/_commit.html.haml +++ b/app/views/events/_commit.html.haml @@ -1,9 +1,9 @@ +- commit = CommitDecorator.decorate(commit) %li.wll.commit - = link_to project_commit_path(project, :id => commit.id) do - %p - %code.left= commit.id.to_s[0..10] - %strong.cgray= commit.author_name - – - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 - %span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding" + %p + = link_to commit.short_id(8), project_commit_path(project, :id => commit.id), :class => "commit_short_id" + %strong.cdark= commit.author_name + – + = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 + = truncate(commit.title, :length => 50) rescue "--broken encoding" diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index 4964c1bb..e184df54 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -1,16 +1,18 @@ %h3 API .back_link - = link_to help_path do + = link_to help_path do ← to index %hr %ol - %li + %li %a{:href => "#README"} README - %li + %li %a{:href => "#projects"} Projects - %li + %li %a{:href => "#users"} Users + %li + %a{:href => "#issues"} Issues .file_holder#README .file_title @@ -39,3 +41,13 @@ .file_content.wiki = preserve do = markdown File.read(Rails.root.join("doc", "api", "users.md")) + +%br + +.file_holder#issues + .file_title + %i.icon-file + Issues + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "issues.md")) diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml index 860cfc86..7511d15d 100644 --- a/app/views/help/permissions.html.haml +++ b/app/views/help/permissions.html.haml @@ -38,7 +38,6 @@ %li Push to non-protected branches %li Remove non-protected branches %li Add tags - %li Create new merge request %li Write a wiki .ui-box.span3 @@ -55,7 +54,6 @@ %li Push to non-protected branches %li Remove non-protected branches %li Add tags - %li Create new merge request %li Write a wiki %li Add new team members %li Push to protected branches diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index e12c3c1a..18294af4 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -24,8 +24,7 @@ - else = image_tag "no_avatar.png", :class => "avatar" - = link_to project_issue_path(issue.project, issue) do - %p.row_title= truncate(issue.title, :length => 100) + %p= link_to truncate(issue.title, :length => 100), project_issue_path(issue.project, issue), :class => "row_title" %span.update-author %small.cdark= "##{issue.id}" diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 8ffc9c2b..4e8bcb89 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -46,9 +46,7 @@ - if @issue.milestone - milestone = @issue.milestone %cite.cgray and attached to milestone - = link_to project_milestone_path(milestone.project, milestone) do - %strong - = truncate(milestone.title, :length => 20) + %strong= link_to truncate(milestone.title, :length => 20), project_milestone_path(milestone.project, milestone) .right - @issue.labels.each do |label| diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index b9a005e0..5cd9b9b2 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -16,8 +16,7 @@ = merge_request.target_branch = image_tag gravatar_icon(merge_request.author_email), :class => "avatar" - = link_to project_merge_request_path(merge_request.project, merge_request) do - %p.row_title= truncate(merge_request.title, :length => 80) + %p= link_to truncate(merge_request.title, :length => 80), project_merge_request_path(merge_request.project, merge_request), :class => "row_title" %span.update-author %small.cdark= "##{merge_request.id}" diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 9912cf9e..81ec92ef 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -6,14 +6,13 @@ = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped" - if can? current_user, :admin_milestone, milestone.project = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped" - = link_to project_milestone_path(milestone.project, milestone) do - %h4.row_title - = truncate(milestone.title, :length => 100) - %small - = milestone.expires_at - %br - .progress.progress-success.span3 - .bar{:style => "width: #{milestone.percent_complete}%;"} + %h4 + = link_to truncate(milestone.title, :length => 100), project_milestone_path(milestone.project, milestone), :class => "row_title" + %small + = milestone.expires_at + %br + .progress.progress-success.span3 + .bar{:style => "width: #{milestone.percent_complete}%;"}   diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index dc3dcd01..7ec49b55 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -50,8 +50,8 @@ %td = link_to [@project, issue] do %span.badge.badge-info ##{issue.id} - – - = truncate issue.title, :length => 60 + – + = link_to truncate(issue.title, :length => 60), [@project, issue] %br = paginate @issues, :theme => "gitlab" diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index f5aa1495..aeaf57e6 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -1,5 +1,5 @@ = form_for [@project, @note], :remote => "true", :multipart => true do |f| - %h3 Leave a comment + %h3.page_title Leave a comment -if @note.errors.any? .alert-message.block-message.error - @note.errors.full_messages.each do |msg| diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml index 8beaf9b5..a5a70053 100644 --- a/app/views/notes/_per_line_form.html.haml +++ b/app/views/notes/_per_line_form.html.haml @@ -2,7 +2,7 @@ %tr.per_line_form %td{:colspan => 3 } = form_for [@project, @note], :remote => "true", :multipart => true do |f| - %h3 Leave a note + %h3.page_title Leave a note %div.span10 -if @note.errors.any? .alert-message.block-message.error @@ -13,19 +13,21 @@ = f.hidden_field :noteable_type = f.hidden_field :line_code = f.text_area :note, :size => 255 - %h5 Notify via email: - .clearfix - = label_tag :notify do - = check_box_tag :notify, 1, @note.noteable_type != "Commit" - %span Project team + .note_actions + .buttons + = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" + = link_to "Cancel", "#", :class => "btn hide-button" + .options + %h6.left Notify via email: + .labels + = label_tag :notify do + = check_box_tag :notify, 1, @note.noteable_type != "Commit" + %span Project team - - if @note.notify_only_author?(current_user) - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" - %span Commit author - .actions - = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" - = link_to "Close", "#", :class => "btn hide-button" + - if @note.notify_only_author?(current_user) + = label_tag :notify_author do + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" + %span Commit author :javascript $(function(){ diff --git a/app/views/notify/note_wiki_email.html.haml b/app/views/notify/note_wiki_email.html.haml new file mode 100644 index 00000000..91270682 --- /dev/null +++ b/app/views/notify/note_wiki_email.html.haml @@ -0,0 +1,24 @@ +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} + %tr + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{:align => "left", :style => "padding: 20px 0 0;"} + %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + New comment - + = link_to project_issue_url(@wiki.project, @wiki, :anchor => "note_#{@note.id}") do + = "Wiki ##{@wiki.title.to_s}" + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %tr + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{:style => "padding: 15px 0 15px;", :valign => "top"} + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + commented on Wiki page: + %br + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} + %tr + %td{:valign => "top"} + %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + = markdown(@note.note) + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml index d171b0d0..52424ae4 100644 --- a/app/views/projects/files.html.haml +++ b/app/views/projects/files.html.haml @@ -14,6 +14,6 @@ ago - else .alert-message.block-message - %p All files attached to project wall, issues etc will be displayed here + %span All files attached to project wall, issues etc will be displayed here diff --git a/app/views/refs/_tree_commit.html.haml b/app/views/refs/_tree_commit.html.haml index 1f2524a4..7da8ae1c 100644 --- a/app/views/refs/_tree_commit.html.haml +++ b/app/views/refs/_tree_commit.html.haml @@ -1,3 +1,3 @@ - if tm %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) -= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" += link_to truncate(content_commit.title, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" diff --git a/app/views/refs/blame.html.haml b/app/views/refs/blame.html.haml index 6a86b91f..0fc08e0c 100644 --- a/app/views/refs/blame.html.haml +++ b/app/views/refs/blame.html.haml @@ -25,15 +25,15 @@ %table - @blame.each do |commit, lines| - commit = Commit.new(commit) + - commit = CommitDecorator.decorate(commit) %tr %td.author = image_tag gravatar_icon(commit.author_email, 16) = commit.author_name %td.blame_commit   - = link_to project_commit_path(@project, :id => commit.id) do - %code= commit.id.to_s[0..10] - %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding" + %code= link_to commit.short_id, project_commit_path(@project, :id => commit.id) + = link_to truncate(commit.title, :length => 30), project_commit_path(@project, :id => commit.id), :class => "row_title" rescue "--broken encoding" %td.lines = preserve do %pre diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml index 4742b92b..3efe83ec 100644 --- a/app/views/repositories/_branch.html.haml +++ b/app/views/repositories/_branch.html.haml @@ -1,3 +1,5 @@ +- commit = Commit.new(branch.commit) +- commit = CommitDecorator.decorate(commit) %tr %td = link_to project_commits_path(@project, :ref => branch.name) do @@ -5,14 +7,14 @@ - if branch.name == @project.root_ref %span.label default %td - = link_to project_commit_path(@project, :id => branch.commit.id) do - %code= branch.commit.id.to_s[0..10] + = link_to project_commit_path(@project, :id => commit.id) do + %code= commit.short_id - = image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16 - = truncate(Commit.new(branch.commit).safe_message, :length => 40) + = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 + = truncate(commit.title, :length => 40) %td %span.update-author.right - = time_ago_in_words(branch.commit.committed_date) + = time_ago_in_words(commit.committed_date) ago %td - if can? current_user, :download_code, @project diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index 07343272..a9a11819 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -1,4 +1,5 @@ - commit = update +- commit = CommitDecorator.new(commit) %tr %td = link_to project_commits_path(@project, :ref => commit.head.name) do @@ -10,9 +11,9 @@ %td %div = link_to project_commits_path(@project, commit.id) do - %code= commit.id.to_s[0..10] + %code= commit.short_id = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 - = truncate(commit.safe_message, :length => 40) + = truncate(commit.title, :length => 40) %td %span.right.cgray = time_ago_in_words(commit.committed_date) diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml index 5e5cca31..d09c40e1 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -9,14 +9,15 @@ %th - @tags.each do |tag| - commit = Commit.new(tag.commit) + - commit = CommitDecorator.decorate(commit) %tr %td %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => "" %td = link_to project_commit_path(@project, commit.id) do - %code= commit.id.to_s[0..10] + %code= commit.short_id = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 - = truncate(commit.safe_message, :length => 40) + = truncate(commit.title, :length => 40) %td %span.update-author.right = time_ago_in_words(commit.committed_date) diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index dbb8648d..20b5b112 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -6,19 +6,21 @@ - @wiki.errors.full_messages.each do |msg| %li= msg - .alert-message.block-message.warning - %p - Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. - %br - To add link to new page you can just type - %code [Link Title](page-slug) - .clearfix - = f.label :title - .input= f.text_field :title, :class => :xxlarge - = f.hidden_field :slug - .clearfix - = f.label :content - .input= f.text_area :content, :class => :xxlarge + .main_box + .top_box_content + = f.label :title + .input= f.text_field :title, :class => 'span8' + = f.hidden_field :slug + .middle_box_content + .input + %span.cgray + Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. + To add link to new page you can just type + %code [Link Title](page-slug) + + .bottom_box_content + = f.label :content + .input= f.text_area :content, :class => 'span8' .actions = f.submit 'Save', :class => "primary btn" = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn" diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 26cbd52a..27d2a8f9 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,3 +1,3 @@ -%h3 Editing page +%h3.page_title Editing page %hr = render 'form' diff --git a/app/views/wikis/empty.html.haml b/app/views/wikis/empty.html.haml new file mode 100644 index 00000000..32b1c925 --- /dev/null +++ b/app/views/wikis/empty.html.haml @@ -0,0 +1,4 @@ +%h3.page_title Empty page +%hr +.alert-message.block-message.warning + %span You are not allowed to create wiki pages diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 6a9b56ae..2e46a90e 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -1,5 +1,6 @@ -%h3 Versions -%table +%h3.page_title Versions +%br +%table.admin-table %thead %tr %th # diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 9aa287df..3e922751 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -5,13 +5,18 @@ = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do History = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do + %i.icon-edit Edit -%hr -.wiki_content - = preserve do - = markdown @wiki.content +%br +.file_holder + .file_content.wiki + = preserve do + = markdown @wiki.content %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago - if can? current_user, :admin_wiki, @project = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do Delete this page + +%hr +.wiki_notes#notes= render "notes/notes", :tid => @wiki.id, :tt => "wiki" diff --git a/doc/api/README.md b/doc/api/README.md index dcf75afd..e0111966 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -27,3 +27,4 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) ++ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) diff --git a/doc/api/issues.md b/doc/api/issues.md new file mode 100644 index 00000000..aaad3305 --- /dev/null +++ b/doc/api/issues.md @@ -0,0 +1,184 @@ +## List issues + +Get all issues created by authenticed user. + +``` +GET /issues +``` + +```json +[ + { + "id": 43, + "project_id": 8, + "title": "4xx/5xx pages", + "description": "", + "labels": [ ], + "milestone": null, + "assignee": null, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": true, + "updated_at": "2012-07-02T17:53:12Z", + "created_at": "2012-07-02T17:53:12Z" + }, + { + "id": 42, + "project_id": 8, + "title": "Add user settings", + "description": "", + "labels": [ + "feature" + ], + "milestone": { + "id": 1, + "title": "v1.0", + "description": "", + "due_date": "2012-07-20", + "closed": false, + "updated_at": "2012-07-04T13:42:48Z", + "created_at": "2012-07-04T13:42:48Z" + }, + "assignee": { + "id": 2, + "email": "jack@example.com", + "name": "Jack Smith", + "blocked": false, + "created_at": "2012-05-23T08:01:01Z" + }, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": false, + "updated_at": "2012-07-12T13:43:19Z", + "created_at": "2012-06-28T12:58:06Z" + } +] +``` + +## List project issues + +Get a list of project issues. + +``` +GET /projects/:id/issues +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project + +## Single issue + +Get a project issue. + +``` +GET /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project issue + +```json +{ + "id": 42, + "project_id": 8, + "title": "Add user settings", + "description": "", + "labels": [ + "feature" + ], + "milestone": { + "id": 1, + "title": "v1.0", + "description": "", + "due_date": "2012-07-20", + "closed": false, + "updated_at": "2012-07-04T13:42:48Z", + "created_at": "2012-07-04T13:42:48Z" + }, + "assignee": { + "id": 2, + "email": "jack@example.com", + "name": "Jack Smith", + "blocked": false, + "created_at": "2012-05-23T08:01:01Z" + }, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": false, + "updated_at": "2012-07-12T13:43:19Z", + "created_at": "2012-06-28T12:58:06Z" +} +``` + +## New issue + +Create a new project issue. + +``` +POST /projects/:id/issues +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `title` (required) - The title of an issue ++ `description` (optional) - The description of an issue ++ `assignee_id` (optional) - The ID of a user to assign issue ++ `milestone_id` (optional) - The ID of a milestone to assign issue ++ `labels` (optional) - Comma-separated label names for an issue + +Will return created issue with status `201 Created` on success, or `404 Not found` on fail. + +## Edit issue + +Update an existing project issue. + +``` +PUT /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project's issue ++ `title` (optional) - The title of an issue ++ `description` (optional) - The description of an issue ++ `assignee_id` (optional) - The ID of a user to assign issue ++ `milestone_id` (optional) - The ID of a milestone to assign issue ++ `labels` (optional) - Comma-separated label names for an issue ++ `closed` (optional) - The state of an issue (0 = false, 1 = true) + +Will return updated issue with status `200 OK` on success, or `404 Not found` on fail. + +## Delete issue + +Delete existing project issue. + +``` +DELETE /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project's issue + +Status code `200` will be returned on success. diff --git a/doc/api/projects.md b/doc/api/projects.md index c748745e..cd94cd42 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1,6 +1,6 @@ ## List projects -Get a list of authenticated users' projects. +Get a list of authenticated user's projects. ``` GET /projects @@ -63,7 +63,7 @@ GET /projects/:id Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json { @@ -91,7 +91,7 @@ Parameters: ## Project repository branches -Get a list of project repository branches. +Get a list of project repository branches sorted by name alphabetically. ``` GET /projects/:id/repository/branches @@ -99,7 +99,7 @@ GET /projects/:id/repository/branches Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json [ @@ -131,7 +131,7 @@ Parameters: ## Project repository tags -Get a list of project repository tags. +Get a list of project repository tags sorted by name in reverse alphabetical order. ``` GET /projects/:id/repository/tags @@ -139,7 +139,7 @@ GET /projects/:id/repository/tags Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json [ @@ -183,7 +183,7 @@ GET /projects/:id/snippets/:snippet_id Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project + `snippet_id` (required) - The ID of a project's snippet ```json @@ -214,7 +214,7 @@ GET /projects/:id/snippets/:snippet_id/raw Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project + `snippet_id` (required) - The ID of a project's snippet ## New snippet @@ -227,7 +227,7 @@ POST /projects/:id/snippets Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project + `title` (required) - The title of a snippet + `file_name` (required) - The name of a snippet file + `lifetime` (optional) - The expiration date of a snippet @@ -245,7 +245,7 @@ PUT /projects/:id/snippets/:snippet_id Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project + `snippet_id` (required) - The ID of a project's snippet + `title` (optional) - The title of a snippet + `file_name` (optional) - The name of a snippet file @@ -264,7 +264,7 @@ DELETE /projects/:id/snippets/:snippet_id Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project + `snippet_id` (required) - The ID of a project's snippet Status code `200` will be returned on success. diff --git a/doc/installation.md b/doc/installation.md index 3dfedfe1..cb54663e 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -119,6 +119,7 @@ Permissions: sudo chmod -R g+rwX /home/git/repositories/ sudo chown -R git:git /home/git/repositories/ + sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive #### CHECK: Logout & login again to apply git group to your user diff --git a/features/step_definitions/project_commits_steps.rb b/features/step_definitions/project_commits_steps.rb index 9bfccfc0..9b3b0aa1 100644 --- a/features/step_definitions/project_commits_steps.rb +++ b/features/step_definitions/project_commits_steps.rb @@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do end Then /^I see commits atom feed$/ do - commit = @project.commit + commit = CommitDecorator.decorate(@project.commit) page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) + page.body.should have_selector("entry summary", :text => commit.description) end Given /^I click on commit link$/ do diff --git a/lib/api.rb b/lib/api.rb index e24e0a78..6a8a3d65 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -15,5 +15,6 @@ module Gitlab mount Users mount Projects + mount Issues end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 35ad4d43..d86fb79c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -16,11 +16,7 @@ module Gitlab expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at end - class ProjectRepositoryBranches < Grape::Entity - expose :name, :commit - end - - class ProjectRepositoryTags < Grape::Entity + class RepoObject < Grape::Entity expose :name, :commit end @@ -29,5 +25,19 @@ module Gitlab expose :author, :using => Entities::UserBasic expose :expires_at, :updated_at, :created_at end + + class Milestone < Grape::Entity + expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at + end + + class Issue < Grape::Entity + expose :id + expose (:project_id) {|issue| issue.project.id} + expose :title, :description + expose :label_list, :as => :labels + expose :milestone, :using => Entities::Milestone + expose :assignee, :author, :using => Entities::UserBasic + expose :closed, :updated_at, :created_at + end end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 424a17b2..c1ea0566 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -4,6 +4,16 @@ module Gitlab @current_user ||= User.find_by_authentication_token(params[:private_token]) end + def user_project + if @project ||= current_user.projects.find_by_id(params[:id]) || + current_user.projects.find_by_code(params[:id]) + else + error!({'message' => '404 Not found'}, 404) + end + + @project + end + def authenticate! error!({'message' => '401 Unauthorized'}, 401) unless current_user end diff --git a/lib/api/issues.rb b/lib/api/issues.rb new file mode 100644 index 00000000..dcb6e535 --- /dev/null +++ b/lib/api/issues.rb @@ -0,0 +1,111 @@ +module Gitlab + # Issues API + class Issues < Grape::API + before { authenticate! } + + resource :issues do + # Get currently authenticated user's issues + # + # Example Request: + # GET /issues + get do + present current_user.issues, :with => Entities::Issue + end + end + + resource :projects do + # Get a list of project issues + # + # Parameters: + # id (required) - The ID or code name of a project + # Example Request: + # GET /projects/:id/issues + get ":id/issues" do + present user_project.issues, :with => Entities::Issue + end + + # Get a single project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # Example Request: + # GET /projects/:id/issues/:issue_id + get ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + present @issue, :with => Entities::Issue + end + + # Create a new project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # title (required) - The title of an issue + # description (optional) - The description of an issue + # assignee_id (optional) - The ID of a user to assign issue + # milestone_id (optional) - The ID of a milestone to assign issue + # labels (optional) - The labels of an issue + # Example Request: + # POST /projects/:id/issues + post ":id/issues" do + @issue = user_project.issues.new( + :title => params[:title], + :description => params[:description], + :assignee_id => params[:assignee_id], + :milestone_id => params[:milestone_id], + :label_list => params[:labels] + ) + @issue.author = current_user + + if @issue.save + present @issue, :with => Entities::Issue + else + error!({'message' => '404 Not found'}, 404) + end + end + + # Update an existing issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # title (optional) - The title of an issue + # description (optional) - The description of an issue + # assignee_id (optional) - The ID of a user to assign issue + # milestone_id (optional) - The ID of a milestone to assign issue + # labels (optional) - The labels of an issue + # closed (optional) - The state of an issue (0 = false, 1 = true) + # Example Request: + # PUT /projects/:id/issues/:issue_id + put ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + parameters = { + :title => (params[:title] || @issue.title), + :description => (params[:description] || @issue.description), + :assignee_id => (params[:assignee_id] || @issue.assignee_id), + :milestone_id => (params[:milestone_id] || @issue.milestone_id), + :label_list => (params[:labels] || @issue.label_list), + :closed => (params[:closed] || @issue.closed) + } + + if @issue.update_attributes(parameters) + present @issue, :with => Entities::Issue + else + error!({'message' => '404 Not found'}, 404) + end + end + + # Delete a project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # Example Request: + # DELETE /projects/:id/issues/:issue_id + delete ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + @issue.destroy + end + end + end +end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 70f8fa2a..8edfa481 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -16,53 +16,49 @@ module Gitlab # Get a single project # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id get ":id" do - @project = current_user.projects.find_by_code(params[:id]) - present @project, :with => Entities::Project + present user_project, :with => Entities::Project end # Get a project repository branches # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id/repository/branches get ":id/repository/branches" do - @project = current_user.projects.find_by_code(params[:id]) - present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches + present user_project.repo.heads.sort_by(&:name), :with => Entities::RepoObject end # Get a project repository tags # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id/repository/tags get ":id/repository/tags" do - @project = current_user.projects.find_by_code(params[:id]) - present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags + present user_project.repo.tags.sort_by(&:name).reverse, :with => Entities::RepoObject end # Get a project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id get ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) present @snippet, :with => Entities::ProjectSnippet end # Create a new project snippet # # Parameters: - # id (required) - The code name of a project + # id (required) - The ID or code name of a project # title (required) - The title of a snippet # file_name (required) - The name of a snippet file # lifetime (optional) - The expiration date of a snippet @@ -70,8 +66,7 @@ module Gitlab # Example Request: # POST /projects/:id/snippets post ":id/snippets" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.new( + @snippet = user_project.snippets.new( :title => params[:title], :file_name => params[:file_name], :expires_at => params[:lifetime], @@ -89,7 +84,7 @@ module Gitlab # Update an existing project snippet # # Parameters: - # id (required) - The code name of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # title (optional) - The title of a snippet # file_name (optional) - The name of a snippet file @@ -98,8 +93,7 @@ module Gitlab # Example Request: # PUT /projects/:id/snippets/:snippet_id put ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) parameters = { :title => (params[:title] || @snippet.title), :file_name => (params[:file_name] || @snippet.file_name), @@ -117,26 +111,24 @@ module Gitlab # Delete a project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) @snippet.destroy end # Get a raw project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id/raw get ":id/snippets/:snippet_id/raw" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) present @snippet.content end end diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb index aff13baf..c3a19e71 100644 --- a/lib/gitlab/logger.rb +++ b/lib/gitlab/logger.rb @@ -10,6 +10,7 @@ module Gitlab def self.read_latest path = Rails.root.join("log/githost.log") + self.build unless File.exist?(path) logs = File.read(path).split("\n") end diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 014483d4..d9053c23 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -121,7 +121,7 @@ namespace :gitlab do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) puts "Dumping repositories:" - project = Project.all.map { |n| [n.name,n.path_to_repo] } + project = Project.all.map { |n| [n.path,n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Dumping repository #{project.first}... " @@ -136,12 +136,18 @@ namespace :gitlab do task :repo_restore => :environment do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") puts "Restoring repositories:" - project = Project.all.map { |n| [n.name,n.path_to_repo] } + project = Project.all.map { |n| [n.path,n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Restoring repository #{project.first}... " FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") + permission_commands = [ + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}", + "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive" + ] + permission_commands.each { |command| Kernel.system(command) } puts "[DONE]".green else puts "[FAILED]".red diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake index ac712234..96b8886f 100644 --- a/lib/tasks/gitlab/status.rake +++ b/lib/tasks/gitlab/status.rake @@ -2,7 +2,7 @@ namespace :gitlab do namespace :app do desc "GITLAB | Check gitlab installation status" task :status => :environment do - puts "Starting diagnostic" + puts "Starting diagnostic".yellow git_base_path = Gitlab.config.git_base_path print "config/database.yml............" @@ -56,7 +56,28 @@ namespace :gitlab do return end - puts "\nFinished" + if Project.count > 0 + puts "Validating projects repositories:".yellow + Project.find_each(:batch_size => 100) do |project| + print "#{project.name}....." + hook_file = File.join(project.path_to_repo, 'hooks','post-receive') + + unless File.exists?(hook_file) + puts "post-receive file missing".red + next + end + + + unless File.owned?(hook_file) + puts "post-receive file is not owner by gitlab".red + next + end + + puts "post-reveice file ok".green + end + end + + puts "\nFinished".blue end end end diff --git a/spec/api/issues_spec.rb b/spec/api/issues_spec.rb new file mode 100644 index 00000000..d81a07e2 --- /dev/null +++ b/spec/api/issues_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Gitlab::API do + let(:user) { Factory :user } + let!(:project) { Factory :project, :owner => user } + let!(:issue) { Factory :issue, :author => user, :assignee => user, :project => project } + before { project.add_access(user, :read) } + + describe "GET /issues" do + it "should return authentication error" do + get "#{api_prefix}/issues" + response.status.should == 401 + end + + describe "authenticated GET /issues" do + it "should return an array of issues" do + get "#{api_prefix}/issues?private_token=#{user.private_token}" + response.status.should == 200 + json_response.should be_an Array + json_response.first['title'].should == issue.title + end + end + end + + describe "GET /projects/:id/issues" do + it "should return project issues" do + get "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}" + response.status.should == 200 + json_response.should be_an Array + json_response.first['title'].should == issue.title + end + end + + describe "GET /projects/:id/issues/:issue_id" do + it "should return a project issue by id" do + get "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}" + response.status.should == 200 + json_response['title'].should == issue.title + end + end + + describe "POST /projects/:id/issues" do + it "should create a new project issue" do + post "#{api_prefix}/projects/#{project.code}/issues?private_token=#{user.private_token}", + :title => 'new issue', :labels => 'label, label2' + response.status.should == 201 + json_response['title'].should == 'new issue' + json_response['description'].should be_nil + json_response['labels'].should == ['label', 'label2'] + end + end + + describe "PUT /projects/:id/issues/:issue_id" do + it "should update a project issue" do + put "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}", + :title => 'updated title', :labels => 'label2', :closed => 1 + response.status.should == 200 + json_response['title'].should == 'updated title' + json_response['labels'].should == ['label2'] + json_response['closed'].should be_true + end + end + + describe "DELETE /projects/:id/issues/:issue_id" do + it "should delete a project issue" do + expect { + delete "#{api_prefix}/projects/#{project.code}/issues/#{issue.id}?private_token=#{user.private_token}" + }.to change { Issue.count }.by(-1) + end + end +end diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb index 9998ee50..8852a0d3 100644 --- a/spec/api/projects_spec.rb +++ b/spec/api/projects_spec.rb @@ -25,11 +25,23 @@ describe Gitlab::API do describe "GET /projects/:id" do it "should return a project by id" do - get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" + get "#{api_prefix}/projects/#{project.id}?private_token=#{user.private_token}" response.status.should == 200 json_response['name'].should == project.name json_response['owner']['email'].should == user.email end + + it "should return a project by code name" do + get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" + response.status.should == 200 + json_response['name'].should == project.name + end + + it "should return a 404 error if not found" do + get "#{api_prefix}/projects/42?private_token=#{user.private_token}" + response.status.should == 404 + json_response['message'].should == '404 Not found' + end end describe "GET /projects/:id/repository/branches" do diff --git a/spec/requests/commits_spec.rb b/spec/requests/commits_spec.rb index 00b69379..ae36a932 100644 --- a/spec/requests/commits_spec.rb +++ b/spec/requests/commits_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe "Commits" do let(:project) { Factory :project } - let!(:commit) { project.commit } + let!(:commit) { CommitDecorator.decorate(project.commit) } before do login_as :user project.add_access(@user, :read) @@ -22,8 +22,8 @@ describe "Commits" do end it "should list commits" do - page.should have_content(commit.message) - page.should have_content(commit.id.to_s[0..5]) + page.should have_content(commit.description) + page.should have_content(commit.short_id(8)) end it "should render atom feed" do @@ -32,7 +32,7 @@ describe "Commits" do page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{project.name}") page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) + page.body.should have_selector("entry summary", :text => commit.description) end it "should render atom feed via private token" do @@ -42,7 +42,7 @@ describe "Commits" do page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{project.name}") page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) + page.body.should have_selector("entry summary", :text => commit.description) end end diff --git a/spec/requests/wikis_notes_spec.rb b/spec/requests/wikis_notes_spec.rb new file mode 100644 index 00000000..144d0318 --- /dev/null +++ b/spec/requests/wikis_notes_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe "Wikis" do + let(:project) { Factory :project } + + before do + login_as :user + project.add_access(@user, :read, :write) + end + + describe "add new note", :js => true do + before do + visit project_wiki_path(project, :index) + + fill_in "Title", :with => 'Test title' + fill_in "Content", :with => '[link test](test)' + click_on "Save" + + page.should have_content("Test title") + + fill_in "note_note", :with => "Comment on wiki!" + click_button "Add Comment" + end + + it "should contain the new note" do + page.should have_content("Comment on wiki!") + end + end +end