librarianp 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +255 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +235 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +55 -0
  10. data/Rakefile +28 -0
  11. data/VERSION +1 -0
  12. data/lib/librarian/action/base.rb +24 -0
  13. data/lib/librarian/action/clean.rb +44 -0
  14. data/lib/librarian/action/ensure.rb +24 -0
  15. data/lib/librarian/action/install.rb +95 -0
  16. data/lib/librarian/action/persist_resolution_mixin.rb +51 -0
  17. data/lib/librarian/action/resolve.rb +46 -0
  18. data/lib/librarian/action/update.rb +44 -0
  19. data/lib/librarian/action.rb +5 -0
  20. data/lib/librarian/algorithms.rb +133 -0
  21. data/lib/librarian/cli/manifest_presenter.rb +89 -0
  22. data/lib/librarian/cli.rb +225 -0
  23. data/lib/librarian/config/database.rb +205 -0
  24. data/lib/librarian/config/file_source.rb +47 -0
  25. data/lib/librarian/config/hash_source.rb +33 -0
  26. data/lib/librarian/config/source.rb +149 -0
  27. data/lib/librarian/config.rb +7 -0
  28. data/lib/librarian/dependency.rb +153 -0
  29. data/lib/librarian/dsl/receiver.rb +42 -0
  30. data/lib/librarian/dsl/target.rb +171 -0
  31. data/lib/librarian/dsl.rb +102 -0
  32. data/lib/librarian/environment/runtime_cache.rb +101 -0
  33. data/lib/librarian/environment.rb +230 -0
  34. data/lib/librarian/error.rb +4 -0
  35. data/lib/librarian/helpers.rb +29 -0
  36. data/lib/librarian/linter/source_linter.rb +55 -0
  37. data/lib/librarian/lockfile/compiler.rb +66 -0
  38. data/lib/librarian/lockfile/parser.rb +123 -0
  39. data/lib/librarian/lockfile.rb +29 -0
  40. data/lib/librarian/logger.rb +46 -0
  41. data/lib/librarian/manifest.rb +146 -0
  42. data/lib/librarian/manifest_set.rb +150 -0
  43. data/lib/librarian/mock/cli.rb +19 -0
  44. data/lib/librarian/mock/dsl.rb +15 -0
  45. data/lib/librarian/mock/environment.rb +21 -0
  46. data/lib/librarian/mock/extension.rb +9 -0
  47. data/lib/librarian/mock/source/mock/registry.rb +83 -0
  48. data/lib/librarian/mock/source/mock.rb +80 -0
  49. data/lib/librarian/mock/source.rb +1 -0
  50. data/lib/librarian/mock/version.rb +5 -0
  51. data/lib/librarian/mock.rb +1 -0
  52. data/lib/librarian/posix.rb +129 -0
  53. data/lib/librarian/resolution.rb +46 -0
  54. data/lib/librarian/resolver/implementation.rb +238 -0
  55. data/lib/librarian/resolver.rb +94 -0
  56. data/lib/librarian/rspec/support/cli_macro.rb +120 -0
  57. data/lib/librarian/source/basic_api.rb +45 -0
  58. data/lib/librarian/source/git/repository.rb +193 -0
  59. data/lib/librarian/source/git.rb +172 -0
  60. data/lib/librarian/source/local.rb +54 -0
  61. data/lib/librarian/source/path.rb +56 -0
  62. data/lib/librarian/source.rb +2 -0
  63. data/lib/librarian/spec.rb +13 -0
  64. data/lib/librarian/spec_change_set.rb +173 -0
  65. data/lib/librarian/specfile.rb +19 -0
  66. data/lib/librarian/support/abstract_method.rb +21 -0
  67. data/lib/librarian/ui.rb +64 -0
  68. data/lib/librarian/version.rb +3 -0
  69. data/lib/librarian.rb +11 -0
  70. data/librarian.gemspec +47 -0
  71. data/spec/functional/cli_spec.rb +27 -0
  72. data/spec/functional/posix_spec.rb +32 -0
  73. data/spec/functional/source/git/repository_spec.rb +199 -0
  74. data/spec/functional/source/git_spec.rb +174 -0
  75. data/spec/support/fakefs.rb +37 -0
  76. data/spec/support/method_patch_macro.rb +30 -0
  77. data/spec/support/project_path_macro.rb +14 -0
  78. data/spec/support/with_env_macro.rb +22 -0
  79. data/spec/unit/action/base_spec.rb +18 -0
  80. data/spec/unit/action/clean_spec.rb +102 -0
  81. data/spec/unit/action/ensure_spec.rb +37 -0
  82. data/spec/unit/action/install_spec.rb +111 -0
  83. data/spec/unit/algorithms_spec.rb +131 -0
  84. data/spec/unit/config/database_spec.rb +320 -0
  85. data/spec/unit/dependency/requirement_spec.rb +12 -0
  86. data/spec/unit/dependency_spec.rb +212 -0
  87. data/spec/unit/dsl_spec.rb +173 -0
  88. data/spec/unit/environment/runtime_cache_spec.rb +73 -0
  89. data/spec/unit/environment_spec.rb +209 -0
  90. data/spec/unit/lockfile/parser_spec.rb +162 -0
  91. data/spec/unit/lockfile_spec.rb +65 -0
  92. data/spec/unit/manifest/version_spec.rb +11 -0
  93. data/spec/unit/manifest_set_spec.rb +202 -0
  94. data/spec/unit/manifest_spec.rb +36 -0
  95. data/spec/unit/mock/environment_spec.rb +25 -0
  96. data/spec/unit/mock/source/mock_spec.rb +22 -0
  97. data/spec/unit/resolver_spec.rb +299 -0
  98. data/spec/unit/source/git_spec.rb +29 -0
  99. data/spec/unit/spec_change_set_spec.rb +169 -0
  100. metadata +257 -0
@@ -0,0 +1,64 @@
1
+ require 'rubygems/user_interaction'
2
+
3
+ module Librarian
4
+ class UI
5
+ def warn(message = nil)
6
+ end
7
+
8
+ def debug(message = nil)
9
+ end
10
+
11
+ def error(message = nil)
12
+ end
13
+
14
+ def info(message = nil)
15
+ end
16
+
17
+ def confirm(message = nil)
18
+ end
19
+
20
+ class Shell < UI
21
+ attr_writer :shell
22
+ attr_reader :debug_line_numbers
23
+
24
+ def initialize(shell)
25
+ @shell = shell
26
+ @quiet = false
27
+ @debug = ENV['DEBUG']
28
+ @debug_line_numbers = false
29
+ end
30
+
31
+ def debug(message = nil)
32
+ @shell.say(message || yield) if @debug && !@quiet
33
+ end
34
+
35
+ def info(message = nil)
36
+ @shell.say(message || yield) if !@quiet
37
+ end
38
+
39
+ def confirm(message = nil)
40
+ @shell.say(message || yield, :green) if !@quiet
41
+ end
42
+
43
+ def warn(message = nil)
44
+ @shell.say(message || yield, :yellow)
45
+ end
46
+
47
+ def error(message = nil)
48
+ @shell.say(message || yield, :red)
49
+ end
50
+
51
+ def be_quiet!
52
+ @quiet = true
53
+ end
54
+
55
+ def debug!
56
+ @debug = true
57
+ end
58
+
59
+ def debug_line_numbers!
60
+ @debug_line_numbers = true
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module Librarian
2
+ VERSION = File.read(File.expand_path("../../../VERSION", __FILE__)).strip
3
+ end
data/lib/librarian.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'librarian/version'
2
+ require 'librarian/environment'
3
+
4
+ module Librarian
5
+ extend self
6
+
7
+ def environment_class
8
+ self::Environment
9
+ end
10
+
11
+ end
data/librarian.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # stub: librarianp 0.1.2 ruby lib
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "librarianp"
6
+ s.version = "0.1.2"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["Jay Feldblum", "Carlos Sanchez"]
11
+ s.date = "2015-02-24"
12
+ s.description = "A Framework for Bundlers, used by librarian-puppet."
13
+ s.email = ["y_feldblum@yahoo.com", "carlos@apache.org"]
14
+ s.files = [".gitignore", ".rspec", ".travis.yml", "CHANGELOG.md", "Gemfile", "Gemfile.lock", "LICENSE.txt", "README.md", "Rakefile", "VERSION", "lib/librarian.rb", "lib/librarian/action.rb", "lib/librarian/action/base.rb", "lib/librarian/action/clean.rb", "lib/librarian/action/ensure.rb", "lib/librarian/action/install.rb", "lib/librarian/action/persist_resolution_mixin.rb", "lib/librarian/action/resolve.rb", "lib/librarian/action/update.rb", "lib/librarian/algorithms.rb", "lib/librarian/cli.rb", "lib/librarian/cli/manifest_presenter.rb", "lib/librarian/config.rb", "lib/librarian/config/database.rb", "lib/librarian/config/file_source.rb", "lib/librarian/config/hash_source.rb", "lib/librarian/config/source.rb", "lib/librarian/dependency.rb", "lib/librarian/dsl.rb", "lib/librarian/dsl/receiver.rb", "lib/librarian/dsl/target.rb", "lib/librarian/environment.rb", "lib/librarian/environment/runtime_cache.rb", "lib/librarian/error.rb", "lib/librarian/helpers.rb", "lib/librarian/linter/source_linter.rb", "lib/librarian/lockfile.rb", "lib/librarian/lockfile/compiler.rb", "lib/librarian/lockfile/parser.rb", "lib/librarian/logger.rb", "lib/librarian/manifest.rb", "lib/librarian/manifest_set.rb", "lib/librarian/mock.rb", "lib/librarian/mock/cli.rb", "lib/librarian/mock/dsl.rb", "lib/librarian/mock/environment.rb", "lib/librarian/mock/extension.rb", "lib/librarian/mock/source.rb", "lib/librarian/mock/source/mock.rb", "lib/librarian/mock/source/mock/registry.rb", "lib/librarian/mock/version.rb", "lib/librarian/posix.rb", "lib/librarian/resolution.rb", "lib/librarian/resolver.rb", "lib/librarian/resolver/implementation.rb", "lib/librarian/rspec/support/cli_macro.rb", "lib/librarian/source.rb", "lib/librarian/source/basic_api.rb", "lib/librarian/source/git.rb", "lib/librarian/source/git/repository.rb", "lib/librarian/source/local.rb", "lib/librarian/source/path.rb", "lib/librarian/spec.rb", "lib/librarian/spec_change_set.rb", "lib/librarian/specfile.rb", "lib/librarian/support/abstract_method.rb", "lib/librarian/ui.rb", "lib/librarian/version.rb", "librarian.gemspec", "spec/functional/cli_spec.rb", "spec/functional/posix_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/functional/source/git_spec.rb", "spec/support/fakefs.rb", "spec/support/method_patch_macro.rb", "spec/support/project_path_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/algorithms_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency/requirement_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment/runtime_cache_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest/version_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/environment_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
15
+ s.homepage = "https://github.com/carlossg/librarian"
16
+ s.licenses = ["MIT"]
17
+ s.rubygems_version = "2.4.3"
18
+ s.summary = "A Framework for Bundlers."
19
+ s.test_files = ["spec/functional/cli_spec.rb", "spec/functional/posix_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/functional/source/git_spec.rb", "spec/support/fakefs.rb", "spec/support/method_patch_macro.rb", "spec/support/project_path_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/algorithms_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency/requirement_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment/runtime_cache_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest/version_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/environment_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 4
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_runtime_dependency(%q<thor>, ["~> 0.15"])
26
+ s.add_runtime_dependency(%q<highline>, [">= 0"])
27
+ s.add_development_dependency(%q<rake>, [">= 0"])
28
+ s.add_development_dependency(%q<rspec>, ["~> 2.14"])
29
+ s.add_development_dependency(%q<json>, [">= 0"])
30
+ s.add_development_dependency(%q<fakefs>, ["~> 0.4.2"])
31
+ else
32
+ s.add_dependency(%q<thor>, ["~> 0.15"])
33
+ s.add_dependency(%q<highline>, [">= 0"])
34
+ s.add_dependency(%q<rake>, [">= 0"])
35
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
36
+ s.add_dependency(%q<json>, [">= 0"])
37
+ s.add_dependency(%q<fakefs>, ["~> 0.4.2"])
38
+ end
39
+ else
40
+ s.add_dependency(%q<thor>, ["~> 0.15"])
41
+ s.add_dependency(%q<highline>, [">= 0"])
42
+ s.add_dependency(%q<rake>, [">= 0"])
43
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
44
+ s.add_dependency(%q<json>, [">= 0"])
45
+ s.add_dependency(%q<fakefs>, ["~> 0.4.2"])
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ require "securerandom"
2
+
3
+ require "librarian/rspec/support/cli_macro"
4
+
5
+ require "librarian/mock/cli"
6
+
7
+ module Librarian
8
+ module Mock
9
+ describe Cli do
10
+ include Librarian::RSpec::Support::CliMacro
11
+
12
+ describe "version" do
13
+ before do
14
+ cli! "version"
15
+ end
16
+
17
+ it "should print the version" do
18
+ expect(stdout).to eq strip_heredoc(<<-STDOUT)
19
+ librarian-#{Librarian::VERSION}
20
+ librarian-mock-#{Librarian::Mock::VERSION}
21
+ STDOUT
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ require "librarian/posix"
2
+
3
+ require "support/project_path_macro"
4
+
5
+ describe Librarian::Posix do
6
+ include Support::ProjectPathMacro
7
+
8
+ let(:tmp_path) { project_path + "tmp/spec/functional/posix" }
9
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
10
+
11
+ describe ".run!" do
12
+
13
+ it "returns the stdout" do
14
+ res = described_class.run!(%w[echo hello there]).strip
15
+ expect(res).to eq "hello there"
16
+ end
17
+
18
+ it "changes directory" do
19
+ tmp_path.mkpath
20
+ res = described_class.run!(%w[pwd], :chdir => tmp_path).strip
21
+ expect(res).to eq tmp_path.to_s
22
+ end
23
+
24
+ it "reads the env" do
25
+ res = described_class.run!(%w[env], :env => {"KOALA" => "BEAR"})
26
+ line = res.lines.find{|l| l.start_with?("KOALA=")}.strip
27
+ expect(line).to eq "KOALA=BEAR"
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,199 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "securerandom"
4
+
5
+ require "librarian/posix"
6
+
7
+ require "librarian/source/git/repository"
8
+
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
12
+
13
+ describe Librarian::Source::Git::Repository do
14
+ include Support::ProjectPathMacro
15
+
16
+ let(:env) { Librarian::Mock::Environment.new }
17
+
18
+ let(:tmp_path) { project_path + "tmp/spec/functional/source/git/repository" }
19
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
20
+ let(:git_source_path) { tmp_path + SecureRandom.hex(16) }
21
+ let(:branch) { "the-branch" }
22
+ let(:tag) { "the-tag" }
23
+ let(:atag) { "the-atag" }
24
+
25
+ def cmd!(command)
26
+ Librarian::Posix.run! command
27
+ end
28
+
29
+ def git!(command)
30
+ cmd!([described_class.bin] + command)
31
+ end
32
+
33
+ before do
34
+ git_source_path.mkpath
35
+ Dir.chdir(git_source_path) do
36
+ git! %W[init]
37
+ git! %W[config user.name Simba]
38
+ git! %W[config user.email simba@savannah-pride.gov]
39
+
40
+ # master
41
+ FileUtils.touch "butter.txt"
42
+ git! %W[add butter.txt]
43
+ git! %W[commit -m #{"Initial Commit"}]
44
+
45
+ # branch
46
+ git! %W[checkout -b #{branch} --quiet]
47
+ FileUtils.touch "jam.txt"
48
+ git! %W[add jam.txt]
49
+ git! %W[commit -m #{"Branch Commit"}]
50
+ git! %W[checkout master --quiet]
51
+
52
+ # tag/atag
53
+ git! %W[checkout -b deletable --quiet]
54
+ FileUtils.touch "jelly.txt"
55
+ git! %W[add jelly.txt]
56
+ git! %W[commit -m #{"Tag Commit"}]
57
+ git! %W[tag #{tag}]
58
+ git! %W[tag -am #{"Annotated Tag Commit"} #{atag}]
59
+ git! %W[checkout master --quiet]
60
+ git! %W[branch -D deletable]
61
+ end
62
+ end
63
+
64
+ describe ".bin" do
65
+ specify { expect(described_class.bin).to_not be_empty }
66
+ end
67
+
68
+ describe ".git_version" do
69
+ specify { expect(described_class.git_version).to match( /^\d+(\.\d+)+$/ ) }
70
+ end
71
+
72
+ context "the original" do
73
+ subject { described_class.new(env, git_source_path) }
74
+
75
+ it "should recognize it" do
76
+ expect(subject).to be_git
77
+ end
78
+
79
+ it "should not list any remotes for it" do
80
+ expect(subject.remote_names).to be_empty
81
+ end
82
+
83
+ it "should not list any remote branches for it" do
84
+ expect(subject.remote_branch_names).to be_empty
85
+ end
86
+
87
+ it "should have divergent shas for master, branch, tag, and atag" do
88
+ revs = %W[ master #{branch} #{tag} #{atag} ]
89
+ rev_parse = proc{|rev| git!(%W[rev-parse #{rev} --quiet]).strip}
90
+ shas = Dir.chdir(git_source_path){revs.map(&rev_parse)}
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
94
+ end
95
+ end
96
+
97
+ context "a clone" do
98
+ let(:git_clone_path) { tmp_path + SecureRandom.hex(16) }
99
+ subject { described_class.clone!(env, git_clone_path, git_source_path) }
100
+
101
+ let(:master_sha) { subject.hash_from("origin", "master") }
102
+ let(:branch_sha) { subject.hash_from("origin", branch) }
103
+ let(:tag_sha) { subject.hash_from("origin", tag) }
104
+ let(:atag_sha) { subject.hash_from("origin", atag) }
105
+
106
+ it "should recognize it" do
107
+ expect(subject).to be_git
108
+ end
109
+
110
+ it "should have a single remote for it" do
111
+ expect(subject).to have(1).remote_names
112
+ end
113
+
114
+ it "should have a remote with the expected name" do
115
+ expect(subject.remote_names.first).to eq "origin"
116
+ end
117
+
118
+ it "should have the remote branch" do
119
+ expect(subject.remote_branch_names["origin"]).to include branch
120
+ end
121
+
122
+ it "should be checked out on the master" do
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
154
+ end
155
+
156
+ context "checking out the branch" do
157
+ before do
158
+ subject.checkout! branch
159
+ end
160
+
161
+ it "should be checked out on the branch" do
162
+ expect(subject).to be_checked_out(branch_sha)
163
+ end
164
+
165
+ it "should not be checked out on the master" do
166
+ expect(subject).to_not be_checked_out(master_sha)
167
+ end
168
+ end
169
+
170
+ context "checking out the tag" do
171
+ before do
172
+ subject.checkout! tag
173
+ end
174
+
175
+ it "should be checked out on the tag" do
176
+ expect(subject).to be_checked_out(tag_sha)
177
+ end
178
+
179
+ it "should not be checked out on the master" do
180
+ expect(subject).to_not be_checked_out(master_sha)
181
+ end
182
+ end
183
+
184
+ context "checking out the annotated tag" do
185
+ before do
186
+ subject.checkout! atag
187
+ end
188
+
189
+ it "should be checked out on the annotated tag" do
190
+ expect(subject).to be_checked_out(atag_sha)
191
+ end
192
+
193
+ it "should not be checked out on the master" do
194
+ expect(subject).to_not be_checked_out(master_sha)
195
+ end
196
+ end
197
+ end
198
+
199
+ end
@@ -0,0 +1,174 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "securerandom"
4
+
5
+ require "librarian/error"
6
+ require "librarian/posix"
7
+ require "librarian/source/git"
8
+ require "librarian/source/git/repository"
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
12
+
13
+ describe Librarian::Source::Git do
14
+ include Support::ProjectPathMacro
15
+
16
+ let(:tmp_path) { project_path + "tmp/spec/functional/source/git" }
17
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
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
31
+
32
+ context "when the remote is bad" do
33
+ let(:remote) { tmp_path.join(SecureRandom.hex(8)).to_s }
34
+ let(:env) { new_env }
35
+ let(:source) { described_class.new(env, remote, {}) }
36
+
37
+ it "fails when caching" do
38
+ expect { source.cache! }.to raise_error Librarian::Error,
39
+ /^fatal: repository .+ does not exist$/ # from git
40
+ end
41
+ end
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
+
174
+ end
@@ -0,0 +1,37 @@
1
+ require "fakefs/safe"
2
+ require "fakefs/spec_helpers"
3
+ require "support/method_patch_macro"
4
+
5
+ if defined?(Rubinius)
6
+ module Rubinius
7
+ class CodeLoader
8
+ class << self
9
+ alias_method :require_fakefs_original, :require
10
+ def require(s)
11
+ ::FakeFS.without { require_fakefs_original(s) }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module Support
19
+ module FakeFS
20
+
21
+ def self.included(base)
22
+ base.module_exec do
23
+ include ::FakeFS::SpecHelpers
24
+ end
25
+
26
+ # Since ruby-1.9.3-p286, Kernel#Pathname was changed in a way that broke
27
+ # FakeFS's assumptions. It used to lookup the Pathname constant (which is
28
+ # where FakeFS hooks) and send it #new, but now it keeps a reference to
29
+ # the Pathname constant (breaking the FakeFS hook).
30
+ base.module_exec do
31
+ include MethodPatchMacro
32
+ with_module_method(Kernel, :Pathname){|s| Pathname.new(s)}
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ require "securerandom"
2
+
3
+ module Support
4
+ module MethodPatchMacro
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def with_module_method(mod, meth, &block)
12
+ tag = SecureRandom.hex(8)
13
+ orig_meth = "_#{tag}_#{meth}".to_sym
14
+ before do
15
+ mod.module_eval do
16
+ alias_method orig_meth, meth
17
+ define_method meth, &block
18
+ end
19
+ end
20
+ after do
21
+ mod.module_eval do
22
+ alias_method meth, orig_meth
23
+ remove_method orig_meth
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ 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
@@ -0,0 +1,22 @@
1
+ module Support
2
+ module WithEnvMacro
3
+
4
+ module ClassMethods
5
+
6
+ def with_env(new)
7
+ old = Hash[new.map{|k, v| [k, ENV[k]]}]
8
+
9
+ before { ENV.update(new) }
10
+ after { ENV.update(old) }
11
+ end
12
+
13
+ end
14
+
15
+ private
16
+
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
19
+ end
20
+
21
+ end
22
+ end