Commit 6d460aa2 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

merge request entity

parent 22442039
# 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/
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
padding: 0; 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 tr,
body.project-page .issue-form-holder table.no-borders td, body.project-page .issue-form-holder table.no-borders td,
body.project-page .new_snippet table tr, body.project-page .new_snippet table tr,
......
// 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 { ...@@ -155,6 +155,8 @@ input.ssh_project_url {
} }
/** FORM INPUTS **/ /** FORM INPUTS **/
.new_merge_request,
.edit_merge_request,
.user_new, .user_new,
.new_key, .new_key,
.new_issue, .new_issue,
...@@ -384,6 +386,19 @@ body.dashboard.project-page .news-feed .project-updates a.project-update span.up ...@@ -384,6 +386,19 @@ 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;} body.dashboard.project-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
/* eo Dashboard Page */ /* 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;}
body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:10px 0; } 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; } body.projects-page input.text.git-url.project_list_url { width:165px; }
......
class MergeRequestsController < ApplicationController
before_filter :authenticate_user!
before_filter :project
before_filter :merge_request, :only => [:edit, :update, :destroy, :show]
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.all
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
@commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)}
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
module MergeRequestsHelper
end
...@@ -17,6 +17,7 @@ class Ability ...@@ -17,6 +17,7 @@ class Ability
:read_issue, :read_issue,
:read_snippet, :read_snippet,
:read_team_member, :read_team_member,
:read_merge_request,
:read_note :read_note
] if project.readers.include?(user) ] if project.readers.include?(user)
...@@ -24,6 +25,7 @@ class Ability ...@@ -24,6 +25,7 @@ class Ability
:write_project, :write_project,
:write_issue, :write_issue,
:write_snippet, :write_snippet,
:write_merge_request,
:write_note :write_note
] if project.writers.include?(user) ] if project.writers.include?(user)
...@@ -32,6 +34,7 @@ class Ability ...@@ -32,6 +34,7 @@ class Ability
:admin_issue, :admin_issue,
:admin_snippet, :admin_snippet,
:admin_team_member, :admin_team_member,
:admin_merge_request,
:admin_note :admin_note
] if project.admins.include?(user) ] if project.admins.include?(user)
...@@ -39,7 +42,7 @@ class Ability ...@@ -39,7 +42,7 @@ class Ability
end end
class << self class << self
[:issue, :note, :snippet].each do |name| [:issue, :note, :snippet, :merge_request].each do |name|
define_method "#{name}_abilities" do |user, subject| define_method "#{name}_abilities" do |user, subject|
if subject.author == user if subject.author == user
[ [
......
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" ...@@ -3,6 +3,7 @@ require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
belongs_to :owner, :class_name => "User" belongs_to :owner, :class_name => "User"
has_many :merge_requests, :dependent => :destroy
has_many :issues, :dependent => :destroy, :order => "position" has_many :issues, :dependent => :destroy, :order => "position"
has_many :users_projects, :dependent => :destroy has_many :users_projects, :dependent => :destroy
has_many :users, :through => :users_projects has_many :users, :through => :users_projects
......
...@@ -39,6 +39,10 @@ ...@@ -39,6 +39,10 @@
Wall Wall
- if @project.common_notes.today.count > 0 - if @project.common_notes.today.count > 0
%span{ :class => "number" }= @project.common_notes.today.count %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 = link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do
Snippets Snippets
- if @project.snippets.non_expired.count > 0 - if @project.snippets.non_expired.count > 0
......
%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 :target_branch, "From"
%td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" })
%tr
%td= f.label :source_branch, "To"
%td= f.select(:source_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();
});
%table
%thead
%th Target branch
%th Source branch
%th Author
%th Assignee
%th Title
%th
%th
%th
- @merge_requests.each do |merge_request|
%tr
%td= merge_request.target_branch
%td= merge_request.source_branch
%td= merge_request.author_id
%td= merge_request.assignee_id
%td= merge_request.title
%td= link_to 'Show', [@project, merge_request]
%td= link_to 'Edit', edit_project_merge_request_path(@project, merge_request)
%td= link_to 'Destroy', [@project, merge_request], :confirm => 'Are you sure?', :method => :delete
%br
= link_to 'New Merge request', new_project_merge_request_path(@project)
.merge-request-show-holder.ui-box.width-100p
%h3
= "Merge Request ##{@merge_request.id}:"
&nbsp;
= "'#{@merge_request.source_branch}'"
&rarr;
= "'#{@merge_request.target_branch}'"
.right
- if @merge_request.closed
%span.tag.high Resolved
- 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
&rarr;
= 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 'Resolve', 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
- 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
= commit.id.to_s
%span.update-author
%strong= commit.author_name
authored
= time_ago_in_words(commit.created_at)
ago
.clear
...@@ -59,6 +59,7 @@ Gitlab::Application.routes.draw do ...@@ -59,6 +59,7 @@ Gitlab::Application.routes.draw do
end end
end end
resources :merge_requests
resources :snippets resources :snippets
resources :commits resources :commits
resources :team_members resources :team_members
......
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
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # 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| create_table "features", :force => true do |t|
t.string "name" t.string "name"
...@@ -21,6 +21,8 @@ ActiveRecord::Schema.define(:version => 20111124115339) do ...@@ -21,6 +21,8 @@ ActiveRecord::Schema.define(:version => 20111124115339) do
t.integer "project_id" t.integer "project_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "version"
t.integer "status", :default => 0, :null => false
end end
create_table "issues", :force => true do |t| create_table "issues", :force => true do |t|
...@@ -45,6 +47,18 @@ ActiveRecord::Schema.define(:version => 20111124115339) do ...@@ -45,6 +47,18 @@ ActiveRecord::Schema.define(:version => 20111124115339) do
t.string "identifier" t.string "identifier"
end 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| create_table "notes", :force => true do |t|
t.text "note" t.text "note"
t.string "noteable_id" t.string "noteable_id"
......
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
require 'spec_helper'
describe MergeRequest do
pending "add some examples to (or delete) #{__FILE__}"
end
require 'spec_helper'
describe "MergeRequests" do
describe "GET /merge_requests" do
it "works! (now write some real specs)" do
# Run the generator again with the --webrat flag if you want to use webrat methods/matchers
get merge_requests_path
response.status.should be(200)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment