treet 0.11.0 → 0.13.1
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/.gitignore +1 -0
- data/lib/treet/gitrepo.rb +54 -26
- data/lib/treet/repo.rb +7 -3
- data/lib/treet/version.rb +1 -1
- data/spec/lib/test_gitrepo.rb +105 -21
- metadata +4 -4
data/.gitignore
CHANGED
data/lib/treet/gitrepo.rb
CHANGED
@@ -37,13 +37,15 @@ class Treet::Gitrepo < Treet::Repo
|
|
37
37
|
end
|
38
38
|
rescue Rugged::ReferenceError
|
39
39
|
# invalid string for source, e.g. blank or illegal punctuation (colons)
|
40
|
-
raise ArgumentError "invalid source string '#{tagname}' for repository tagging"
|
40
|
+
raise ArgumentError, "invalid source string '#{tagname}' for repository tagging"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def patch(patchdef)
|
45
45
|
super
|
46
|
-
|
46
|
+
if git_changes?(patchdef)
|
47
|
+
add_and_commit!
|
48
|
+
end
|
47
49
|
end
|
48
50
|
|
49
51
|
def to_hash(opts = {})
|
@@ -52,9 +54,8 @@ class Treet::Gitrepo < Treet::Repo
|
|
52
54
|
elsif opts[:tag]
|
53
55
|
tag_snapshot(opts[:tag])
|
54
56
|
else
|
55
|
-
# snapshot(head.target)
|
56
57
|
super()
|
57
|
-
end
|
58
|
+
end.merge(augmentation)
|
58
59
|
end
|
59
60
|
|
60
61
|
def entries
|
@@ -62,7 +63,7 @@ class Treet::Gitrepo < Treet::Repo
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def branches
|
65
|
-
refs(/heads/).map(
|
66
|
+
refs(/heads/).map {|ref| ref.name.gsub(/^refs\/heads\//, '')} - ['master']
|
66
67
|
end
|
67
68
|
|
68
69
|
# always branch from tip of master (private representation)
|
@@ -70,15 +71,22 @@ class Treet::Gitrepo < Treet::Repo
|
|
70
71
|
Rugged::Reference.create(gitrepo, "refs/heads/#{name}", head.target)
|
71
72
|
end
|
72
73
|
|
74
|
+
def tagged?(tagname)
|
75
|
+
! commit_id_for(tagname).nil?
|
76
|
+
end
|
77
|
+
|
73
78
|
def version(opts = {})
|
74
|
-
if
|
75
|
-
|
76
|
-
ref && ref.target
|
79
|
+
if tagname = opts[:tag]
|
80
|
+
commit_id_for(tagname)
|
77
81
|
else
|
78
82
|
head.target
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
86
|
+
def current?(tagname)
|
87
|
+
commit_id_for(tagname) == head.target
|
88
|
+
end
|
89
|
+
|
82
90
|
private
|
83
91
|
|
84
92
|
attr_reader :gitrepo, :author
|
@@ -113,6 +121,7 @@ class Treet::Gitrepo < Treet::Repo
|
|
113
121
|
def add_and_commit!
|
114
122
|
current_index = entries
|
115
123
|
Dir.chdir(root) do
|
124
|
+
# automatically ignores dotfiles
|
116
125
|
current_files = Dir.glob('**/*')
|
117
126
|
|
118
127
|
# additions
|
@@ -135,11 +144,22 @@ class Treet::Gitrepo < Treet::Repo
|
|
135
144
|
# `index#remove` handles directories
|
136
145
|
index.remove(file)
|
137
146
|
end
|
147
|
+
|
148
|
+
index.write
|
149
|
+
tree_sha = index.write_tree
|
150
|
+
commit!(tree_sha)
|
138
151
|
end
|
152
|
+
end
|
139
153
|
|
140
|
-
|
141
|
-
|
142
|
-
|
154
|
+
def gitget(obj)
|
155
|
+
data = gitrepo.read(obj[:oid]).data
|
156
|
+
begin
|
157
|
+
JSON.load(data)
|
158
|
+
rescue JSON::ParserError
|
159
|
+
# parser errors are not fatal
|
160
|
+
# this just indicates a string entry rather than a hash
|
161
|
+
data.empty? ? obj[:name] : data
|
162
|
+
end
|
143
163
|
end
|
144
164
|
|
145
165
|
def snapshot(commit_sha)
|
@@ -150,31 +170,39 @@ class Treet::Gitrepo < Treet::Repo
|
|
150
170
|
tree.each do |obj|
|
151
171
|
data[obj[:name]] = case obj[:type]
|
152
172
|
when :blob
|
153
|
-
|
154
|
-
JSON.load(gitrepo.read(obj[:oid]).data)
|
155
|
-
rescue JSON::ParserError
|
156
|
-
raise JSON::ParserError, "bad JSON in blob #{obj[:name]}: #{gitrepo.read(obj[:oid]).data}"
|
157
|
-
end
|
173
|
+
gitget(obj)
|
158
174
|
when :tree
|
159
|
-
|
160
|
-
|
161
|
-
d << JSON.load(gitrepo.read(subobj[:oid]).data)
|
162
|
-
end
|
163
|
-
rescue JSON::ParserError
|
164
|
-
raise JSON::ParserError, "bad JSON in tree #{obj[:name]}: #{gitrepo.read(obj[:oid]).data}"
|
175
|
+
gitrepo.lookup(obj[:oid]).each_with_object([]) do |subobj,d|
|
176
|
+
d << gitget(subobj)
|
165
177
|
end
|
166
178
|
else
|
167
179
|
raise TypeError, "UNRECOGNIZED GIT OBJECT TYPE #{obj[:type]}"
|
168
180
|
end
|
169
181
|
end
|
170
182
|
|
171
|
-
# decorate(data)
|
172
183
|
data
|
173
184
|
end
|
174
185
|
|
186
|
+
def commit_id_for(tagname)
|
187
|
+
(ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tagname}")) && ref.target
|
188
|
+
end
|
189
|
+
|
175
190
|
def tag_snapshot(tagname)
|
176
|
-
|
177
|
-
|
178
|
-
|
191
|
+
if commitid = version(:tag => tagname)
|
192
|
+
snapshot(commitid)
|
193
|
+
else
|
194
|
+
# this tag does not appear in the repo; this is NOT an exception
|
195
|
+
{}
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def augmentation(path = root)
|
200
|
+
dotfiles = Dir.entries(path).select {|f| f =~ /^\./ && f !~ /^(\.|\.\.|\.git)$/}
|
201
|
+
dotfiles.each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
|
202
|
+
end
|
203
|
+
|
204
|
+
# any patches in here that affect anything that must be recorded in git?
|
205
|
+
def git_changes?(patchdef)
|
206
|
+
patchdef.find {|p| p[1] =~ /^[^.]/}
|
179
207
|
end
|
180
208
|
end
|
data/lib/treet/repo.rb
CHANGED
@@ -27,7 +27,8 @@ class Treet::Repo
|
|
27
27
|
[keyname, '', nil]
|
28
28
|
elsif keyname =~ /\./
|
29
29
|
# subelement
|
30
|
-
|
30
|
+
# negative lookbehind; don't split on a dot at beginning of string
|
31
|
+
filename,field = keyname.split(/(?<!^)\./)
|
31
32
|
['.', filename, field]
|
32
33
|
else
|
33
34
|
['.', keyname]
|
@@ -143,7 +144,10 @@ class Treet::Repo
|
|
143
144
|
end
|
144
145
|
|
145
146
|
def expand(path)
|
146
|
-
|
147
|
-
|
147
|
+
filenames(path).each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
|
148
|
+
end
|
149
|
+
|
150
|
+
def filenames(path)
|
151
|
+
Dir.entries(path).select {|f| f !~ /^\./}
|
148
152
|
end
|
149
153
|
end
|
data/lib/treet/version.rb
CHANGED
data/spec/lib/test_gitrepo.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
require "test_helper"
|
3
|
-
require "pp"
|
4
3
|
|
5
4
|
# convert a hash to a gitrepo
|
6
5
|
# convert a plain repo to a gitrepo
|
@@ -42,13 +41,18 @@ describe Treet::Gitrepo do
|
|
42
41
|
}
|
43
42
|
thash = Treet::Hash.new(data)
|
44
43
|
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
45
|
-
Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
44
|
+
r = Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
45
|
+
r.patch([]) # should be no-op, trigger no commit
|
46
|
+
r
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
50
|
let(:johnb) { self.class.make_johnb }
|
50
51
|
|
51
52
|
it "should have exactly one commit" do
|
53
|
+
Dir.chdir(johnb.root) do
|
54
|
+
`git log --oneline`.lines.count.must_equal 1
|
55
|
+
end
|
52
56
|
johnb.head.wont_be_nil
|
53
57
|
johnb.refs.count.must_equal 1
|
54
58
|
johnb.refs.first.target.must_equal johnb.head.target
|
@@ -69,10 +73,6 @@ describe Treet::Gitrepo do
|
|
69
73
|
johnb.tags.must_be_empty
|
70
74
|
end
|
71
75
|
|
72
|
-
it "should fail on unknown tag lookups" do
|
73
|
-
->{johnb.to_hash(:tag => 'nosuchtag')}.must_raise ArgumentError
|
74
|
-
end
|
75
|
-
|
76
76
|
it "should have no branches" do
|
77
77
|
johnb.branches.must_be_empty
|
78
78
|
end
|
@@ -81,8 +81,43 @@ describe Treet::Gitrepo do
|
|
81
81
|
johnb.version.must_equal johnb.head.target
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
84
|
+
describe "an unknown tag" do
|
85
|
+
it "should have no commit" do
|
86
|
+
johnb.version(:tag => 'nosuchtag').must_be_nil
|
87
|
+
end
|
88
|
+
it "should not be present" do
|
89
|
+
refute johnb.tagged?('nosuchtag')
|
90
|
+
end
|
91
|
+
it "should return empty data" do
|
92
|
+
assert johnb.to_hash(:tag => 'nosuchtag').empty?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "a gitrepo with an array of strings" do
|
98
|
+
def self.make_repo
|
99
|
+
@repo ||= begin
|
100
|
+
data = {
|
101
|
+
"label" => "Rainbow Colors",
|
102
|
+
"colors" => %w{red orange yellow green blue purple}
|
103
|
+
}
|
104
|
+
thash = Treet::Hash.new(data)
|
105
|
+
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
106
|
+
Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
let(:repo) { self.class.make_repo }
|
111
|
+
|
112
|
+
it "should fetch directly from file system" do
|
113
|
+
repo.to_hash.wont_be_nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should fetch via git" do
|
117
|
+
data = repo.to_hash(:commit => repo.head.target)
|
118
|
+
data.wont_be_nil
|
119
|
+
assert data['label'] == 'Rainbow Colors'
|
120
|
+
assert data['colors'].to_set == %w{red orange yellow green blue purple}.to_set
|
86
121
|
end
|
87
122
|
end
|
88
123
|
|
@@ -191,7 +226,7 @@ describe Treet::Gitrepo do
|
|
191
226
|
:xrefkey => 'app1',
|
192
227
|
:xref => 'APP1_ID'
|
193
228
|
)
|
194
|
-
r.tag('
|
229
|
+
r.tag('pre-edit')
|
195
230
|
r.patch([
|
196
231
|
[
|
197
232
|
"-",
|
@@ -220,24 +255,31 @@ describe Treet::Gitrepo do
|
|
220
255
|
repo.index.count.must_equal 2
|
221
256
|
end
|
222
257
|
|
223
|
-
it "should have tag
|
258
|
+
it "should have one tag" do
|
224
259
|
repo.tags.count.must_equal 1
|
225
|
-
repo.tags.first.name.must_equal "refs/tags/app1"
|
226
|
-
repo.tags.first.target.wont_equal repo.head.target
|
227
|
-
end
|
228
|
-
|
229
|
-
it "should have the original image for the tag" do
|
230
|
-
refute hashalike(repo.to_hash, repo.to_hash(:tag => 'app1'))
|
231
|
-
assert hashalike(repo.to_hash(:tag => 'app1'), load_json('two'))
|
232
260
|
end
|
233
261
|
|
234
262
|
it "should have no branches" do
|
235
263
|
repo.branches.must_be_empty
|
236
264
|
end
|
237
265
|
|
238
|
-
|
239
|
-
|
240
|
-
|
266
|
+
describe "head state" do
|
267
|
+
it "should track version label by tag" do
|
268
|
+
assert repo.version == repo.head.target
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
describe "pre-patch state" do
|
273
|
+
it "should not be same as HEAD" do
|
274
|
+
assert repo.tagged?("pre-edit")
|
275
|
+
refute repo.current?("pre-edit")
|
276
|
+
assert repo.version(:tag => "pre-edit") != repo.version
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should have the original image" do
|
280
|
+
refute hashalike(repo.to_hash, repo.to_hash(:tag => 'pre-edit'))
|
281
|
+
assert hashalike(repo.to_hash(:tag => 'pre-edit'), load_json('two'))
|
282
|
+
end
|
241
283
|
end
|
242
284
|
end
|
243
285
|
|
@@ -251,6 +293,8 @@ describe Treet::Gitrepo do
|
|
251
293
|
it "should have tags" do
|
252
294
|
repo.tags.count.must_equal 1
|
253
295
|
repo.tags.first.name.must_equal "refs/tags/source1"
|
296
|
+
assert repo.tagged?("source1")
|
297
|
+
assert repo.current?("source1")
|
254
298
|
end
|
255
299
|
|
256
300
|
it "should have no branches" do
|
@@ -330,6 +374,9 @@ describe Treet::Gitrepo do
|
|
330
374
|
versions = ['app1', 'app2', 'app3', 'app4'].map {|s| repo[:repo].version(:tag => s)}
|
331
375
|
versions.uniq.count.must_equal 4
|
332
376
|
end
|
377
|
+
|
378
|
+
it "should know which tag matches the HEAD state" do
|
379
|
+
end
|
333
380
|
end
|
334
381
|
|
335
382
|
describe "a branched gitrepo" do
|
@@ -340,7 +387,44 @@ describe Treet::Gitrepo do
|
|
340
387
|
end
|
341
388
|
|
342
389
|
it "should show a branch" do
|
343
|
-
repo.branches.must_equal ['
|
390
|
+
repo.branches.must_equal ['mybranch']
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe "repo with non-gitified attributes" do
|
395
|
+
let(:repo) do
|
396
|
+
@data = {'foo' => 'bar', '.attr' => {'key' => 'value'}}
|
397
|
+
thash = Treet::Hash.new(@data)
|
398
|
+
trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
|
399
|
+
r = Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
|
400
|
+
r.tag('testing')
|
401
|
+
r.patch([["~", ".attr.key", "newvalue"]])
|
402
|
+
@updated = {'foo' => 'bar', '.attr' => {'key' => 'newvalue'}}
|
403
|
+
r
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should retrieve all attributes" do
|
407
|
+
repo.to_hash.must_equal @updated
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should not create new commits for edits to dot attributes" do
|
411
|
+
Dir.chdir(repo.root) do
|
412
|
+
`git log --oneline`.lines.count.must_equal 1
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
it "should retrieve non-gitified attrs even via tags and commits" do
|
417
|
+
repo.to_hash(:tag => 'testing').must_equal @updated
|
418
|
+
repo.to_hash(:commit => repo.version(:tag => 'testing')).must_equal @updated
|
419
|
+
repo.to_hash(:commit => repo.version).must_equal @updated
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should not commit the dot-prefixed attributes" do
|
423
|
+
Dir.chdir(repo.root) do
|
424
|
+
gitified = `git ls-tree --name-only HEAD`
|
425
|
+
gitified.must_include('foo')
|
426
|
+
gitified.wont_include('.attr')
|
427
|
+
end
|
344
428
|
end
|
345
429
|
end
|
346
430
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: treet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -206,7 +206,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
206
206
|
version: '0'
|
207
207
|
segments:
|
208
208
|
- 0
|
209
|
-
hash:
|
209
|
+
hash: 1191802132244638868
|
210
210
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
211
211
|
none: false
|
212
212
|
requirements:
|
@@ -215,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
215
|
version: '0'
|
216
216
|
segments:
|
217
217
|
- 0
|
218
|
-
hash:
|
218
|
+
hash: 1191802132244638868
|
219
219
|
requirements: []
|
220
220
|
rubyforge_project:
|
221
221
|
rubygems_version: 1.8.24
|