jbox-gitolite 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -7
- data/Guardfile +2 -2
- data/README.md +3 -2
- data/Rakefile +26 -8
- data/gitolite.gemspec +3 -3
- data/lib/gitolite.rb +5 -2
- data/lib/gitolite/config.rb +181 -152
- data/lib/gitolite/config/group.rb +11 -0
- data/lib/gitolite/config/repo.rb +22 -9
- data/lib/gitolite/dirty_proxy.rb +3 -0
- data/lib/gitolite/gitolite_admin.rb +0 -2
- data/lib/gitolite/ssh_key.rb +52 -38
- data/lib/gitolite/version.rb +1 -1
- data/spec/config_spec.rb +18 -11
- data/spec/dirty_proxy_spec.rb +4 -1
- data/spec/fixtures/configs/complicated.conf +311 -0
- data/spec/fixtures/configs/simple.conf +5 -0
- data/spec/{keys/bob-ins@zilla-site.com@desktop.pub → fixtures/keys/bob+joe@test.zilla.com@desktop.pub} +0 -0
- data/spec/{keys/bob.joe@test.zilla.com@desktop.pub → fixtures/keys/bob-ins@zilla-site.com@desktop.pub} +0 -0
- data/spec/{keys/bob@zilla.com@desktop.pub → fixtures/keys/bob.joe@test.zilla.com@desktop.pub} +0 -0
- data/spec/{keys → fixtures/keys}/bob.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@desktop.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@foo-bar.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@zilla.com.pub +0 -0
- data/spec/{keys/joe-bob@god-zilla.com@desktop.pub → fixtures/keys/bob@zilla.com@desktop.pub} +0 -0
- data/spec/{keys → fixtures/keys}/jakub123.pub +0 -0
- data/spec/{keys → fixtures/keys}/jakub123@foo.net.pub +0 -0
- data/spec/fixtures/keys/joe-bob@god-zilla.com@desktop.pub +1 -0
- data/spec/{keys → fixtures/keys}/joe@sch.ool.edu.pub +0 -0
- data/spec/{keys → fixtures/keys}/joe@sch.ool.edu@desktop.pub +0 -0
- data/spec/gitolite_admin_spec.rb +6 -8
- data/spec/group_spec.rb +0 -1
- data/spec/repo_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/ssh_key_spec.rb +15 -10
- metadata +39 -37
@@ -1,9 +1,11 @@
|
|
1
1
|
module Gitolite
|
2
2
|
class Config
|
3
|
+
|
3
4
|
# Represents a group inside the gitolite configuration. The name and users
|
4
5
|
# options are all encapsulated in this class. All users are stored as
|
5
6
|
# Strings!
|
6
7
|
class Group
|
8
|
+
|
7
9
|
attr_accessor :name, :users
|
8
10
|
|
9
11
|
PREPEND_CHAR = '@'
|
@@ -15,37 +17,46 @@ module Gitolite
|
|
15
17
|
@users = []
|
16
18
|
end
|
17
19
|
|
20
|
+
|
18
21
|
def empty!
|
19
22
|
@users.clear
|
20
23
|
end
|
21
24
|
|
25
|
+
|
22
26
|
def add_user(user)
|
23
27
|
return if has_user?(user)
|
24
28
|
@users.push(user.to_s).sort!
|
25
29
|
end
|
26
30
|
|
31
|
+
|
27
32
|
def add_users(*users)
|
28
33
|
fixed_users = users.flatten.map{ |u| u.to_s }
|
29
34
|
@users.concat(fixed_users).sort!.uniq!
|
30
35
|
end
|
31
36
|
|
37
|
+
|
32
38
|
def rm_user(user)
|
33
39
|
@users.delete(user.to_s)
|
34
40
|
end
|
35
41
|
|
42
|
+
|
36
43
|
def has_user?(user)
|
37
44
|
@users.include? user.to_s
|
38
45
|
end
|
39
46
|
|
47
|
+
|
40
48
|
def size
|
41
49
|
@users.length
|
42
50
|
end
|
43
51
|
|
52
|
+
|
44
53
|
def to_s
|
45
54
|
members = @users.join(' ')
|
46
55
|
name = "#{PREPEND_CHAR}#{@name}"
|
47
56
|
"#{name.ljust(20)}= #{members}\n"
|
48
57
|
end
|
58
|
+
|
49
59
|
end
|
60
|
+
|
50
61
|
end
|
51
62
|
end
|
data/lib/gitolite/config/repo.rb
CHANGED
@@ -1,28 +1,32 @@
|
|
1
1
|
module Gitolite
|
2
2
|
class Config
|
3
|
-
|
4
|
-
#
|
3
|
+
|
4
|
+
# Represents a repo inside the gitolite configuration. The name, permissions, and git config
|
5
|
+
# options are all encapsulated in this class
|
5
6
|
class Repo
|
7
|
+
|
6
8
|
ALLOWED_PERMISSIONS = /-|C|R|RW\+?(?:C?D?|D?C?)M?/
|
7
9
|
|
8
10
|
attr_accessor :permissions, :name, :config, :options, :owner, :description
|
9
11
|
|
10
12
|
def initialize(name)
|
11
|
-
#Store the perm hash in a lambda since we have to create a new one on every deny rule
|
12
|
-
#The perm hash is stored as a 2D hash, with individual permissions being the first
|
13
|
-
#degree and individual refexes being the second degree. Both Hashes must respect order
|
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
|
14
16
|
@perm_hash_lambda = lambda { Hash.new {|k,v| k[v] = Hash.new{|k2, v2| k2[v2] = [] }} }
|
15
17
|
@permissions = Array.new.push(@perm_hash_lambda.call)
|
16
18
|
|
17
19
|
@name = name
|
18
|
-
@config = {} #git config
|
19
|
-
@options = {} #gitolite config
|
20
|
+
@config = {} # git config
|
21
|
+
@options = {} # gitolite config
|
20
22
|
end
|
21
23
|
|
24
|
+
|
22
25
|
def clean_permissions
|
23
26
|
@permissions = Array.new.push(@perm_hash_lambda.call)
|
24
27
|
end
|
25
28
|
|
29
|
+
|
26
30
|
def add_permission(perm, refex = "", *users)
|
27
31
|
if perm =~ ALLOWED_PERMISSIONS
|
28
32
|
#Handle deny rules
|
@@ -37,22 +41,27 @@ module Gitolite
|
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
44
|
+
|
40
45
|
def set_git_config(key, value)
|
41
46
|
@config[key] = value
|
42
47
|
end
|
43
48
|
|
49
|
+
|
44
50
|
def unset_git_config(key)
|
45
51
|
@config.delete(key)
|
46
52
|
end
|
47
53
|
|
54
|
+
|
48
55
|
def set_gitolite_option(key, value)
|
49
56
|
@options[key] = value
|
50
57
|
end
|
51
58
|
|
59
|
+
|
52
60
|
def unset_gitolite_option(key)
|
53
61
|
@options.delete(key)
|
54
62
|
end
|
55
63
|
|
64
|
+
|
56
65
|
def to_s
|
57
66
|
repo = "repo #{@name}\n"
|
58
67
|
|
@@ -75,6 +84,7 @@ module Gitolite
|
|
75
84
|
repo
|
76
85
|
end
|
77
86
|
|
87
|
+
|
78
88
|
def gitweb_description
|
79
89
|
if @description.nil?
|
80
90
|
nil
|
@@ -85,10 +95,13 @@ module Gitolite
|
|
85
95
|
end
|
86
96
|
end
|
87
97
|
|
88
|
-
|
89
|
-
#
|
98
|
+
|
99
|
+
# Gets raised if a permission that isn't in the allowed
|
100
|
+
# list is passed in
|
90
101
|
class InvalidPermissionError < ArgumentError
|
91
102
|
end
|
103
|
+
|
92
104
|
end
|
105
|
+
|
93
106
|
end
|
94
107
|
end
|
data/lib/gitolite/dirty_proxy.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Gitolite
|
2
|
+
|
2
3
|
# Very simple proxy object for checking if the proxied object was modified
|
3
4
|
# since the last clean_up! method called. It works correctly only for objects
|
4
5
|
# with proper hash method!
|
@@ -25,5 +26,7 @@ module Gitolite
|
|
25
26
|
def clean_up!
|
26
27
|
@clean_hash = @target.hash
|
27
28
|
end
|
29
|
+
|
28
30
|
end
|
31
|
+
|
29
32
|
end
|
data/lib/gitolite/ssh_key.rb
CHANGED
@@ -1,63 +1,73 @@
|
|
1
1
|
module Gitolite
|
2
|
-
|
3
|
-
#
|
2
|
+
|
3
|
+
# Models an SSH key within gitolite
|
4
|
+
# provides support for multikeys
|
4
5
|
#
|
5
|
-
#Types of multi keys:
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# Types of multi keys:
|
7
|
+
# bob.pub => username: bob
|
8
|
+
# bob@desktop.pub => username: bob, location: desktop
|
9
|
+
# bob@email.com.pub => username: bob@email.com
|
10
|
+
# bob@email.com@desktop.pub => username: bob@email.com, location: desktop
|
10
11
|
|
11
12
|
class SSHKey
|
13
|
+
|
12
14
|
attr_accessor :owner, :location, :type, :blob, :email
|
13
15
|
|
14
|
-
|
15
|
-
@type = type
|
16
|
-
@blob = blob
|
17
|
-
@email = email
|
16
|
+
class << self
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
end
|
18
|
+
def from_file(key)
|
19
|
+
raise "#{key} does not exist!" unless File.exists?(key)
|
22
20
|
|
23
|
-
|
24
|
-
|
21
|
+
# Get our owner and location
|
22
|
+
File.basename(key) =~ /^([\+\w\.-]+(?:@(?:[\w-]+\.)+\D{2,4})?)(?:@([\w-]+))?.pub$/i
|
23
|
+
owner = $1
|
24
|
+
location = $2 || ""
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
location = $2 || ""
|
26
|
+
# Use string key constructor
|
27
|
+
self.from_string(File.read(key), owner, location)
|
28
|
+
end
|
30
29
|
|
31
|
-
# Use string key constructor
|
32
|
-
self.from_string(File.read(key), owner, location)
|
33
|
-
end
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
# Construct a SSHKey from a string
|
32
|
+
def from_string(key_string, owner, location = "")
|
33
|
+
if owner.nil?
|
34
|
+
raise ArgumentError, "owner was nil, you must specify an owner"
|
35
|
+
end
|
40
36
|
|
41
|
-
|
42
|
-
|
37
|
+
# Get parts of the key
|
38
|
+
type, blob, email = key_string.split
|
43
39
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
# We need at least a type or blob
|
41
|
+
if type.nil? || blob.nil?
|
42
|
+
raise ArgumentError, "'#{key_string}' is not a valid SSH key string"
|
43
|
+
end
|
44
|
+
|
45
|
+
# If the key didn't have an email, just use the owner
|
46
|
+
if email.nil?
|
47
|
+
email = owner
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
if email.nil?
|
51
|
-
email = owner
|
50
|
+
self.new(type, blob, email, owner, location)
|
52
51
|
end
|
53
52
|
|
54
|
-
self.new(type, blob, email, owner, location)
|
55
53
|
end
|
56
54
|
|
55
|
+
|
56
|
+
def initialize(type, blob, email, owner = nil, location = "")
|
57
|
+
@type = type
|
58
|
+
@blob = blob
|
59
|
+
@email = email
|
60
|
+
|
61
|
+
@owner = owner || email
|
62
|
+
@location = location
|
63
|
+
end
|
64
|
+
|
65
|
+
|
57
66
|
def to_s
|
58
67
|
[@type, @blob, @email].join(' ')
|
59
68
|
end
|
60
69
|
|
70
|
+
|
61
71
|
def to_file(path)
|
62
72
|
key_file = File.join(path, self.filename)
|
63
73
|
File.open(key_file, "w") do |f|
|
@@ -67,12 +77,14 @@ module Gitolite
|
|
67
77
|
key_file
|
68
78
|
end
|
69
79
|
|
80
|
+
|
70
81
|
def filename
|
71
82
|
file = @owner
|
72
83
|
file += "@#{@location}" unless @location.empty?
|
73
84
|
file += ".pub"
|
74
85
|
end
|
75
86
|
|
87
|
+
|
76
88
|
def ==(key)
|
77
89
|
@type == key.type &&
|
78
90
|
@blob == key.blob &&
|
@@ -81,8 +93,10 @@ module Gitolite
|
|
81
93
|
@location == key.location
|
82
94
|
end
|
83
95
|
|
96
|
+
|
84
97
|
def hash
|
85
98
|
[@owner, @location, @type, @blob, @email].hash
|
86
99
|
end
|
100
|
+
|
87
101
|
end
|
88
102
|
end
|
data/lib/gitolite/version.rb
CHANGED
data/spec/config_spec.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
require 'gratr'
|
2
|
-
require 'gitolite/config'
|
3
1
|
require 'spec_helper'
|
4
2
|
|
5
3
|
describe Gitolite::Config do
|
6
|
-
|
4
|
+
|
5
|
+
conf_dir = File.join(File.dirname(__FILE__), 'fixtures', 'configs')
|
6
|
+
output_dir = '/tmp'
|
7
|
+
# output_dir = File.join(File.dirname(File.dirname(__FILE__)), 'tmp')
|
7
8
|
|
8
9
|
describe "#new" do
|
9
10
|
it 'should read a simple configuration' do
|
@@ -15,7 +16,7 @@ describe Gitolite::Config do
|
|
15
16
|
it 'should read a complex configuration' do
|
16
17
|
c = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
17
18
|
c.groups.length.should == 5
|
18
|
-
c.repos.length.should ==
|
19
|
+
c.repos.length.should == 13
|
19
20
|
end
|
20
21
|
|
21
22
|
describe 'gitweb operations' do
|
@@ -327,17 +328,23 @@ describe Gitolite::Config do
|
|
327
328
|
describe "#to_file" do
|
328
329
|
it 'should create a file at the given path with the config\'s file name' do
|
329
330
|
c = Gitolite::Config.init
|
330
|
-
file = c.to_file(
|
331
|
-
File.file?(File.join(
|
331
|
+
file = c.to_file(output_dir)
|
332
|
+
File.file?(File.join(output_dir, c.filename)).should be true
|
332
333
|
File.unlink(file)
|
333
334
|
end
|
334
335
|
|
336
|
+
it 'should create a file at the given path with the config file passed' do
|
337
|
+
c = Gitolite::Config.new(File.join(conf_dir, 'complicated.conf'))
|
338
|
+
file = c.to_file(output_dir)
|
339
|
+
File.file?(File.join(output_dir, c.filename)).should be true
|
340
|
+
end
|
341
|
+
|
335
342
|
it 'should create a file at the given path when a different filename is specified' do
|
336
343
|
filename = "test.conf"
|
337
344
|
c = Gitolite::Config.init
|
338
345
|
c.filename = filename
|
339
|
-
file = c.to_file(
|
340
|
-
File.file?(File.join(
|
346
|
+
file = c.to_file(output_dir)
|
347
|
+
File.file?(File.join(output_dir, filename)).should be true
|
341
348
|
File.unlink(file)
|
342
349
|
end
|
343
350
|
|
@@ -373,7 +380,7 @@ describe Gitolite::Config do
|
|
373
380
|
c.add_group(g)
|
374
381
|
|
375
382
|
# Write the config to a file
|
376
|
-
file = c.to_file(
|
383
|
+
file = c.to_file(output_dir)
|
377
384
|
|
378
385
|
# Read the conf and make sure our order is correct
|
379
386
|
f = File.read(file)
|
@@ -411,7 +418,7 @@ describe Gitolite::Config do
|
|
411
418
|
c.add_group(g)
|
412
419
|
|
413
420
|
# Attempt to write the config file
|
414
|
-
lambda{ c.to_file(
|
421
|
+
lambda{ c.to_file(output_dir)}.should raise_error(Gitolite::Config::GroupDependencyError)
|
415
422
|
end
|
416
423
|
|
417
424
|
it 'should resolve group dependencies even when there are disconnected portions of the graph' do
|
@@ -436,7 +443,7 @@ describe Gitolite::Config do
|
|
436
443
|
c.add_group(g)
|
437
444
|
|
438
445
|
# Write the config to a file
|
439
|
-
file = c.to_file(
|
446
|
+
file = c.to_file(output_dir)
|
440
447
|
|
441
448
|
# Read the conf and make sure our order is correct
|
442
449
|
f = File.read(file)
|
data/spec/dirty_proxy_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'gitolite/dirty_proxy'
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe Gitolite::DirtyProxy do
|
@@ -7,9 +6,11 @@ describe Gitolite::DirtyProxy do
|
|
7
6
|
Gitolite::DirtyProxy.new([]).should_not be_nil
|
8
7
|
end
|
9
8
|
|
9
|
+
|
10
10
|
let(:target) { ['foo', 'bar'] }
|
11
11
|
let(:proxy) { Gitolite::DirtyProxy.new(target) }
|
12
12
|
|
13
|
+
|
13
14
|
describe 'delegating to the target object' do
|
14
15
|
it 'should act as instance of the target' do
|
15
16
|
proxy.should be_instance_of target.class
|
@@ -24,6 +25,7 @@ describe Gitolite::DirtyProxy do
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
28
|
+
|
27
29
|
describe 'dirty checking methods' do
|
28
30
|
it 'should respond to clean_up!' do
|
29
31
|
proxy.respond_to?(:clean_up!).should be_true
|
@@ -60,4 +62,5 @@ describe Gitolite::DirtyProxy do
|
|
60
62
|
include_examples 'dirty? clean_up!'
|
61
63
|
end
|
62
64
|
end
|
65
|
+
|
63
66
|
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
# example conf file for gitolite
|
2
|
+
|
3
|
+
# ----------------------------------------------------------------------------
|
4
|
+
# overall syntax:
|
5
|
+
# - everything is space-separated; no commas, semicolons, etc (except in
|
6
|
+
# the description string for gitweb)
|
7
|
+
# - comments in the normal shell-ish style; no surprises there
|
8
|
+
# - there are NO continuation lines of any kind
|
9
|
+
# - user/repo names as simple as possible; they must start with an
|
10
|
+
# alphanumeric, but after that they can also contain ".", "_", "-".
|
11
|
+
# - usernames can optionally be followed by an "@" and a domainname
|
12
|
+
# containing at least one "." (this allows you to use an email
|
13
|
+
# address as someone's username)
|
14
|
+
# - reponames can contain "/" characters (this allows you to
|
15
|
+
# put your repos in a tree-structure for convenience)
|
16
|
+
|
17
|
+
# objectives, over and above gitosis:
|
18
|
+
# - simpler syntax
|
19
|
+
# - easier gitweb/daemon control
|
20
|
+
# - specify who can push a branch/tag
|
21
|
+
# - specify who can rewind a branch/rewrite a tag
|
22
|
+
|
23
|
+
# ----------------------------------------------------------------------------
|
24
|
+
|
25
|
+
# GROUPS
|
26
|
+
# ------
|
27
|
+
|
28
|
+
# syntax:
|
29
|
+
# @groupname = [one or more names]
|
30
|
+
|
31
|
+
# groups let you club (user or group) names together for convenience
|
32
|
+
|
33
|
+
# * a group is like a #define in C except that it can *accumulate* values
|
34
|
+
# * the config file is parsed in a single-pass, so later *additions* to a
|
35
|
+
# group name cannot affect earlier *uses* of it
|
36
|
+
|
37
|
+
# The following examples should illustrate all this:
|
38
|
+
|
39
|
+
# you can have a group of people...
|
40
|
+
@staff = sitaram some_dev another-dev
|
41
|
+
|
42
|
+
# ...or a group of repos
|
43
|
+
@oss_repos = gitolite linux git perl rakudo entrans vkc
|
44
|
+
|
45
|
+
# ...or even a group of refexes
|
46
|
+
@important = master$ QA_done refs/tags/v[0-9]
|
47
|
+
# (see later for what "refex"s are; I'm only mentioning it
|
48
|
+
# here to emphasise that you can group them too)
|
49
|
+
|
50
|
+
# even sliced and diced differently
|
51
|
+
@admins = sitaram admin2
|
52
|
+
# notice that sitaram is in 2 groups (staff and admins)
|
53
|
+
|
54
|
+
# if you repeat a group name in another definition line, the
|
55
|
+
# new ones get added to the old ones (they accumulate)
|
56
|
+
@staff = au.thor
|
57
|
+
# so now "@staff" expands to all 4 names
|
58
|
+
|
59
|
+
# groups can include other groups, and the included group will
|
60
|
+
# be expanded to whatever value it currently has
|
61
|
+
@interns = indy james
|
62
|
+
@staff = bob @interns
|
63
|
+
# "@staff" expands to 7 names now
|
64
|
+
@interns = han
|
65
|
+
# "@interns" now has 3 names in it, but note that this does
|
66
|
+
# not change @staff
|
67
|
+
|
68
|
+
# REPO AND BRANCH PERMISSIONS
|
69
|
+
# ---------------------------
|
70
|
+
|
71
|
+
# syntax:
|
72
|
+
# start line:
|
73
|
+
# repo [one or more repos and/or repo groups]
|
74
|
+
# followed by one or more permissions lines:
|
75
|
+
# (C|R|RW|RW+|RWC|RW+C|RWD|RW+D|RWCD|RW+CD) [zero or more refexes] = [one or more users]
|
76
|
+
|
77
|
+
# there are 6 types of permissions: R, RW, and RW+ are simple (the "+" means
|
78
|
+
# permission to "rewind" -- force push a non-fast forward to -- a branch).
|
79
|
+
# The *standalone* C permission pertains to creating a REPO and is described
|
80
|
+
# in doc/wildcard-repositories.mkd. The C and D *suffixes* to the RW/RW+
|
81
|
+
# permissions pertain to creating or deleting a BRANCH, and are described in
|
82
|
+
# doc/3-faq-tips-etc.mkd, in the sections on "separating push and create
|
83
|
+
# rights" and "separating delete and rewind rights" respectively.
|
84
|
+
|
85
|
+
# how permissions are matched:
|
86
|
+
# - user, repo, and access (W or +) are known. For that combination, if
|
87
|
+
# any of the refexes match the refname being updated, the push succeeds.
|
88
|
+
# If none of them match, it fails
|
89
|
+
|
90
|
+
# what's a refex? a regex to match against the ref being updated (get it?)
|
91
|
+
# See next section for more on refexes
|
92
|
+
|
93
|
+
# BASIC PERMISSIONS (repo level only; apply to all branches/tags in repo)
|
94
|
+
|
95
|
+
# most important rule of all -- specify who can make changes
|
96
|
+
# to *this* file take effect
|
97
|
+
repo gitolite-admin
|
98
|
+
RW+ = @admins
|
99
|
+
|
100
|
+
# "@all" is a special, predefined, group name of all users
|
101
|
+
# (everyone who has a pubkey in keydir)
|
102
|
+
repo testing
|
103
|
+
RW+ = @all
|
104
|
+
|
105
|
+
# this repo is visible to staff but only sitaram can write to it
|
106
|
+
repo gitolite
|
107
|
+
R = @staff
|
108
|
+
RW+ = sitaram
|
109
|
+
|
110
|
+
# you can split up access rules for a repo for convenience
|
111
|
+
# (notice that @oss_repos contains gitolite also)
|
112
|
+
repo @oss_repos
|
113
|
+
R = @all
|
114
|
+
|
115
|
+
# set permissions to all repos. *Please* do see
|
116
|
+
# doc/3-faq-tips-etc.mkd for notes on this feature
|
117
|
+
repo @all
|
118
|
+
RW+ = @admins
|
119
|
+
|
120
|
+
# SPECIFYING AND USING A REFEX
|
121
|
+
|
122
|
+
# - refexes are specified in perl regex syntax
|
123
|
+
# - refexes are prefix-matched (they are internally anchored with "^"
|
124
|
+
# before being used), which means a refex like "refs/tags/v[0-9]"
|
125
|
+
# matches anything *starting with* that pattern. There may be text
|
126
|
+
# after it (example: refs/tags/v4-r3/p7), and it will still match
|
127
|
+
|
128
|
+
# ADVANCED PERMISSIONS USING REFEXES
|
129
|
+
|
130
|
+
# - if no refex appears, the rule applies to all refs in that repo
|
131
|
+
# - a refex is automatically prefixed by "refs/heads/" if it doesn't start
|
132
|
+
# with "refs/" (so tags have to be explicitly named as
|
133
|
+
# refs/tags/pattern)
|
134
|
+
|
135
|
+
# here's the example from
|
136
|
+
# Documentation/howto/update-hook-example.txt:
|
137
|
+
|
138
|
+
# refs/heads/master junio
|
139
|
+
# +refs/heads/pu junio
|
140
|
+
# refs/heads/cogito$ pasky
|
141
|
+
# refs/heads/bw/.* linus
|
142
|
+
# refs/heads/tmp/.* .*
|
143
|
+
# refs/tags/v[0-9].* junio
|
144
|
+
|
145
|
+
# and here're the equivalent gitolite refexes
|
146
|
+
repo git
|
147
|
+
RW = bobzilla
|
148
|
+
RW master = junio
|
149
|
+
RW+ pu = junio
|
150
|
+
RW cogito$ = pasky
|
151
|
+
RW bw/ = linus
|
152
|
+
RW tmp/ = @all
|
153
|
+
RW refs/tags/v[0-9] = junio
|
154
|
+
|
155
|
+
# DENY/EXCLUDE RULES
|
156
|
+
|
157
|
+
# ***IMPORTANT NOTES ABOUT "DENY" RULES***:
|
158
|
+
|
159
|
+
# - deny rules do NOT affect read access. They only apply to write access.
|
160
|
+
#
|
161
|
+
# - when using deny rules, the order of your rules starts to matter, where
|
162
|
+
# earlier it did not. The first matching rule applies, where "matching" is
|
163
|
+
# defined as either permitting the operation you're attempting (`W` or `+`),
|
164
|
+
# which results in success, or a "deny" (`-`), which results in failure.
|
165
|
+
# (As before, a fallthrough also results in failure).
|
166
|
+
|
167
|
+
# in the example above, you cannot easily say "anyone can write any tag,
|
168
|
+
# except version tags can only be written by junio". The following might look
|
169
|
+
# like it works but it doesn't:
|
170
|
+
|
171
|
+
# RW refs/tags/v[0-9] = junio
|
172
|
+
# RW refs/tags/ = junio linus pasky @others
|
173
|
+
|
174
|
+
# if you use "deny" rules, however, you can do this (a "deny" rule just uses
|
175
|
+
# "-" instead of "R" or "RW" or "RW+" in the permission field)
|
176
|
+
|
177
|
+
RW refs/tags/v[0-9] = junio
|
178
|
+
- refs/tags/v[0-9] = linus pasky @others
|
179
|
+
RW refs/tags/ = junio linus pasky @others
|
180
|
+
|
181
|
+
# FILE/DIR NAME BASED RESTRICTIONS
|
182
|
+
# --------------------------------
|
183
|
+
|
184
|
+
# Here's a hopefully self-explanatory example. Assume the project has the
|
185
|
+
# following contents at the top level: a README, a "doc/" directory, and an
|
186
|
+
# "src/" directory.
|
187
|
+
|
188
|
+
repo foo
|
189
|
+
RW+ = lead_dev # rule 1
|
190
|
+
RW = dev1 dev2 dev3 dev4 # rule 2
|
191
|
+
|
192
|
+
RW NAME/ = lead_dev # rule 3
|
193
|
+
RW NAME/doc/ = dev1 dev2 # rule 4
|
194
|
+
RW NAME/src/ = dev1 dev2 dev3 dev4 # rule 5
|
195
|
+
option mirror.master = mars
|
196
|
+
option mirror.slaves = phobos deimos
|
197
|
+
option mirror.redirectOK = all
|
198
|
+
|
199
|
+
|
200
|
+
repo foo2
|
201
|
+
RW+ = @all-devs
|
202
|
+
- VREF/COUNT/5 = @junior-devs
|
203
|
+
- VREF/NAME/Makefile = @junior-devs
|
204
|
+
|
205
|
+
# Notes
|
206
|
+
|
207
|
+
# - the "NAME/" is part of the syntax; think of it as a keyword if you like.
|
208
|
+
# The rest of it is treated as a refex to match against each file being
|
209
|
+
# touched (see "SPECIFYING AND USING A REFEX" above for details)
|
210
|
+
|
211
|
+
# - file/dir NAME-based restrictions are *in addition* to normal (branch-name
|
212
|
+
# based) restrictions; they are not a *replacement* for them. This is why
|
213
|
+
# rule #2 (or something like it, maybe with a more specific branch-name) is
|
214
|
+
# needed; without it, dev1/2/3/4 cannot push any branches.
|
215
|
+
|
216
|
+
# - if a repo has *any* NAME/ rules, then NAME-based restrictions are checked
|
217
|
+
# for *all* users. This is why rule 3 is needed, even though we don't
|
218
|
+
# actually have any NAME-based restrictions on lead_dev. Notice the pattern
|
219
|
+
# on rule 3.
|
220
|
+
|
221
|
+
# - *each* file touched by the commits being pushed is checked against those
|
222
|
+
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
223
|
+
# changes to files in "doc/" and "src/" (but not the top level README), and
|
224
|
+
# dev3/4 can only push changes to files in "src/".
|
225
|
+
|
226
|
+
# GITWEB AND DAEMON STUFF
|
227
|
+
# -----------------------
|
228
|
+
|
229
|
+
# No specific syntax for gitweb and daemon access; just make the repo readable
|
230
|
+
# ("R" access) to the special users "gitweb" and "daemon"
|
231
|
+
|
232
|
+
# make "@oss_repos" (all 7 of them!) accessible via git daemon
|
233
|
+
repo @oss_repos
|
234
|
+
R = daemon
|
235
|
+
|
236
|
+
# make the two *large* repos accessible via gitweb
|
237
|
+
repo linux perl
|
238
|
+
R = gitweb
|
239
|
+
|
240
|
+
# REPO OWNER/DESCRIPTION LINE FOR GITWEB
|
241
|
+
|
242
|
+
# syntax, one of:
|
243
|
+
# reponame = "some description string in double quotes"
|
244
|
+
# reponame "owner name" = "some description string in double quotes"
|
245
|
+
|
246
|
+
# note: setting a description also gives gitweb access; you do not have to
|
247
|
+
# give gitweb access as described above if you're specifying a description
|
248
|
+
|
249
|
+
gitolite "Sitaram Chamarty" = "fast, secure, access control for git in a corporate environment"
|
250
|
+
foo = "Foo is a nice test repo"
|
251
|
+
foobar "Bob Zilla" = "Foobar is top secret"
|
252
|
+
bar = "A nice place to get drinks"
|
253
|
+
|
254
|
+
# REPO SPECIFIC GITCONFIG
|
255
|
+
# -----------------------
|
256
|
+
|
257
|
+
# update 2010-02-06; this won't work unless the rc file has the right
|
258
|
+
# settings; please see comments around the variable $GL_GITCONFIG_KEYS in
|
259
|
+
# conf/example.gitolite.rc for details and security information.
|
260
|
+
|
261
|
+
# (Thanks to teemu dot matilainen at iki dot fi)
|
262
|
+
|
263
|
+
# this should be specified within a "repo" stanza
|
264
|
+
|
265
|
+
# syntax:
|
266
|
+
# config sectionname.keyname = [optional value_string]
|
267
|
+
|
268
|
+
# example usage: if you placed a hook in hooks/common that requires
|
269
|
+
# configuration information that is specific to each repo, you could do this:
|
270
|
+
|
271
|
+
repo gitolite
|
272
|
+
config hooks.mailinglist = gitolite-commits@example.tld
|
273
|
+
config hooks.emailprefix = "[gitolite] "
|
274
|
+
config foo.bar = ""
|
275
|
+
config foo.baz =
|
276
|
+
|
277
|
+
# This does either a plain "git config section.key value" (for the first 3
|
278
|
+
# examples above) or "git config --unset-all section.key" (for the last
|
279
|
+
# example). Other forms (--add, the value_regex, etc) are not supported.
|
280
|
+
|
281
|
+
# INCLUDE SOME OTHER FILE
|
282
|
+
# -----------------------
|
283
|
+
|
284
|
+
include "foo.conf"
|
285
|
+
subconf "bar.conf"
|
286
|
+
|
287
|
+
# this includes the contents of $GL_ADMINDIR/conf/foo.conf here
|
288
|
+
|
289
|
+
# Notes:
|
290
|
+
# - the include statement is not allowed inside delegated fragments for
|
291
|
+
# security reasons.
|
292
|
+
# - you can also use an absolute path if you like, although in the interests
|
293
|
+
# of cloning the admin-repo sanely you should avoid doing this!
|
294
|
+
|
295
|
+
# EXTERNAL COMMAND HELPERS -- RSYNC
|
296
|
+
# ---------------------------------
|
297
|
+
|
298
|
+
# If $RSYNC_BASE is non-empty, the following config entries come into play
|
299
|
+
# (otherwise they are ignored):
|
300
|
+
|
301
|
+
# a "fake" git repository to collect rsync rules. Gitolite does not
|
302
|
+
# auto-create any repo whose name starts with EXTCMD/
|
303
|
+
repo EXTCMD/rsync
|
304
|
+
# grant permissions to files/dirs within the $RSYNC_BASE tree. A leading
|
305
|
+
# NAME/ is required as a prefix; the actual path starts after that. Matching
|
306
|
+
# follows the same rules as given in "FILE/DIR NAME BASED RESTRICTIONS" above
|
307
|
+
RW NAME/ = sitaram
|
308
|
+
RW NAME/foo/ = user1
|
309
|
+
R NAME/bar/ = user2
|
310
|
+
# just to remind you that these are perl regexes, not shell globs
|
311
|
+
RW NAME/baz/.*/*.c = user3
|