librarian 0.1.1 → 0.1.2

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile +2 -0
  5. data/VERSION +1 -0
  6. data/lib/librarian/algorithms.rb +133 -0
  7. data/lib/librarian/cli/manifest_presenter.rb +1 -5
  8. data/lib/librarian/dependency.rb +7 -1
  9. data/lib/librarian/environment.rb +20 -2
  10. data/lib/librarian/environment/runtime_cache.rb +101 -0
  11. data/lib/librarian/manifest.rb +7 -1
  12. data/lib/librarian/manifest_set.rb +11 -12
  13. data/lib/librarian/posix.rb +14 -5
  14. data/lib/librarian/resolver.rb +22 -9
  15. data/lib/librarian/resolver/implementation.rb +64 -49
  16. data/lib/librarian/source/git.rb +47 -11
  17. data/lib/librarian/source/git/repository.rb +33 -3
  18. data/lib/librarian/version.rb +1 -1
  19. data/librarian.gemspec +8 -6
  20. data/spec/functional/cli_spec.rb +1 -1
  21. data/spec/functional/posix_spec.rb +6 -8
  22. data/spec/functional/source/git/repository_spec.rb +55 -27
  23. data/spec/functional/source/git_spec.rb +152 -8
  24. data/spec/support/project_path_macro.rb +14 -0
  25. data/spec/unit/action/base_spec.rb +1 -1
  26. data/spec/unit/action/clean_spec.rb +6 -6
  27. data/spec/unit/action/install_spec.rb +5 -5
  28. data/spec/unit/algorithms_spec.rb +131 -0
  29. data/spec/unit/config/database_spec.rb +38 -38
  30. data/spec/unit/dependency/requirement_spec.rb +12 -0
  31. data/spec/unit/dsl_spec.rb +49 -49
  32. data/spec/unit/environment/runtime_cache_spec.rb +73 -0
  33. data/spec/unit/environment_spec.rb +28 -28
  34. data/spec/unit/lockfile/parser_spec.rb +18 -18
  35. data/spec/unit/lockfile_spec.rb +3 -3
  36. data/spec/unit/manifest/version_spec.rb +11 -0
  37. data/spec/unit/manifest_set_spec.rb +20 -20
  38. data/spec/unit/mock/environment_spec.rb +4 -4
  39. data/spec/unit/resolver_spec.rb +61 -20
  40. data/spec/unit/spec_change_set_spec.rb +19 -19
  41. metadata +19 -5
@@ -15,7 +15,7 @@ module Librarian
15
15
  end
16
16
 
17
17
  it "should print the version" do
18
- stdout.should == strip_heredoc(<<-STDOUT)
18
+ expect(stdout).to eq strip_heredoc(<<-STDOUT)
19
19
  librarian-#{Librarian::VERSION}
20
20
  librarian-mock-#{Librarian::Mock::VERSION}
21
21
  STDOUT
@@ -1,12 +1,10 @@
1
1
  require "librarian/posix"
2
2
 
3
+ require "support/project_path_macro"
4
+
3
5
  describe Librarian::Posix do
6
+ include Support::ProjectPathMacro
4
7
 
5
- let(:project_path) do
6
- project_path = Pathname.new(__FILE__).expand_path
7
- project_path = project_path.dirname until project_path.join("Rakefile").exist?
8
- project_path
9
- end
10
8
  let(:tmp_path) { project_path + "tmp/spec/functional/posix" }
11
9
  after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
12
10
 
@@ -14,19 +12,19 @@ describe Librarian::Posix do
14
12
 
15
13
  it "returns the stdout" do
16
14
  res = described_class.run!(%w[echo hello there]).strip
17
- res.should be == "hello there"
15
+ expect(res).to eq "hello there"
18
16
  end
19
17
 
20
18
  it "changes directory" do
21
19
  tmp_path.mkpath
22
20
  res = described_class.run!(%w[pwd], :chdir => tmp_path).strip
23
- res.should be == tmp_path.to_s
21
+ expect(res).to eq tmp_path.to_s
24
22
  end
25
23
 
26
24
  it "reads the env" do
27
25
  res = described_class.run!(%w[env], :env => {"KOALA" => "BEAR"})
28
26
  line = res.lines.find{|l| l.start_with?("KOALA=")}.strip
29
- line.should be == "KOALA=BEAR"
27
+ expect(line).to eq "KOALA=BEAR"
30
28
  end
31
29
 
32
30
  end
@@ -6,17 +6,15 @@ require "librarian/posix"
6
6
 
7
7
  require "librarian/source/git/repository"
8
8
 
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
12
+
9
13
  describe Librarian::Source::Git::Repository do
14
+ include Support::ProjectPathMacro
10
15
 
