Commit 35d0de8f367e949c3bab50506916ca87eeb5d5ab
Exists in
master
and in
4 other branches
merging upstream changes
Showing
49 changed files
with
511 additions
and
168 deletions
Show diff stats
app/assets/javascripts/application.js
| @@ -11,6 +11,7 @@ | @@ -11,6 +11,7 @@ | ||
| 11 | //= require jquery.tagify | 11 | //= require jquery.tagify |
| 12 | //= require jquery.cookie | 12 | //= require jquery.cookie |
| 13 | //= require jquery.endless-scroll | 13 | //= require jquery.endless-scroll |
| 14 | +//= require jquery.highlight | ||
| 14 | //= require bootstrap-modal | 15 | //= require bootstrap-modal |
| 15 | //= require modernizr | 16 | //= require modernizr |
| 16 | //= require chosen | 17 | //= require chosen |
app/assets/javascripts/merge_requests.js
| @@ -11,7 +11,7 @@ var MergeRequest = { | @@ -11,7 +11,7 @@ var MergeRequest = { | ||
| 11 | 11 | ||
| 12 | $(".tabs a.merge-notes-tab").live("click", function(e) { | 12 | $(".tabs a.merge-notes-tab").live("click", function(e) { |
| 13 | $(".merge-request-diffs").hide(); | 13 | $(".merge-request-diffs").hide(); |
| 14 | - $(".merge-request-notes").show(); | 14 | + $(".merge_request_notes").show(); |
| 15 | e.preventDefault(); | 15 | e.preventDefault(); |
| 16 | }); | 16 | }); |
| 17 | 17 | ||
| @@ -19,7 +19,7 @@ var MergeRequest = { | @@ -19,7 +19,7 @@ var MergeRequest = { | ||
| 19 | if(!MergeRequest.diffs_loaded) { | 19 | if(!MergeRequest.diffs_loaded) { |
| 20 | MergeRequest.loadDiff(); | 20 | MergeRequest.loadDiff(); |
| 21 | } | 21 | } |
| 22 | - $(".merge-request-notes").hide(); | 22 | + $(".merge_request_notes").hide(); |
| 23 | $(".merge-request-diffs").show(); | 23 | $(".merge-request-diffs").show(); |
| 24 | e.preventDefault(); | 24 | e.preventDefault(); |
| 25 | }); | 25 | }); |
| @@ -33,7 +33,7 @@ var MergeRequest = { | @@ -33,7 +33,7 @@ var MergeRequest = { | ||
| 33 | url: $(".merge-diffs-tab").attr("data-url"), | 33 | url: $(".merge-diffs-tab").attr("data-url"), |
| 34 | complete: function(){ | 34 | complete: function(){ |
| 35 | MergeRequest.diffs_loaded = true; | 35 | MergeRequest.diffs_loaded = true; |
| 36 | - $(".merge-request-notes").hide(); | 36 | + $(".merge_request_notes").hide(); |
| 37 | $(".dashboard-loader").hide()}, | 37 | $(".dashboard-loader").hide()}, |
| 38 | dataType: "script"}); | 38 | dataType: "script"}); |
| 39 | } | 39 | } |
app/assets/stylesheets/common.scss
| @@ -3,7 +3,7 @@ a { | @@ -3,7 +3,7 @@ a { | ||
| 3 | color: $link_color; | 3 | color: $link_color; |
| 4 | &:hover { | 4 | &:hover { |
| 5 | text-decoration:none; | 5 | text-decoration:none; |
| 6 | - color: $style_color; | 6 | + color: $blue_link; |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | &.btn { | 9 | &.btn { |
| @@ -11,6 +11,18 @@ a { | @@ -11,6 +11,18 @@ a { | ||
| 11 | } | 11 | } |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | +.btn { | ||
| 15 | + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f1f1f1), color-stop(25%, #f1f1f1), to(#e6e6e6)); | ||
| 16 | + background-image: -webkit-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); | ||
| 17 | + background-image: -moz-linear-gradient(top, #f1f1f1, #f1f1f1 25%, #e6e6e6); | ||
| 18 | + background-image: -ms-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); | ||
| 19 | + background-image: -o-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); | ||
| 20 | + background-image: linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); | ||
| 21 | + | ||
| 22 | + &:hover { | ||
| 23 | + } | ||
| 24 | +} | ||
| 25 | + | ||
| 14 | a:focus { | 26 | a:focus { |
| 15 | outline: none; | 27 | outline: none; |
| 16 | } | 28 | } |
| @@ -29,6 +41,29 @@ a:focus { | @@ -29,6 +41,29 @@ a:focus { | ||
| 29 | 41 | ||
| 30 | .label { | 42 | .label { |
| 31 | background-color: #474D57; | 43 | background-color: #474D57; |
| 44 | + | ||
| 45 | + &.pushed { | ||
| 46 | + background-color: $link_color; | ||
| 47 | + } | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +.pretty_label { | ||
| 51 | + @include round-borders-all(4px); | ||
| 52 | + padding:2px 4px; | ||
| 53 | + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | ||
| 54 | + background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 55 | + background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 56 | + background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 57 | + color: #777; | ||
| 58 | + border: 1px solid #DEDFE1; | ||
| 59 | + | ||
| 60 | + &.branch { | ||
| 61 | + border:none; | ||
| 62 | + font-size:13px; | ||
| 63 | + background: #474D57; | ||
| 64 | + color:#fff; | ||
| 65 | + font-family: monospace; | ||
| 66 | + } | ||
| 32 | } | 67 | } |
| 33 | 68 | ||
| 34 | .tabs > li > a, .pills > li > a { | 69 | .tabs > li > a, .pills > li > a { |
| @@ -807,12 +842,19 @@ p.time { | @@ -807,12 +842,19 @@ p.time { | ||
| 807 | width:840px; | 842 | width:840px; |
| 808 | margin:auto; | 843 | margin:auto; |
| 809 | 844 | ||
| 810 | - .wll { | ||
| 811 | - padding:5px; | ||
| 812 | - margin-top:5px; | 845 | + .dash_project_item { |
| 846 | + margin-bottom:10px; | ||
| 813 | border:none; | 847 | border:none; |
| 814 | &:hover { | 848 | &:hover { |
| 815 | background:none; | 849 | background:none; |
| 850 | + | ||
| 851 | + h4 { | ||
| 852 | + color:#2FA0BB; | ||
| 853 | + .arrow { | ||
| 854 | + background:#2FA0BB; | ||
| 855 | + color:#fff; | ||
| 856 | + } | ||
| 857 | + } | ||
| 816 | } | 858 | } |
| 817 | 859 | ||
| 818 | h4 { | 860 | h4 { |
| @@ -887,7 +929,7 @@ p.time { | @@ -887,7 +929,7 @@ p.time { | ||
| 887 | } | 929 | } |
| 888 | a:last-child h4 { border:none; } | 930 | a:last-child h4 { border:none; } |
| 889 | 931 | ||
| 890 | - a.active { | 932 | + a:hover { |
| 891 | h4 { | 933 | h4 { |
| 892 | color:#111; | 934 | color:#111; |
| 893 | border-right:4px solid $styled_border_color; | 935 | border-right:4px solid $styled_border_color; |
| @@ -974,3 +1016,32 @@ p.time { | @@ -974,3 +1016,32 @@ p.time { | ||
| 974 | } | 1016 | } |
| 975 | } | 1017 | } |
| 976 | } | 1018 | } |
| 1019 | + | ||
| 1020 | +.highlight_word { | ||
| 1021 | + background:#EEDC94; | ||
| 1022 | +} | ||
| 1023 | + | ||
| 1024 | +.status_info { | ||
| 1025 | + font-size:14px; | ||
| 1026 | + padding:5px 15px; | ||
| 1027 | + line-height:24px; | ||
| 1028 | + width:60px; | ||
| 1029 | + text-align:center; | ||
| 1030 | + float:left; | ||
| 1031 | + margin-right:20px; | ||
| 1032 | +} | ||
| 1033 | + | ||
| 1034 | +.merge_request_status_holder { | ||
| 1035 | + margin-bottom:20px; | ||
| 1036 | +} | ||
| 1037 | + | ||
| 1038 | +.arrow{ | ||
| 1039 | + float: right; | ||
| 1040 | + background: #E3E5EA; | ||
| 1041 | + padding: 10px; | ||
| 1042 | + border-radius: 5px; | ||
| 1043 | + text-shadow: none; | ||
| 1044 | + color: #999; | ||
| 1045 | + line-height: 16px; | ||
| 1046 | + font-weight:bold; | ||
| 1047 | +} |
app/assets/stylesheets/main.scss
| @@ -15,7 +15,7 @@ $app_padding:20px; | @@ -15,7 +15,7 @@ $app_padding:20px; | ||
| 15 | $bg_color: #FFF; | 15 | $bg_color: #FFF; |
| 16 | $styled_border_color: #2FA0BB; | 16 | $styled_border_color: #2FA0BB; |
| 17 | $color: "#4BB8D2"; | 17 | $color: "#4BB8D2"; |
| 18 | -$blue_link: "#2fa0bb"; | 18 | +$blue_link: #2fa0bb; |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | /** Style colors **/ | 21 | /** Style colors **/ |
app/assets/stylesheets/ui_basic.scss
app/controllers/dashboard_controller.rb
| @@ -18,7 +18,7 @@ class DashboardController < ApplicationController | @@ -18,7 +18,7 @@ class DashboardController < ApplicationController | ||
| 18 | # Get authored or assigned open merge requests | 18 | # Get authored or assigned open merge requests |
| 19 | def merge_requests | 19 | def merge_requests |
| 20 | @projects = current_user.projects.all | 20 | @projects = current_user.projects.all |
| 21 | - @merge_requests = MergeRequest.where("author_id = :id or assignee_id = :id", :id => current_user.id).opened.order("created_at DESC").limit(40) | 21 | + @merge_requests = current_user.cared_merge_requests.order("created_at DESC").limit(40) |
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | # Get only assigned issues | 24 | # Get only assigned issues |
app/controllers/merge_requests_controller.rb
| @@ -41,13 +41,9 @@ class MergeRequestsController < ApplicationController | @@ -41,13 +41,9 @@ class MergeRequestsController < ApplicationController | ||
| 41 | 41 | ||
| 42 | @note = @project.notes.new(:noteable => @merge_request) | 42 | @note = @project.notes.new(:noteable => @merge_request) |
| 43 | 43 | ||
| 44 | - @commits = @project.repo. | ||
| 45 | - commits_between(@merge_request.target_branch, @merge_request.source_branch). | ||
| 46 | - map {|c| Commit.new(c)}. | ||
| 47 | - sort_by(&:created_at). | ||
| 48 | - reverse | ||
| 49 | - | ||
| 50 | - render_full_content | 44 | + # Get commits from repository |
| 45 | + # or from cache if already merged | ||
| 46 | + @commits = @merge_request.commits | ||
| 51 | 47 | ||
| 52 | respond_to do |format| | 48 | respond_to do |format| |
| 53 | format.html | 49 | format.html |
| @@ -76,6 +72,7 @@ class MergeRequestsController < ApplicationController | @@ -76,6 +72,7 @@ class MergeRequestsController < ApplicationController | ||
| 76 | 72 | ||
| 77 | respond_to do |format| | 73 | respond_to do |format| |
| 78 | if @merge_request.save | 74 | if @merge_request.save |
| 75 | + @merge_request.reload_code | ||
| 79 | format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' } | 76 | format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' } |
| 80 | format.json { render json: @merge_request, status: :created, location: @merge_request } | 77 | format.json { render json: @merge_request, status: :created, location: @merge_request } |
| 81 | else | 78 | else |
| @@ -88,6 +85,7 @@ class MergeRequestsController < ApplicationController | @@ -88,6 +85,7 @@ class MergeRequestsController < ApplicationController | ||
| 88 | def update | 85 | def update |
| 89 | respond_to do |format| | 86 | respond_to do |format| |
| 90 | if @merge_request.update_attributes(params[:merge_request].merge(:author_id_of_changes => current_user.id)) | 87 | if @merge_request.update_attributes(params[:merge_request].merge(:author_id_of_changes => current_user.id)) |
| 88 | + @merge_request.reload_code | ||
| 91 | format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' } | 89 | format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' } |
| 92 | format.json { head :ok } | 90 | format.json { head :ok } |
| 93 | else | 91 | else |
app/controllers/projects_controller.rb
| @@ -13,6 +13,7 @@ class ProjectsController < ApplicationController | @@ -13,6 +13,7 @@ class ProjectsController < ApplicationController | ||
| 13 | def index | 13 | def index |
| 14 | @projects = current_user.projects | 14 | @projects = current_user.projects |
| 15 | @projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse | 15 | @projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse |
| 16 | + @events = Event.where(:project_id => @projects.map(&:id)).recent.limit(40) | ||
| 16 | end | 17 | end |
| 17 | 18 | ||
| 18 | def new | 19 | def new |
| @@ -78,7 +79,6 @@ class ProjectsController < ApplicationController | @@ -78,7 +79,6 @@ class ProjectsController < ApplicationController | ||
| 78 | render "projects/empty" | 79 | render "projects/empty" |
| 79 | end | 80 | end |
| 80 | end | 81 | end |
| 81 | - format.js | ||
| 82 | end | 82 | end |
| 83 | end | 83 | end |
| 84 | 84 |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +class SearchController < ApplicationController | ||
| 2 | + def show | ||
| 3 | + query = params[:search] | ||
| 4 | + if query.blank? | ||
| 5 | + @projects = [] | ||
| 6 | + @merge_requests = [] | ||
| 7 | + else | ||
| 8 | + @projects = Project.search(query).limit(10) | ||
| 9 | + @merge_requests = MergeRequest.search(query).limit(10) | ||
| 10 | + end | ||
| 11 | + end | ||
| 12 | +end |
app/models/event.rb
| @@ -7,6 +7,7 @@ class Event < ActiveRecord::Base | @@ -7,6 +7,7 @@ class Event < ActiveRecord::Base | ||
| 7 | Reopened = 4 | 7 | Reopened = 4 |
| 8 | Pushed = 5 | 8 | Pushed = 5 |
| 9 | Commented = 6 | 9 | Commented = 6 |
| 10 | + Merged = 7 | ||
| 10 | 11 | ||
| 11 | belongs_to :project | 12 | belongs_to :project |
| 12 | belongs_to :target, :polymorphic => true | 13 | belongs_to :target, :polymorphic => true |
app/models/merge_request.rb
| 1 | +require File.join(Rails.root, "app/models/commit") | ||
| 2 | + | ||
| 1 | class MergeRequest < ActiveRecord::Base | 3 | class MergeRequest < ActiveRecord::Base |
| 2 | belongs_to :project | 4 | belongs_to :project |
| 3 | belongs_to :author, :class_name => "User" | 5 | belongs_to :author, :class_name => "User" |
| 4 | belongs_to :assignee, :class_name => "User" | 6 | belongs_to :assignee, :class_name => "User" |
| 5 | has_many :notes, :as => :noteable, :dependent => :destroy | 7 | has_many :notes, :as => :noteable, :dependent => :destroy |
| 6 | 8 | ||
| 9 | + serialize :st_commits | ||
| 10 | + serialize :st_diffs | ||
| 11 | + | ||
| 7 | attr_protected :author, :author_id, :project, :project_id | 12 | attr_protected :author, :author_id, :project, :project_id |
| 8 | attr_accessor :author_id_of_changes | 13 | attr_accessor :author_id_of_changes |
| 9 | 14 | ||
| @@ -32,6 +37,13 @@ class MergeRequest < ActiveRecord::Base | @@ -32,6 +37,13 @@ class MergeRequest < ActiveRecord::Base | ||
| 32 | scope :closed, where(:closed => true) | 37 | scope :closed, where(:closed => true) |
| 33 | scope :assigned, lambda { |u| where(:assignee_id => u.id)} | 38 | scope :assigned, lambda { |u| where(:assignee_id => u.id)} |
| 34 | 39 | ||
| 40 | + def self.search query | ||
| 41 | + where("title like :query", :query => "%#{query}%") | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + def self.find_all_by_branch(branch_name) | ||
| 45 | + where("source_branch like :branch or target_branch like :branch", :branch => branch_name) | ||
| 46 | + end | ||
| 35 | 47 | ||
| 36 | def validate_branches | 48 | def validate_branches |
| 37 | if target_branch == source_branch | 49 | if target_branch == source_branch |
| @@ -39,23 +51,99 @@ class MergeRequest < ActiveRecord::Base | @@ -39,23 +51,99 @@ class MergeRequest < ActiveRecord::Base | ||
| 39 | end | 51 | end |
| 40 | end | 52 | end |
| 41 | 53 | ||
| 54 | + def reload_code | ||
| 55 | + self.reloaded_commits | ||
| 56 | + self.reloaded_diffs | ||
| 57 | + end | ||
| 58 | + | ||
| 42 | def new? | 59 | def new? |
| 43 | today? && created_at == updated_at | 60 | today? && created_at == updated_at |
| 44 | end | 61 | end |
| 45 | 62 | ||
| 46 | def diffs | 63 | def diffs |
| 64 | + st_diffs || [] | ||
| 65 | + end | ||
| 66 | + | ||
| 67 | + def reloaded_diffs | ||
| 68 | + if open? && unmerged_diffs.any? | ||
| 69 | + self.st_diffs = unmerged_diffs | ||
| 70 | + save | ||
| 71 | + end | ||
| 72 | + diffs | ||
| 73 | + end | ||
| 74 | + | ||
| 75 | + def unmerged_diffs | ||
| 47 | commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} | 76 | commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} |
| 48 | diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] | 77 | diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] |
| 49 | end | 78 | end |
| 50 | 79 | ||
| 51 | def last_commit | 80 | def last_commit |
| 52 | - project.commit(source_branch) | 81 | + commits.first |
| 82 | + end | ||
| 83 | + | ||
| 84 | + def merged? | ||
| 85 | + merged && merge_event | ||
| 86 | + end | ||
| 87 | + | ||
| 88 | + def merge_event | ||
| 89 | + self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Merged).last | ||
| 90 | + end | ||
| 91 | + | ||
| 92 | + def closed_event | ||
| 93 | + self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Closed).last | ||
| 53 | end | 94 | end |
| 54 | 95 | ||
| 96 | + | ||
| 55 | # Return the number of +1 comments (upvotes) | 97 | # Return the number of +1 comments (upvotes) |
| 56 | def upvotes | 98 | def upvotes |
| 57 | notes.select(&:upvote?).size | 99 | notes.select(&:upvote?).size |
| 58 | end | 100 | end |
| 101 | + | ||
| 102 | + def commits | ||
| 103 | + st_commits || [] | ||
| 104 | + end | ||
| 105 | + | ||
| 106 | + def probably_merged? | ||
| 107 | + unmerged_commits.empty? && | ||
| 108 | + commits.any? && open? | ||
| 109 | + end | ||
| 110 | + | ||
| 111 | + def open? | ||
| 112 | + !closed | ||
| 113 | + end | ||
| 114 | + | ||
| 115 | + def mark_as_merged! | ||
| 116 | + self.merged = true | ||
| 117 | + self.closed = true | ||
| 118 | + save | ||
| 119 | + end | ||
| 120 | + | ||
| 121 | + def reloaded_commits | ||
| 122 | + if open? && unmerged_commits.any? | ||
| 123 | + self.st_commits = unmerged_commits | ||
| 124 | + save | ||
| 125 | + end | ||
| 126 | + commits | ||
| 127 | + end | ||
| 128 | + | ||
| 129 | + def unmerged_commits | ||
| 130 | + self.project.repo. | ||
| 131 | + commits_between(self.target_branch, self.source_branch). | ||
| 132 | + map {|c| Commit.new(c)}. | ||
| 133 | + sort_by(&:created_at). | ||
| 134 | + reverse | ||
| 135 | + end | ||
| 136 | + | ||
| 137 | + def merge!(user_id) | ||
| 138 | + self.mark_as_merged! | ||
| 139 | + Event.create( | ||
| 140 | + :project => self.project, | ||
| 141 | + :action => Event::Merged, | ||
| 142 | + :target_id => self.id, | ||
| 143 | + :target_type => "MergeRequest", | ||
| 144 | + :author_id => user_id | ||
| 145 | + ) | ||
| 146 | + end | ||
| 59 | end | 147 | end |
| 60 | # == Schema Information | 148 | # == Schema Information |
| 61 | # | 149 | # |
app/models/project.rb
| @@ -54,6 +54,10 @@ class Project < ActiveRecord::Base | @@ -54,6 +54,10 @@ class Project < ActiveRecord::Base | ||
| 54 | UsersProject.access_roles | 54 | UsersProject.access_roles |
| 55 | end | 55 | end |
| 56 | 56 | ||
| 57 | + def self.search query | ||
| 58 | + where("name like :query or code like :query or path like :query", :query => "%#{query}%") | ||
| 59 | + end | ||
| 60 | + | ||
| 57 | def to_param | 61 | def to_param |
| 58 | code | 62 | code |
| 59 | end | 63 | end |
| @@ -73,6 +77,24 @@ class Project < ActiveRecord::Base | @@ -73,6 +77,24 @@ class Project < ActiveRecord::Base | ||
| 73 | ) | 77 | ) |
| 74 | end | 78 | end |
| 75 | 79 | ||
| 80 | + def update_merge_requests(oldrev, newrev, ref, author_key_id) | ||
| 81 | + return true unless ref =~ /heads/ | ||
| 82 | + branch_name = ref.gsub("refs/heads/", "") | ||
| 83 | + user = Key.find_by_identifier(author_key_id).user | ||
| 84 | + c_ids = self.commits_between(oldrev, newrev).map(&:id) | ||
| 85 | + | ||
| 86 | + # Update code for merge requests | ||
| 87 | + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all | ||
| 88 | + mrs.each { |merge_request| merge_request.reload_code } | ||
| 89 | + | ||
| 90 | + # Close merge requests | ||
| 91 | + mrs = self.merge_requests.opened.where(:target_branch => branch_name).all | ||
| 92 | + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) } | ||
| 93 | + mrs.each { |merge_request| merge_request.merge!(user.id) } | ||
| 94 | + | ||
| 95 | + true | ||
| 96 | + end | ||
| 97 | + | ||
| 76 | def execute_web_hooks(oldrev, newrev, ref, author_key_id) | 98 | def execute_web_hooks(oldrev, newrev, ref, author_key_id) |
| 77 | ref_parts = ref.split('/') | 99 | ref_parts = ref.split('/') |
| 78 | 100 |
app/models/user.rb
| @@ -86,6 +86,10 @@ class User < ActiveRecord::Base | @@ -86,6 +86,10 @@ class User < ActiveRecord::Base | ||
| 86 | ) | 86 | ) |
| 87 | end | 87 | end |
| 88 | end | 88 | end |
| 89 | + | ||
| 90 | + def cared_merge_requests | ||
| 91 | + MergeRequest.where("author_id = :id or assignee_id = :id", :id => self.id).opened | ||
| 92 | + end | ||
| 89 | end | 93 | end |
| 90 | # == Schema Information | 94 | # == Schema Information |
| 91 | # | 95 | # |
app/views/commits/show.html.haml
| @@ -12,8 +12,8 @@ | @@ -12,8 +12,8 @@ | ||
| 12 | = @commit.committer_name | 12 | = @commit.committer_name |
| 13 | %small= @commit.committed_date.stamp("Aug 21, 2011 9:23pm") | 13 | %small= @commit.committed_date.stamp("Aug 21, 2011 9:23pm") |
| 14 | 14 | ||
| 15 | -%hr | ||
| 16 | -%pre.commit_message | 15 | +%br |
| 16 | +%pre.commit_message.prettyprint | ||
| 17 | = commit_msg_with_link_to_issues(@project, @commit.safe_message) | 17 | = commit_msg_with_link_to_issues(@project, @commit.safe_message) |
| 18 | .clear | 18 | .clear |
| 19 | %br | 19 | %br |
app/views/dashboard/_events_feed.html.haml
app/views/dashboard/_issues_feed.html.haml
| @@ -3,8 +3,10 @@ | @@ -3,8 +3,10 @@ | ||
| 3 | = link_to [issue.project, issue] do | 3 | = link_to [issue.project, issue] do |
| 4 | %p | 4 | %p |
| 5 | %strong | 5 | %strong |
| 6 | - %span.label= issue.project.name | 6 | + %span.pretty_label= issue.project.name |
| 7 | – | 7 | – |
| 8 | Issue # | 8 | Issue # |
| 9 | = issue.id | 9 | = issue.id |
| 10 | = truncate issue.title, :length => 50 | 10 | = truncate issue.title, :length => 50 |
| 11 | + %span.right.cgray | ||
| 12 | + = issue.updated_at.stamp("Aug 21, 2011") |
app/views/dashboard/_merge_requests_feed.html.haml
| @@ -3,8 +3,9 @@ | @@ -3,8 +3,9 @@ | ||
| 3 | = link_to [merge_request.project, merge_request] do | 3 | = link_to [merge_request.project, merge_request] do |
| 4 | %p | 4 | %p |
| 5 | %strong | 5 | %strong |
| 6 | - %span.label= merge_request.project.name | 6 | + %span.pretty_label= merge_request.project.name |
| 7 | – | 7 | – |
| 8 | - Merge Request # | ||
| 9 | - = merge_request.id | 8 | + Merge Request ##{merge_request.id} |
| 10 | = truncate merge_request.title, :length => 50 | 9 | = truncate merge_request.title, :length => 50 |
| 10 | + %span.right.cgray | ||
| 11 | + = merge_request.updated_at.stamp("Aug 21, 2011") |
app/views/dashboard/_projects_feed.html.haml
| 1 | -- @active_projects.first(5).each do |project| | ||
| 2 | - .wll | 1 | +- projects.first(5).each do |project| |
| 2 | + %div.dash_project_item | ||
| 3 | = link_to project do | 3 | = link_to project do |
| 4 | %h4 | 4 | %h4 |
| 5 | %span.ico.project | 5 | %span.ico.project |
| @@ -7,3 +7,5 @@ | @@ -7,3 +7,5 @@ | ||
| 7 | %small | 7 | %small |
| 8 | last activity at | 8 | last activity at |
| 9 | = project.last_activity_date.stamp("Aug 25, 2011") | 9 | = project.last_activity_date.stamp("Aug 25, 2011") |
| 10 | + %span.right.arrow | ||
| 11 | + → |
app/views/dashboard/index.html.haml
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | .row | 20 | .row |
| 21 | .dashboard_block | 21 | .dashboard_block |
| 22 | .row | 22 | .row |
| 23 | - .span10= render "dashboard/projects_feed" | 23 | + .span10= render "dashboard/projects_feed", :projects => @active_projects |
| 24 | .span4.right | 24 | .span4.right |
| 25 | - if current_user.can_create_project? | 25 | - if current_user.can_create_project? |
| 26 | .alert-message.block-message.warning | 26 | .alert-message.block-message.warning |
| @@ -65,4 +65,4 @@ | @@ -65,4 +65,4 @@ | ||
| 65 | 65 | ||
| 66 | %hr | 66 | %hr |
| 67 | .row | 67 | .row |
| 68 | - .dashboard_block= render "dashboard/events_feed" | 68 | + .dashboard_block= render @events |
app/views/events/_event_changed_issue.html.haml
| 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 2 | %strong #{event.author_name} | 2 | %strong #{event.author_name} |
| 3 | -- if event.closed? | ||
| 4 | - closed | ||
| 5 | -- else | ||
| 6 | - reopened | ||
| 7 | -issue | 3 | +%span.label.important |
| 4 | + - if event.closed? | ||
| 5 | + closed | ||
| 6 | + - else | ||
| 7 | + reopened | ||
| 8 | + issue | ||
| 8 | = link_to project_issue_path(event.project, event.issue) do | 9 | = link_to project_issue_path(event.project, event.issue) do |
| 9 | %strong= truncate event.issue_title | 10 | %strong= truncate event.issue_title |
| 10 | at | 11 | at |
app/views/events/_event_changed_merge_request.html.haml
| 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 2 | %strong #{event.author_name} | 2 | %strong #{event.author_name} |
| 3 | -- if event.closed? | ||
| 4 | - closed | ||
| 5 | -- else | ||
| 6 | - reopened | ||
| 7 | -merge request | 3 | +%span.label.important |
| 4 | + - if event.closed? | ||
| 5 | + closed | ||
| 6 | + - else | ||
| 7 | + reopened | ||
| 8 | + merge request | ||
| 8 | = link_to project_merge_request_path(event.project, event.merge_request) do | 9 | = link_to project_merge_request_path(event.project, event.merge_request) do |
| 9 | %strong= truncate event.merge_request_title | 10 | %strong= truncate event.merge_request_title |
| 10 | at | 11 | at |
| @@ -12,7 +13,6 @@ at | @@ -12,7 +13,6 @@ at | ||
| 12 | %span.cgray | 13 | %span.cgray |
| 13 | = time_ago_in_words(event.created_at) | 14 | = time_ago_in_words(event.created_at) |
| 14 | ago. | 15 | ago. |
| 15 | -%br | ||
| 16 | %span.label= event.merge_request.source_branch | 16 | %span.label= event.merge_request.source_branch |
| 17 | → | 17 | → |
| 18 | %span.label= event.merge_request.target_branch | 18 | %span.label= event.merge_request.target_branch |
app/views/events/_event_new_issue.html.haml
| 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 2 | %strong #{event.author_name} | 2 | %strong #{event.author_name} |
| 3 | -created new issue | 3 | +%span.label.success created |
| 4 | + new issue | ||
| 4 | = link_to project_issue_path(event.project, event.issue) do | 5 | = link_to project_issue_path(event.project, event.issue) do |
| 5 | %strong= truncate event.issue_title | 6 | %strong= truncate event.issue_title |
| 6 | at | 7 | at |
app/views/events/_event_new_merge_request.html.haml
| 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 2 | %strong #{event.author_name} | 2 | %strong #{event.author_name} |
| 3 | -requested merge | 3 | +%span.label.success requested |
| 4 | + merge | ||
| 4 | = link_to project_merge_request_path(event.project, event.merge_request) do | 5 | = link_to project_merge_request_path(event.project, event.merge_request) do |
| 5 | %strong= truncate event.merge_request_title | 6 | %strong= truncate event.merge_request_title |
| 6 | at | 7 | at |
| @@ -8,7 +9,6 @@ at | @@ -8,7 +9,6 @@ at | ||
| 8 | %span.cgray | 9 | %span.cgray |
| 9 | = time_ago_in_words(event.created_at) | 10 | = time_ago_in_words(event.created_at) |
| 10 | ago. | 11 | ago. |
| 11 | -%br | ||
| 12 | %span.label= event.merge_request.source_branch | 12 | %span.label= event.merge_request.source_branch |
| 13 | → | 13 | → |
| 14 | %span.label= event.merge_request.target_branch | 14 | %span.label= event.merge_request.target_branch |
app/views/events/_event_push.html.haml
| 1 | - if event.new_branch? || event.new_tag? | 1 | - if event.new_branch? || event.new_tag? |
| 2 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 2 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 3 | %strong #{event.author_name} | 3 | %strong #{event.author_name} |
| 4 | - pushed new | 4 | + %span.label.pushed pushed |
| 5 | + new | ||
| 5 | - if event.new_tag? | 6 | - if event.new_tag? |
| 6 | tag | 7 | tag |
| 7 | = link_to project_commits_path(event.project, :ref => event.tag_name) do | 8 | = link_to project_commits_path(event.project, :ref => event.tag_name) do |
| @@ -18,7 +19,8 @@ | @@ -18,7 +19,8 @@ | ||
| 18 | - else | 19 | - else |
| 19 | = image_tag gravatar_icon(event.author_email), :class => "avatar" | 20 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
| 20 | %strong #{event.author_name} | 21 | %strong #{event.author_name} |
| 21 | - pushed to | 22 | + %span.label.pushed pushed |
| 23 | + to | ||
| 22 | = link_to project_commits_path(event.project, :ref => event.branch_name) do | 24 | = link_to project_commits_path(event.project, :ref => event.branch_name) do |
| 23 | %strong= event.branch_name | 25 | %strong= event.branch_name |
| 24 | at | 26 | at |
| @@ -30,10 +32,10 @@ | @@ -30,10 +32,10 @@ | ||
| 30 | = link_to compare_project_commits_path(event.project, :from => event.commits.first.prev_commit_id, :to => event.commits.last.id) do | 32 | = link_to compare_project_commits_path(event.project, :from => event.commits.first.prev_commit_id, :to => event.commits.last.id) do |
| 31 | Compare #{event.commits.first.commit.id[0..8]}...#{event.commits.last.id[0..8]} | 33 | Compare #{event.commits.first.commit.id[0..8]}...#{event.commits.last.id[0..8]} |
| 32 | - @project = event.project | 34 | - @project = event.project |
| 33 | - %ul.unstyled | ||
| 34 | - - if event.commits.size > 4 | ||
| 35 | - = render event.commits[0..2] | ||
| 36 | - %li ... and #{event.commits.size - 3} more commits | 35 | + %ul.unstyled.event_commits |
| 36 | + - if event.commits.size > 3 | ||
| 37 | + = render event.commits[0...2] | ||
| 38 | + %li ... and #{event.commits.size - 2} more commits | ||
| 37 | - else | 39 | - else |
| 38 | = render event.commits | 40 | = render event.commits |
| 39 | 41 |
app/views/layouts/_app_menu.html.haml
| 1 | %nav.main_menu | 1 | %nav.main_menu |
| 2 | = render "layouts/const_menu_links" | 2 | = render "layouts/const_menu_links" |
| 3 | = link_to "Projects", projects_path, :class => "#{"current" if current_page?(projects_path)}" | 3 | = link_to "Projects", projects_path, :class => "#{"current" if current_page?(projects_path)}" |
| 4 | - = link_to "Issues", dashboard_issues_path, :class => "#{"current" if current_page?(dashboard_issues_path)}", :id => "issues_slide" | ||
| 5 | - = link_to "Requests", dashboard_merge_requests_path, :class => "#{"current" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide" | 4 | + = link_to dashboard_issues_path, :class => "#{"current" if current_page?(dashboard_issues_path)}", :id => "issues_slide" do |
| 5 | + Issues | ||
| 6 | + %span.count= current_user.assigned_issues.opened.count | ||
| 7 | + = link_to dashboard_merge_requests_path, :class => "#{"current" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide" do | ||
| 8 | + Requests | ||
| 9 | + %span.count= current_user.cared_merge_requests.count | ||
| 10 | + = link_to "Search", search_path, :class => "#{"current" if current_page?(search_path)}" | ||
| 6 | = link_to "Help", help_path, :class => "#{"current" if controller.controller_name == "help"}" | 11 | = link_to "Help", help_path, :class => "#{"current" if controller.controller_name == "help"}" |
app/views/layouts/_head_panel.html.haml
| @@ -7,7 +7,9 @@ | @@ -7,7 +7,9 @@ | ||
| 7 | %h1 | 7 | %h1 |
| 8 | GITLAB | 8 | GITLAB |
| 9 | %h1.project_name= title | 9 | %h1.project_name= title |
| 10 | - .search= text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" | 10 | + .search |
| 11 | + = form_tag search_path, :method => :get do |f| | ||
| 12 | + = text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" | ||
| 11 | - if current_user.is_admin? | 13 | - if current_user.is_admin? |
| 12 | = link_to admin_projects_path, :class => "admin_link", :title => "Admin area" do | 14 | = link_to admin_projects_path, :class => "admin_link", :title => "Admin area" do |
| 13 | = image_tag "admin.PNG", :width => 16 | 15 | = image_tag "admin.PNG", :width => 16 |
app/views/merge_requests/_commits.html.haml
app/views/merge_requests/_how_to_merge.html.haml
| @@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
| 15 | :javascript | 15 | :javascript |
| 16 | $(function(){ | 16 | $(function(){ |
| 17 | var modal = $('#modal_merge_info').modal({modal: true}); | 17 | var modal = $('#modal_merge_info').modal({modal: true}); |
| 18 | - $('.info_link').bind("click", function(){ | 18 | + $('.how_to_merge_link').bind("click", function(){ |
| 19 | modal.show(); | 19 | modal.show(); |
| 20 | }); | 20 | }); |
| 21 | $('.modal-header .close').bind("click", function(){ | 21 | $('.modal-header .close').bind("click", function(){ |
app/views/merge_requests/_merge_request.html.haml
| @@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
| 6 | = time_ago_in_words(merge_request.created_at) | 6 | = time_ago_in_words(merge_request.created_at) |
| 7 | ago | 7 | ago |
| 8 | - if merge_request.notes.any? | 8 | - if merge_request.notes.any? |
| 9 | - %span.label= pluralize merge_request.notes.count, 'note' | 9 | + %span.pretty_label= pluralize merge_request.notes.count, 'note' |
| 10 | - if merge_request.upvotes > 0 | 10 | - if merge_request.upvotes > 0 |
| 11 | %span.label.success= "+#{merge_request.upvotes}" | 11 | %span.label.success= "+#{merge_request.upvotes}" |
| 12 | .right | 12 | .right |
app/views/merge_requests/show.html.haml
| 1 | %h3 | 1 | %h3 |
| 2 | = "Merge Request ##{@merge_request.id}:" | 2 | = "Merge Request ##{@merge_request.id}:" |
| 3 | | 3 | |
| 4 | - %span.label= @merge_request.source_branch | 4 | + %span.pretty_label.branch= @merge_request.source_branch |
| 5 | → | 5 | → |
| 6 | - %span.label= @merge_request.target_branch | 6 | + %span.pretty_label.branch= @merge_request.target_branch |
| 7 | 7 | ||
| 8 | %small | 8 | %small |
| 9 | created at | 9 | created at |
| @@ -11,12 +11,10 @@ | @@ -11,12 +11,10 @@ | ||
| 11 | 11 | ||
| 12 | %span.right | 12 | %span.right |
| 13 | - if can?(current_user, :modify_merge_request, @merge_request) | 13 | - if can?(current_user, :modify_merge_request, @merge_request) |
| 14 | - - if @merge_request.closed | ||
| 15 | - = link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "btn" | ||
| 16 | - - else | 14 | + - if @merge_request.open? |
| 17 | = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "btn", :title => "Close merge request" | 15 | = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "btn", :title => "Close merge request" |
| 18 | - = link_to edit_project_merge_request_path(@project, @merge_request), :class => "btn" do | ||
| 19 | - Edit | 16 | + = link_to edit_project_merge_request_path(@project, @merge_request), :class => "btn" do |
| 17 | + Edit | ||
| 20 | 18 | ||
| 21 | %br | 19 | %br |
| 22 | - if @merge_request.upvotes > 0 | 20 | - if @merge_request.upvotes > 0 |
| @@ -28,17 +26,27 @@ | @@ -28,17 +26,27 @@ | ||
| 28 | 26 | ||
| 29 | 27 | ||
| 30 | %hr | 28 | %hr |
| 31 | -- if @merge_request.closed | ||
| 32 | - .alert-message.error Closed | ||
| 33 | -- else | ||
| 34 | - .alert-message.success | ||
| 35 | - = link_to "#", :class => "info_link", :title => "How To Merge" do | ||
| 36 | - = image_tag "Info-UI.PNG" | ||
| 37 | - Open | 29 | +.merge_request_status_holder |
| 30 | + - if @merge_request.closed | ||
| 31 | + %h5 | ||
| 32 | + .alert-message.error.status_info Closed | ||
| 33 | + - if @merge_request.merged? | ||
| 34 | + %span | ||
| 35 | + Merged by #{@merge_request.merge_event.author_name} | ||
| 36 | + %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. | ||
| 37 | + - elsif @merge_request.closed_event | ||
| 38 | + %span | ||
| 39 | + Closed by #{@merge_request.closed_event.author_name} | ||
| 40 | + %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. | ||
| 41 | + %br | ||
| 42 | + - else | ||
| 43 | + %h5 | ||
| 44 | + .alert-message.success.status_info Open | ||
| 45 | + = link_to "How to merge", "#", :class => "vlink how_to_merge_link", :title => "How To Merge" | ||
| 38 | 46 | ||
| 39 | = render "merge_requests/how_to_merge" | 47 | = render "merge_requests/how_to_merge" |
| 40 | 48 | ||
| 41 | -%div.well | 49 | +%div.well.prettyprint |
| 42 | %div | 50 | %div |
| 43 | %cite.cgray Created by | 51 | %cite.cgray Created by |
| 44 | = image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av" | 52 | = image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av" |
app/views/profile/password.html.haml
| 1 | -%h3 Password | ||
| 2 | -%hr | ||
| 3 | -= form_for @user, :url => profile_password_path, :method => :put do |f| | ||
| 4 | - .data | ||
| 5 | - .alert-message.block-message.warning | ||
| 6 | - %p After successfull password update you will be redirected to login page where you should login with new password | ||
| 7 | - -if @user.errors.any? | ||
| 8 | - .alert-message.block-message.error | ||
| 9 | - %ul | ||
| 10 | - - @user.errors.full_messages.each do |msg| | ||
| 11 | - %li= msg | 1 | +.row |
| 2 | + .span8 | ||
| 3 | + %h3 Password | ||
| 4 | + %hr | ||
| 5 | + = form_for @user, :url => profile_password_path, :method => :put do |f| | ||
| 6 | + .data | ||
| 7 | + .alert-message.block-message.warning | ||
| 8 | + %p After successfull password update you will be redirected to login page where you should login with new password | ||
| 9 | + -if @user.errors.any? | ||
| 10 | + .alert-message.block-message.error | ||
| 11 | + %ul | ||
| 12 | + - @user.errors.full_messages.each do |msg| | ||
| 13 | + %li= msg | ||
| 14 | + | ||
| 15 | + .clearfix | ||
| 16 | + = f.label :password | ||
| 17 | + .input= f.password_field :password | ||
| 18 | + .clearfix | ||
| 19 | + = f.label :password_confirmation | ||
| 20 | + .input= f.password_field :password_confirmation | ||
| 21 | + .actions | ||
| 22 | + = f.submit 'Save', :class => "btn" | ||
| 12 | 23 | ||
| 13 | - .clearfix | ||
| 14 | - = f.label :password | ||
| 15 | - .input= f.password_field :password | ||
| 16 | - .clearfix | ||
| 17 | - = f.label :password_confirmation | ||
| 18 | - .input= f.password_field :password_confirmation | ||
| 19 | - .actions | ||
| 20 | - = f.submit 'Save', :class => "btn" | ||
| 21 | - | ||
| 22 | -%h3 | ||
| 23 | - Private token | ||
| 24 | - %span.cred.right | ||
| 25 | - keep it in secret! | ||
| 26 | -%hr | ||
| 27 | -= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f| | ||
| 28 | - .data | ||
| 29 | - %p Private token used to access application resources without authentication. | ||
| 30 | - %p For example its required to access commits feed. | 24 | + .span7.right |
| 25 | + %h3 | ||
| 26 | + Private token | ||
| 27 | + %span.cred.right | ||
| 28 | + keep it in secret! | ||
| 31 | %hr | 29 | %hr |
| 32 | - %p.cgray | ||
| 33 | - - if current_user.private_token | ||
| 34 | - = text_field_tag "token", current_user.private_token | ||
| 35 | - - else | ||
| 36 | - You don`t have one yet. Click generate to fix it. | ||
| 37 | - .actions | ||
| 38 | - - if current_user.private_token | ||
| 39 | - = f.submit 'Reset', :confirm => "Are you sure?", :class => "btn" | ||
| 40 | - - else | ||
| 41 | - = f.submit 'Generate', :class => "btn" | 30 | + = form_for @user, :url => profile_reset_private_token_path, :method => :put do |f| |
| 31 | + .data | ||
| 32 | + .alert-message.block-message.warning | ||
| 33 | + %p Private token used to access application resources without authentication. | ||
| 34 | + %hr | ||
| 35 | + %p * required for rss feed | ||
| 36 | + %p.cgray | ||
| 37 | + - if current_user.private_token | ||
| 38 | + = text_field_tag "token", current_user.private_token | ||
| 39 | + - else | ||
| 40 | + You don`t have one yet. Click generate to fix it. | ||
| 41 | + .actions | ||
| 42 | + - if current_user.private_token | ||
| 43 | + = f.submit 'Reset', :confirm => "Are you sure?", :class => "btn" | ||
| 44 | + - else | ||
| 45 | + = f.submit 'Generate', :class => "btn" | ||
| 42 | 46 |
app/views/projects/_show.html.haml
app/views/projects/empty.html.haml
| @@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
| 6 | %li Visit profile → keys and add public key of every machine you want to use for work with gitlabhq. | 6 | %li Visit profile → keys and add public key of every machine you want to use for work with gitlabhq. |
| 7 | 7 | ||
| 8 | .alert-message.block-message.error | 8 | .alert-message.block-message.error |
| 9 | - %ul.alert_holder | 9 | + %ul.unstyled.alert_holder |
| 10 | %li You should push repository to proceed. | 10 | %li You should push repository to proceed. |
| 11 | %li After push you will be able to browse code, commits etc. | 11 | %li After push you will be able to browse code, commits etc. |
| 12 | 12 |
app/views/projects/index.html.haml
| 1 | - if @projects.any? | 1 | - if @projects.any? |
| 2 | .row | 2 | .row |
| 3 | - .span4 | 3 | + .span11 |
| 4 | + = render @events | ||
| 5 | + .span5.right | ||
| 4 | %div.leftbar.ui-box | 6 | %div.leftbar.ui-box |
| 5 | %h5 | 7 | %h5 |
| 6 | Projects | 8 | Projects |
| 9 | + %small | ||
| 10 | + (#{@projects.count}) | ||
| 7 | - if current_user.can_create_project? | 11 | - if current_user.can_create_project? |
| 8 | %span.right | 12 | %span.right |
| 9 | = link_to new_project_path, :class => "btn very_small info" do | 13 | = link_to new_project_path, :class => "btn very_small info" do |
| 10 | New Project | 14 | New Project |
| 11 | .content_list | 15 | .content_list |
| 12 | - @projects.each do |project| | 16 | - @projects.each do |project| |
| 13 | - = link_to project_path(project), :remote => true, :class => dom_class(project) do | 17 | + = link_to project_path(project), :class => dom_class(project) do |
| 14 | %h4 | 18 | %h4 |
| 15 | %span.ico.project | 19 | %span.ico.project |
| 16 | - = truncate(project.name, :length => 22) | ||
| 17 | - .span12.right | ||
| 18 | - .show_holder.ui-box.padded | ||
| 19 | - .loading | 20 | + = truncate(project.name, :length => 25) |
| 21 | + %span.right | ||
| 22 | + → | ||
| 20 | 23 | ||
| 21 | - else | 24 | - else |
| 22 | %h3 Nothing here | 25 | %h3 Nothing here |
| @@ -31,20 +34,3 @@ | @@ -31,20 +34,3 @@ | ||
| 31 | New Project » | 34 | New Project » |
| 32 | - else | 35 | - else |
| 33 | If you will be added to project - it will be displayed here | 36 | If you will be added to project - it will be displayed here |
| 34 | - | ||
| 35 | - | ||
| 36 | -:javascript | ||
| 37 | - $(function(){ | ||
| 38 | - $("a.project").live("ajax:before", function() { | ||
| 39 | - $(".show_holder").html("<div class='loading'>"); | ||
| 40 | - $('a.project').removeClass("active"); | ||
| 41 | - $(this).addClass("active"); | ||
| 42 | - }); | ||
| 43 | - $('a.project:first-child').trigger("click"); | ||
| 44 | - }); | ||
| 45 | - | ||
| 46 | -- if @projects.count == @limit | ||
| 47 | - :javascript | ||
| 48 | - $(function(){ | ||
| 49 | - Pager.init(#{@limit}); | ||
| 50 | - }); |
app/views/projects/show.html.haml
| @@ -21,9 +21,13 @@ | @@ -21,9 +21,13 @@ | ||
| 21 | = text_field_tag :project_clone, @project.url_to_repo, :class => "xlarge one_click_select git_clone_url" | 21 | = text_field_tag :project_clone, @project.url_to_repo, :class => "xlarge one_click_select git_clone_url" |
| 22 | 22 | ||
| 23 | - if @project.description.present? | 23 | - if @project.description.present? |
| 24 | - = markdown @project.description | 24 | + .prettyprint= markdown @project.description |
| 25 | - unless @events.blank? | 25 | - unless @events.blank? |
| 26 | - %h5.cgray Recent Activity | 26 | + %br |
| 27 | + %h5.cgray | ||
| 28 | + %span.ico.activities | ||
| 29 | + Recent Activity | ||
| 30 | + %hr | ||
| 27 | .content_list= render @events | 31 | .content_list= render @events |
| 28 | 32 | ||
| 29 | 33 |
app/views/projects/show.js.haml
| @@ -1,7 +0,0 @@ | @@ -1,7 +0,0 @@ | ||
| 1 | -- if @project.repo_exists? && @project.has_commits? | ||
| 2 | - :plain | ||
| 3 | - $(".show_holder").html("#{escape_javascript(render(:partial => 'projects/show'))}"); | ||
| 4 | -- else | ||
| 5 | - :plain | ||
| 6 | - $(".show_holder").html("#{escape_javascript(render(:template => 'projects/empty'))}"); | ||
| 7 | - |
No preview for this file type
| @@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
| 1 | += form_tag search_path, :method => :get do |f| | ||
| 2 | + .padded | ||
| 3 | + = label_tag :search, "Looking for" | ||
| 4 | + .input | ||
| 5 | + = text_field_tag :search, params[:search],:placeholder => "issue 143", :class => "xxlarge" | ||
| 6 | + = submit_tag 'Search', :class => "btn primary" | ||
| 7 | +- if params[:search].present? | ||
| 8 | + %br | ||
| 9 | + %h3 Search results | ||
| 10 | + %hr | ||
| 11 | + .search_results | ||
| 12 | + - if @projects.empty? && @merge_requests.empty? | ||
| 13 | + %h3 | ||
| 14 | + %small Nothing here | ||
| 15 | + - else | ||
| 16 | + - if @projects.any? | ||
| 17 | + - @projects.each do |project| | ||
| 18 | + = link_to project do | ||
| 19 | + %h4 | ||
| 20 | + %span.ico.project | ||
| 21 | + = project.name | ||
| 22 | + %small | ||
| 23 | + last activity at | ||
| 24 | + = project.last_activity_date.stamp("Aug 25, 2011") | ||
| 25 | + - if @merge_requests.any? | ||
| 26 | + - @merge_requests.each do |merge_request| | ||
| 27 | + = link_to [merge_request.project, merge_request] do | ||
| 28 | + %h5 | ||
| 29 | + Merge Request # | ||
| 30 | + = merge_request.id | ||
| 31 | + – | ||
| 32 | + = truncate merge_request.title, :length => 50 | ||
| 33 | + %small | ||
| 34 | + updated at | ||
| 35 | + = merge_request.updated_at.stamp("Aug 25, 2011") | ||
| 36 | + %strong | ||
| 37 | + %span.label= merge_request.project.name | ||
| 38 | + :javascript | ||
| 39 | + $(function() { | ||
| 40 | + $(".search_results").highlight("#{params[:search]}"); | ||
| 41 | + }) |
app/workers/post_receive.rb
| @@ -8,7 +8,13 @@ class PostReceive | @@ -8,7 +8,13 @@ class PostReceive | ||
| 8 | # Ignore push from non-gitlab users | 8 | # Ignore push from non-gitlab users |
| 9 | return false unless Key.find_by_identifier(author_key_id) | 9 | return false unless Key.find_by_identifier(author_key_id) |
| 10 | 10 | ||
| 11 | + # Create push event | ||
| 11 | project.observe_push(oldrev, newrev, ref, author_key_id) | 12 | project.observe_push(oldrev, newrev, ref, author_key_id) |
| 13 | + | ||
| 14 | + # Close merged MR | ||
| 15 | + project.update_merge_requests(oldrev, newrev, ref, author_key_id) | ||
| 16 | + | ||
| 17 | + # Execute web hooks | ||
| 12 | project.execute_web_hooks(oldrev, newrev, ref, author_key_id) | 18 | project.execute_web_hooks(oldrev, newrev, ref, author_key_id) |
| 13 | end | 19 | end |
| 14 | end | 20 | end |
config/routes.rb
| 1 | Gitlab::Application.routes.draw do | 1 | Gitlab::Application.routes.draw do |
| 2 | - | 2 | + get 'search' => "search#show" |
| 3 | 3 | ||
| 4 | # Optionally, enable Resque here | 4 | # Optionally, enable Resque here |
| 5 | require 'resque/server' | 5 | require 'resque/server' |
| @@ -40,6 +40,7 @@ Gitlab::Application.routes.draw do | @@ -40,6 +40,7 @@ Gitlab::Application.routes.draw do | ||
| 40 | get "dashboard", :to => "dashboard#index" | 40 | get "dashboard", :to => "dashboard#index" |
| 41 | get "dashboard/issues", :to => "dashboard#issues" | 41 | get "dashboard/issues", :to => "dashboard#issues" |
| 42 | get "dashboard/merge_requests", :to => "dashboard#merge_requests" | 42 | get "dashboard/merge_requests", :to => "dashboard#merge_requests" |
| 43 | + get "dashboard/activities", :to => "dashboard#activities" | ||
| 43 | 44 | ||
| 44 | #get "profile/:id", :to => "profile#show" | 45 | #get "profile/:id", :to => "profile#show" |
| 45 | 46 |
db/migrate/20120315111711_add_commits_diff_store_to_merge_request.rb
0 → 100644
db/migrate/20120315132931_add_merged_to_merge_request.rb
0 → 100644
db/schema.rb
| @@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
| 11 | # | 11 | # |
| 12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
| 13 | 13 | ||
| 14 | -ActiveRecord::Schema.define(:version => 20120307095918) do | 14 | +ActiveRecord::Schema.define(:version => 20120315132931) do |
| 15 | 15 | ||
| 16 | create_table "events", :force => true do |t| | 16 | create_table "events", :force => true do |t| |
| 17 | t.string "target_type" | 17 | t.string "target_type" |
| @@ -61,6 +61,9 @@ ActiveRecord::Schema.define(:version => 20120307095918) do | @@ -61,6 +61,9 @@ ActiveRecord::Schema.define(:version => 20120307095918) do | ||
| 61 | t.boolean "closed", :default => false, :null => false | 61 | t.boolean "closed", :default => false, :null => false |
| 62 | t.datetime "created_at", :null => false | 62 | t.datetime "created_at", :null => false |
| 63 | t.datetime "updated_at", :null => false | 63 | t.datetime "updated_at", :null => false |
| 64 | + t.text "st_commits" | ||
| 65 | + t.text "st_diffs" | ||
| 66 | + t.boolean "merged", :default => false, :null => false | ||
| 64 | end | 67 | end |
| 65 | 68 | ||
| 66 | add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" | 69 | add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" |
doc/installation.md
| @@ -209,7 +209,7 @@ Application can be started with next command: | @@ -209,7 +209,7 @@ Application can be started with next command: | ||
| 209 | 209 | ||
| 210 | cd /home/gitlab/gitlab | 210 | cd /home/gitlab/gitlab |
| 211 | sudo -u gitlab cp config/unicorn.rb.orig config/unicorn.rb | 211 | sudo -u gitlab cp config/unicorn.rb.orig config/unicorn.rb |
| 212 | - sudo -u gitlab unicorn_rails -c config/unicorn.rb -E production -D | 212 | + sudo -u gitlab bundle exec unicorn_rails -c config/unicorn.rb -E production -D |
| 213 | 213 | ||
| 214 | Edit /etc/nginx/nginx.conf. Add next code to **http** section: | 214 | Edit /etc/nginx/nginx.conf. Add next code to **http** section: |
| 215 | 215 | ||
| @@ -256,33 +256,38 @@ Create init script in /etc/init.d/gitlab: | @@ -256,33 +256,38 @@ Create init script in /etc/init.d/gitlab: | ||
| 256 | NAME=unicorn | 256 | NAME=unicorn |
| 257 | DESC="Gitlab service" | 257 | DESC="Gitlab service" |
| 258 | PID=/home/gitlab/gitlab/tmp/pids/unicorn.pid | 258 | PID=/home/gitlab/gitlab/tmp/pids/unicorn.pid |
| 259 | + RESQUE_PID=/home/gitlab/gitlab/tmp/pids/resque_worker.pid | ||
| 259 | 260 | ||
| 260 | case "$1" in | 261 | case "$1" in |
| 261 | start) | 262 | start) |
| 262 | CD_TO_APP_DIR="cd /home/gitlab/gitlab" | 263 | CD_TO_APP_DIR="cd /home/gitlab/gitlab" |
| 263 | START_DAEMON_PROCESS="bundle exec unicorn_rails $DAEMON_OPTS" | 264 | START_DAEMON_PROCESS="bundle exec unicorn_rails $DAEMON_OPTS" |
| 265 | + START_RESQUE_PROCESS="./resque.sh" | ||
| 264 | 266 | ||
| 265 | echo -n "Starting $DESC: " | 267 | echo -n "Starting $DESC: " |
| 266 | if [ `whoami` = root ]; then | 268 | if [ `whoami` = root ]; then |
| 267 | - sudo -u gitlab sh -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS" | 269 | + sudo -u gitlab sh -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS" |
| 268 | else | 270 | else |
| 269 | - $CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS | 271 | + $CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS |
| 270 | fi | 272 | fi |
| 271 | echo "$NAME." | 273 | echo "$NAME." |
| 272 | ;; | 274 | ;; |
| 273 | stop) | 275 | stop) |
| 274 | echo -n "Stopping $DESC: " | 276 | echo -n "Stopping $DESC: " |
| 275 | kill -QUIT `cat $PID` | 277 | kill -QUIT `cat $PID` |
| 278 | + kill -QUIT `cat $RESQUE_PID` | ||
| 276 | echo "$NAME." | 279 | echo "$NAME." |
| 277 | ;; | 280 | ;; |
| 278 | restart) | 281 | restart) |
| 279 | echo -n "Restarting $DESC: " | 282 | echo -n "Restarting $DESC: " |
| 280 | kill -USR2 `cat $PID` | 283 | kill -USR2 `cat $PID` |
| 284 | + kill -USR2 `cat $RESQUE_PID` | ||
| 281 | echo "$NAME." | 285 | echo "$NAME." |
| 282 | ;; | 286 | ;; |
| 283 | reload) | 287 | reload) |
| 284 | echo -n "Reloading $DESC configuration: " | 288 | echo -n "Reloading $DESC configuration: " |
| 285 | kill -HUP `cat $PID` | 289 | kill -HUP `cat $PID` |
| 290 | + kill -HUP `cat $RESQUE_PID` | ||
| 286 | echo "$NAME." | 291 | echo "$NAME." |
| 287 | ;; | 292 | ;; |
| 288 | *) | 293 | *) |
resque.sh
| 1 | mkdir tmp/pids | 1 | mkdir tmp/pids |
| 2 | -nohup bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production PIDFILE=tmp/pids/resque_worker_QUEUE.pid & >> log/resque_worker_QUEUE.log 2>&1 | 2 | +nohup bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid & >> log/resque_worker.log 2>&1 |
spec/models/project_spec.rb
| @@ -160,6 +160,34 @@ describe Project do | @@ -160,6 +160,34 @@ describe Project do | ||
| 160 | end | 160 | end |
| 161 | end | 161 | end |
| 162 | end | 162 | end |
| 163 | + | ||
| 164 | + describe :update_merge_requests do | ||
| 165 | + let(:project) { Factory :project } | ||
| 166 | + | ||
| 167 | + before do | ||
| 168 | + @merge_request = Factory :merge_request, | ||
| 169 | + :project => project, | ||
| 170 | + :merged => false, | ||
| 171 | + :closed => false | ||
| 172 | + @key = Factory :key, :user_id => project.owner.id | ||
| 173 | + end | ||
| 174 | + | ||
| 175 | + it "should close merge request if last commit from source branch was pushed to target branch" do | ||
| 176 | + @merge_request.reloaded_commits | ||
| 177 | + @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" | ||
| 178 | + project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.identifier) | ||
| 179 | + @merge_request.reload | ||
| 180 | + @merge_request.merged.should be_true | ||
| 181 | + @merge_request.closed.should be_true | ||
| 182 | + end | ||
| 183 | + | ||
| 184 | + it "should update merge request commits with new one if pushed to source branch" do | ||
| 185 | + @merge_request.last_commit.should == nil | ||
| 186 | + project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/master", @key.identifier) | ||
| 187 | + @merge_request.reload | ||
| 188 | + @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" | ||
| 189 | + end | ||
| 190 | + end | ||
| 163 | end | 191 | end |
| 164 | # == Schema Information | 192 | # == Schema Information |
| 165 | # | 193 | # |
spec/requests/dashboard_spec.rb
| 1 | require 'spec_helper' | 1 | require 'spec_helper' |
| 2 | -__END__ | ||
| 3 | -# Disabled for now | ||
| 4 | describe "Dashboard" do | 2 | describe "Dashboard" do |
| 5 | before do | 3 | before do |
| 6 | @project = Factory :project | 4 | @project = Factory :project |
| @@ -22,19 +20,7 @@ describe "Dashboard" do | @@ -22,19 +20,7 @@ describe "Dashboard" do | ||
| 22 | end | 20 | end |
| 23 | 21 | ||
| 24 | it "should have projects panel" do | 22 | it "should have projects panel" do |
| 25 | - within ".project-list" do | ||
| 26 | - page.should have_content(@project.name) | ||
| 27 | - end | 23 | + page.should have_content(@project.name) |
| 28 | end | 24 | end |
| 29 | - | ||
| 30 | - # Temporary disabled cause of travis | ||
| 31 | - # TODO: fix or rewrite | ||
| 32 | - #it "should have news feed" do | ||
| 33 | - #within "#news-feed" do | ||
| 34 | - #page.should have_content("commit") | ||
| 35 | - #page.should have_content(@project.commit.author.name) | ||
| 36 | - #page.should have_content(@project.commit.safe_message) | ||
| 37 | - #end | ||
| 38 | - #end | ||
| 39 | end | 25 | end |
| 40 | end | 26 | end |
spec/requests/merge_requests_spec.rb
| @@ -42,7 +42,7 @@ describe "MergeRequests" do | @@ -42,7 +42,7 @@ describe "MergeRequests" do | ||
| 42 | 42 | ||
| 43 | it { should have_content(@merge_request.title[0..10]) } | 43 | it { should have_content(@merge_request.title[0..10]) } |
| 44 | it "Show page should inform user that merge request closed" do | 44 | it "Show page should inform user that merge request closed" do |
| 45 | - page.should have_content "Reopen" | 45 | + page.should have_content "Closed" |
| 46 | end | 46 | end |
| 47 | end | 47 | end |
| 48 | end | 48 | end |
| @@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
| 1 | +/* | ||
| 2 | + | ||
| 3 | +highlight v3 | ||
| 4 | + | ||
| 5 | +Highlights arbitrary terms. | ||
| 6 | + | ||
| 7 | +<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html> | ||
| 8 | + | ||
| 9 | +MIT license. | ||
| 10 | + | ||
| 11 | +Johann Burkard | ||
| 12 | +<http://johannburkard.de> | ||
| 13 | +<mailto:jb@eaio.com> | ||
| 14 | + | ||
| 15 | +*/ | ||
| 16 | + | ||
| 17 | +jQuery.fn.highlight = function(pat) { | ||
| 18 | + function innerHighlight(node, pat) { | ||
| 19 | + var skip = 0; | ||
| 20 | + if (node.nodeType == 3) { | ||
| 21 | + var pos = node.data.toUpperCase().indexOf(pat); | ||
| 22 | + if (pos >= 0) { | ||
| 23 | + var spannode = document.createElement('span'); | ||
| 24 | + spannode.className = 'highlight_word'; | ||
| 25 | + var middlebit = node.splitText(pos); | ||
| 26 | + var endbit = middlebit.splitText(pat.length); | ||
| 27 | + var middleclone = middlebit.cloneNode(true); | ||
| 28 | + spannode.appendChild(middleclone); | ||
| 29 | + middlebit.parentNode.replaceChild(spannode, middlebit); | ||
| 30 | + skip = 1; | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { | ||
| 34 | + for (var i = 0; i < node.childNodes.length; ++i) { | ||
| 35 | + i += innerHighlight(node.childNodes[i], pat); | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + return skip; | ||
| 39 | + } | ||
| 40 | + return this.each(function() { | ||
| 41 | + innerHighlight(this, pat.toUpperCase()); | ||
| 42 | + }); | ||
| 43 | +}; | ||
| 44 | + | ||
| 45 | +jQuery.fn.removeHighlight = function() { | ||
| 46 | + return this.find("span.highlight").each(function() { | ||
| 47 | + this.parentNode.firstChild.nodeName; | ||
| 48 | + with (this.parentNode) { | ||
| 49 | + replaceChild(this.firstChild, this); | ||
| 50 | + normalize(); | ||
| 51 | + } | ||
| 52 | + }).end(); | ||
| 53 | +}; |