diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -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/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 47ec5f5a..3a5af7c6 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -49,3 +49,4 @@ .no-padding { padding:0 !important; } + diff --git a/app/assets/stylesheets/issues.css.scss b/app/assets/stylesheets/issues.css.scss index a283a456..a34be642 100644 --- a/app/assets/stylesheets/issues.css.scss +++ b/app/assets/stylesheets/issues.css.scss @@ -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, diff --git a/app/assets/stylesheets/merge_requests.css.scss b/app/assets/stylesheets/merge_requests.css.scss new file mode 100644 index 00000000..2b60605b --- /dev/null +++ b/app/assets/stylesheets/merge_requests.css.scss @@ -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; + } +} diff --git a/app/assets/stylesheets/projects.css.scss b/app/assets/stylesheets/projects.css.scss index b6c14c80..8cfe58b2 100644 --- a/app/assets/stylesheets/projects.css.scss +++ b/app/assets/stylesheets/projects.css.scss @@ -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; +} diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb new file mode 100644 index 00000000..c83423ed --- /dev/null +++ b/app/controllers/merge_requests_controller.rb @@ -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 diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index ad9531e0..5bf30056 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -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 diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb new file mode 100644 index 00000000..fac9870f --- /dev/null +++ b/app/helpers/merge_requests_helper.rb @@ -0,0 +1,2 @@ +module MergeRequestsHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 5ab70650..c41704f9 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -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 [ diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb new file mode 100644 index 00000000..dc4c92a9 --- /dev/null +++ b/app/models/merge_request.rb @@ -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 diff --git a/app/models/project.rb b/app/models/project.rb index 7998979d..ae63efb6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -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 diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 7eba0adf..1d95f4f1 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -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" diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index 0c121cc9..20553c94 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -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 diff --git a/app/views/merge_requests/_commits.html.haml b/app/views/merge_requests/_commits.html.haml new file mode 100644 index 00000000..508aa231 --- /dev/null +++ b/app/views/merge_requests/_commits.html.haml @@ -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 + diff --git a/app/views/merge_requests/_diffs.html.haml b/app/views/merge_requests/_diffs.html.haml new file mode 100644 index 00000000..eb44de68 --- /dev/null +++ b/app/views/merge_requests/_diffs.html.haml @@ -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 + diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml new file mode 100644 index 00000000..d0848e64 --- /dev/null +++ b/app/views/merge_requests/_form.html.haml @@ -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(); + }); + diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml new file mode 100644 index 00000000..c5bcf779 --- /dev/null +++ b/app/views/merge_requests/_merge_request.html.haml @@ -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 + diff --git a/app/views/merge_requests/edit.html.haml b/app/views/merge_requests/edit.html.haml new file mode 100644 index 00000000..bcc58327 --- /dev/null +++ b/app/views/merge_requests/edit.html.haml @@ -0,0 +1 @@ += render 'form' diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml new file mode 100644 index 00000000..c3f8d06a --- /dev/null +++ b/app/views/merge_requests/index.html.haml @@ -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" diff --git a/app/views/merge_requests/new.html.haml b/app/views/merge_requests/new.html.haml new file mode 100644 index 00000000..bcc58327 --- /dev/null +++ b/app/views/merge_requests/new.html.haml @@ -0,0 +1 @@ += render 'form' diff --git a/app/views/merge_requests/show.html.haml b/app/views/merge_requests/show.html.haml new file mode 100644 index 00000000..96afb47a --- /dev/null +++ b/app/views/merge_requests/show.html.haml @@ -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(); + }) diff --git a/config/routes.rb b/config/routes.rb index 840ef524..c74cf226 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20111127155345_create_merge_requests.rb b/db/migrate/20111127155345_create_merge_requests.rb new file mode 100644 index 00000000..1555ae84 --- /dev/null +++ b/db/migrate/20111127155345_create_merge_requests.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 502f52ad..8ffd874c 100644 --- a/db/schema.rb +++ b/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" diff --git a/spec/factories.rb b/spec/factories.rb index 36aa4fc9..6951ca2c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -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 diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb deleted file mode 100644 index 3e174ca4..00000000 --- a/spec/helpers/application_helper_spec.rb +++ /dev/null @@ -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 diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb new file mode 100644 index 00000000..cb260fc5 --- /dev/null +++ b/spec/models/merge_request_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe MergeRequest do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/merge_requests_spec.rb b/spec/requests/merge_requests_spec.rb new file mode 100644 index 00000000..b03ab219 --- /dev/null +++ b/spec/requests/merge_requests_spec.rb @@ -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 diff --git a/spec/requests/projects_security_spec.rb b/spec/requests/projects_security_spec.rb index 5f17cf40..e9674755 100644 --- a/spec/requests/projects_security_spec.rb +++ b/spec/requests/projects_security_spec.rb @@ -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