gitolite 0.0.2.alpha → 0.0.3.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemtest +0 -0
- data/.gitignore +3 -0
- data/Gemfile.lock +17 -12
- data/LICENSE +22 -0
- data/README.rdoc +84 -20
- data/Rakefile +32 -0
- data/gitolite.gemspec +5 -2
- data/lib/gitolite.rb +1 -0
- data/lib/gitolite/config.rb +112 -63
- data/lib/gitolite/config/group.rb +51 -0
- data/lib/gitolite/config/repo.rb +83 -0
- data/lib/gitolite/gitolite_admin.rb +83 -26
- data/lib/gitolite/ssh_key.rb +2 -2
- data/lib/gitolite/version.rb +1 -1
- data/spec/concurrency_spec.rb +2 -0
- data/spec/config_spec.rb +354 -1
- data/spec/configs/complicated.conf +3 -0
- data/spec/group_spec.rb +126 -0
- data/spec/keys/bob-ins@zilla-site.com@desktop.pub +1 -0
- data/spec/keys/bob.joe@test.zilla.com@desktop.pub +1 -0
- data/spec/keys/joe-bob@god-zilla.com@desktop.pub +1 -0
- data/spec/repo_spec.rb +97 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/ssh_key_spec.rb +13 -1
- metadata +157 -48
@@ -0,0 +1,51 @@
|
|
1
|
+
module Gitolite
|
2
|
+
class Config
|
3
|
+
# Represents a group inside the gitolite configuration. The name and users
|
4
|
+
# options are all encapsulated in this class. All users are stored as
|
5
|
+
# Strings!
|
6
|
+
class Group
|
7
|
+
attr_accessor :name, :users
|
8
|
+
|
9
|
+
PREPEND_CHAR = '@'
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
# naively remove the prepend char
|
13
|
+
# I don't think you can have two of them in a group name
|
14
|
+
@name = name.gsub(PREPEND_CHAR, '')
|
15
|
+
@users = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty!
|
19
|
+
@users.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_user(user)
|
23
|
+
return if has_user?(user)
|
24
|
+
@users.push(user.to_s).sort!
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_users(*users)
|
28
|
+
fixed_users = users.flatten.map{ |u| u.to_s }
|
29
|
+
@users.concat(fixed_users).sort!.uniq!
|
30
|
+
end
|
31
|
+
|
32
|
+
def rm_user(user)
|
33
|
+
@users.delete(user.to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_user?(user)
|
37
|
+
@users.include? user.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def size
|
41
|
+
@users.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
members = @users.join(' ')
|
46
|
+
name = "#{PREPEND_CHAR}#{@name}"
|
47
|
+
"#{name.ljust(20)}= #{members}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'hashery'
|
2
|
+
|
3
|
+
module Gitolite
|
4
|
+
class Config
|
5
|
+
#Represents a repo inside the gitolite configuration. The name, permissions, and git config
|
6
|
+
#options are all encapsulated in this class
|
7
|
+
class Repo
|
8
|
+
ALLOWED_PERMISSIONS = /-|R|RW+?C?D?/
|
9
|
+
|
10
|
+
attr_accessor :permissions, :name, :config, :owner, :description
|
11
|
+
|
12
|
+
def initialize(name)
|
13
|
+
#Store the perm hash in a lambda since we have to create a new one on every deny rule
|
14
|
+
#The perm hash is stored as a 2D hash, with individual permissions being the first
|
15
|
+
#degree and individual refexes being the second degree. Both Hashes must respect order
|
16
|
+
@perm_hash_lambda = lambda { OrderedHash.new {|k,v| k[v] = OrderedHash.new{|k2, v2| k2[v2] = [] }} }
|
17
|
+
@permissions = Array.new.push(@perm_hash_lambda.call)
|
18
|
+
|
19
|
+
@name = name
|
20
|
+
@config = {} #git config
|
21
|
+
end
|
22
|
+
|
23
|
+
def clean_permissions
|
24
|
+
@permissions = Array.new.push(@perm_hash_lambda.call)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_permission(perm, refex = "", *users)
|
28
|
+
if perm =~ ALLOWED_PERMISSIONS
|
29
|
+
#Handle deny rules
|
30
|
+
if perm == '-'
|
31
|
+
@permissions.push(@perm_hash_lambda.call)
|
32
|
+
end
|
33
|
+
|
34
|
+
@permissions.last[perm][refex].concat users.flatten
|
35
|
+
@permissions.last[perm][refex].uniq!
|
36
|
+
else
|
37
|
+
raise InvalidPermissionError, "#{perm} is not in the allowed list of permissions!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_git_config(key, value)
|
42
|
+
@config[key] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def unset_git_config(key)
|
46
|
+
@config.delete(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
repo = "repo #{@name}\n"
|
51
|
+
|
52
|
+
@permissions.each do |perm_hash|
|
53
|
+
perm_hash.each do |perm, list|
|
54
|
+
list.each do |refex, users|
|
55
|
+
repo += " " + perm.ljust(6) + refex.ljust(25) + "= " + users.join(' ') + "\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
@config.each do |k, v|
|
61
|
+
repo += " config " + k + " = " + v + "\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
repo
|
65
|
+
end
|
66
|
+
|
67
|
+
def gitweb_description
|
68
|
+
if @description.nil?
|
69
|
+
nil
|
70
|
+
else
|
71
|
+
desc = "#{@name} "
|
72
|
+
desc += "\"#{@owner}\" " unless @owner.nil?
|
73
|
+
desc += "= \"#{@description}\""
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
#Gets raised if a permission that isn't in the allowed
|
78
|
+
#list is passed in
|
79
|
+
class InvalidPermissionError < ArgumentError
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -6,8 +6,8 @@ module Gitolite
|
|
6
6
|
CONFDIR = "conf"
|
7
7
|
KEYDIR = "keydir"
|
8
8
|
|
9
|
-
#Intialize with the path to
|
10
|
-
#the gitolite-admin repository
|
9
|
+
# Intialize with the path to
|
10
|
+
# the gitolite-admin repository
|
11
11
|
def initialize(path, options = {})
|
12
12
|
@gl_admin = Grit::Repo.new(path)
|
13
13
|
|
@@ -19,38 +19,78 @@ module Gitolite
|
|
19
19
|
@config = Config.new(File.join(path, @confdir, @conf))
|
20
20
|
end
|
21
21
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
22
|
+
# This method will bootstrap a gitolite-admin repo
|
23
|
+
# at the given path. A typical gitolite-admin
|
24
|
+
# repo will have the following tree:
|
25
|
+
#
|
26
|
+
# gitolite-admin
|
27
|
+
# conf
|
28
|
+
# gitolite.conf
|
29
|
+
# keydir
|
30
|
+
def self.bootstrap(path, options = {})
|
31
|
+
if self.is_gitolite_admin_repo?(path)
|
32
|
+
if options[:overwrite]
|
33
|
+
FileUtils.rm_rf(File.join(path, '*'))
|
34
|
+
else
|
35
|
+
return self.new(path)
|
36
|
+
end
|
37
|
+
end
|
26
38
|
|
27
|
-
|
28
|
-
new_conf = @config.to_file(@confdir)
|
29
|
-
@gl_admin.add(new_conf)
|
39
|
+
FileUtils.mkdir_p([File.join(path,"conf"), File.join(path,"keydir")])
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
41
|
+
options[:perm] ||= "RW+"
|
42
|
+
options[:refex] ||= ""
|
43
|
+
options[:user] ||= "git"
|
34
44
|
|
35
|
-
|
36
|
-
|
45
|
+
c = Config.init
|
46
|
+
r = Config::Repo.new(options[:repo] || "gitolite-admin")
|
47
|
+
r.add_permission(options[:perm], options[:refex], options[:user])
|
48
|
+
c.add_repo(r)
|
49
|
+
config = c.to_file(File.join(path, "conf"))
|
50
|
+
|
51
|
+
repo = Grit::Repo.init(path)
|
52
|
+
Dir.chdir(path) do
|
53
|
+
repo.add(config)
|
54
|
+
repo.commit_index(options[:message] || "Config bootstrapped by the gitolite gem")
|
55
|
+
end
|
56
|
+
|
57
|
+
self.new(path)
|
58
|
+
end
|
37
59
|
|
38
|
-
|
39
|
-
|
40
|
-
|
60
|
+
#Writes all aspects out to the file system
|
61
|
+
#will also stage all changes
|
62
|
+
def save
|
63
|
+
Dir.chdir(@gl_admin.working_dir) do
|
64
|
+
#Process config file
|
65
|
+
new_conf = @config.to_file(@confdir)
|
66
|
+
@gl_admin.add(new_conf)
|
67
|
+
|
68
|
+
#Process ssh keys
|
69
|
+
files = list_keys(@keydir).map{|f| File.basename f}
|
70
|
+
keys = @ssh_keys.values.map{|f| f.map {|t| t.filename}}.flatten
|
71
|
+
|
72
|
+
to_remove = (files - keys).map { |f| File.join(@keydir, f)}
|
73
|
+
@gl_admin.remove(to_remove)
|
74
|
+
|
75
|
+
@ssh_keys.each_value do |key|
|
76
|
+
key.each do |k|
|
77
|
+
@gl_admin.add(k.to_file(@keydir))
|
78
|
+
end
|
41
79
|
end
|
42
80
|
end
|
43
81
|
end
|
44
82
|
|
45
83
|
#commits all staged changes and pushes back
|
46
84
|
#to origin
|
47
|
-
|
48
|
-
|
49
|
-
|
85
|
+
#
|
86
|
+
#TODO: generate a better commit message
|
87
|
+
#TODO: add the ability to specify the remote and branch
|
88
|
+
#TODO: detect existance of origin instead of just dying
|
89
|
+
def apply(commit_message = "Commit by gitolite gem")
|
90
|
+
@gl_admin.commit_index(commit_message)
|
50
91
|
@gl_admin.git.push({}, "origin", "master")
|
51
92
|
end
|
52
93
|
|
53
|
-
#Calls save and apply in order
|
54
94
|
def save_and_apply
|
55
95
|
self.save
|
56
96
|
self.apply
|
@@ -65,6 +105,24 @@ module Gitolite
|
|
65
105
|
@ssh_keys[key.owner].delete key
|
66
106
|
end
|
67
107
|
|
108
|
+
#Checks to see if the given path is a gitolite-admin repository
|
109
|
+
#A valid repository contains a conf folder, keydir folder,
|
110
|
+
#and a configuration file within the conf folder
|
111
|
+
def self.is_gitolite_admin_repo?(dir)
|
112
|
+
# First check if it is a git repository
|
113
|
+
begin
|
114
|
+
Grit::Repo.new(dir)
|
115
|
+
rescue Grit::InvalidGitRepositoryError
|
116
|
+
return false
|
117
|
+
end
|
118
|
+
|
119
|
+
# If we got here it is a valid git repo,
|
120
|
+
# now check directory structure
|
121
|
+
File.exists?(File.join(dir, 'conf')) &&
|
122
|
+
File.exists?(File.join(dir, 'keydir')) &&
|
123
|
+
!Dir.glob(File.join(dir, 'conf', '*.conf')).empty?
|
124
|
+
end
|
125
|
+
|
68
126
|
private
|
69
127
|
#Loads all .pub files in the gitolite-admin
|
70
128
|
#keydir directory
|
@@ -82,11 +140,10 @@ module Gitolite
|
|
82
140
|
end
|
83
141
|
|
84
142
|
def list_keys(path)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
keys
|
143
|
+
Dir.chdir(path) do
|
144
|
+
keys = Dir.glob("**/*.pub")
|
145
|
+
keys
|
146
|
+
end
|
90
147
|
end
|
91
148
|
end
|
92
149
|
end
|
data/lib/gitolite/ssh_key.rb
CHANGED
@@ -25,7 +25,7 @@ module Gitolite
|
|
25
25
|
raise "#{key} does not exist!" unless File.exists?(key)
|
26
26
|
|
27
27
|
#Get our owner and location
|
28
|
-
File.basename(key) =~ /^(\w+(?:@(
|
28
|
+
File.basename(key) =~ /^([\w\.-]+(?:@(?:[\w-]+\.)+\D{2,4})?)(?:@(\w+))?.pub$/i
|
29
29
|
owner = $1
|
30
30
|
location = $2 || ""
|
31
31
|
|
@@ -47,7 +47,7 @@ module Gitolite
|
|
47
47
|
def to_file(path)
|
48
48
|
key_file = File.join(path, self.filename)
|
49
49
|
File.open(key_file, "w") do |f|
|
50
|
-
f.write
|
50
|
+
f.write(self.to_s)
|
51
51
|
end
|
52
52
|
key_file
|
53
53
|
end
|
data/lib/gitolite/version.rb
CHANGED
data/spec/config_spec.rb
CHANGED
@@ -1,4 +1,357 @@
|
|
1
1
|
require 'gitolite/config'
|
2
|
+
require 'spec_helper'
|
2
3
|
|
3
4
|
describe Gitolite::Config do
|
4
|
-
|
5
|
+
conf_dir = File.join(File.dirname(__FILE__),'configs')
|
6
|
+
|
7
|
+
describe "#new" do
|
8
|
+
it 'should read a simple configuration' do
|
9
|
+
c = Gitolite::Config.new(File.join(conf_dir, 'simple.conf'))
|
10
|
+
c.repos.length.should == 2
|
11
|
+
c.groups.length.should == 0
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should read a complex configuration' do
|
15
|
+
c = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
16
|
+
c.groups.length.should == 5
|
17
|
+
c.repos.length.should == 12
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'gitweb operations' do
|
21
|
+
before :all do
|
22
|
+
@config = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should correctly read gitweb options for an existing repo' do
|
26
|
+
r = @config.get_repo('gitolite')
|
27
|
+
r.owner.should == "Sitaram Chamarty"
|
28
|
+
r.description.should == "fast, secure, access control for git in a corporate environment"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should correctly read a gitweb option with no owner for an existing repo' do
|
32
|
+
r = @config.get_repo('foo')
|
33
|
+
r.owner.should be nil
|
34
|
+
r.description.should == "Foo is a nice test repo"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should correctly read gitweb options for a new repo' do
|
38
|
+
r = @config.get_repo('foobar')
|
39
|
+
r.owner.should == "Bob Zilla"
|
40
|
+
r.description.should == "Foobar is top secret"
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should correctly read gitweb options with no owner for a new repo' do
|
44
|
+
r = @config.get_repo('bar')
|
45
|
+
r.owner.should be nil
|
46
|
+
r.description.should == "A nice place to get drinks"
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should raise a ParseError when a description is not specified' do
|
50
|
+
t = Tempfile.new('bad_conf.conf')
|
51
|
+
t.write('gitolite "Bob Zilla"')
|
52
|
+
t.close
|
53
|
+
|
54
|
+
lambda { Gitolite::Config.new(t.path) }.should raise_error(Gitolite::Config::ParseError)
|
55
|
+
|
56
|
+
t.unlink
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should raise a ParseError when a Gitweb description is specified for a group' do
|
60
|
+
t = Tempfile.new('bad_conf.conf')
|
61
|
+
t.write('@gitolite "Bob Zilla" = "Test description"')
|
62
|
+
t.close
|
63
|
+
|
64
|
+
lambda { Gitolite::Config.new(t.path) }.should raise_error(Gitolite::Config::ParseError)
|
65
|
+
|
66
|
+
t.unlink
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#init" do
|
72
|
+
it 'should create a valid, blank Gitolite::Config' do
|
73
|
+
c = Gitolite::Config.init
|
74
|
+
|
75
|
+
c.should be_an_instance_of Gitolite::Config
|
76
|
+
c.repos.should_not be nil
|
77
|
+
c.repos.length.should be 0
|
78
|
+
c.groups.should_not be nil
|
79
|
+
c.groups.length.should be 0
|
80
|
+
c.filename.should == "gitolite.conf"
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should create a valid, blank Gitolite::Config with the given filename' do
|
84
|
+
filename = "test.conf"
|
85
|
+
c = Gitolite::Config.init(filename)
|
86
|
+
|
87
|
+
c.should be_an_instance_of Gitolite::Config
|
88
|
+
c.repos.should_not be nil
|
89
|
+
c.repos.length.should be 0
|
90
|
+
c.groups.should_not be nil
|
91
|
+
c.groups.length.should be 0
|
92
|
+
c.filename.should == filename
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "repo management" do
|
97
|
+
before :each do
|
98
|
+
@config = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#get_repo" do
|
102
|
+
it 'should fetch a repo by a string containing the name' do
|
103
|
+
@config.get_repo('gitolite').should be_an_instance_of Gitolite::Config::Repo
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should fetch a repo via a symbol representing the name' do
|
107
|
+
@config.get_repo(:gitolite).should be_an_instance_of Gitolite::Config::Repo
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should return nil for a repo that does not exist' do
|
111
|
+
@config.get_repo(:glite).should be nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#has_repo?" do
|
116
|
+
it 'should return false for a repo that does not exist' do
|
117
|
+
@config.has_repo?(:glite).should be false
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should check for the existance of a repo given a repo object' do
|
121
|
+
r = @config.repos["gitolite"]
|
122
|
+
@config.has_repo?(r).should be true
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should check for the existance of a repo given a string containing the name' do
|
126
|
+
@config.has_repo?('gitolite').should be true
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should check for the existance of a repo given a symbol representing the name' do
|
130
|
+
@config.has_repo?(:gitolite).should be true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#add_repo" do
|
135
|
+
it 'should throw an ArgumentError for non-Gitolite::Config::Repo objects passed in' do
|
136
|
+
lambda{ @config.add_repo("not-a-repo") }.should raise_error(ArgumentError)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should add a given repo to the list of repos' do
|
140
|
+
r = Gitolite::Config::Repo.new('cool_repo')
|
141
|
+
nrepos = @config.repos.size
|
142
|
+
@config.add_repo(r)
|
143
|
+
|
144
|
+
@config.repos.size.should == nrepos + 1
|
145
|
+
@config.has_repo?(:cool_repo).should be true
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should merge a given repo with an existing repo' do
|
149
|
+
#Make two new repos
|
150
|
+
repo1 = Gitolite::Config::Repo.new('cool_repo')
|
151
|
+
repo2 = Gitolite::Config::Repo.new('cool_repo')
|
152
|
+
|
153
|
+
#Add some perms to those repos
|
154
|
+
repo1.add_permission("RW+", "", "bob", "joe", "sam")
|
155
|
+
repo1.add_permission("R", "", "sue", "jen", "greg")
|
156
|
+
repo1.add_permission("-", "refs/tags/test[0-9]", "@students", "jessica")
|
157
|
+
repo1.add_permission("RW", "refs/tags/test[0-9]", "@teachers", "bill", "todd")
|
158
|
+
repo1.add_permission("R", "refs/tags/test[0-9]", "@profs")
|
159
|
+
|
160
|
+
repo2.add_permission("RW+", "", "jim", "cynthia", "arnold")
|
161
|
+
repo2.add_permission("R", "", "daniel", "mary", "ben")
|
162
|
+
repo2.add_permission("-", "refs/tags/test[0-9]", "@more_students", "stephanie")
|
163
|
+
repo2.add_permission("RW", "refs/tags/test[0-9]", "@student_teachers", "mike", "judy")
|
164
|
+
repo2.add_permission("R", "refs/tags/test[0-9]", "@leaders")
|
165
|
+
|
166
|
+
#Add the repos
|
167
|
+
@config.add_repo(repo1)
|
168
|
+
@config.add_repo(repo2)
|
169
|
+
|
170
|
+
#Make sure perms were properly merged
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should overwrite an existing repo when overwrite = true' do
|
174
|
+
#Make two new repos
|
175
|
+
repo1 = Gitolite::Config::Repo.new('cool_repo')
|
176
|
+
repo2 = Gitolite::Config::Repo.new('cool_repo')
|
177
|
+
|
178
|
+
#Add some perms to those repos
|
179
|
+
repo1.add_permission("RW+", "", "bob", "joe", "sam")
|
180
|
+
repo1.add_permission("R", "", "sue", "jen", "greg")
|
181
|
+
repo2.add_permission("RW+", "", "jim", "cynthia", "arnold")
|
182
|
+
repo2.add_permission("R", "", "daniel", "mary", "ben")
|
183
|
+
|
184
|
+
#Add the repos
|
185
|
+
@config.add_repo(repo1)
|
186
|
+
@config.add_repo(repo2, true)
|
187
|
+
|
188
|
+
#Make sure repo2 overwrote repo1
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "#rm_repo" do
|
193
|
+
it 'should remove a repo for the Gitolite::Config::Repo object given' do
|
194
|
+
r = @config.get_repo(:gitolite)
|
195
|
+
r2 = @config.rm_repo(r)
|
196
|
+
r2.name.should == r.name
|
197
|
+
r2.permissions.length.should == r.permissions.length
|
198
|
+
r2.owner.should == r.owner
|
199
|
+
r2.description.should == r.description
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'should remove a repo given a string containing the name' do
|
203
|
+
r = @config.get_repo(:gitolite)
|
204
|
+
r2 = @config.rm_repo('gitolite')
|
205
|
+
r2.name.should == r.name
|
206
|
+
r2.permissions.length.should == r.permissions.length
|
207
|
+
r2.owner.should == r.owner
|
208
|
+
r2.description.should == r.description
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should remove a repo given a symbol representing the name' do
|
212
|
+
r = @config.get_repo(:gitolite)
|
213
|
+
r2 = @config.rm_repo(:gitolite)
|
214
|
+
r2.name.should == r.name
|
215
|
+
r2.permissions.length.should == r.permissions.length
|
216
|
+
r2.owner.should == r.owner
|
217
|
+
r2.description.should == r.description
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "group management" do
|
223
|
+
before :each do
|
224
|
+
@config = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
225
|
+
end
|
226
|
+
|
227
|
+
describe "#has_group?" do
|
228
|
+
it 'should find the staff group using a symbol' do
|
229
|
+
@config.has_group?(:staff).should be true
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'should find the staff group using a string' do
|
233
|
+
@config.has_group?('staff').should be true
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should find the staff group using a Gitolite::Config::Group object' do
|
237
|
+
g = Gitolite::Config::Group.new("staff")
|
238
|
+
@config.has_group?(g).should be true
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "#get_group" do
|
243
|
+
it 'should return the Gitolite::Config::Group object for the group name String' do
|
244
|
+
g = @config.get_group("staff")
|
245
|
+
g.is_a?(Gitolite::Config::Group).should be true
|
246
|
+
g.size.should == 6
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should return the Gitolite::Config::Group object for the group name Symbol' do
|
250
|
+
g = @config.get_group(:staff)
|
251
|
+
g.is_a?(Gitolite::Config::Group).should be true
|
252
|
+
g.size.should == 6
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "#add_group" do
|
257
|
+
it 'should throw an ArgumentError for non-Gitolite::Config::Group objects passed in' do
|
258
|
+
lambda{ @config.add_group("not-a-group") }.should raise_error(ArgumentError)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should add a given group to the groups list' do
|
262
|
+
g = Gitolite::Config::Group.new('cool_group')
|
263
|
+
ngroups = @config.groups.size
|
264
|
+
@config.add_group(g)
|
265
|
+
@config.groups.size.should be ngroups + 1
|
266
|
+
@config.has_group?(:cool_group).should be true
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "#rm_group" do
|
272
|
+
it 'should remove a group for the Gitolite::Config::Group object given' do
|
273
|
+
g = @config.get_group(:oss_repos)
|
274
|
+
g2 = @config.rm_group(g)
|
275
|
+
g.should_not be nil
|
276
|
+
g2.name.should == g.name
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should remove a group given a string containing the name' do
|
280
|
+
g = @config.get_group(:oss_repos)
|
281
|
+
g2 = @config.rm_group('oss_repos')
|
282
|
+
g2.name.should == g.name
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'should remove a group given a symbol representing the name' do
|
286
|
+
g = @config.get_group(:oss_repos)
|
287
|
+
g2 = @config.rm_group(:oss_repos)
|
288
|
+
g2.name.should == g.name
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "#to_file" do
|
295
|
+
it 'should create a file at the given path with the config\'s file name' do
|
296
|
+
c = Gitolite::Config.init
|
297
|
+
file = c.to_file('/tmp')
|
298
|
+
File.file?(File.join('/tmp', c.filename)).should be true
|
299
|
+
File.unlink(file)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should create a file at the given path when a different filename is specified' do
|
303
|
+
filename = "test.conf"
|
304
|
+
c = Gitolite::Config.init
|
305
|
+
c.filename = filename
|
306
|
+
file = c.to_file('/tmp')
|
307
|
+
File.file?(File.join('/tmp', filename)).should be true
|
308
|
+
File.unlink(file)
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'should raise an ArgumentError when an invalid path is specified' do
|
312
|
+
c = Gitolite::Config.init
|
313
|
+
lambda { c.to_file('/does/not/exist') }.should raise_error(ArgumentError)
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'should raise an ArgumentError when a filename is specified in the path' do
|
317
|
+
c = Gitolite::Config.init
|
318
|
+
lambda{ c.to_file('/home/test.rb') }.should raise_error(ArgumentError)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#cleanup_config_line" do
|
323
|
+
before(:each) do
|
324
|
+
@config = Gitolite::Config.init
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should remove comments' do
|
328
|
+
s = "#comment"
|
329
|
+
@config.instance_eval { cleanup_config_line(s) }.empty?.should == true
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'should remove inline comments, keeping content before the comment' do
|
333
|
+
s = "blablabla #comment"
|
334
|
+
@config.instance_eval { cleanup_config_line(s) }.should == "blablabla"
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'should pad = with spaces on each side' do
|
338
|
+
s = "bob=joe"
|
339
|
+
@config.instance_eval { cleanup_config_line(s) }.should == "bob = joe"
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'should replace multiple space characters with a single space' do
|
343
|
+
s = "bob = joe"
|
344
|
+
@config.instance_eval { cleanup_config_line(s) }.should == "bob = joe"
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'should cleanup whitespace at the beginning and end of lines' do
|
348
|
+
s = " bob = joe "
|
349
|
+
@config.instance_eval { cleanup_config_line(s) }.should == "bob = joe"
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'should cleanup whitespace and comments effectively' do
|
353
|
+
s = " bob = joe #comment"
|
354
|
+
@config.instance_eval { cleanup_config_line(s) }.should == "bob = joe"
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|