Merge branch 'feature/merge_requests'
This commit is contained in:
commit
22ac0cc7eb
29 changed files with 531 additions and 42 deletions
3
app/assets/javascripts/merge_requests.js.coffee
Normal file
3
app/assets/javascripts/merge_requests.js.coffee
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Place all the behaviors and hooks related to the matching controller here.
|
||||
# All this logic will automatically be available in application.js.
|
||||
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
|
|
@ -49,3 +49,4 @@
|
|||
.no-padding {
|
||||
padding:0 !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
body.project-page .merge-request-form-holder table.no-borders tr,
|
||||
body.project-page .merge-request-form-holder table.no-borders td,
|
||||
body.project-page .issue-form-holder table.no-borders tr,
|
||||
body.project-page .issue-form-holder table.no-borders td,
|
||||
body.project-page .new_snippet table tr,
|
||||
|
|
10
app/assets/stylesheets/merge_requests.css.scss
Normal file
10
app/assets/stylesheets/merge_requests.css.scss
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Place all the styles related to the MergeRequests controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
|
||||
|
||||
.merge-request-form-holder {
|
||||
select {
|
||||
width:300px;
|
||||
}
|
||||
}
|
|
@ -155,6 +155,8 @@ input.ssh_project_url {
|
|||
}
|
||||
|
||||
/** FORM INPUTS **/
|
||||
.new_merge_request,
|
||||
.edit_merge_request,
|
||||
.user_new,
|
||||
.new_key,
|
||||
.new_issue,
|
||||
|
@ -326,12 +328,16 @@ body.project-page table .commit {
|
|||
border:none;
|
||||
text-shadow:none;
|
||||
|
||||
&.high {
|
||||
&.inline {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
&.high, &.closed {
|
||||
background: #D12F19;
|
||||
color:white;
|
||||
}
|
||||
|
||||
&.today {
|
||||
&.today, &.open {
|
||||
background: #44aa22;
|
||||
color:white;
|
||||
}
|
||||
|
@ -384,6 +390,32 @@ body.dashboard.project-page .news-feed .project-updates a.project-update span.up
|
|||
body.dashboard.project-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
|
||||
/* eo Dashboard Page */
|
||||
|
||||
|
||||
/** Merge requests */
|
||||
body.project-page .merge-request-commits {margin-bottom: 20px; display: block; width: 100%;}
|
||||
body.project-page .merge-request-commits .data{ padding: 0}
|
||||
body.project-page .merge-request-commits a.commit {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
|
||||
body.project-page .merge-request-commits a.commit:last-child{border-bottom: 0}
|
||||
body.project-page .merge-request-commits a.commit img{float: left; margin-right: 10px;}
|
||||
body.project-page .merge-request-commits a.commit span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
|
||||
body.project-page .merge-request-commits a.commit span.update-title{margin-bottom: 10px}
|
||||
body.project-page .merge-request-commits a.commit span.update-author{color: #999; font-weight: normal; font-style: italic;}
|
||||
body.project-page .merge-request-commits a.commit span.update-author strong{font-weight: bold; font-style: normal;}
|
||||
|
||||
|
||||
/** Update entry **/
|
||||
.update-data { padding: 0 }
|
||||
.update-data { width:100%; }
|
||||
.update-data.ui-box .data { padding:0; }
|
||||
a.update-item {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
|
||||
a.update-item:last-child{border-bottom: 0}
|
||||
a.update-item img{float: left; margin-right: 10px;}
|
||||
a.update-item span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
|
||||
a.update-item span.update-title{margin-bottom: 10px}
|
||||
a.update-item span.update-author{color: #999; font-weight: normal; font-style: italic;}
|
||||
a.update-item span.update-author strong{font-weight: bold; font-style: normal;}
|
||||
|
||||
|
||||
body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:10px 0; }
|
||||
|
||||
body.projects-page input.text.git-url.project_list_url { width:165px; }
|
||||
|
@ -394,3 +426,44 @@ body.project-page table.no-borders tr,
|
|||
body.project-page table.no-borders td{
|
||||
border:none;
|
||||
}
|
||||
|
||||
#gitlab-tabs {
|
||||
.ui-tabs-nav {
|
||||
border-bottom: 1px solid #DEDFE1;
|
||||
|
||||
li {
|
||||
background: none;
|
||||
border:none;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
margin: 0;
|
||||
padding: 10px 16px;
|
||||
width:150px;
|
||||
}
|
||||
|
||||
&.ui-tabs-selected {
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
|
||||
background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
|
||||
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
|
||||
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
|
||||
font-weight: bold;
|
||||
border:1px solid #DEDFE1;
|
||||
border-bottom: 1px solid #DEDFE1;
|
||||
-webkit-border-top-left-radius: 5px;
|
||||
-webkit-border-top-right-radius: 5px;
|
||||
-moz-border-radius-topleft: 5px;
|
||||
-moz-border-radius-topright: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ajax-tab-loading {
|
||||
padding:40px;
|
||||
display:none;
|
||||
}
|
||||
|
|
90
app/controllers/merge_requests_controller.rb
Normal file
90
app/controllers/merge_requests_controller.rb
Normal file
|
@ -0,0 +1,90 @@
|
|||
class MergeRequestsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :project
|
||||
before_filter :merge_request, :only => [:edit, :update, :destroy, :show, :commits, :diffs]
|
||||
layout "project"
|
||||
|
||||
# Authorize
|
||||
before_filter :add_project_abilities
|
||||
before_filter :authorize_read_project!
|
||||
before_filter :authorize_write_project!, :only => [:new, :create, :edit, :update]
|
||||
|
||||
def index
|
||||
@merge_requests = @project.merge_requests
|
||||
end
|
||||
|
||||
def show
|
||||
unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) &&
|
||||
@project.repo.heads.map(&:name).include?(@merge_request.source_branch)
|
||||
head(404)and return
|
||||
end
|
||||
|
||||
@notes = @merge_request.notes.inc_author.order("created_at DESC").limit(20)
|
||||
@note = @project.notes.new(:noteable => @merge_request)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js { respond_with_notes }
|
||||
end
|
||||
end
|
||||
|
||||
def commits
|
||||
@commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)}
|
||||
render :template => "merge_requests/_commits", :layout => false
|
||||
end
|
||||
|
||||
def diffs
|
||||
@commit = @project.commit(@merge_request.source_branch)
|
||||
@diffs = @project.repo.diff(@merge_request.target_branch, @merge_request.source_branch)
|
||||
render :template => "merge_requests/_diffs", :layout => false
|
||||
end
|
||||
|
||||
def new
|
||||
@merge_request = @project.merge_requests.new
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def create
|
||||
@merge_request = @project.merge_requests.new(params[:merge_request])
|
||||
@merge_request.author = current_user
|
||||
|
||||
respond_to do |format|
|
||||
if @merge_request.save
|
||||
format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' }
|
||||
format.json { render json: @merge_request, status: :created, location: @merge_request }
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
format.json { render json: @merge_request.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @merge_request.update_attributes(params[:merge_request])
|
||||
format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' }
|
||||
format.json { head :ok }
|
||||
else
|
||||
format.html { render action: "edit" }
|
||||
format.json { render json: @merge_request.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@merge_request.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to project_merge_requests_url(@project) }
|
||||
format.json { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def merge_request
|
||||
@merge_request ||= @project.merge_requests.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -42,6 +42,8 @@ class NotesController < ApplicationController
|
|||
Notify.note_commit_email(u, @note).deliver
|
||||
when "Issue" then
|
||||
Notify.note_issue_email(u, @note).deliver
|
||||
when "MergeRequest"
|
||||
true # someone should write email notification
|
||||
when "Snippet"
|
||||
true
|
||||
else
|
||||
|
|
2
app/helpers/merge_requests_helper.rb
Normal file
2
app/helpers/merge_requests_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
module MergeRequestsHelper
|
||||
end
|
|
@ -17,6 +17,7 @@ class Ability
|
|||
:read_issue,
|
||||
:read_snippet,
|
||||
:read_team_member,
|
||||
:read_merge_request,
|
||||
:read_note
|
||||
] if project.readers.include?(user)
|
||||
|
||||
|
@ -24,6 +25,7 @@ class Ability
|
|||
:write_project,
|
||||
:write_issue,
|
||||
:write_snippet,
|
||||
:write_merge_request,
|
||||
:write_note
|
||||
] if project.writers.include?(user)
|
||||
|
||||
|
@ -32,6 +34,7 @@ class Ability
|
|||
:admin_issue,
|
||||
:admin_snippet,
|
||||
:admin_team_member,
|
||||
:admin_merge_request,
|
||||
:admin_note
|
||||
] if project.admins.include?(user)
|
||||
|
||||
|
@ -39,7 +42,7 @@ class Ability
|
|||
end
|
||||
|
||||
class << self
|
||||
[:issue, :note, :snippet].each do |name|
|
||||
[:issue, :note, :snippet, :merge_request].each do |name|
|
||||
define_method "#{name}_abilities" do |user, subject|
|
||||
if subject.author == user
|
||||
[
|
||||
|
|
36
app/models/merge_request.rb
Normal file
36
app/models/merge_request.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
class MergeRequest < ActiveRecord::Base
|
||||
belongs_to :project
|
||||
belongs_to :author, :class_name => "User"
|
||||
belongs_to :assignee, :class_name => "User"
|
||||
has_many :notes, :as => :noteable
|
||||
|
||||
attr_protected :author, :author_id, :project, :project_id
|
||||
|
||||
validates_presence_of :project_id
|
||||
validates_presence_of :assignee_id
|
||||
validates_presence_of :author_id
|
||||
validates_presence_of :source_branch
|
||||
validates_presence_of :target_branch
|
||||
|
||||
delegate :name,
|
||||
:email,
|
||||
:to => :author,
|
||||
:prefix => true
|
||||
|
||||
delegate :name,
|
||||
:email,
|
||||
:to => :assignee,
|
||||
:prefix => true
|
||||
|
||||
validates :title,
|
||||
:presence => true,
|
||||
:length => { :within => 0..255 }
|
||||
|
||||
scope :opened, where(:closed => false)
|
||||
scope :closed, where(:closed => true)
|
||||
scope :assigned, lambda { |u| where(:assignee_id => u.id)}
|
||||
|
||||
def new?
|
||||
today? && created_at == updated_at
|
||||
end
|
||||
end
|
|
@ -3,6 +3,7 @@ require "grit"
|
|||
class Project < ActiveRecord::Base
|
||||
belongs_to :owner, :class_name => "User"
|
||||
|
||||
has_many :merge_requests, :dependent => :destroy
|
||||
has_many :issues, :dependent => :destroy, :order => "position"
|
||||
has_many :users_projects, :dependent => :destroy
|
||||
has_many :users, :through => :users_projects
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
= "Issue ##{@issue.id}"
|
||||
.right
|
||||
- if @issue.closed
|
||||
%span.tag.high Resolved
|
||||
%span.tag.closed Closed
|
||||
- else
|
||||
%span.tag.today Open
|
||||
%span.tag.open Open
|
||||
|
||||
.data
|
||||
%p= @issue.title
|
||||
|
@ -28,7 +28,7 @@
|
|||
- if @issue.closed
|
||||
= link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button"
|
||||
- else
|
||||
= link_to 'Resolve', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button"
|
||||
= link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button"
|
||||
.right
|
||||
= link_to 'Edit', edit_project_issue_path(@project, @issue), :class => "grey-button positive"
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@
|
|||
Wall
|
||||
- if @project.common_notes.today.count > 0
|
||||
%span{ :class => "number" }= @project.common_notes.today.count
|
||||
= link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do
|
||||
Merge Requests
|
||||
- if @project.merge_requests.opened.count > 0
|
||||
%span{ :class => "number" }= @project.merge_requests.opened.count
|
||||
= link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do
|
||||
Snippets
|
||||
- if @project.snippets.non_expired.count > 0
|
||||
|
|
17
app/views/merge_requests/_commits.html.haml
Normal file
17
app/views/merge_requests/_commits.html.haml
Normal file
|
@ -0,0 +1,17 @@
|
|||
- if @commits.size > 0
|
||||
.merge-request-commits.ui-box.width-100p
|
||||
- @commits.each do |commit|
|
||||
%a{ :class => "commit", :href => project_commit_path(@project, :id => commit.id) }
|
||||
- if commit.author_email
|
||||
= image_tag gravatar_icon(commit.author_email), :class => "left", :width => 40, :style => "padding-right:5px;"
|
||||
- else
|
||||
= image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;"
|
||||
%span.update-title
|
||||
= truncate commit.safe_message, :length => 60
|
||||
%span.update-author
|
||||
%strong= commit.author_name
|
||||
authored
|
||||
= time_ago_in_words(commit.created_at)
|
||||
ago
|
||||
.clear
|
||||
|
22
app/views/merge_requests/_diffs.html.haml
Normal file
22
app/views/merge_requests/_diffs.html.haml
Normal file
|
@ -0,0 +1,22 @@
|
|||
- @diffs.each do |diff|
|
||||
- next if diff.diff.empty?
|
||||
- file = (@commit.tree / diff.b_path)
|
||||
- next unless file
|
||||
.diff_file
|
||||
.diff_file_header
|
||||
- if diff.deleted_file
|
||||
%strong{:id => "#{diff.b_path}"}= diff.a_path
|
||||
- else
|
||||
= link_to tree_file_project_ref_path(@project, @commit.id, diff.b_path) do
|
||||
%strong{:id => "#{diff.b_path}"}= diff.b_path
|
||||
%br/
|
||||
.diff_file_content
|
||||
- if file.text?
|
||||
= render :partial => "commits/text_file", :locals => { :diff => diff }
|
||||
- elsif file.image?
|
||||
.diff_file_content_image
|
||||
%img{:src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
|
||||
- else
|
||||
%p
|
||||
%center No preview for this file type
|
||||
|
39
app/views/merge_requests/_form.html.haml
Normal file
39
app/views/merge_requests/_form.html.haml
Normal file
|
@ -0,0 +1,39 @@
|
|||
%div.merge-request-form-holder
|
||||
.ui-box.width-100p
|
||||
%h3
|
||||
= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}"
|
||||
= form_for [@project, @merge_request] do |f|
|
||||
.data
|
||||
%table.no-borders
|
||||
-if @merge_request.errors.any?
|
||||
%tr
|
||||
%td Errors
|
||||
%td
|
||||
#error_explanation
|
||||
- @merge_request.errors.full_messages.each do |msg|
|
||||
%span= msg
|
||||
%br
|
||||
|
||||
%tr
|
||||
%td= f.label :title
|
||||
%td= f.text_field :title
|
||||
%tr
|
||||
%td= f.label :source_branch, "From"
|
||||
%td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" })
|
||||
%tr
|
||||
%td= f.label :target_branch, "To"
|
||||
%td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" })
|
||||
%tr
|
||||
%td= f.label :assignee_id, "Assign to"
|
||||
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
|
||||
.buttons
|
||||
= f.submit 'Save', :class => "grey-button"
|
||||
.right= link_to 'Back', project_merge_requests_path(@project), :class => "grey-button"
|
||||
|
||||
:javascript
|
||||
$(function(){
|
||||
$('select#merge_request_assignee_id').chosen();
|
||||
$('select#merge_request_source_branch').chosen();
|
||||
$('select#merge_request_target_branch').chosen();
|
||||
});
|
||||
|
14
app/views/merge_requests/_merge_request.html.haml
Normal file
14
app/views/merge_requests/_merge_request.html.haml
Normal file
|
@ -0,0 +1,14 @@
|
|||
%a.update-item{:href => project_merge_request_path(@project, merge_request)}
|
||||
= image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40
|
||||
%span.update-title
|
||||
= merge_request.title
|
||||
%span.update-author
|
||||
%strong= merge_request.author_name
|
||||
authored
|
||||
= time_ago_in_words(merge_request.created_at)
|
||||
ago
|
||||
.right
|
||||
%span.tag.commit= merge_request.source_branch
|
||||
→
|
||||
%span.tag.commit= merge_request.target_branch
|
||||
|
1
app/views/merge_requests/edit.html.haml
Normal file
1
app/views/merge_requests/edit.html.haml
Normal file
|
@ -0,0 +1 @@
|
|||
= render 'form'
|
20
app/views/merge_requests/index.html.haml
Normal file
20
app/views/merge_requests/index.html.haml
Normal file
|
@ -0,0 +1,20 @@
|
|||
- if @merge_requests.opened.count > 0
|
||||
%div{ :class => "update-data ui-box ui-box-small ui-box-big" }
|
||||
%h3
|
||||
%span.tag.open Open
|
||||
.data
|
||||
= render @merge_requests.opened
|
||||
|
||||
.clear
|
||||
%br
|
||||
|
||||
- if @merge_requests.closed.count > 0
|
||||
%div{ :class => "update-data ui-box ui-box-small ui-box-big" }
|
||||
%h3
|
||||
%span.tag.closed Closed
|
||||
.data
|
||||
= render @merge_requests.closed
|
||||
.clear
|
||||
%br
|
||||
|
||||
= link_to 'New Merge request', new_project_merge_request_path(@project), :class => "grey-button"
|
1
app/views/merge_requests/new.html.haml
Normal file
1
app/views/merge_requests/new.html.haml
Normal file
|
@ -0,0 +1 @@
|
|||
= render 'form'
|
59
app/views/merge_requests/show.html.haml
Normal file
59
app/views/merge_requests/show.html.haml
Normal file
|
@ -0,0 +1,59 @@
|
|||
.merge-request-show-holder.ui-box.width-100p
|
||||
%h3
|
||||
= "Merge Request ##{@merge_request.id}:"
|
||||
|
||||
.tag.commit.inline= @merge_request.source_branch
|
||||
→
|
||||
.tag.commit.inline= @merge_request.target_branch
|
||||
.right
|
||||
- if @merge_request.closed
|
||||
%span.tag.high Closed
|
||||
- else
|
||||
%span.tag.today Open
|
||||
|
||||
.data
|
||||
%p= @merge_request.title
|
||||
|
||||
- if @merge_request.author == @merge_request.assignee
|
||||
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;"
|
||||
= @merge_request.assignee_name
|
||||
- else
|
||||
= image_tag gravatar_icon(@merge_request.author_email), :width => 20, :style => "padding:0 5px;"
|
||||
= @merge_request.author_name
|
||||
→
|
||||
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;"
|
||||
= @merge_request.assignee_name
|
||||
.right
|
||||
%cite.cgray= @merge_request.created_at.stamp("21 Aug 2011, 11:15pm")
|
||||
.clear
|
||||
|
||||
.buttons
|
||||
- if can? current_user, :write_project, @project
|
||||
- if @merge_request.closed
|
||||
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button"
|
||||
- else
|
||||
= link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button"
|
||||
.right
|
||||
= link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), :class => "grey-button positive"
|
||||
|
||||
.clear
|
||||
%br
|
||||
%br
|
||||
|
||||
#gitlab-tabs
|
||||
%ul
|
||||
%li= link_to "Notes", "#merge-notes"
|
||||
%li= link_to "Commits", commits_project_merge_request_path(@project, @merge_request)
|
||||
%li= link_to "Diff", diffs_project_merge_request_path(@project, @merge_request)
|
||||
|
||||
#merge-notes
|
||||
.issue_notes= render "notes/notes"
|
||||
.loading{ :style => "display:none;"}
|
||||
%center= image_tag "ajax-loader.gif"
|
||||
.clear
|
||||
|
||||
|
||||
:javascript
|
||||
$(function(){
|
||||
$("#gitlab-tabs").tabs();
|
||||
})
|
|
@ -59,6 +59,12 @@ Gitlab::Application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :merge_requests do
|
||||
member do
|
||||
get :diffs
|
||||
get :commits
|
||||
end
|
||||
end
|
||||
resources :snippets
|
||||
resources :commits
|
||||
resources :team_members
|
||||
|
|
15
db/migrate/20111127155345_create_merge_requests.rb
Normal file
15
db/migrate/20111127155345_create_merge_requests.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class CreateMergeRequests < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :merge_requests do |t|
|
||||
t.string :target_branch, :null => false
|
||||
t.string :source_branch, :null => false
|
||||
t.integer :project_id, :null => false
|
||||
t.integer :author_id
|
||||
t.integer :assignee_id
|
||||
t.string :title
|
||||
t.boolean :closed, :default => false, :null => false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
16
db/schema.rb
16
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20111124115339) do
|
||||
ActiveRecord::Schema.define(:version => 20111127155345) do
|
||||
|
||||
create_table "features", :force => true do |t|
|
||||
t.string "name"
|
||||
|
@ -21,6 +21,8 @@ ActiveRecord::Schema.define(:version => 20111124115339) do
|
|||
t.integer "project_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "version"
|
||||
t.integer "status", :default => 0, :null => false
|
||||
end
|
||||
|
||||
create_table "issues", :force => true do |t|
|
||||
|
@ -45,6 +47,18 @@ ActiveRecord::Schema.define(:version => 20111124115339) do
|
|||
t.string "identifier"
|
||||
end
|
||||
|
||||
create_table "merge_requests", :force => true do |t|
|
||||
t.string "target_branch", :null => false
|
||||
t.string "source_branch", :null => false
|
||||
t.integer "project_id", :null => false
|
||||
t.integer "author_id"
|
||||
t.integer "assignee_id"
|
||||
t.string "title"
|
||||
t.boolean "closed", :default => false, :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "notes", :force => true do |t|
|
||||
t.text "note"
|
||||
t.string "noteable_id"
|
||||
|
|
|
@ -34,6 +34,12 @@ Factory.add(:issue, Issue) do |obj|
|
|||
obj.title = Faker::Lorem.sentence
|
||||
end
|
||||
|
||||
Factory.add(:merge_request, MergeRequest) do |obj|
|
||||
obj.title = Faker::Lorem.sentence
|
||||
obj.source_branch = "master"
|
||||
obj.target_branch = "master"
|
||||
end
|
||||
|
||||
Factory.add(:snippet, Snippet) do |obj|
|
||||
obj.title = Faker::Lorem.sentence
|
||||
obj.file_name = Faker::Lorem.sentence
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ApplicationHelper do
|
||||
context ".gravatar_icon" do
|
||||
context "over http" do
|
||||
it "returns the correct URL to www.gravatar.com" do
|
||||
expected = "http://www.gravatar.com/avatar/f7daa65b2aa96290bb47c4d68d11fe6a?s=40&d=identicon"
|
||||
|
||||
# Pretend we're running over HTTP
|
||||
helper.stub(:request) do
|
||||
request = double('request')
|
||||
request.stub(:ssl?) { false }
|
||||
request
|
||||
end
|
||||
|
||||
helper.gravatar_icon("admin@local.host").should == expected
|
||||
end
|
||||
end
|
||||
|
||||
context "over https" do
|
||||
it "returns the correct URL to secure.gravatar.com" do
|
||||
expected = "https://secure.gravatar.com/avatar/f7daa65b2aa96290bb47c4d68d11fe6a?s=40&d=identicon"
|
||||
|
||||
# Pretend we're running over HTTPS
|
||||
helper.stub(:request) do
|
||||
request = double('request')
|
||||
request.stub(:ssl?) { true }
|
||||
request
|
||||
end
|
||||
|
||||
helper.gravatar_icon("admin@local.host").should == expected
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
5
spec/models/merge_request_spec.rb
Normal file
5
spec/models/merge_request_spec.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe MergeRequest do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
69
spec/requests/merge_requests_spec.rb
Normal file
69
spec/requests/merge_requests_spec.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "MergeRequests" do
|
||||
let(:project) { Factory :project }
|
||||
|
||||
before do
|
||||
login_as :user
|
||||
project.add_access(@user, :read, :write)
|
||||
@merge_request = Factory :merge_request,
|
||||
:author => @user,
|
||||
:assignee => @user,
|
||||
:project => project
|
||||
end
|
||||
|
||||
describe "GET /merge_requests" do
|
||||
before do
|
||||
visit project_merge_requests_path(project)
|
||||
end
|
||||
|
||||
subject { page }
|
||||
|
||||
it { should have_content(@merge_request.title) }
|
||||
it { should have_content(@merge_request.target_branch) }
|
||||
it { should have_content(@merge_request.source_branch) }
|
||||
it { should have_content(@merge_request.assignee.name) }
|
||||
end
|
||||
|
||||
describe "GET /merge_request/:id" do
|
||||
before do
|
||||
visit project_merge_request_path(project, @merge_request)
|
||||
end
|
||||
|
||||
subject { page }
|
||||
|
||||
it { should have_content(@merge_request.title) }
|
||||
it { should have_content(@merge_request.target_branch) }
|
||||
it { should have_content(@merge_request.source_branch) }
|
||||
it { should have_content(@merge_request.assignee.name) }
|
||||
|
||||
describe "Close merge request" do
|
||||
before { click_link "Close" }
|
||||
|
||||
it { should have_content(@merge_request.title) }
|
||||
it "Show page should inform user that merge request closed" do
|
||||
within ".merge-request-show-holder h3" do
|
||||
page.should have_content "Closed"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /merge_requests/new" do
|
||||
before do
|
||||
visit new_project_merge_request_path(project)
|
||||
fill_in "merge_request_title", :with => "Merge Request Title"
|
||||
select "master", :from => "merge_request_source_branch"
|
||||
select "master", :from => "merge_request_target_branch"
|
||||
select @user.name, :from => "merge_request_assignee_id"
|
||||
click_button "Save"
|
||||
end
|
||||
|
||||
it { current_path.should == project_merge_request_path(project, project.merge_requests.last) }
|
||||
|
||||
it "should create merge request" do
|
||||
page.should have_content "Open"
|
||||
page.should have_content @user.name
|
||||
end
|
||||
end
|
||||
end
|
|
@ -122,5 +122,14 @@ describe "Projects" do
|
|||
it { project_snippets_path(@project).should be_denied_for :user }
|
||||
it { project_snippets_path(@project).should be_denied_for :visitor }
|
||||
end
|
||||
|
||||
describe "GET /project_code/merge_requests" do
|
||||
it { project_merge_requests_path(@project).should be_allowed_for @u1 }
|
||||
it { project_merge_requests_path(@project).should be_allowed_for @u3 }
|
||||
it { project_merge_requests_path(@project).should be_denied_for :admin }
|
||||
it { project_merge_requests_path(@project).should be_denied_for @u2 }
|
||||
it { project_merge_requests_path(@project).should be_denied_for :user }
|
||||
it { project_merge_requests_path(@project).should be_denied_for :visitor }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue