Commit 0625af3b authored by Douwe Maan's avatar Douwe Maan

Consistently create, update, and delete files, taking CRLF settings into account

parent faaca5e1
...@@ -752,24 +752,28 @@ class Repository ...@@ -752,24 +752,28 @@ class Repository
message:, branch_name:, message:, branch_name:,
author_email: nil, author_name: nil, author_email: nil, author_name: nil,
start_branch_name: nil, start_project: project) start_branch_name: nil, start_project: project)
check_tree_entry_for_dir(branch_name, path)
if start_branch_name entry = tree_entry_at(start_branch_name || branch_name, path)
start_project.repository. if entry
check_tree_entry_for_dir(start_branch_name, path) if entry[:type] == :blob
raise Gitlab::Git::Repository::InvalidBlobName.new(
"Directory already exists as a file")
else
raise Gitlab::Git::Repository::InvalidBlobName.new(
"Directory already exists")
end
end end
commit_file( multi_action(
user, user: user,
"#{path}/.gitkeep",
'',
message: message, message: message,
branch_name: branch_name, branch_name: branch_name,
update: false,
author_email: author_email, author_email: author_email,
author_name: author_name, author_name: author_name,
start_branch_name: start_branch_name, start_branch_name: start_branch_name,
start_project: start_project) start_project: start_project,
actions: [{ action: :create_dir,
file_path: path }])
end end
# rubocop:enable Metrics/ParameterLists # rubocop:enable Metrics/ParameterLists
...@@ -779,18 +783,8 @@ class Repository ...@@ -779,18 +783,8 @@ class Repository
message:, branch_name:, update: true, message:, branch_name:, update: true,
author_email: nil, author_name: nil, author_email: nil, author_name: nil,
start_branch_name: nil, start_project: project) start_branch_name: nil, start_project: project)
unless update
error_message = "Filename already exists; update not allowed"
if tree_entry_at(branch_name, path)
raise Gitlab::Git::Repository::InvalidBlobName.new(error_message)
end
if start_branch_name && action = update ? :update : :create
start_project.repository.tree_entry_at(start_branch_name, path)
raise Gitlab::Git::Repository::InvalidBlobName.new(error_message)
end
end
multi_action( multi_action(
user: user, user: user,
...@@ -800,7 +794,7 @@ class Repository ...@@ -800,7 +794,7 @@ class Repository
author_name: author_name, author_name: author_name,
start_branch_name: start_branch_name, start_branch_name: start_branch_name,
start_project: start_project, start_project: start_project,
actions: [{ action: :create, actions: [{ action: action,
file_path: path, file_path: path,
content: content }]) content: content }])
end end
...@@ -839,6 +833,7 @@ class Repository ...@@ -839,6 +833,7 @@ class Repository
message:, branch_name:, message:, branch_name:,
author_email: nil, author_name: nil, author_email: nil, author_name: nil,
start_branch_name: nil, start_project: project) start_branch_name: nil, start_project: project)
multi_action( multi_action(
user: user, user: user,
message: message, message: message,
...@@ -861,21 +856,22 @@ class Repository ...@@ -861,21 +856,22 @@ class Repository
branch_name, branch_name,
start_branch_name: start_branch_name, start_branch_name: start_branch_name,
start_project: start_project) do |start_commit| start_project: start_project) do |start_commit|
index = rugged.index
parents = if start_commit index = Gitlab::Git::Index.new(raw_repository)
if start_commit
index.read_tree(start_commit.raw_commit.tree) index.read_tree(start_commit.raw_commit.tree)
[start_commit.sha] parents = [start_commit.sha]
else else
[] parents = []
end end
actions.each do |act| actions.each do |options|
git_action(index, act) index.__send__(options.delete(:action), options)
end end
options = { options = {
tree: index.write_tree(rugged), tree: index.write_tree,
message: message, message: message,
parents: parents parents: parents
} }
...@@ -1174,22 +1170,6 @@ class Repository ...@@ -1174,22 +1170,6 @@ class Repository
raw_repository.send(:tree_entry, commit(branch_name), path) raw_repository.send(:tree_entry, commit(branch_name), path)
end end
def check_tree_entry_for_dir(branch_name, path)
return unless branch_exists?(branch_name)
entry = tree_entry_at(branch_name, path)
return unless entry
if entry[:type] == :blob
raise Gitlab::Git::Repository::InvalidBlobName.new(
"Directory already exists as a file")
else
raise Gitlab::Git::Repository::InvalidBlobName.new(
"Directory already exists")
end
end
private private
def blob_data_at(sha, path) def blob_data_at(sha, path)
...@@ -1200,58 +1180,6 @@ class Repository ...@@ -1200,58 +1180,6 @@ class Repository
blob.data blob.data
end end
def git_action(index, action)
path = normalize_path(action[:file_path])
if action[:action] == :move
previous_path = normalize_path(action[:previous_path])
end
case action[:action]
when :create, :update, :move
mode =
case action[:action]
when :update
index.get(path)[:mode]
when :move
index.get(previous_path)[:mode]
end
mode ||= 0o100644
index.remove(previous_path) if action[:action] == :move
content = if action[:encoding] == 'base64'
Base64.decode64(action[:content])
else
action[:content]
end
detect = CharlockHolmes::EncodingDetector.new.detect(content) if content
unless detect && detect[:type] == :binary
# When writing to the repo directly as we are doing here,
# the `core.autocrlf` config isn't taken into account.
content.gsub!("\r\n", "\n") if self.autocrlf
end
oid = rugged.write(content, :blob)
index.add(path: path, oid: oid, mode: mode)
when :delete
index.remove(path)
end
end
def normalize_path(path)
pathname = Gitlab::Git::PathHelper.normalize_path(path)
if pathname.each_filename.include?('..')
raise Gitlab::Git::Repository::InvalidBlobName.new('Invalid path')
end
pathname.to_s
end
def refs_directory_exists? def refs_directory_exists?
return false unless path_with_namespace return false unless path_with_namespace
......
...@@ -2,6 +2,8 @@ module Files ...@@ -2,6 +2,8 @@ module Files
class MultiService < Files::BaseService class MultiService < Files::BaseService
class FileChangedError < StandardError; end class FileChangedError < StandardError; end
ACTIONS = %w[create update delete move].freeze
def commit def commit
repository.multi_action( repository.multi_action(
user: current_user, user: current_user,
...@@ -19,15 +21,23 @@ module Files ...@@ -19,15 +21,23 @@ module Files
def validate def validate
super super
params[:actions].each_with_index do |action, index| params[:actions].each_with_index do |action, index|
unless action[:file_path].present? unless action[:file_path].present?
raise_error("You must specify a file_path.") raise_error("You must specify a file_path.")
end end
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/')
regex_check(action[:file_path]) regex_check(action[:file_path])
regex_check(action[:previous_path]) if action[:previous_path] regex_check(action[:previous_path]) if action[:previous_path]
if ACTIONS.include?(action[:action].to_s)
action[:action] = action[:action].to_sym
else
raise_error("Unknown action type `#{action[:action]}`.")
end
if project.empty_repo? && action[:action] != :create if project.empty_repo? && action[:action] != :create
raise_error("No files to #{action[:action]}.") raise_error("No files to #{action[:action]}.")
end end
...@@ -43,8 +53,6 @@ module Files ...@@ -43,8 +53,6 @@ module Files
validate_delete(action) validate_delete(action)
when :move when :move
validate_move(action, index) validate_move(action, index)
else
raise_error("Unknown action type `#{action[:action]}`.")
end end
end end
end end
......
...@@ -155,17 +155,9 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -155,17 +155,9 @@ class Gitlab::Seeder::CycleAnalytics
issue.project.repository.add_branch(@user, branch_name, 'master') issue.project.repository.add_branch(@user, branch_name, 'master')
options = { commit_sha = issue.project.repository.commit_file(@user, filename, "content", options, message: "Commit for ##{issue.iid}", branch_name: branch_name)
committer: issue.project.repository.user_to_committer(@user),
author: issue.project.repository.user_to_committer(@user),
commit: { message: "Commit for ##{issue.iid}", branch: branch_name, update_ref: true },
file: { content: "content", path: filename, update: false }
}
commit_sha = Gitlab::Git::Blob.commit(issue.project.repository, options)
issue.project.repository.commit(commit_sha) issue.project.repository.commit(commit_sha)
GitPushService.new(issue.project, GitPushService.new(issue.project,
@user, @user,
oldrev: issue.project.repository.commit("master").sha, oldrev: issue.project.repository.commit("master").sha,
......
...@@ -52,13 +52,6 @@ module API ...@@ -52,13 +52,6 @@ module API
attrs = declared_params.merge(start_branch: declared_params[:branch], target_branch: declared_params[:branch]) attrs = declared_params.merge(start_branch: declared_params[:branch], target_branch: declared_params[:branch])
attrs[:actions].map! do |action|
action[:action] = action[:action].to_sym
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/')
action
end
result = ::Files::MultiService.new(user_project, current_user, attrs).execute result = ::Files::MultiService.new(user_project, current_user, attrs).execute
if result[:status] == :success if result[:status] == :success
......
...@@ -93,163 +93,6 @@ module Gitlab ...@@ -93,163 +93,6 @@ module Gitlab
commit_id: sha, commit_id: sha,
) )
end end
# Commit file in repository and return commit sha
#
# options should contain next structure:
# file: {
# content: 'Lorem ipsum...',
# path: 'documents/story.txt',
# update: true
# },
# author: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# committer: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# commit: {
# message: 'Wow such commit',
# branch: 'master',
# update_ref: false
# }
#
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def commit(repository, options, action = :add)
file = options[:file]
update = file[:update].nil? ? true : file[:update]
author = options[:author]
committer = options[:committer]
commit = options[:commit]
repo = repository.rugged
ref = commit[:branch]
update_ref = commit[:update_ref].nil? ? true : commit[:update_ref]
parents = []
mode = 0o100644
unless ref.start_with?('refs/')
ref = 'refs/heads/' + ref
end
path_name = Gitlab::Git::PathHelper.normalize_path(file[:path])
# Abort if any invalid characters remain (e.g. ../foo)
raise Gitlab::Git::Repository::InvalidBlobName.new("Invalid path") if path_name.each_filename.to_a.include?('..')
filename = path_name.to_s
index = repo.index
unless repo.empty?
rugged_ref = repo.references[ref]
raise Gitlab::Git::Repository::InvalidRef.new("Invalid branch name") unless rugged_ref
last_commit = rugged_ref.target
index.read_tree(last_commit.tree)
parents = [last_commit]
end
if action == :remove
index.remove(filename)
else
file_entry = index.get(filename)
if action == :rename
old_path_name = Gitlab::Git::PathHelper.normalize_path(file[:previous_path])
old_filename = old_path_name.to_s
file_entry = index.get(old_filename)
index.remove(old_filename) unless file_entry.blank?
end
if file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("Filename already exists; update not allowed") unless update
# Preserve the current file mode if one is available
mode = file_entry[:mode] if file_entry[:mode]
end
content = file[:content]
detect = CharlockHolmes::EncodingDetector.new.detect(content) if content
unless detect && detect[:type] == :binary
# When writing to the repo directly as we are doing here,
# the `core.autocrlf` config isn't taken into account.
content.gsub!("\r\n", "\n") if repository.autocrlf
end
oid = repo.write(content, :blob)
index.add(path: filename, oid: oid, mode: mode)
end
opts = {}
opts[:tree] = index.write_tree(repo)
opts[:author] = author
opts[:committer] = committer
opts[:message] = commit[:message]
opts[:parents] = parents
opts[:update_ref] = ref if update_ref
Rugged::Commit.create(repo, opts)
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
# Remove file from repository and return commit sha
#
# options should contain next structure:
# file: {
# path: 'documents/story.txt'
# },
# author: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# committer: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# commit: {
# message: 'Remove FILENAME',
# branch: 'master'
# }
#
def remove(repository, options)
commit(repository, options, :remove)
end
# Rename file from repository and return commit sha
#
# options should contain next structure:
# file: {
# previous_path: 'documents/old_story.txt'
# path: 'documents/story.txt'
# content: 'Lorem ipsum...',
# update: true
# },
# author: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# committer: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# commit: {
# message: 'Rename FILENAME',
# branch: 'master'
# }
#
def rename(repository, options)
commit(repository, options, :rename)
end
end end
def initialize(options) def initialize(options)
......
module Gitlab
module Git
class Index
DEFAULT_MODE = 0o100644
attr_reader :repository, :raw_index
def initialize(repository)
@repository = repository
@raw_index = repository.rugged.index
end
def read_tree(tree)
raw_index.read_tree(tree)
end
def write_tree
raw_index.write_tree(repository.rugged)
end
def get(*args)
raw_index.get(*args)
end
def create(options)
normalize_options!(options)
file_entry = raw_index.get(options[:file_path])
if file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("Filename already exists")
end
add_blob(options)
end
def create_dir(options)
normalize_options!(options)
file_entry = raw_index.get(options[:file_path])
if file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("Directory already exists as a file")
end
options = options.dup
options[:file_path] += '/.gitkeep'
options[:content] = ''
add_blob(options)
end
def update(options)
normalize_options!(options)
file_entry = raw_index.get(options[:file_path])
unless file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
end
add_blob(options, mode: file_entry[:mode])
end
def move(options)
normalize_options!(options)
file_entry = raw_index.get(options[:previous_path])
unless file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
end
raw_index.remove(options[:previous_path])
add_blob(options, mode: file_entry[:mode])
end
def delete(options)
normalize_options!(options)
file_entry = raw_index.get(options[:file_path])
unless file_entry
raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
end
raw_index.remove(options[:file_path])
end
private
def normalize_options!(options)
options[:file_path] = normalize_path(options[:file_path]) if options[:file_path]
options[:previous_path] = normalize_path(options[:previous_path]) if options[:previous_path]
end
def normalize_path(path)
pathname = Gitlab::Git::PathHelper.normalize_path(path)
if pathname.each_filename.include?('..')
raise Gitlab::Git::Repository::InvalidBlobName.new('Invalid path')
end
pathname.to_s
end
def add_blob(options, mode: nil)
content = options[:content]
return unless content
content = Base64.decode64(content) if options[:encoding] == 'base64'
detect = CharlockHolmes::EncodingDetector.new.detect(content)
unless detect && detect[:type] == :binary
# When writing to the repo directly as we are doing here,
# the `core.autocrlf` config isn't taken into account.
content.gsub!("\r\n", "\n") if repository.autocrlf
end
oid = repository.rugged.write(content, :blob)
raw_index.add(path: options[:file_path], oid: oid, mode: mode || DEFAULT_MODE)
rescue Rugged::IndexError => e
raise Gitlab::Git::Repository::InvalidBlobName.new(e.message)
end
end
end
end
...@@ -837,57 +837,6 @@ module Gitlab ...@@ -837,57 +837,6 @@ module Gitlab
rugged.config['core.autocrlf'] = AUTOCRLF_VALUES.invert[value] rugged.config['core.autocrlf'] = AUTOCRLF_VALUES.invert[value]
end end
# Create a new directory with a .gitkeep file. Creates
# all required nested directories (i.e. mkdir -p behavior)
#
# options should contain next structure:
# author: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# committer: {
# email: 'user@example.com',
# name: 'Test User',
# time: Time.now
# },
# commit: {
# message: 'Wow such commit',
# branch: 'master',
# update_ref: false
# }
def mkdir(path, options = {})
# Check if this directory exists; if it does, then don't bother
# adding .gitkeep file.
ref = options[:commit][:branch]
path = Gitlab::Git::PathHelper.normalize_path(path).to_s
rugged_ref = rugged.ref(ref)
raise InvalidRef.new("Invalid ref") if rugged_ref.nil?
target_commit = rugged_ref.target
raise InvalidRef.new("Invalid target commit") if target_commit.nil?
entry = tree_entry(target_commit, path)
if entry
if entry[:type] == :blob
raise InvalidBlobName.new("Directory already exists as a file")
else
raise InvalidBlobName.new("Directory already exists")
end
end
options[:file] = {
content: '',
path: "#{path}/.gitkeep",
update: true
}
Gitlab::Git::Blob.commit(self, options)
end
# Returns result like "git ls-files" , recursive and full file path # Returns result like "git ls-files" , recursive and full file path
# #
# Ex. # Ex.
......
...@@ -222,191 +222,6 @@ describe Gitlab::Git::Blob, seed_helper: true do ...@@ -222,191 +222,6 @@ describe Gitlab::Git::Blob, seed_helper: true do
end end
end end
describe :commit do
let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
let(:commit_options) do
{
file: {
content: 'Lorem ipsum...',
path: 'documents/story.txt'
},
author: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
committer: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Wow such commit',
branch: 'fix-mode'
}
}
end
let(:commit_sha) { Gitlab::Git::Blob.commit(repository, commit_options) }
let(:commit) { repository.lookup(commit_sha) }
it 'should add file with commit' do
# Commit message valid
expect(commit.message).to eq('Wow such commit')
tree = commit.tree.to_a.find { |tree| tree[:name] == 'documents' }
# Directory was created
expect(tree[:type]).to eq(:tree)
# File was created
expect(repository.lookup(tree[:oid]).first[:name]).to eq('story.txt')
end
describe "ref updating" do
it 'creates a commit but does not udate a ref' do
commit_opts = commit_options.tap{ |opts| opts[:commit][:update_ref] = false}
commit_sha = Gitlab::Git::Blob.commit(repository, commit_opts)
commit = repository.lookup(commit_sha)
# Commit message valid
expect(commit.message).to eq('Wow such commit')
# Does not update any related ref
expect(repository.lookup("fix-mode").oid).not_to eq(commit.oid)
expect(repository.lookup("HEAD").oid).not_to eq(commit.oid)
end
end
describe 'reject updates' do
it 'should reject updates' do
commit_options[:file][:update] = false
commit_options[:file][:path] = 'files/executables/ls'
expect{ commit_sha }.to raise_error('Filename already exists; update not allowed')
end
end
describe 'file modes' do
it 'should preserve file modes with commit' do
commit_options[:file][:path] = 'files/executables/ls'
entry = Gitlab::Git::Blob.find_entry_by_path(repository, commit.tree.oid, commit_options[:file][:path])
expect(entry[:filemode]).to eq(0100755)
end
end
end
describe :rename do
let(:repository) { Gitlab::Git::Repository.new(TEST_NORMAL_REPO_PATH) }
let(:rename_options) do
{
file: {
path: 'NEWCONTRIBUTING.md',
previous_path: 'CONTRIBUTING.md',
content: 'Lorem ipsum...',
update: true
},
author: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
committer: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Rename readme',
branch: 'master'
}
}
end
let(:rename_options2) do
{
file: {
content: 'Lorem ipsum...',
path: 'bin/new_executable',
previous_path: 'bin/executable',
},
author: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
committer: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Updates toberenamed.txt',
branch: 'master',
update_ref: false
}
}
end
it 'maintains file permissions when renaming' do
mode = 0o100755
Gitlab::Git::Blob.rename(repository, rename_options2)
expect(repository.rugged.index.get(rename_options2[:file][:path])[:mode]).to eq(mode)
end
it 'renames the file with commit and not change file permissions' do
ref = rename_options[:commit][:branch]
expect(repository.rugged.index.get('CONTRIBUTING.md')).not_to be_nil
expect { Gitlab::Git::Blob.rename(repository, rename_options) }.to change { repository.commit_count(ref) }.by(1)
expect(repository.rugged.index.get('CONTRIBUTING.md')).to be_nil
expect(repository.rugged.index.get('NEWCONTRIBUTING.md')).not_to be_nil
end
end
describe :remove do
let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
let(:commit_options) do
{
file: {
path: 'README.md'
},
author: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
committer: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Remove readme',
branch: 'feature'
}
}
end
let(:commit_sha) { Gitlab::Git::Blob.remove(repository, commit_options) }
let(:commit) { repository.lookup(commit_sha) }
let(:blob) { Gitlab::Git::Blob.find(repository, commit_sha, "README.md") }
it 'should remove file with commit' do
# Commit message valid
expect(commit.message).to eq('Remove readme')
# File was removed
expect(blob).to be_nil
end
end
describe :lfs_pointers do describe :lfs_pointers do
context 'file a valid lfs pointer' do context 'file a valid lfs pointer' do
let(:blob) do let(:blob) do
......
require 'spec_helper'
describe Gitlab::Git::Index, seed_helper: true do
let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
let(:index) { described_class.new(repository) }
before do
index.read_tree(repository.lookup('master').tree)
end
describe '#create' do
let(:options) do
{
content: 'Lorem ipsum...',
file_path: 'documents/story.txt'
}
end
context 'when no file at that path exists' do
it 'creates the file in the index' do
index.create(options)
entry = index.get(options[:file_path])
expect(entry).not_to be_nil
expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
end
end
context 'when a file at that path exists' do
before do
options[:file_path] = 'files/executables/ls'
end
it 'raises an error' do
expect { index.create(options) }.to raise_error('Filename already exists')
end
end
context 'when content is in base64' do
before do
options[:content] = Base64.encode64(options[:content])
options[:encoding] = 'base64'
end
it 'decodes base64' do
index.create(options)
entry = index.get(options[:file_path])
expect(repository.lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content]))
end
end
context 'when content contains CRLF' do
before do
repository.autocrlf = :input
options[:content] = "Hello,\r\nWorld"
end
it 'converts to LF' do
index.create(options)
entry = index.get(options[:file_path])
expect(repository.lookup(entry[:oid]).content).to eq("Hello,\nWorld")
end
end
end
describe '#create_dir' do
let(:options) do
{
file_path: 'newdir'
}
end
context 'when no file or dir at that path exists' do
it 'creates the dir in the index' do
index.create_dir(options)
entry = index.get(options[:file_path] + '/.gitkeep')
expect(entry).not_to be_nil
end
end
context 'when a file at that path exists' do
before do
options[:file_path] = 'files/executables/ls'
end
it 'raises an error' do
expect { index.create_dir(options) }.to raise_error('Directory already exists as a file')
end
end
end
describe '#update' do
let(:options) do
{
content: 'Lorem ipsum...',
file_path: 'README.md'
}
end
context 'when no file at that path exists' do
before do
options[:file_path] = 'documents/story.txt'
end
it 'raises an error' do
expect { index.update(options) }.to raise_error("File doesn't exist")
end
end
context 'when a file at that path exists' do
it 'updates the file in the index' do
index.update(options)
entry = index.get(options[:file_path])
expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
end
it 'preserves file mode' do
options[:file_path] = 'files/executables/ls'
index.update(options)
entry = index.get(options[:file_path])
expect(entry[:mode]).to eq(0100755)
end
end
end
describe '#move' do
let(:options) do
{
content: 'Lorem ipsum...',
previous_path: 'README.md',
file_path: 'NEWREADME.md'
}
end
context 'when no file at that path exists' do
it 'raises an error' do
options[:previous_path] = 'documents/story.txt'
expect { index.move(options) }.to raise_error("File doesn't exist")
end
end
context 'when a file at that path exists' do
it 'removes the old file in the index' do
index.move(options)
entry = index.get(options[:previous_path])
expect(entry).to be_nil
end
it 'creates the new file in the index' do
index.move(options)
entry = index.get(options[:file_path])
expect(entry).not_to be_nil
expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
end
it 'preserves file mode' do
options[:previous_path] = 'files/executables/ls'
index.move(options)
entry = index.get(options[:file_path])
expect(entry[:mode]).to eq(0100755)
end
end
end
describe '#delete' do
let(:options) do
{
file_path: 'README.md'
}
end
context 'when no file at that path exists' do
before do
options[:file_path] = 'documents/story.txt'
end
it 'raises an error' do
expect { index.delete(options) }.to raise_error("File doesn't exist")
end
end
context 'when a file at that path exists' do
it 'removes the file in the index' do
index.delete(options)
entry = index.get(options[:file_path])
expect(entry).to be_nil
end
end
end
end
...@@ -844,81 +844,6 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -844,81 +844,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
describe '#mkdir' do
let(:commit_options) do
{
author: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
committer: {
email: 'user@example.com',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Test message',
branch: 'refs/heads/fix',
}
}
end
def generate_diff_for_path(path)
"diff --git a/#{path}/.gitkeep b/#{path}/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/#{path}/.gitkeep\n"
end
shared_examples 'mkdir diff check' do |path, expected_path|
it 'creates a directory' do
result = repository.mkdir(path, commit_options)
expect(result).not_to eq(nil)
# Verify another mkdir doesn't create a directory that already exists
expect{ repository.mkdir(path, commit_options) }.to raise_error('Directory already exists')
end
end
describe 'creates a directory in root directory' do
it_should_behave_like 'mkdir diff check', 'new_dir', 'new_dir'
end
describe 'creates a directory in subdirectory' do
it_should_behave_like 'mkdir diff check', 'files/ruby/test', 'files/ruby/test'
end
describe 'creates a directory in subdirectory with a slash' do
it_should_behave_like 'mkdir diff check', '/files/ruby/test2', 'files/ruby/test2'
end
describe 'creates a directory in subdirectory with multiple slashes' do
it_should_behave_like 'mkdir diff check', '//files/ruby/test3', 'files/ruby/test3'
end
describe 'handles relative paths' do
it_should_behave_like 'mkdir diff check', 'files/ruby/../test_relative', 'files/test_relative'
end
describe 'creates nested directories' do
it_should_behave_like 'mkdir diff check', 'files/missing/test', 'files/missing/test'
end
it 'does not attempt to create a directory with invalid relative path' do
expect{ repository.mkdir('../files/missing/test', commit_options) }.to raise_error('Invalid path')
end
it 'does not attempt to overwrite a file' do
expect{ repository.mkdir('README.md', commit_options) }.to raise_error('Directory already exists as a file')
end
it 'does not attempt to overwrite a directory' do
expect{ repository.mkdir('files', commit_options) }.to raise_error('Directory already exists')
end
end
describe "#ls_files" do describe "#ls_files" do
let(:master_file_paths) { repository.ls_files("master") } let(:master_file_paths) { repository.ls_files("master") }
let(:not_existed_branch) { repository.ls_files("not_existed_branch") } let(:not_existed_branch) { repository.ls_files("not_existed_branch") }
......
...@@ -355,7 +355,7 @@ describe Repository, models: true do ...@@ -355,7 +355,7 @@ describe Repository, models: true do
repository.commit_file(user, 'hello.txt', "Hello,\r\nWorld", repository.commit_file(user, 'hello.txt', "Hello,\r\nWorld",
message: 'Add hello world', message: 'Add hello world',
branch_name: 'master', branch_name: 'master',
update: true) update: false)
blob = repository.blob_at('master', 'hello.txt') blob = repository.blob_at('master', 'hello.txt')
......
...@@ -9,14 +9,7 @@ module CycleAnalyticsHelpers ...@@ -9,14 +9,7 @@ module CycleAnalyticsHelpers
commit_shas = Array.new(count) do |index| commit_shas = Array.new(count) do |index|
filename = random_git_name filename = random_git_name
options = { commit_sha = project.repository.commit_file(user, filename, "content", message: message, branch_name: branch_name)
committer: project.repository.user_to_committer(user),
author: project.repository.user_to_committer(user),
commit: { message: message, branch: branch_name, update_ref: true },
file: { content: "content", path: filename, update: false }
}
commit_sha = Gitlab::Git::Blob.commit(project.repository, options)
project.repository.commit(commit_sha) project.repository.commit(commit_sha)
commit_sha commit_sha
......
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