11
- let(:env) do
12
- double(:ui => nil, :logger => double(:debug => nil, :info => nil))
13
- end
16
+ let(:env) { Librarian::Mock::Environment.new }
14
17
 
15
- let(:project_path) do
16
- project_path = Pathname.new(__FILE__).expand_path
17
- project_path = project_path.dirname until project_path.join("Rakefile").exist?
18
- project_path
19
- end
20
18
  let(:tmp_path) { project_path + "tmp/spec/functional/source/git/repository" }
21
19
  after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
22
20
  let(:git_source_path) { tmp_path + SecureRandom.hex(16) }
@@ -64,35 +62,35 @@ describe Librarian::Source::Git::Repository do
64
62
  end
65
63
 
66
64
  describe ".bin" do
67
- specify { described_class.bin.should_not be_empty }
65
+ specify { expect(described_class.bin).to_not be_empty }
68
66
  end
69
67
 
70
68
  describe ".git_version" do
71
- specify { described_class.git_version.should =~ /^\d+(\.\d+)+$/ }
69
+ specify { expect(described_class.git_version).to match( /^\d+(\.\d+)+$/ ) }
72
70
  end
73
71
 
74
72
  context "the original" do
75
73
  subject { described_class.new(env, git_source_path) }
76
74
 
77
75
  it "should recognize it" do
78
- subject.should be_git
76
+ expect(subject).to be_git
79
77
  end
80
78
 
81
79
  it "should not list any remotes for it" do
82
- subject.remote_names.should be_empty
80
+ expect(subject.remote_names).to be_empty
83
81
  end
84
82
 
85
83
  it "should not list any remote branches for it" do
86
- subject.remote_branch_names.should be_empty
84
+ expect(subject.remote_branch_names).to be_empty
87
85
  end
88
86
 
89
87
  it "should have divergent shas for master, branch, tag, and atag" do
