rosette-core 1.0.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.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +26 -0
  3. data/History.txt +3 -0
  4. data/README.md +94 -0
  5. data/Rakefile +18 -0
  6. data/lib/rosette/core.rb +110 -0
  7. data/lib/rosette/core/branch_utils.rb +152 -0
  8. data/lib/rosette/core/commands.rb +139 -0
  9. data/lib/rosette/core/commands/errors.rb +17 -0
  10. data/lib/rosette/core/commands/git/commit_command.rb +65 -0
  11. data/lib/rosette/core/commands/git/diff_base_command.rb +301 -0
  12. data/lib/rosette/core/commands/git/diff_command.rb +188 -0
  13. data/lib/rosette/core/commands/git/diff_entry.rb +44 -0
  14. data/lib/rosette/core/commands/git/fetch_command.rb +27 -0
  15. data/lib/rosette/core/commands/git/repo_snapshot_command.rb +40 -0
  16. data/lib/rosette/core/commands/git/show_command.rb +70 -0
  17. data/lib/rosette/core/commands/git/snapshot_command.rb +50 -0
  18. data/lib/rosette/core/commands/git/status_command.rb +128 -0
  19. data/lib/rosette/core/commands/git/with_non_merge_ref.rb +48 -0
  20. data/lib/rosette/core/commands/git/with_ref.rb +92 -0
  21. data/lib/rosette/core/commands/git/with_refs.rb +92 -0
  22. data/lib/rosette/core/commands/git/with_repo_name.rb +50 -0
  23. data/lib/rosette/core/commands/git/with_snapshots.rb +45 -0
  24. data/lib/rosette/core/commands/queuing/enqueue_commit_command.rb +37 -0
  25. data/lib/rosette/core/commands/queuing/requeue_commit_command.rb +46 -0
  26. data/lib/rosette/core/commands/translations/export_command.rb +257 -0
  27. data/lib/rosette/core/commands/translations/translation_lookup_command.rb +66 -0
  28. data/lib/rosette/core/commands/translations/with_locale.rb +47 -0
  29. data/lib/rosette/core/configurator.rb +160 -0
  30. data/lib/rosette/core/error_reporters/buffered_error_reporter.rb +96 -0
  31. data/lib/rosette/core/error_reporters/error_reporter.rb +31 -0
  32. data/lib/rosette/core/error_reporters/nil_error_reporter.rb +25 -0
  33. data/lib/rosette/core/error_reporters/printing_error_reporter.rb +58 -0
  34. data/lib/rosette/core/error_reporters/raising_error_reporter.rb +27 -0
  35. data/lib/rosette/core/errors.rb +93 -0
  36. data/lib/rosette/core/extractor/commit_log.rb +33 -0
  37. data/lib/rosette/core/extractor/commit_log_status.rb +57 -0
  38. data/lib/rosette/core/extractor/commit_processor.rb +109 -0
  39. data/lib/rosette/core/extractor/extractor.rb +72 -0
  40. data/lib/rosette/core/extractor/extractor_config.rb +74 -0
  41. data/lib/rosette/core/extractor/locale.rb +118 -0
  42. data/lib/rosette/core/extractor/phrase.rb +76 -0
  43. data/lib/rosette/core/extractor/phrase/phrase_index_policy.rb +108 -0
  44. data/lib/rosette/core/extractor/phrase/phrase_to_hash.rb +33 -0
  45. data/lib/rosette/core/extractor/repo_config.rb +339 -0
  46. data/lib/rosette/core/extractor/serializer_config.rb +55 -0
  47. data/lib/rosette/core/extractor/static_extractor.rb +44 -0
  48. data/lib/rosette/core/extractor/translation.rb +44 -0
  49. data/lib/rosette/core/extractor/translation/translation_to_hash.rb +28 -0
  50. data/lib/rosette/core/git/diff_finder.rb +131 -0
  51. data/lib/rosette/core/git/ref.rb +116 -0
  52. data/lib/rosette/core/git/repo.rb +378 -0
  53. data/lib/rosette/core/path_matcher_factory.rb +330 -0
  54. data/lib/rosette/core/resolvers/extractor_id.rb +37 -0
  55. data/lib/rosette/core/resolvers/integration_id.rb +37 -0
  56. data/lib/rosette/core/resolvers/preprocessor_id.rb +38 -0
  57. data/lib/rosette/core/resolvers/resolver.rb +115 -0
  58. data/lib/rosette/core/resolvers/serializer_id.rb +37 -0
  59. data/lib/rosette/core/snapshots/cached_head_snapshot_factory.rb +51 -0
  60. data/lib/rosette/core/snapshots/cached_snapshot_factory.rb +67 -0
  61. data/lib/rosette/core/snapshots/head_snapshot_factory.rb +58 -0
  62. data/lib/rosette/core/snapshots/repo_config_path_filter.rb +83 -0
  63. data/lib/rosette/core/snapshots/snapshot_factory.rb +184 -0
  64. data/lib/rosette/core/string_utils.rb +23 -0
  65. data/lib/rosette/core/translation_status.rb +81 -0
  66. data/lib/rosette/core/validators.rb +18 -0
  67. data/lib/rosette/core/validators/commit_validator.rb +62 -0
  68. data/lib/rosette/core/validators/commits_validator.rb +32 -0
  69. data/lib/rosette/core/validators/encoding_validator.rb +32 -0
  70. data/lib/rosette/core/validators/locale_validator.rb +37 -0
  71. data/lib/rosette/core/validators/repo_validator.rb +33 -0
  72. data/lib/rosette/core/validators/serializer_validator.rb +37 -0
  73. data/lib/rosette/core/validators/validator.rb +31 -0
  74. data/lib/rosette/core/version.rb +8 -0
  75. data/lib/rosette/data_stores.rb +11 -0
  76. data/lib/rosette/data_stores/errors.rb +26 -0
  77. data/lib/rosette/data_stores/phrase_status.rb +59 -0
  78. data/lib/rosette/integrations.rb +12 -0
  79. data/lib/rosette/integrations/errors.rb +15 -0
  80. data/lib/rosette/integrations/integratable.rb +58 -0
  81. data/lib/rosette/integrations/integration.rb +23 -0
  82. data/lib/rosette/preprocessors.rb +11 -0
  83. data/lib/rosette/preprocessors/errors.rb +14 -0
  84. data/lib/rosette/preprocessors/preprocessor.rb +48 -0
  85. data/lib/rosette/queuing.rb +14 -0
  86. data/lib/rosette/queuing/commits.rb +19 -0
  87. data/lib/rosette/queuing/commits/commit_conductor.rb +90 -0
  88. data/lib/rosette/queuing/commits/commit_job.rb +93 -0
  89. data/lib/rosette/queuing/commits/commits_queue_configurator.rb +60 -0
  90. data/lib/rosette/queuing/commits/extract_stage.rb +46 -0
  91. data/lib/rosette/queuing/commits/fetch_stage.rb +51 -0
  92. data/lib/rosette/queuing/commits/finalize_stage.rb +76 -0
  93. data/lib/rosette/queuing/commits/phrase_storage_granularity.rb +20 -0
  94. data/lib/rosette/queuing/commits/push_stage.rb +91 -0
  95. data/lib/rosette/queuing/commits/stage.rb +96 -0
  96. data/lib/rosette/queuing/job.rb +74 -0
  97. data/lib/rosette/queuing/queue.rb +28 -0
  98. data/lib/rosette/queuing/queue_configurator.rb +76 -0
  99. data/lib/rosette/queuing/worker.rb +30 -0
  100. data/lib/rosette/serializers.rb +10 -0
  101. data/lib/rosette/serializers/serializer.rb +98 -0
  102. data/lib/rosette/tms.rb +9 -0
  103. data/lib/rosette/tms/repository.rb +95 -0
  104. data/rosette-core.gemspec +24 -0
  105. data/spec/core/branch_utils_spec.rb +110 -0
  106. data/spec/core/commands/git/commit_command_spec.rb +60 -0
  107. data/spec/core/commands/git/diff_command_spec.rb +263 -0
  108. data/spec/core/commands/git/fetch_command_spec.rb +61 -0
  109. data/spec/core/commands/git/repo_snapshot_command_spec.rb +72 -0
  110. data/spec/core/commands/git/show_command_spec.rb +128 -0
  111. data/spec/core/commands/git/snapshot_command_spec.rb +86 -0
  112. data/spec/core/commands/git/status_command_spec.rb +154 -0
  113. data/spec/core/commands/queuing/enqueue_commit_command_spec.rb +34 -0
  114. data/spec/core/commands/queuing/requeue_commit_command_spec.rb +46 -0
  115. data/spec/core/commands/translations/export_command_spec.rb +113 -0
  116. data/spec/core/commands/translations/translation_lookup_command_spec.rb +58 -0
  117. data/spec/core/configurator_spec.rb +47 -0
  118. data/spec/core/error_reporters/buffered_error_reporter_spec.rb +61 -0
  119. data/spec/core/error_reporters/nil_error_reporter_spec.rb +16 -0
  120. data/spec/core/error_reporters/printing_error_reporter_spec.rb +60 -0
  121. data/spec/core/extractor/commit_log_status_spec.rb +216 -0
  122. data/spec/core/extractor/commit_processor_spec.rb +68 -0
  123. data/spec/core/extractor/extractor_config_spec.rb +47 -0
  124. data/spec/core/extractor/extractor_spec.rb +26 -0
  125. data/spec/core/extractor/locale_spec.rb +92 -0
  126. data/spec/core/extractor/phrase/phrase_index_policy_spec.rb +116 -0
  127. data/spec/core/extractor/phrase/phrase_to_hash_spec.rb +18 -0
  128. data/spec/core/extractor/repo_config_spec.rb +147 -0
  129. data/spec/core/extractor/translation/translation_to_hash_spec.rb +25 -0
  130. data/spec/core/git/diff_finder_spec.rb +74 -0
  131. data/spec/core/git/ref_spec.rb +118 -0
  132. data/spec/core/git/repo_spec.rb +216 -0
  133. data/spec/core/path_matcher_factory_spec.rb +139 -0
  134. data/spec/core/resolvers/extractor_id_spec.rb +47 -0
  135. data/spec/core/resolvers/integration_id_spec.rb +47 -0
  136. data/spec/core/resolvers/preprocessor_id_spec.rb +47 -0
  137. data/spec/core/resolvers/serializer_id_spec.rb +47 -0
  138. data/spec/core/snapshots/snapshot_factory_spec.rb +145 -0
  139. data/spec/core/string_utils_spec.rb +19 -0
  140. data/spec/core/translation_status_spec.rb +91 -0
  141. data/spec/core/validators/commit_validator_spec.rb +40 -0
  142. data/spec/core/validators/encoding_validator_spec.rb +30 -0
  143. data/spec/core/validators/locale_validator_spec.rb +31 -0
  144. data/spec/core/validators/repo_validator_spec.rb +30 -0
  145. data/spec/core/validators/serializer_validator_spec.rb +31 -0
  146. data/spec/integrations/integratable_spec.rb +58 -0
  147. data/spec/queuing/commits/commit_conductor_spec.rb +71 -0
  148. data/spec/queuing/commits/commit_job_spec.rb +87 -0
  149. data/spec/queuing/commits/extract_stage_spec.rb +68 -0
  150. data/spec/queuing/commits/fetch_stage_spec.rb +101 -0
  151. data/spec/queuing/commits/finalize_stage_spec.rb +88 -0
  152. data/spec/queuing/commits/push_stage_spec.rb +145 -0
  153. data/spec/queuing/commits/stage_spec.rb +80 -0
  154. data/spec/queuing/job_spec.rb +33 -0
  155. data/spec/queuing/queue_configurator_spec.rb +44 -0
  156. data/spec/spec_helper.rb +90 -0
  157. data/spec/test_helpers/fake_commit_stage.rb +17 -0
  158. metadata +257 -0
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Core
6
+
7
+ describe TranslationToHash do
8
+ describe '#to_h' do
9
+ let(:phrase) do
10
+ TestPhrase.new('key', 'meta key', 'file', 'commit id')
11
+ end
12
+
13
+ it 'returns a hash of the appropriate attributes' do
14
+ TestTranslation.new(translation: 'translation', locale: 'es', phrase: phrase) do |t|
15
+ expect(t.to_h).to eq({
16
+ translation: 'translation', locale: 'es',
17
+ phrase: {
18
+ key: 'key', meta_key: 'meta key',
19
+ file: 'file', commit_id: 'commit id'
20
+ }
21
+ })
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Core
6
+
7
+ java_import 'org.eclipse.jgit.revwalk.RevWalk'
8
+ java_import 'org.eclipse.jgit.lib.ObjectId'
9
+
10
+ describe DiffFinder do
11
+ let(:repo_name) { 'double_commit' }
12
+ let(:fixture) { load_repo_fixture(repo_name) }
13
+ let(:repo) { Repo.from_path(fixture.repo_fixture.working_dir.join('.git').to_s) }
14
+ let(:rev_walk) { RevWalk.new(repo.jgit_repo) }
15
+ let(:diff_finder) { DiffFinder.new(repo.jgit_repo, rev_walk) }
16
+
17
+ let(:revs) do
18
+ fixture.each_commit.map do |fixture_commit|
19
+ rev_walk.parseCommit(ObjectId.fromString(fixture_commit.sha))
20
+ end
21
+ end
22
+
23
+ let(:first_file_contents) do
24
+ "I'm a little teapot\n" +
25
+ "The green albatross flitters in the moonlight\n"
26
+ end
27
+
28
+ let(:second_file_contents) do
29
+ "Chatanooga Choo Choo\n" +
30
+ "Diamonds are a girl's best friend.\n" +
31
+ "Cash for the merchandise; cash for the fancy goods.\n" +
32
+ "I'm in Spañish.\n"
33
+ end
34
+
35
+ describe '#diff' do
36
+ it 'returns the diff between the first two commits' do
37
+ commit_id = revs.first.getName
38
+
39
+ diff_finder.diff(revs.first, revs.last).tap do |diff|
40
+ expect(diff.size).to eq(1)
41
+ expect(diff[commit_id].first.getNewPath).to eq('second_file.txt')
42
+ expect(diff_finder.read_new_entry(diff[commit_id].first)).to(
43
+ eq(second_file_contents)
44
+ )
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#diff_with_parent' do
50
+ it 'returns the diff between the first two commits (just as a regular diff would do)' do
51
+ commit_id = revs.first.getName
52
+
53
+ diff_finder.diff_with_parents(revs.last).tap do |diff|
54
+ expect(diff.size).to eq(1)
55
+ expect(diff[revs.first.getName].first.getNewPath).to eq('second_file.txt')
56
+ expect(diff_finder.read_new_entry(diff[revs.first.getName].first)).to(
57
+ eq(second_file_contents)
58
+ )
59
+ end
60
+ end
61
+
62
+ it "returns the diff successfully if the rev doesn't have a parent" do
63
+ commit_id = revs.first.getName
64
+
65
+ diff_finder.diff_with_parents(revs.first).tap do |diff|
66
+ expect(diff.size).to eq(1)
67
+ expect(diff[commit_id].first.getNewPath).to eq('first_file.txt')
68
+ expect(diff_finder.read_new_entry(diff[commit_id].first)).to(
69
+ eq(first_file_contents)
70
+ )
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Core
6
+
7
+ describe Ref do
8
+ describe '.parse' do
9
+ it 'parses remotes' do
10
+ ref = Ref.parse('refs/remotes/origin/foobar')
11
+ expect(ref).to be_a(Remote)
12
+ end
13
+
14
+ it 'parses heads' do
15
+ ref = Ref.parse('refs/heads/foobar')
16
+ expect(ref).to be_a(Head)
17
+ end
18
+
19
+ it 'parses tags' do
20
+ ref = Ref.parse('refs/tags/foobar')
21
+ expect(ref).to be_a(Tag)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe Remote do
27
+ describe '.create_from' do
28
+ it 'creates a new remote ref' do
29
+ remote = Remote.create_from(%w(remotes origin foobar))
30
+ expect(remote.remote).to eq('origin')
31
+ expect(remote.name).to eq('foobar')
32
+ end
33
+ end
34
+
35
+ context 'with a remote' do
36
+ let(:remote) { Remote.new('origin', 'foobar') }
37
+
38
+ describe '#type' do
39
+ it 'returns the correct type' do
40
+ expect(remote.type).to eq(:remote)
41
+ end
42
+ end
43
+
44
+ describe '#to_s' do
45
+ it 'constructs a string representation' do
46
+ expect(remote.to_s).to eq('refs/remotes/origin/foobar')
47
+ end
48
+ end
49
+
50
+ it 'responds correctly to query methods' do
51
+ expect(remote).to be_remote
52
+ expect(remote).to_not be_head
53
+ expect(remote).to_not be_tag
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Head do
59
+ describe '.create_from' do
60
+ it 'creates a new head' do
61
+ head = Head.create_from(%w(heads foobar))
62
+ expect(head.name).to eq('foobar')
63
+ end
64
+ end
65
+
66
+ context 'with a head' do
67
+ let(:head) { Head.new('foobar') }
68
+
69
+ describe '#type' do
70
+ it 'returns the correct type' do
71
+ expect(head.type).to eq(:head)
72
+ end
73
+ end
74
+
75
+ describe '#to_s' do
76
+ it 'constructs a string representation' do
77
+ expect(head.to_s).to eq('refs/heads/foobar')
78
+ end
79
+ end
80
+
81
+ it 'responds correctly to query methods' do
82
+ expect(head).to be_head
83
+ expect(head).to_not be_remote
84
+ expect(head).to_not be_tag
85
+ end
86
+ end
87
+ end
88
+
89
+ describe Tag do
90
+ describe '.create_from' do
91
+ it 'creates a new tag' do
92
+ tag = Tag.create_from(%w(tags foobar))
93
+ expect(tag.name).to eq('foobar')
94
+ end
95
+ end
96
+
97
+ context 'with a tag' do
98
+ let(:tag) { Tag.new('foobar') }
99
+
100
+ describe '#type' do
101
+ it 'returns the correct type' do
102
+ expect(tag.type).to eq(:tag)
103
+ end
104
+ end
105
+
106
+ describe '#to_s' do
107
+ it 'constructs a string representation' do
108
+ expect(tag.to_s).to eq('refs/tags/foobar')
109
+ end
110
+ end
111
+
112
+ it 'responds correctly to query methods' do
113
+ expect(tag).to be_tag
114
+ expect(tag).to_not be_head
115
+ expect(tag).to_not be_remote
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,216 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Core
6
+
7
+ java_import 'org.eclipse.jgit.lib.ObjectId'
8
+
9
+ describe Repo do
10
+ let(:repo_class) { Repo }
11
+
12
+ describe 'self.from_path' do
13
+ it 'returns a new repo at the given path' do
14
+ tmp_repo = TmpRepo.new
15
+ repo = repo_class.from_path(tmp_repo.working_dir.join('.git').to_s)
16
+ expect(repo.path).to eq(tmp_repo.working_dir.to_s)
17
+ tmp_repo.unlink
18
+ end
19
+ end
20
+
21
+ context 'with the double commit fixture' do
22
+ let(:repo_name) { 'double_commit' }
23
+ let(:fixture) { load_repo_fixture(repo_name) }
24
+ let(:repo) { repo_class.from_path(fixture.working_dir.join('.git').to_s) }
25
+ let(:commits) do
26
+ fixture.git('rev-list --all').split("\n").map do |sha|
27
+ repo.get_rev_commit(sha)
28
+ end.reverse
29
+ end
30
+
31
+ describe '#get_rev_commit' do
32
+ it 'returns a rev commit for a symbolic ref' do
33
+ commit = repo.get_rev_commit('HEAD')
34
+ expect(commit.getName).to eq(commits.last.getName)
35
+ end
36
+
37
+ it 'returns a rev commit for a sha' do
38
+ commit = repo.get_rev_commit(commits.last.getName)
39
+ expect(commit.getName).to eq(commits.last.getName)
40
+ end
41
+
42
+ it "falls back to remotes if the branch hasn't been checked out locally" do
43
+ branch_name = 'my_remote_branch'
44
+
45
+ remote_repo = TmpRepo.new.tap do |r|
46
+ r.create_branch(branch_name)
47
+ r.create_file('foo.txt') { |f| f.write('foo') }
48
+ r.add_all
49
+ r.commit('Initial commit')
50
+ end
51
+
52
+ fixture.repo.git("remote add origin file://#{remote_repo.working_dir}")
53
+ fixture.repo.git('fetch')
54
+
55
+ remote_commit_id = remote_repo.git('rev-parse HEAD').strip
56
+ commit = repo.get_rev_commit(branch_name)
57
+ expect(commit.getName).to eq(remote_commit_id)
58
+ end
59
+ end
60
+
61
+ describe '#diff' do
62
+ it 'returns the diff when a symbolic ref is involved' do
63
+ commit_id = commits.first.getName
64
+ repo.diff(commit_id, 'HEAD').tap do |diff|
65
+ expect(diff.size).to eq(1)
66
+ expect(diff[commit_id].first.getNewPath).to eq('second_file.txt')
67
+ end
68
+ end
69
+
70
+ it 'returns the diff between two shas' do
71
+ first_commit_id = commits.first.getName
72
+ second_commit_id = commits.last.getName
73
+ repo.diff(first_commit_id, second_commit_id).tap do |diff|
74
+ expect(diff.size).to eq(1)
75
+ expect(diff[first_commit_id].first.getNewPath).to eq('second_file.txt')
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#ref_diff_with_parents' do
81
+ it 'returns the correct diff' do
82
+ commit_id = commits.first.getName
83
+ repo.ref_diff_with_parents('HEAD').tap do |diff|
84
+ expect(diff.size).to eq(1)
85
+ expect(diff[commit_id].first.getNewPath).to eq('second_file.txt')
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#rev_diff_with_parents' do
91
+ it 'returns the correct diff' do
92
+ commit_id = commits.first.getName
93
+ repo.rev_diff_with_parents(repo.get_rev_commit('HEAD')).tap do |diff|
94
+ expect(diff.size).to eq(1)
95
+ expect(diff[commit_id].first.getNewPath).to eq('second_file.txt')
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#path' do
101
+ it 'returns the current working directory' do
102
+ expect(repo.path).to eq(fixture.working_dir.to_s)
103
+ end
104
+ end
105
+
106
+ describe '#read_object_bytes' do
107
+ it 'returns a byte array containing the object of the given id' do
108
+ object_id = ObjectId.fromString(fixture.git('hash-object first_file.txt').strip)
109
+ actual_bytes = repo.read_object_bytes(object_id)
110
+ expected_bytes = "I'm a little teapot\nThe green albatross flitters in the moonlight\n".bytes
111
+
112
+ expected_bytes.each_with_index do |expected_byte, index|
113
+ expect(actual_bytes[index]).to eq(expected_byte)
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#each_commit' do
119
+ it 'yields each commit or returns an enumerator' do
120
+ repo.each_commit.tap do |commit_enum|
121
+ expect(commit_enum).to be_a(Enumerator)
122
+ expect(commit_enum.map(&:getName)).to eq(commits.map(&:getName))
123
+ end
124
+ end
125
+ end
126
+
127
+ describe '#commit_count' do
128
+ it 'returns the total number of commits in the repo' do
129
+ expect(repo.commit_count).to eq(2)
130
+ end
131
+ end
132
+ end
133
+
134
+ context 'with the four commits fixture' do
135
+ let(:repo_name) { 'four_commits' }
136
+ let(:fixture) { load_repo_fixture(repo_name) }
137
+ let(:repo) { repo_class.from_path(fixture.working_dir.join('.git').to_s) }
138
+ let(:commits) do
139
+ fixture.git('rev-list --all').split("\n").map do |sha|
140
+ repo.get_rev_commit(sha)
141
+ end.reverse
142
+ end
143
+
144
+ describe '#each_commit_in_range' do
145
+ it 'yields only the commits in the given range' do
146
+ commit_args = [commits[2].getId.name, commits[0].getId.name]
147
+
148
+ found_commits = repo.each_commit_in_range(*commit_args).map do |c|
149
+ c.getId.name
150
+ end
151
+
152
+ expect(found_commits).to(
153
+ eq(commits[0..2].map { |c| c.getId.name }.reverse)
154
+ )
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'with a merge commit fixture' do
160
+ let(:repo_name) { 'merge_commit' }
161
+ let(:fixture) { load_repo_fixture(repo_name) }
162
+ let(:repo) { repo_class.from_path(fixture.working_dir.join('.git').to_s) }
163
+ let(:commits) do
164
+ fixture.git('rev-list --all').split("\n").map do |sha|
165
+ repo.get_rev_commit(sha)
166
+ end
167
+ end
168
+
169
+ describe '#parents_of' do
170
+ it 'returns a single commit for a commit with a single parent' do
171
+ repo.parents_of(commits[1]).tap do |parents|
172
+ expect(parents.size).to eq(1)
173
+ expect(parents.first.getName).to eq(commits.last.getName)
174
+ end
175
+ end
176
+
177
+ it 'returns multiple parents when given a merge commit' do
178
+ repo.parents_of(commits.first).tap do |parents|
179
+ expect(parents.size).to eq(2)
180
+ parent_shas = parents.map(&:getName)
181
+ expect(parent_shas).to include(commits.last.getName)
182
+ expect(parent_shas).to include(commits[1].getName)
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '#parent_ids_of' do
188
+ it 'returns a single sha for a commit with a single parent' do
189
+ repo.parent_ids_of(commits[1]).tap do |parent_ids|
190
+ expect(parent_ids).to eq([commits.last.getName])
191
+ end
192
+ end
193
+
194
+ it 'returns multiple parent shas when given a merge commit' do
195
+ repo.parent_ids_of(commits.first).tap do |parent_ids|
196
+ expect(parent_ids).to eq(commits[1..-1].reverse.map(&:getName))
197
+ end
198
+ end
199
+ end
200
+
201
+ describe '#commit_count' do
202
+ it 'returns the total number of commits in the repo' do
203
+ expect(repo.commit_count).to eq(3)
204
+ end
205
+ end
206
+
207
+ describe '#refs_containing' do
208
+ it 'returns the refs that contain the given commit' do
209
+ refs = repo.refs_containing(commits.last.getId.name)
210
+ expect(refs.map(&:getName)).to eq([
211
+ "HEAD", "refs/heads/master", "refs/heads/mybranch"
212
+ ])
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ include Rosette::Core
6
+
7
+ describe PathMatcherFactory do
8
+ let(:factory) { PathMatcherFactory }
9
+
10
+ describe '#create_root' do
11
+ it 'returns an empty, generic node' do
12
+ # instance_of returns false for subclasses of Node
13
+ expect(factory.create_root).to be_instance_of(factory::Node)
14
+ end
15
+ end
16
+
17
+ let(:root) { factory.create_root }
18
+
19
+ describe 'operators' do
20
+ it 'supports the and binary operator' do
21
+ node = root.match_path('foo/bar').and(root.match_path('foo/baz'))
22
+ expect(node).to be_a(factory::BinaryNode)
23
+ expect(node).to be_a(factory::AndNode)
24
+
25
+ node.left.tap do |left|
26
+ expect(left).to be_a(factory::PathNode)
27
+ expect(left.path).to eq('foo/bar')
28
+ end
29
+
30
+ node.right.tap do |right|
31
+ expect(right).to be_a(factory::PathNode)
32
+ expect(right.path).to eq('foo/baz')
33
+ end
34
+ end
35
+
36
+ it 'supports the or binary operator' do
37
+ node = root.match_path('foo/bar').or(root.match_path('foo/baz'))
38
+ expect(node).to be_a(factory::BinaryNode)
39
+ expect(node).to be_a(factory::OrNode)
40
+
41
+ node.left.tap do |left|
42
+ expect(left).to be_a(factory::PathNode)
43
+ expect(left.path).to eq('foo/bar')
44
+ end
45
+
46
+ node.right.tap do |right|
47
+ expect(right).to be_a(factory::PathNode)
48
+ expect(right.path).to eq('foo/baz')
49
+ end
50
+ end
51
+
52
+ it 'supports the unary not operator' do
53
+ node = root.match_path('foo/bar').not
54
+ expect(node).to be_a(factory::UnaryNode)
55
+ expect(node).to be_a(factory::NotNode)
56
+
57
+ node.child.tap do |child|
58
+ expect(child).to be_a(factory::PathNode)
59
+ expect(child.path).to eq('foo/bar')
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ context 'nodes' do
66
+ let(:factory) { PathMatcherFactory }
67
+ let(:root) { factory.create_root }
68
+
69
+ describe PathMatcherFactory::AndNode do
70
+ describe '#matches?' do
71
+ it 'returns true if both paths match, false otherwise' do
72
+ node = root.match_path('foo/bar').and(root.match_path('foo/bar/baz'))
73
+ expect(node).to be_a(factory::AndNode)
74
+ expect(node.matches?('foo/bar/baz/goo')).to be_truthy
75
+ expect(node.matches?('foo/bar')).to be_falsy
76
+ end
77
+ end
78
+ end
79
+
80
+ describe PathMatcherFactory::OrNode do
81
+ describe '#matches?' do
82
+ it 'returns true if either path matches, false otherwise' do
83
+ node = root.match_path('foo').or(root.match_path('goo'))
84
+ expect(node).to be_a(factory::OrNode)
85
+ expect(node.matches?('foo')).to be_truthy
86
+ expect(node.matches?('foo/bar')).to be_truthy
87
+ expect(node.matches?('goo')).to be_truthy
88
+ expect(node.matches?('goo/boo')).to be_truthy
89
+ expect(node.matches?('ya/ya')).to be_falsy
90
+ end
91
+ end
92
+ end
93
+
94
+ describe PathMatcherFactory::NotNode do
95
+ describe '#matches?' do
96
+ it "returns true if the path doesn't match, false otherwise" do
97
+ node = root.match_path('foo').not
98
+ expect(node).to be_a(factory::NotNode)
99
+ expect(node.matches?('bar')).to be_truthy
100
+ expect(node.matches?('foo')).to be_falsy
101
+ expect(node.matches?('foo/bar')).to be_falsy
102
+ end
103
+ end
104
+ end
105
+
106
+ describe PathMatcherFactory::FileExtensionNode do
107
+ describe '#matches?' do
108
+ it 'returns true if the file extension matches, false otherwise' do
109
+ node = root.match_file_extension('.rb')
110
+ expect(node).to be_a(factory::FileExtensionNode)
111
+ expect(node.matches?('file.rb')).to be_truthy
112
+ expect(node.matches?('file.txt')).to be_falsy
113
+ end
114
+ end
115
+ end
116
+
117
+ describe PathMatcherFactory::PathNode do
118
+ describe '#matches?' do
119
+ it 'returns true if the path matches, false otherwise' do
120
+ node = root.match_path('foo/bar')
121
+ expect(node).to be_a(factory::PathNode)
122
+ expect(node.matches?('foo/bar')).to be_truthy
123
+ expect(node.matches?('foo/bar/baz')).to be_truthy
124
+ expect(node.matches?('foo')).to be_falsy
125
+ end
126
+ end
127
+ end
128
+
129
+ describe PathMatcherFactory::RegexNode do
130
+ describe '#matches?' do
131
+ it 'returns true if the path matches a regex, false otherwise' do
132
+ node = root.match_regex(/[a-z]{2}\.rb/)
133
+ expect(node).to be_a(factory::RegexNode)
134
+ expect(node.matches?('fi.rb')).to be_truthy
135
+ expect(node.matches?('fi.txt')).to be_falsy
136
+ end
137
+ end
138
+ end
139
+ end