2014-09-02 18:07:02 +05:30
require 'spec_helper'
2017-09-10 17:25:29 +05:30
describe Commit do
2017-08-17 22:00:37 +05:30
let ( :project ) { create ( :project , :public , :repository ) }
2015-09-11 14:41:01 +05:30
let ( :commit ) { project . commit }
describe 'modules' do
subject { described_class }
it { is_expected . to include_module ( Mentionable ) }
it { is_expected . to include_module ( Participable ) }
it { is_expected . to include_module ( Referable ) }
it { is_expected . to include_module ( StaticModel ) }
end
2018-03-17 18:26:18 +05:30
describe '.lazy' do
set ( :project ) { create ( :project , :repository ) }
context 'when the commits are found' do
let ( :oids ) do
%w(
498214 de67004b1da3d820901307bed2a68a8ef6
c642fe9b8b9f28f9225d7ea953fe14e74748d53b
6 f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
04 8721 d90c449b244b7b4c53a9186b04330174ec
281 d3a76f31c812dbf48abce82ccf6860adedd81
)
end
subject { oids . map { | oid | described_class . lazy ( project , oid ) } }
it 'batches requests for commits' do
expect ( project . repository ) . to receive ( :commits_by ) . once . and_call_original
subject . first . title
subject . last . title
end
it 'maintains ordering' do
subject . each_with_index do | commit , i |
expect ( commit . id ) . to eq ( oids [ i ] )
end
end
end
context 'when not found' do
it 'returns nil as commit' do
commit = described_class . lazy ( project , 'deadbeef' ) . __sync
expect ( commit ) . to be_nil
end
end
end
2016-09-13 17:45:13 +05:30
describe '#author' do
it 'looks up the author in a case-insensitive way' do
user = create ( :user , email : commit . author_email . upcase )
expect ( commit . author ) . to eq ( user )
end
2017-09-10 17:25:29 +05:30
it 'caches the author' , :request_store do
2016-09-13 17:45:13 +05:30
user = create ( :user , email : commit . author_email )
2017-09-10 17:25:29 +05:30
expect ( User ) . to receive ( :find_by_any_email ) . and_call_original
2016-09-13 17:45:13 +05:30
expect ( commit . author ) . to eq ( user )
2017-09-10 17:25:29 +05:30
key = " Commit:author: #{ commit . author_email . downcase } "
2016-09-13 17:45:13 +05:30
expect ( RequestStore . store [ key ] ) . to eq ( user )
expect ( commit . author ) . to eq ( user )
end
end
2015-09-11 14:41:01 +05:30
describe '#to_reference' do
2017-08-17 22:00:37 +05:30
let ( :project ) { create ( :project , :repository , path : 'sample-project' ) }
2015-09-11 14:41:01 +05:30
it 'returns a String reference to the object' do
expect ( commit . to_reference ) . to eq commit . id
end
it 'supports a cross-project reference' do
2017-08-17 22:00:37 +05:30
another_project = build ( :project , :repository , name : 'another-project' , namespace : project . namespace )
expect ( commit . to_reference ( another_project ) ) . to eq " sample-project@ #{ commit . id } "
2015-09-11 14:41:01 +05:30
end
end
2014-09-02 18:07:02 +05:30
2015-12-23 02:04:40 +05:30
describe '#reference_link_text' do
2017-08-17 22:00:37 +05:30
let ( :project ) { create ( :project , :repository , path : 'sample-project' ) }
2015-12-23 02:04:40 +05:30
it 'returns a String reference to the object' do
expect ( commit . reference_link_text ) . to eq commit . short_id
end
it 'supports a cross-project reference' do
2017-08-17 22:00:37 +05:30
another_project = build ( :project , :repository , name : 'another-project' , namespace : project . namespace )
expect ( commit . reference_link_text ( another_project ) ) . to eq " sample-project@ #{ commit . short_id } "
2015-12-23 02:04:40 +05:30
end
end
2014-09-02 18:07:02 +05:30
describe '#title' do
it " returns no_commit_message when safe_message is blank " do
2015-04-26 12:48:37 +05:30
allow ( commit ) . to receive ( :safe_message ) . and_return ( '' )
expect ( commit . title ) . to eq ( " --no commit message " )
2014-09-02 18:07:02 +05:30
end
2017-09-10 17:25:29 +05:30
it 'truncates a message without a newline at natural break to 80 characters' do
2014-09-02 18:07:02 +05:30
message = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.'
2015-04-26 12:48:37 +05:30
allow ( commit ) . to receive ( :safe_message ) . and_return ( message )
2017-09-10 17:25:29 +05:30
expect ( commit . title ) . to eq ( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis…' )
2014-09-02 18:07:02 +05:30
end
it " truncates a message with a newline before 80 characters at the newline " do
message = commit . safe_message . split ( " " ) . first
2015-04-26 12:48:37 +05:30
allow ( commit ) . to receive ( :safe_message ) . and_return ( message + " \n " + message )
expect ( commit . title ) . to eq ( message )
2014-09-02 18:07:02 +05:30
end
it " does not truncates a message with a newline after 80 but less 100 characters " do
2016-06-02 11:05:42 +05:30
message = <<eos
2014-09-02 18:07:02 +05:30
Lorem ipsum dolor sit amet , consectetur adipiscing elit . Donec sodales id felis id blandit .
Vivamus egestas lacinia lacus , sed rutrum mauris .
eos
2015-04-26 12:48:37 +05:30
allow ( commit ) . to receive ( :safe_message ) . and_return ( message )
expect ( commit . title ) . to eq ( message . split ( " \n " ) . first )
2014-09-02 18:07:02 +05:30
end
end
2016-09-13 17:45:13 +05:30
describe '#full_title' do
it " returns no_commit_message when safe_message is blank " do
allow ( commit ) . to receive ( :safe_message ) . and_return ( '' )
expect ( commit . full_title ) . to eq ( " --no commit message " )
end
it " returns entire message if there is no newline " do
message = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.'
allow ( commit ) . to receive ( :safe_message ) . and_return ( message )
expect ( commit . full_title ) . to eq ( message )
end
it " returns first line of message if there is a newLine " do
message = commit . safe_message . split ( " " ) . first
allow ( commit ) . to receive ( :safe_message ) . and_return ( message + " \n " + message )
expect ( commit . full_title ) . to eq ( message )
end
end
2017-09-10 17:25:29 +05:30
describe 'description' do
it 'returns description of commit message if title less than 100 characters' do
message = <<eos
Lorem ipsum dolor sit amet , consectetur adipiscing elit . Donec sodales id felis id blandit .
Vivamus egestas lacinia lacus , sed rutrum mauris .
eos
allow ( commit ) . to receive ( :safe_message ) . and_return ( message )
expect ( commit . description ) . to eq ( 'Vivamus egestas lacinia lacus, sed rutrum mauris.' )
end
it 'returns full commit message if commit title more than 100 characters' do
message = <<eos
Lorem ipsum dolor sit amet , consectetur adipiscing elit . Donec sodales id felis id blandit . Vivamus egestas lacinia lacus , sed rutrum mauris .
Vivamus egestas lacinia lacus , sed rutrum mauris .
eos
allow ( commit ) . to receive ( :safe_message ) . and_return ( message )
expect ( commit . description ) . to eq ( message )
end
end
2014-09-02 18:07:02 +05:30
describe " delegation " do
subject { commit }
2015-04-26 12:48:37 +05:30
it { is_expected . to respond_to ( :message ) }
it { is_expected . to respond_to ( :authored_date ) }
it { is_expected . to respond_to ( :committed_date ) }
it { is_expected . to respond_to ( :committer_email ) }
it { is_expected . to respond_to ( :author_email ) }
it { is_expected . to respond_to ( :parents ) }
it { is_expected . to respond_to ( :date ) }
it { is_expected . to respond_to ( :diffs ) }
it { is_expected . to respond_to ( :id ) }
it { is_expected . to respond_to ( :to_patch ) }
2014-09-02 18:07:02 +05:30
end
describe '#closes_issues' do
let ( :issue ) { create :issue , project : project }
2017-09-10 17:25:29 +05:30
let ( :other_project ) { create ( :project , :public ) }
2015-04-26 12:48:37 +05:30
let ( :other_issue ) { create :issue , project : other_project }
2016-06-02 11:05:42 +05:30
let ( :commiter ) { create :user }
before do
2018-03-17 18:26:18 +05:30
project . add_developer ( commiter )
other_project . add_developer ( commiter )
2016-06-02 11:05:42 +05:30
end
2014-09-02 18:07:02 +05:30
it 'detects issues that this commit is marked as closing' do
2017-09-10 17:25:29 +05:30
ext_ref = " #{ other_project . full_path } # #{ other_issue . iid } "
2016-06-02 11:05:42 +05:30
allow ( commit ) . to receive_messages (
safe_message : " Fixes # #{ issue . iid } and #{ ext_ref } " ,
committer_email : commiter . email
)
2015-12-23 02:04:40 +05:30
expect ( commit . closes_issues ) . to include ( issue )
expect ( commit . closes_issues ) . to include ( other_issue )
2014-09-02 18:07:02 +05:30
end
end
it_behaves_like 'a mentionable' do
2017-08-17 22:00:37 +05:30
subject { create ( :project , :repository ) . commit }
2015-09-11 14:41:01 +05:30
2015-10-24 18:46:33 +05:30
let ( :author ) { create ( :user , email : subject . author_email ) }
2015-04-26 12:48:37 +05:30
let ( :backref_text ) { " commit #{ subject . id } " }
2015-09-11 14:41:01 +05:30
let ( :set_mentionable_text ) do
- > ( txt ) { allow ( subject ) . to receive ( :safe_message ) . and_return ( txt ) }
end
2014-09-02 18:07:02 +05:30
# Include the subject in the repository stub.
let ( :extra_commits ) { [ subject ] }
end
2015-12-23 02:04:40 +05:30
describe '#hook_attrs' do
let ( :data ) { commit . hook_attrs ( with_changed_files : true ) }
it { expect ( data ) . to be_a ( Hash ) }
2016-11-03 12:29:30 +05:30
it { expect ( data [ :message ] ) . to include ( 'adds bar folder and branch-test text file to check Repository merged_to_root_ref method' ) }
2018-03-17 18:26:18 +05:30
it { expect ( data [ :timestamp ] ) . to eq ( '2016-09-27T14:37:46Z' ) }
it { expect ( data [ :added ] ) . to contain_exactly ( " bar/branch-test.txt " ) }
2016-11-03 12:29:30 +05:30
it { expect ( data [ :modified ] ) . to eq ( [ ] ) }
2015-12-23 02:04:40 +05:30
it { expect ( data [ :removed ] ) . to eq ( [ ] ) }
end
2016-04-02 18:10:28 +05:30
2018-03-17 18:26:18 +05:30
describe '#cherry_pick_message' do
let ( :user ) { create ( :user ) }
context 'of a regular commit' do
let ( :commit ) { project . commit ( 'video' ) }
it { expect ( commit . cherry_pick_message ( user ) ) . to include ( " \n \n (cherry picked from commit 88790590ed1337ab189bccaa355f068481c90bec) " ) }
end
context 'of a merge commit' do
let ( :repository ) { project . repository }
let ( :merge_request ) do
create ( :merge_request ,
source_branch : 'video' ,
target_branch : 'master' ,
source_project : project ,
author : user )
end
let ( :merge_commit ) do
merge_commit_id = repository . merge ( user ,
merge_request . diff_head_sha ,
merge_request ,
'Test message' )
repository . commit ( merge_commit_id )
end
context 'that is found' do
before do
# Artificially mark as completed.
merge_request . update ( merge_commit_sha : merge_commit . id )
end
it do
expected_appended_text = << ~ STR . rstrip
( cherry picked from commit #{merge_commit.sha})
467 dc98f Add new 'videos' directory
88790590 Upload new video file
STR
expect ( merge_commit . cherry_pick_message ( user ) ) . to include ( expected_appended_text )
end
end
context " that is existing but not found " do
it 'does not include details of the merged commits' do
expect ( merge_commit . cherry_pick_message ( user ) ) . to end_with ( " (cherry picked from commit #{ merge_commit . sha } ) " )
end
end
end
end
2016-04-02 18:10:28 +05:30
describe '#reverts_commit?' do
let ( :another_commit ) { double ( :commit , revert_description : " This reverts commit #{ commit . sha } " ) }
2017-01-15 13:20:01 +05:30
let ( :user ) { commit . author }
2016-04-02 18:10:28 +05:30
2017-01-15 13:20:01 +05:30
it { expect ( commit . reverts_commit? ( another_commit , user ) ) . to be_falsy }
2016-04-02 18:10:28 +05:30
context 'commit has no description' do
2017-09-10 17:25:29 +05:30
before do
allow ( commit ) . to receive ( :description? ) . and_return ( false )
end
2016-04-02 18:10:28 +05:30
2017-01-15 13:20:01 +05:30
it { expect ( commit . reverts_commit? ( another_commit , user ) ) . to be_falsy }
2016-04-02 18:10:28 +05:30
end
context " another_commit's description does not revert commit " do
2017-09-10 17:25:29 +05:30
before do
allow ( commit ) . to receive ( :description ) . and_return ( " Foo Bar " )
end
2016-04-02 18:10:28 +05:30
2017-01-15 13:20:01 +05:30
it { expect ( commit . reverts_commit? ( another_commit , user ) ) . to be_falsy }
2016-04-02 18:10:28 +05:30
end
context " another_commit's description reverts commit " do
2017-09-10 17:25:29 +05:30
before do
allow ( commit ) . to receive ( :description ) . and_return ( " Foo #{ another_commit . revert_description } Bar " )
end
2016-04-02 18:10:28 +05:30
2017-01-15 13:20:01 +05:30
it { expect ( commit . reverts_commit? ( another_commit , user ) ) . to be_truthy }
2016-04-02 18:10:28 +05:30
end
context " another_commit's description reverts merged merge request " do
before do
revert_description = " This reverts merge request !foo123 "
allow ( another_commit ) . to receive ( :revert_description ) . and_return ( revert_description )
allow ( commit ) . to receive ( :description ) . and_return ( " Foo #{ another_commit . revert_description } Bar " )
end
2017-01-15 13:20:01 +05:30
it { expect ( commit . reverts_commit? ( another_commit , user ) ) . to be_truthy }
2016-04-02 18:10:28 +05:30
end
end
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
describe '#last_pipeline' do
let! ( :first_pipeline ) do
create ( :ci_empty_pipeline ,
project : project ,
sha : commit . sha ,
status : 'success' )
end
let! ( :second_pipeline ) do
create ( :ci_empty_pipeline ,
project : project ,
sha : commit . sha ,
status : 'success' )
end
2016-11-24 13:41:30 +05:30
2017-08-17 22:00:37 +05:30
it 'returns last pipeline' do
expect ( commit . last_pipeline ) . to eq second_pipeline
end
end
2016-11-24 13:41:30 +05:30
2017-08-17 22:00:37 +05:30
describe '#status' do
context 'without ref argument' do
before do
%w[ success failed created pending ] . each do | status |
create ( :ci_empty_pipeline ,
project : project ,
sha : commit . sha ,
status : status )
end
2016-11-24 13:41:30 +05:30
end
2017-08-17 22:00:37 +05:30
it 'gives compound status from latest pipelines' do
expect ( commit . status ) . to eq ( Ci :: Pipeline . latest_status )
expect ( commit . status ) . to eq ( 'pending' )
2016-11-24 13:41:30 +05:30
end
end
context 'when a particular ref is specified' do
let! ( :pipeline_from_master ) do
create ( :ci_empty_pipeline ,
project : project ,
sha : commit . sha ,
ref : 'master' ,
status : 'failed' )
end
let! ( :pipeline_from_fix ) do
create ( :ci_empty_pipeline ,
project : project ,
sha : commit . sha ,
ref : 'fix' ,
status : 'success' )
end
it 'gives pipelines from a particular branch' do
expect ( commit . status ( 'master' ) ) . to eq ( pipeline_from_master . status )
expect ( commit . status ( 'fix' ) ) . to eq ( pipeline_from_fix . status )
end
2017-08-17 22:00:37 +05:30
it 'gives compound status from latest pipelines if ref is nil' do
2018-03-17 18:26:18 +05:30
expect ( commit . status ( nil ) ) . to eq ( pipeline_from_fix . status )
2016-11-24 13:41:30 +05:30
end
end
2016-06-02 11:05:42 +05:30
end
2016-06-16 23:09:34 +05:30
2018-03-17 18:26:18 +05:30
describe '#set_status_for_ref' do
it 'sets the status for a given reference' do
commit . set_status_for_ref ( 'master' , 'failed' )
expect ( commit . status ( 'master' ) ) . to eq ( 'failed' )
end
end
2016-06-16 23:09:34 +05:30
describe '#participants' do
let ( :user1 ) { build ( :user ) }
let ( :user2 ) { build ( :user ) }
let! ( :note1 ) do
create ( :note_on_commit ,
commit_id : commit . id ,
project : project ,
note : 'foo' )
end
let! ( :note2 ) do
create ( :note_on_commit ,
commit_id : commit . id ,
project : project ,
note : 'bar' )
end
before do
allow ( commit ) . to receive ( :author ) . and_return ( user1 )
allow ( commit ) . to receive ( :committer ) . and_return ( user2 )
end
it 'includes the commit author' do
expect ( commit . participants ) . to include ( commit . author )
end
it 'includes the committer' do
expect ( commit . participants ) . to include ( commit . committer )
end
it 'includes the authors of the commit notes' do
expect ( commit . participants ) . to include ( note1 . author , note2 . author )
end
end
2016-06-22 15:30:34 +05:30
describe '#uri_type' do
2018-03-17 18:26:18 +05:30
shared_examples 'URI type' do
it 'returns the URI type at the given path' do
expect ( commit . uri_type ( 'files/html' ) ) . to be ( :tree )
expect ( commit . uri_type ( 'files/images/logo-black.png' ) ) . to be ( :raw )
expect ( project . commit ( 'video' ) . uri_type ( 'files/videos/intro.mp4' ) ) . to be ( :raw )
expect ( commit . uri_type ( 'files/js/application.js' ) ) . to be ( :blob )
end
it " returns nil if the path doesn't exists " do
expect ( commit . uri_type ( 'this/path/doesnt/exist' ) ) . to be_nil
end
2016-06-22 15:30:34 +05:30
end
2018-03-17 18:26:18 +05:30
context 'when Gitaly commit_tree_entry feature is enabled' do
it_behaves_like 'URI type'
end
context 'when Gitaly commit_tree_entry feature is disabled' , :disable_gitaly do
it_behaves_like 'URI type'
2016-06-22 15:30:34 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '.from_hash' do
let ( :new_commit ) { described_class . from_hash ( commit . to_hash , project ) }
it 'returns a Commit' do
expect ( new_commit ) . to be_an_instance_of ( described_class )
end
it 'wraps a Gitlab::Git::Commit' do
expect ( new_commit . raw ) . to be_an_instance_of ( Gitlab :: Git :: Commit )
end
it 'stores the correct commit fields' do
expect ( new_commit . id ) . to eq ( commit . id )
expect ( new_commit . message ) . to eq ( commit . message )
end
end
describe '#work_in_progress?' do
[ 'squash! ' , 'fixup! ' , 'wip: ' , 'WIP: ' , '[WIP] ' ] . each do | wip_prefix |
it " detects the ' #{ wip_prefix } ' prefix " do
commit . message = " #{ wip_prefix } #{ commit . message } "
expect ( commit ) . to be_work_in_progress
end
end
it " detects WIP for a commit just saying 'wip' " do
commit . message = " wip "
expect ( commit ) . to be_work_in_progress
end
it " doesn't detect WIP for a commit that begins with 'FIXUP! ' " do
commit . message = " FIXUP! #{ commit . message } "
expect ( commit ) . not_to be_work_in_progress
end
it " doesn't detect WIP for words starting with WIP " do
commit . message = " Wipout #{ commit . message } "
expect ( commit ) . not_to be_work_in_progress
end
end
describe '.valid_hash?' do
it 'checks hash contents' do
expect ( described_class . valid_hash? ( 'abcdef01239ABCDEF' ) ) . to be true
expect ( described_class . valid_hash? ( " abcdef01239ABCD \n EF " ) ) . to be false
expect ( described_class . valid_hash? ( ' abcdef01239ABCDEF ' ) ) . to be false
expect ( described_class . valid_hash? ( 'Gabcdef01239ABCDEF' ) ) . to be false
expect ( described_class . valid_hash? ( 'gabcdef01239ABCDEF' ) ) . to be false
expect ( described_class . valid_hash? ( '-abcdef01239ABCDEF' ) ) . to be false
end
it 'checks hash length' do
expect ( described_class . valid_hash? ( 'a' * 6 ) ) . to be false
expect ( described_class . valid_hash? ( 'a' * 7 ) ) . to be true
expect ( described_class . valid_hash? ( 'a' * 40 ) ) . to be true
expect ( described_class . valid_hash? ( 'a' * 41 ) ) . to be false
end
end
2018-03-17 18:26:18 +05:30
describe '#merge_requests' do
let! ( :project ) { create ( :project , :repository ) }
let! ( :merge_request1 ) { create ( :merge_request , source_project : project , source_branch : 'master' , target_branch : 'feature' ) }
let! ( :merge_request2 ) { create ( :merge_request , source_project : project , source_branch : 'merged-target' , target_branch : 'feature' ) }
let ( :commit1 ) { merge_request1 . merge_request_diff . commits . last }
let ( :commit2 ) { merge_request1 . merge_request_diff . commits . first }
it 'returns merge_requests that introduced that commit' do
expect ( commit1 . merge_requests ) . to contain_exactly ( merge_request1 , merge_request2 )
expect ( commit2 . merge_requests ) . to contain_exactly ( merge_request1 )
end
end
2014-09-02 18:07:02 +05:30
end