90
88
  revs = %W[ master #{branch} #{tag} #{atag} ]
91
89
  rev_parse = proc{|rev| git!(%W[rev-parse #{rev} --quiet]).strip}
92
90
  shas = Dir.chdir(git_source_path){revs.map(&rev_parse)}
93
- shas.map(&:class).uniq.should be == [String]
94
- shas.map(&:size).uniq.should be == [40]
95
- shas.uniq.should be == shas
91
+ expect(shas.map(&:class).uniq).to eq [String]
92
+ expect(shas.map(&:size).uniq).to eq [40]
93
+ expect(shas.uniq).to eq shas
96
94
  end
97
95
  end
98
96
 
@@ -106,23 +104,53 @@ describe Librarian::Source::Git::Repository do
106
104
  let(:atag_sha) { subject.hash_from("origin", atag) }
107
105
 
108
106
  it "should recognize it" do
109
- subject.should be_git
107
+ expect(subject).to be_git
110
108
  end
111
109
 
112
110
  it "should have a single remote for it" do
113
- subject.should have(1).remote_names
111
+ expect(subject).to have(1).remote_names
114
112
  end
115
113
 
116
114
  it "should have a remote with the expected name" do
117
- subject.remote_names.first.should == "origin"
115
+ expect(subject.remote_names.first).to eq "origin"
118
116
  end
119
117
 
120
118
  it "should have the remote branch" do
121
- subject.remote_branch_names["origin"].should include branch
119
+ expect(subject.remote_branch_names["origin"]).to include branch
122
120
  end
123
121
 
124
122
  it "should be checked out on the master" do
125
- subject.should be_checked_out(master_sha)
123
+ expect(subject).to be_checked_out(master_sha)
124
+ end
125
+
126
+ context "checking for commits" do
127
+ it "has the master commit" do
128
+ expect(subject).to have_commit(master_sha)
129
+ end
130
+
131
+ it "has the branch commit" do
132
+ expect(subject).to have_commit(branch_sha)
133
+ end
134
+
135
+ it "has the tag commit" do
136
+ expect(subject).to have_commit(tag_sha)
137
+ end
138
+
139
+ it "has the atag commit" do
140
+ expect(subject).to have_commit(atag_sha)
141
+ end
142
+
143
+ it "does not have a made-up commit" do
144
+ expect(subject).to_not have_commit(SecureRandom.hex(20))
145
+ end
146
+
147
+ it "does not have a tree commit" do
148
+ master_tree_sha = Dir.chdir(git_source_path) do
149
+ git!(%W[log -1 --no-color --format=tformat:%T master]).strip
150
+ end
151
+ expect(master_tree_sha).to match(/\A[0-9a-f]{40}\z/) # sanity
152
+ expect(subject).to_not have_commit(master_tree_sha)
153
+ end
126
154
  end
127
155
 
128
156
  context "checking out the branch" do
@@ -131,11 +159,11 @@ describe Librarian::Source::Git::Repository do
131
159
  end
132
160
 
133
161
  it "should be checked out on the branch" do
134
- subject.should be_checked_out(branch_sha)
162
+ expect(subject).to be_checked_out(branch_sha)
135
163
  end
136
164
 
137
165
  it "should not be checked out on the master" do
138
- subject.should_not be_checked_out(master_sha)
166
+ expect(subject).to_not be_checked_out(master_sha)
139
167
  end
140
168
  end
141
169
 
@@ -145,11 +173,11 @@ describe Librarian::Source::Git::Repository do
145
173
  end
146
174
 
147
175
  it "should be checked out on the tag" do
148
- subject.should be_checked_out(tag_sha)
176
+ expect(subject).to be_checked_out(tag_sha)
149
177
  end
150
178
 
151
179
  it "should not be checked out on the master" do
152
- subject.should_not be_checked_out(master_sha)
180
+ expect(subject).to_not be_checked_out(master_sha)
153
181
  end
154
182
  end
155
183
 
@@ -159,11 +187,11 @@ describe Librarian::Source::Git::Repository do
159
187
  end
160
188
 
161
189
  it "should be checked out on the annotated tag" do
162
- subject.should be_checked_out(atag_sha)
190
+ expect(subject).to be_checked_out(atag_sha)
163
191
  end
164
192
 
165
193
  it "should not be checked out on the master" do
166
- subject.should_not be_checked_out(master_sha)
194
+ expect(subject).to_not be_checked_out(master_sha)
167
195
  end
168
196
  end
169
197
  end
@@ -1,24 +1,37 @@
1
+ require "fileutils"
1
2
  require "pathname"
2
3
  require "securerandom"
3
4
 
4
5
  require "librarian/error"
6
+ require "librarian/posix"
5
7
  require "librarian/source/git"
8
+ require "librarian/source/git/repository"
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
6
12
 
7
13
  describe Librarian::Source::Git do
14
+ include Support::ProjectPathMacro
8
15
 
9
- let(:project_path) do
10
- project_path = Pathname.new(__FILE__).expand_path
11
- project_path = project_path.dirname until project_path.join("Rakefile").exist?
12
- project_path
13
- end
14
16
  let(:tmp_path) { project_path + "tmp/spec/functional/source/git" }
15
17
  after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
16
- let(:cache_path) { tmp_path + "cache" }
18
+ let(:env_project_path) { tmp_path + "project" }
19
+
20
+ def cmd!(command)
21
+ Librarian::Posix.run! command
22
+ end
23
+
24
+ def git!(command)
25
+ cmd!([Librarian::Source::Git::Repository.bin] + command)
26
+ end
27
+
28
+ def new_env
29
+ Librarian::Mock::Environment.new(:project_path => env_project_path)
30
+ end
17
31
 
18
32
  context "when the remote is bad" do
19
33
  let(:remote) { tmp_path.join(SecureRandom.hex(8)).to_s }
20
- let(:logger) { double(:debug => nil, :info => nil) }
21
- let(:env) { double(:ui => nil, :logger => logger, :cache_path => cache_path) }
34
+ let(:env) { new_env }
22
35
  let(:source) { described_class.new(env, remote, {}) }
23
36
 
24
37
  it "fails when caching" do
@@ -27,4 +40,135 @@ describe Librarian::Source::Git do
27
40
  end
28
41
  end
29
42
 
43
+ context "when the remote has a repo" do
44
+ let(:remote) { tmp_path.join(SecureRandom.hex(8)).to_s }
45
+ let(:git_source_path) { Pathname.new(remote) }
46
+ let(:env) { new_env }
47
+ let(:source) { described_class.new(env, remote, {}) }
48
+
49
+ before do
50
+ git_source_path.mkpath
51
+ Dir.chdir(git_source_path) do
52
+ git! %W[init]
53
+ git! %W[config user.name Simba]
54
+ git! %W[config user.email simba@savannah-pride.gov]
55
+ FileUtils.touch "butter.txt"
56
+ git! %W[add butter.txt]
57
+ git! %W[commit -m #{"Initial Commit"}]
58
+ end
59
+ end
60
+
61
+ let(:sha) do
62
+ Dir.chdir(git_source_path) do
63
+ git!(%W[rev-parse master]).strip
64
+ end
65
+ end
66
+
67
+ context "when caching once" do
68
+ it "has the expected sha" do
69
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
70
+ end
71
+
72
+ it "records the history" do
73
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(9)
74
+ end
75
+ end
76
+
77
+ context "when caching twice" do
78
+ before { source.cache! }
79
+
80
+ it "keeps the expected sha" do
81
+ expect{source.cache!}.to_not change{source.sha}
82
+ end
83
+
84
+ it "runs git commands once" do
85
+ expect{source.cache!}.to_not change{source.git_ops_count}
86
+ end
87
+ end
88
+
89
+ context "when caching twice from different sources" do
90
+ let(:other_source) { described_class.new(env, remote, {}) }
91
+ before { other_source.cache! }
92
+
93
+ it "has the expected sha" do
94
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
95
+ end
96
+
97
+ it "records the history" do
98
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(1)
99
+ end
100
+ end
101
+
102
+ context "when caching twice from different sources, second time with sha" do
103
+ let(:other_source) { described_class.new(env, remote, {}) }
104
+ before { other_source.cache! }
105
+
106
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
107
+
108
+ it "has the expected sha" do
109
+ expect{source.cache!}.to_not change{source.sha}
110
+ end
111
+
112
+ it "records the history" do
113
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(1)
114
+ end
115
+ end
116
+
117
+ context "when caching twice from different environments" do
118
+ let(:other_source) { described_class.new(new_env, remote, {}) }
119
+ before { other_source.cache! }
120
+
121
+ it "has the expected sha" do
122
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
123
+ end
124
+
125
+ it "records the history" do
126
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(8)
127
+ end
128
+ end
129
+
130
+ context "when caching twice from different environments, second time with sha" do
131
+ let(:other_source) { described_class.new(new_env, remote, {}) }
132
+ before { other_source.cache! }
133
+
134
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
135
+
136
+ it "has the expected sha" do
137
+ expect{source.cache!}.to_not change{source.sha}
138
+ end
139
+
140
+ it "records the history" do
141
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(3)
142
+ end
143
+ end
144
+
145
+ context "when the sha is missing from a cached repo" do
146
+ let(:other_source) { described_class.new(new_env, remote, {}) }
147
+ before { other_source.cache! }
148
+
149
+ before do
150
+ Dir.chdir(git_source_path) do
151
+ FileUtils.touch "jam.txt"
152
+ git! %w[add jam.txt]
153
+ git! %W[commit -m #{"Some Jam"}]
154
+ end
155
+ end
156
+
157
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
158
+
159
+ it "has a new remote sha" do
160
+ expect(sha).to_not eq(other_source.sha)
161
+ end
162
+
163
+ it "has the expected sha" do
164
+ expect{source.cache!}.to_not change{source.sha}
165
+ end
166
+
167
+ it "records the history" do
168
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(8)
169
+ end
170
+ end
171
+
172
+ end
173
+
30
174
  end
@@ -0,0 +1,14 @@
1
+ module Support
2
+ module ProjectPathMacro
3
+
4
+ project_path = Pathname.new(__FILE__).expand_path
5
+ project_path = project_path.dirname until project_path.join("Rakefile").exist?
6
+
7
+ PROJECT_PATH = project_path
8
+
9
+ def project_path
10
+ PROJECT_PATH
11
+ end
12
+
13
+ end
14
+ end
@@ -11,7 +11,7 @@ module Librarian
11
11
  it { should respond_to :environment }
12
12
 
13
13
  it "should have the environment that was assigned to it" do
14
- action.environment.should be env
14
+ expect(action.environment).to be env
15
15
  end
16
16
 
17
17
  end
@@ -30,7 +30,7 @@ module Librarian
30
30
  end
31
31
 
32
32
  it "should not try to clear the cache path" do
33
- env.cache_path.should_receive(:rmtree).never
33
+ expect(env.cache_path).to receive(:rmtree).never
34
34
  end
35
35
  end
36
36
 
@@ -40,7 +40,7 @@ module Librarian
40
40
  end
41
41
 
42
42
  it "should try to clear the cache path" do
43
- env.cache_path.should_receive(:rmtree).exactly(:once)
43
+ expect(env.cache_path).to receive(:rmtree).exactly(:once)
44
44
  end
45
45
  end
46
46
 
@@ -58,7 +58,7 @@ module Librarian
58
58
  end
59
59
 
60
60
  it "should not try to clear the install path" do
61
- env.install_path.should_receive(:children).never
61
+ expect(env.install_path).to receive(:children).never
62
62
  end
63
63
  end
64
64
 
@@ -75,7 +75,7 @@ module Librarian
75
75
  env.stub_chain(:install_path, :children) { children }
76
76
 
77
77
  children.each do |child|
78
- child.should_receive(:rmtree).exactly(:once)
78
+ expect(child).to receive(:rmtree).exactly(:once)
79
79
  end
80
80
  end
81
81
 
@@ -84,10 +84,10 @@ module Librarian
84
84
  env.stub_chain(:install_path, :children) { children }
85
85
 
86
86
  children.select(&:file?).each do |child|
87
- child.should_receive(:rmtree).never
87
+ expect(child).to receive(:rmtree).never
88
88
  end
89
89
  children.reject(&:file?).each do |child|
90
- child.should_receive(:rmtree).exactly(:once)
90
+ expect(child).to receive(:rmtree).exactly(:once)
91
91
  end
92
92
  end
93
93
  end