defmastership 1.3.6 → 1.3.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b282623e3f26fd7e1b8f88df3605ffb8a536c5d7a71e3f8f6b41d937d740c77c
4
- data.tar.gz: af43d982dc66141dced00cf731300759631b5730fda62b250c43bde1d026d844
3
+ metadata.gz: 12ede2830cace7dbc8665f7db780d2bb60acf8f5beb771b4ec9bfdb9fbd74c5b
4
+ data.tar.gz: 92010c0156be9e4c74f36789b4c269097d61d9bde4d87ccfa2fc1a8869aa4475
5
5
  SHA512:
6
- metadata.gz: dbcdd3fc1b665dd867760123c43927f6f27b83726000a8e567f20fc716269ae073ca4c70f3362c029ff4347d6f0371068b6e15ab893e74fef89cf6419cbd9487
7
- data.tar.gz: 67e21c19f23d236f53bda017cfd5fdf1ce7700490b8e68c805c042f3f902123c7d1f275b06046a2c3ecc6614e5bf527dc3db0d5fb6addbc24c0a002337ae06bd
6
+ metadata.gz: 10b08062de66121b2a7785bb4a169ad8bf367566cd18dfad55d068324b8efa78075d8b6ec27362bf20256d306e73fd8f57a08e9d509ded3c415690cfd2f7ddb8
7
+ data.tar.gz: 27a73e65de9d300640b068dc4e4131bd0059e777cf4bcae2e1b0ea9d93d42795420e6e61c9678298ebb64aab3cbf33c6c9fda8218151e63709d0aa5d7cbf36ee
data/Gemfile CHANGED
@@ -54,5 +54,5 @@ end
54
54
 
55
55
  group :debugging do
56
56
  # Sometimes, we need to debug
57
- gem 'pry', '~> 0.16'
57
+ gem 'pry', '~> 0.16'
58
58
  end
@@ -221,6 +221,47 @@ Feature: definitions version
221
221
  :ref_tag: THE_TAG
222
222
  """
223
223
 
224
+ Scenario: Update explicit version based on git tag with definitions inside a git submodule
225
+ Given I initialize a git repo in "submodule_origin"
226
+ And a file named "submodule_origin/ref_doc.adoc" with:
227
+ """
228
+ [define, requirement, TOTO-0001]
229
+ --
230
+ initial text.
231
+ --
232
+ """
233
+ And I add and commit the changes in repo "submodule_origin"
234
+ And I initialize a git repo
235
+ And I set the environment variable "GIT_ALLOW_PROTOCOL" to "file"
236
+ And I add the repo "submodule_origin" as a submodule "submodule"
237
+ And I set the "THE_TAG" tag
238
+ And a file named "submodule/ref_doc.adoc" with:
239
+ """
240
+ [define, requirement, TOTO-0001(whatever)]
241
+ --
242
+ modified text.
243
+ --
244
+ """
245
+ And a file named "modifications.yml" with:
246
+ """
247
+ ---
248
+ :update_requirement_version:
249
+ :type: update_def_version
250
+ :config:
251
+ :def_type: requirement
252
+ :first_version: a
253
+ :ref_tag: 'THE_TAG'
254
+ """
255
+ And I set the environment variable "GIT_ALLOW_PROTOCOL" to "file"
256
+ When I successfully run `defmastership modify --modifications update_requirement_version submodule/ref_doc.adoc`
257
+ Then the file "submodule/ref_doc.adoc" should contain:
258
+ """
259
+ [define, requirement, TOTO-0001(a)]
260
+ --
261
+ modified text.
262
+ --
263
+ """
264
+
224
265
  Scenario: Update explicit version based on git tag on a different git repo
225
266
  And a file named "defmastership-example.adoc" with:
226
267
  """
@@ -603,3 +644,244 @@ Feature: definitions version
603
644
  Whatever: modified text.
604
645
  --
605
646
  """
647
+
648
+ Scenario: Set forced explicit version when definition has changed and had a previous version
649
+ Given a file named "ref_doc.adoc" with:
650
+ """
651
+ [define, requirement, TOTO-0001(3)]
652
+ --
653
+ initial text.
654
+ --
655
+ """
656
+ Given a file named "thedoc.adoc" with:
657
+ """
658
+ [define, requirement, TOTO-0001(whatever)]
659
+ --
660
+ modified text.
661
+ --
662
+ """
663
+ And a file named "modifications.yml" with:
664
+ """
665
+ ---
666
+ :update_requirement_version:
667
+ :type: update_def_version
668
+ :config:
669
+ :def_type: requirement
670
+ :force_version: '42'
671
+ :ref_document: ./ref_doc.adoc
672
+ """
673
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
674
+ And the stdout should not contain anything
675
+ Then the file "thedoc.adoc" should contain:
676
+ """
677
+ [define, requirement, TOTO-0001(42)]
678
+ --
679
+ modified text.
680
+ --
681
+ """
682
+
683
+ Scenario: Set forced explicit version when definition has changed and had no previous version
684
+ Given a file named "ref_doc.adoc" with:
685
+ """
686
+ [define, requirement, TOTO-0001]
687
+ --
688
+ initial text.
689
+ --
690
+ """
691
+ Given a file named "thedoc.adoc" with:
692
+ """
693
+ [define, requirement, TOTO-0001(whatever)]
694
+ --
695
+ modified text.
696
+ --
697
+ """
698
+ And a file named "modifications.yml" with:
699
+ """
700
+ ---
701
+ :update_requirement_version:
702
+ :type: update_def_version
703
+ :config:
704
+ :def_type: requirement
705
+ :force_version: '42'
706
+ :ref_document: ./ref_doc.adoc
707
+ """
708
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
709
+ And the stdout should not contain anything
710
+ Then the file "thedoc.adoc" should contain:
711
+ """
712
+ [define, requirement, TOTO-0001(42)]
713
+ --
714
+ modified text.
715
+ --
716
+ """
717
+
718
+ Scenario: Do not set forced explicit version when definition has NOT changed and had a previous version
719
+ Given a file named "ref_doc.adoc" with:
720
+ """
721
+ [define, requirement, TOTO-0001(3)]
722
+ --
723
+ initial text.
724
+ --
725
+ """
726
+ Given a file named "thedoc.adoc" with:
727
+ """
728
+ [define, requirement, TOTO-0001(whatever)]
729
+ --
730
+ initial text.
731
+ --
732
+ """
733
+ And a file named "modifications.yml" with:
734
+ """
735
+ ---
736
+ :update_requirement_version:
737
+ :type: update_def_version
738
+ :config:
739
+ :def_type: requirement
740
+ :force_version: '42'
741
+ :ref_document: ./ref_doc.adoc
742
+ """
743
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
744
+ And the stdout should not contain anything
745
+ Then the file "thedoc.adoc" should contain:
746
+ """
747
+ [define, requirement, TOTO-0001(3)]
748
+ --
749
+ initial text.
750
+ --
751
+ """
752
+
753
+ Scenario: Do not set forced explicit version when definition has NOT changed and had no previous version
754
+ Given a file named "ref_doc.adoc" with:
755
+ """
756
+ [define, requirement, TOTO-0001]
757
+ --
758
+ initial text.
759
+ --
760
+ """
761
+ Given a file named "thedoc.adoc" with:
762
+ """
763
+ [define, requirement, TOTO-0001(whatever)]
764
+ --
765
+ initial text.
766
+ --
767
+ """
768
+ And a file named "modifications.yml" with:
769
+ """
770
+ ---
771
+ :update_requirement_version:
772
+ :type: update_def_version
773
+ :config:
774
+ :def_type: requirement
775
+ :force_version: '42'
776
+ :ref_document: ./ref_doc.adoc
777
+ """
778
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
779
+ And the stdout should not contain anything
780
+ Then the file "thedoc.adoc" should contain:
781
+ """
782
+ [define, requirement, TOTO-0001]
783
+ --
784
+ initial text.
785
+ --
786
+ """
787
+
788
+ Scenario: Generate an error when the definition has changed but the reference version is already equal to force_version
789
+ Given a file named "ref_doc.adoc" with:
790
+ """
791
+ [define, requirement, TOTO-0001(42)]
792
+ --
793
+ initial text.
794
+ --
795
+ """
796
+ Given a file named "thedoc.adoc" with:
797
+ """
798
+ [define, requirement, TOTO-0001(whatever)]
799
+ --
800
+ modified text.
801
+ --
802
+ """
803
+ And a file named "modifications.yml" with:
804
+ """
805
+ ---
806
+ :update_requirement_version:
807
+ :type: update_def_version
808
+ :config:
809
+ :def_type: requirement
810
+ :force_version: '42'
811
+ :ref_document: ./ref_doc.adoc
812
+ """
813
+ When I run `defmastership modify --modifications update_requirement_version thedoc.adoc`
814
+ Then it should fail with:
815
+ """
816
+ error: TOTO-0001 has changed but its version in reference document is already at force_version (42)
817
+ """
818
+
819
+ Scenario: Do not set version when definition is new and first_version is configured
820
+ Given a file named "ref_doc.adoc" with:
821
+ """
822
+ [define, requirement, TOTO-0002]
823
+ --
824
+ initial text.
825
+ --
826
+ """
827
+ Given a file named "thedoc.adoc" with:
828
+ """
829
+ [define, requirement, TOTO-0001]
830
+ --
831
+ modified text.
832
+ --
833
+ """
834
+ And a file named "modifications.yml" with:
835
+ """
836
+ ---
837
+ :update_requirement_version:
838
+ :type: update_def_version
839
+ :config:
840
+ :def_type: requirement
841
+ :first_version: '1'
842
+ :ref_document: ./ref_doc.adoc
843
+ """
844
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
845
+ And the stdout should not contain anything
846
+ Then the file "thedoc.adoc" should contain:
847
+ """
848
+ [define, requirement, TOTO-0001]
849
+ --
850
+ modified text.
851
+ --
852
+ """
853
+
854
+ Scenario: Set forced explicit version when definition is new and force_version is configured
855
+ Given a file named "ref_doc.adoc" with:
856
+ """
857
+ [define, requirement, TOTO-0002]
858
+ --
859
+ initial text.
860
+ --
861
+ """
862
+ Given a file named "thedoc.adoc" with:
863
+ """
864
+ [define, requirement, TOTO-0001]
865
+ --
866
+ modified text.
867
+ --
868
+ """
869
+ And a file named "modifications.yml" with:
870
+ """
871
+ ---
872
+ :update_requirement_version:
873
+ :type: update_def_version
874
+ :config:
875
+ :def_type: requirement
876
+ :force_version: '42'
877
+ :ref_document: ./ref_doc.adoc
878
+ """
879
+ When I successfully run `defmastership modify --modifications update_requirement_version thedoc.adoc`
880
+ And the stdout should not contain anything
881
+ Then the file "thedoc.adoc" should contain:
882
+ """
883
+ [define, requirement, TOTO-0001(42)]
884
+ --
885
+ modified text.
886
+ --
887
+ """
@@ -20,3 +20,33 @@ Given('I set the {string} tag') do |tag_name|
20
20
  git = Git.open(Aruba.config.home_directory)
21
21
  git.add_tag(tag_name)
22
22
  end
23
+
24
+ Given('I initialize a git repo in {string}') do |repo_dir|
25
+ require 'fileutils'
26
+ repo_path = File.join(Aruba.config.home_directory, repo_dir)
27
+ FileUtils.mkdir_p(repo_path)
28
+
29
+ git = Git.init(repo_path)
30
+ git.config('user.name', 'Bob Léponge')
31
+ git.config('user.email', 'bob.léponge@example.com')
32
+ end
33
+
34
+ Given('I add and commit the changes in repo {string}') do |repo_dir|
35
+ repo_path = File.join(Aruba.config.home_directory, repo_dir)
36
+ git = Git.open(repo_path)
37
+
38
+ git.config('user.name', 'Bob Léponge')
39
+ git.config('user.email', 'bob.léponge@example.com')
40
+ git.add(all: true)
41
+ git.commit('Commit changes')
42
+ end
43
+
44
+ Given('I add the repo {string} as a submodule {string}') do |remote_dir, submodule_dir|
45
+ run_command("git submodule add ./#{remote_dir} #{submodule_dir}")
46
+ last_command_started.wait
47
+
48
+ main_git = Git.open(Aruba.config.home_directory)
49
+ main_git.add('.gitmodules')
50
+ main_git.add(submodule_dir)
51
+ main_git.commit("Add submodule #{submodule_dir}")
52
+ end
@@ -64,7 +64,7 @@ module Defmastership
64
64
 
65
65
  def apply_to_one(filename, text, method)
66
66
  text.lines.map { |line| public_send(method, filename, line) }
67
- .join
67
+ .join
68
68
  end
69
69
  end
70
70
  end
@@ -15,7 +15,8 @@ module Defmastership
15
15
  ref_document: [],
16
16
  ref_tag: '',
17
17
  ref_repo: '.',
18
- first_version: ''
18
+ first_version: '',
19
+ force_version: ''
19
20
  }
20
21
  end
21
22
 
@@ -49,8 +50,14 @@ module Defmastership
49
50
  private
50
51
 
51
52
  def parse_ref_files_from_git(adoc_sources, tmpdir)
52
- Git.clone(ref_repo, tmpdir, branch: ref_tag)
53
+ repo_url = Helper.resolve_remote_url(ref_repo)
54
+
55
+ Git.clone(repo_url, tmpdir, branch: ref_tag, recursive: true)
53
56
  ref_sources = ref_document.empty? ? adoc_sources.keys : ref_document
57
+ parse_tmpdir_files(tmpdir, ref_sources)
58
+ end
59
+
60
+ def parse_tmpdir_files(tmpdir, ref_sources)
54
61
  ref_sources.each do |adoc_file|
55
62
  @ref_document.parse_file_with_preprocessor("#{tmpdir}/#{adoc_file}")
56
63
  end
@@ -70,14 +77,40 @@ module Defmastership
70
77
 
71
78
  def version_string(match)
72
79
  ref_definition = Helper.def_from_match(@ref_document, match)
80
+ return force_version_for_new unless ref_definition
81
+
73
82
  definition = Helper.def_from_match(document, match)
74
- return unless ref_definition
83
+ Helper.ref_version(ref_definition, definition, self)
84
+ end
75
85
 
76
- Helper.ref_version(ref_definition, definition, first_version)
86
+ # @return [String, nil] the forced version if configured and the definition is new
87
+ def force_version_for_new
88
+ forced = config.fetch(:force_version).to_s
89
+ forced unless forced.empty?
77
90
  end
78
91
 
79
92
  # Helper functions
80
93
  module Helper
94
+ # @param path [String] the repository path
95
+ # @return [String, nil] the origin URL if found
96
+ def self.find_origin_url(path)
97
+ local_git = Git.open(path)
98
+ origin_remote = local_git.remotes.find { |remote| remote.name.eql?('origin') }
99
+ origin_remote&.url
100
+ rescue ArgumentError
101
+ nil
102
+ end
103
+
104
+ # @param path [String] the repository path
105
+ # @return [String] the resolved remote URL
106
+ def self.resolve_remote_url(path)
107
+ if File.directory?(path)
108
+ find_origin_url(path) || path
109
+ else
110
+ path
111
+ end
112
+ end
113
+
81
114
  # @param doc [Document] the document with defintions
82
115
  # @param match [MatchData] Regexp match matching a reference
83
116
  # @return [Definition] the definition from a +Document+ with a matching reference
@@ -87,13 +120,44 @@ module Defmastership
87
120
 
88
121
  # @param ref_definition [Definition] the definition from the reference document
89
122
  # @param definition [Definition] the definition from the current document
90
- # @param first_version [String] first version from configuration
123
+ # @param modifier [UpdateDefVersion] the modifier configuration
91
124
  # @return [String] the current definition version
92
- def self.ref_version(ref_definition, definition, first_version)
93
- new_ref_version = ref_definition.explicit_version
94
- return new_ref_version if definition.sha256_short.eql?(ref_definition.sha256_short)
125
+ def self.ref_version(ref_definition, definition, modifier)
126
+ ref_ver = ref_definition.explicit_version
127
+ return ref_ver if definition.sha256_short.eql?(ref_definition.sha256_short)
95
128
 
96
- new_ref_version ? new_ref_version.next : first_version
129
+ forced = modifier.config.fetch(:force_version).to_s
130
+ return next_or_first(ref_ver, modifier.first_version) if forced.empty?
131
+
132
+ check_and_return_forced(ref_definition, ref_ver, forced)
133
+ end
134
+
135
+ # @param explicit_version [String, nil] the explicit version from the reference document
136
+ # @param first_version [String] the first version
137
+ # @return [String] the selected version
138
+ def self.next_or_first(explicit_version, first_version)
139
+ explicit_version ? explicit_version.next : first_version
140
+ end
141
+
142
+ # @param ref_definition [Definition] the definition from the reference document
143
+ # @param ref_ver [String, nil] the explicit version from the reference document
144
+ # @param forced [String] the forced version
145
+ # @return [String] the forced version
146
+ def self.check_and_return_forced(ref_definition, ref_ver, forced)
147
+ raise_already_forced(ref_definition, forced) if ref_ver.eql?(forced)
148
+
149
+ forced
150
+ end
151
+
152
+ # @param ref_definition [Definition] the definition from the reference document
153
+ # @param force_version [String] forced version from configuration
154
+ def self.raise_already_forced(ref_definition, force_version)
155
+ raise(
156
+ ArgumentError,
157
+ "#{ref_definition.reference} has changed " \
158
+ 'but its version in reference document is ' \
159
+ "already at force_version (#{force_version})"
160
+ )
97
161
  end
98
162
 
99
163
  # Make sure that ref_document configuration is an Array
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Defmastership
5
5
  # [String] Gem version
6
- VERSION = '1.3.6'
6
+ VERSION = '1.3.8'
7
7
  public_constant :VERSION
8
8
  end
@@ -12,6 +12,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
12
12
  it { is_expected.to(have_attributes(def_type: '')) }
13
13
  it { is_expected.to(have_attributes(ref_document: [])) }
14
14
  it { is_expected.to(have_attributes(first_version: '')) }
15
+ it { is_expected.to(have_attributes(force_version: '')) }
15
16
  end
16
17
 
17
18
  describe '.replacement_methods' do
@@ -116,6 +117,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
116
117
  before do
117
118
  allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
118
119
  allow(Git).to(receive(:clone))
120
+ allow(Git).to(receive(:open)).and_raise(ArgumentError)
119
121
  allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
120
122
  allow(document).to(receive(:parse_file_with_preprocessor).with('file1.adoc'))
121
123
  allow(document).to(receive(:parse_file_with_preprocessor).with('file2.adoc'))
@@ -131,7 +133,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
131
133
  end
132
134
 
133
135
  it { expect(Dir).to(have_received(:mktmpdir).with('defmastership')) }
134
- it { expect(Git).to(have_received(:clone).with('.', 'tmp', branch: 'THE_TAG')) }
136
+ it { expect(Git).to(have_received(:clone).with('.', 'tmp', branch: 'THE_TAG', recursive: true)) }
135
137
  it { expect(Defmastership::Document).to(have_received(:new).twice) }
136
138
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('tmp/file1.adoc')) }
137
139
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('tmp/file2.adoc')) }
@@ -142,6 +144,111 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
142
144
  end
143
145
  end
144
146
 
147
+ context 'when ref_repo is not a directory' do
148
+ subject(:modifier) do
149
+ described_class.new(ref_tag: 'THE_TAG', ref_repo: 'not_a_directory', def_type: 'req', first_version: 'a')
150
+ end
151
+
152
+ let(:adoc_sources) do
153
+ {
154
+ 'file1.adoc' => "[define,req,REFERENCE]\nfile1 line2"
155
+ }
156
+ end
157
+
158
+ before do
159
+ document = instance_double(Defmastership::Document, 'document')
160
+ ref_document = instance_double(Defmastership::Document, 'ref_document')
161
+ definition = instance_double(Defmastership::Definition, 'definition')
162
+ ref_definition = instance_double(Defmastership::Definition, 'ref_definitions')
163
+
164
+ allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
165
+ allow(Git).to(receive(:clone))
166
+ allow(File).to(receive(:directory?).with('not_a_directory').and_return(false))
167
+
168
+ allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
169
+ allow(document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: definition))
170
+ allow(ref_document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: ref_definition))
171
+ allow(ref_definition).to(receive_messages(explicit_version: nil, sha256_short: 'something_else'))
172
+ allow(definition).to(receive(:sha256_short).and_return('something'))
173
+ end
174
+
175
+ it 'clones the non-directory path directly as the repository URL' do
176
+ modifier.do_modifications(adoc_sources)
177
+ expect(Git).to(have_received(:clone).with('not_a_directory', 'tmp', branch: 'THE_TAG', recursive: true))
178
+ end
179
+ end
180
+
181
+ context 'when ref_repo is a local git repository' do
182
+ subject(:modifier) { described_class.new(ref_tag: 'THE_TAG', def_type: 'req', first_version: 'a') }
183
+
184
+ let(:local_git) { instance_double(Git::Base) }
185
+ let(:remote) { instance_double(Git::Remote, name: 'origin', url: 'https://gitlab.example.com/repo.git') }
186
+ let(:adoc_sources) do
187
+ {
188
+ 'file1.adoc' => "[define,req,REFERENCE]\nfile1 line2"
189
+ }
190
+ end
191
+
192
+ before do
193
+ document = instance_double(Defmastership::Document, 'document')
194
+ ref_document = instance_double(Defmastership::Document, 'ref_document')
195
+ definition = instance_double(Defmastership::Definition, 'definition')
196
+ ref_definition = instance_double(Defmastership::Definition, 'ref_definitions')
197
+
198
+ allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
199
+ allow(Git).to(receive(:clone))
200
+ allow(File).to(receive(:directory?).with('.').and_return(true))
201
+ allow(Git).to(receive(:open)).with('.').and_return(local_git)
202
+ allow(local_git).to(receive(:remotes)).and_return([remote])
203
+
204
+ allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
205
+ allow(document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: definition))
206
+ allow(ref_document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: ref_definition))
207
+ allow(ref_definition).to(receive_messages(explicit_version: nil, sha256_short: 'something_else'))
208
+ allow(definition).to(receive(:sha256_short).and_return('something'))
209
+
210
+ modifier.do_modifications(adoc_sources)
211
+ end
212
+
213
+ it { expect(Git).to(have_received(:clone).with('https://gitlab.example.com/repo.git', 'tmp', branch: 'THE_TAG', recursive: true)) }
214
+ end
215
+
216
+ context 'when ref_repo is a local git repository without an origin remote' do
217
+ subject(:modifier) { described_class.new(ref_tag: 'THE_TAG', def_type: 'req', first_version: 'a') }
218
+
219
+ let(:local_git) { instance_double(Git::Base) }
220
+ let(:remote) { instance_double(Git::Remote, name: 'upstream', url: 'https://gitlab.example.com/repo.git') }
221
+ let(:adoc_sources) do
222
+ {
223
+ 'file1.adoc' => "[define,req,REFERENCE]\nfile1 line2"
224
+ }
225
+ end
226
+
227
+ before do
228
+ document = instance_double(Defmastership::Document, 'document')
229
+ ref_document = instance_double(Defmastership::Document, 'ref_document')
230
+ definition = instance_double(Defmastership::Definition, 'definition')
231
+ ref_definition = instance_double(Defmastership::Definition, 'ref_definitions')
232
+
233
+ allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
234
+ allow(Git).to(receive(:clone))
235
+ allow(File).to(receive(:directory?).with('.').and_return(true))
236
+ allow(Git).to(receive(:open)).with('.').and_return(local_git)
237
+ # Setup the mock so it doesn't find 'origin'
238
+ allow(local_git).to(receive(:remotes)).and_return([remote])
239
+
240
+ allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
241
+ allow(document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: definition))
242
+ allow(ref_document).to(receive_messages(parse_file_with_preprocessor: nil, ref_to_def: ref_definition))
243
+ allow(ref_definition).to(receive_messages(explicit_version: nil, sha256_short: 'something_else'))
244
+ allow(definition).to(receive(:sha256_short).and_return('something'))
245
+
246
+ modifier.do_modifications(adoc_sources)
247
+ end
248
+
249
+ it { expect(Git).to(have_received(:clone).with('.', 'tmp', branch: 'THE_TAG', recursive: true)) }
250
+ end
251
+
145
252
  context 'when ref_tag and ref_repo is provided' do
146
253
  subject(:modifier) do
147
254
  described_class.new(ref_tag: 'THE_TAG', ref_repo: 'not dot', def_type: 'req', first_version: 'a')
@@ -161,6 +268,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
161
268
  before do
162
269
  allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
163
270
  allow(Git).to(receive(:clone))
271
+ allow(Git).to(receive(:open)).and_raise(ArgumentError)
164
272
  allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
165
273
  allow(document).to(receive(:parse_file_with_preprocessor).with('file1.adoc'))
166
274
  allow(document).to(receive(:parse_file_with_preprocessor).with('file2.adoc'))
@@ -176,7 +284,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
176
284
  end
177
285
 
178
286
  it { expect(Dir).to(have_received(:mktmpdir).with('defmastership')) }
179
- it { expect(Git).to(have_received(:clone).with('not dot', 'tmp', branch: 'THE_TAG')) }
287
+ it { expect(Git).to(have_received(:clone).with('not dot', 'tmp', branch: 'THE_TAG', recursive: true)) }
180
288
  it { expect(Defmastership::Document).to(have_received(:new).twice) }
181
289
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('tmp/file1.adoc')) }
182
290
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('tmp/file2.adoc')) }
@@ -211,6 +319,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
211
319
  before do
212
320
  allow(Dir).to(receive(:mktmpdir).and_yield('tmp'))
213
321
  allow(Git).to(receive(:clone))
322
+ allow(Git).to(receive(:open)).and_raise(ArgumentError)
214
323
  allow(Defmastership::Document).to(receive(:new).twice.and_return(ref_document, document))
215
324
  allow(document).to(receive(:parse_file_with_preprocessor).with('file1.adoc'))
216
325
  allow(document).to(receive(:parse_file_with_preprocessor).with('file2.adoc'))
@@ -225,7 +334,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
225
334
  end
226
335
 
227
336
  it { expect(Dir).to(have_received(:mktmpdir).with('defmastership')) }
228
- it { expect(Git).to(have_received(:clone).with('.', 'tmp', branch: 'THE_TAG')) }
337
+ it { expect(Git).to(have_received(:clone).with('.', 'tmp', branch: 'THE_TAG', recursive: true)) }
229
338
  it { expect(Defmastership::Document).to(have_received(:new).twice) }
230
339
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('tmp/./another/doc.adoc')) }
231
340
  it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).once) }
@@ -236,6 +345,77 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
236
345
  end
237
346
  end
238
347
 
348
+ describe '.resolve_remote_url' do
349
+ subject(:resolved_url) { described_class.const_get(:Helper).resolve_remote_url(path) }
350
+
351
+ context 'when the path is not a directory' do
352
+ let(:path) { 'git@github.com:org/repo.git' }
353
+
354
+ before do
355
+ allow(File).to(receive(:directory?).with(path).and_return(false))
356
+ end
357
+
358
+ it 'returns the exact path itself' do
359
+ expect(resolved_url).to(be(path))
360
+ end
361
+
362
+ it 'queries File.directory?' do
363
+ resolved_url
364
+ expect(File).to(have_received(:directory?).with(path))
365
+ end
366
+ end
367
+
368
+ context 'when the path is a directory and has an origin remote' do
369
+ let(:path) { '/path/to/local/repo' }
370
+ let(:local_git) { instance_double(Git::Base) }
371
+ let(:remote) { instance_double(Git::Remote, name: 'origin', url: 'https://gitlab.example.com/repo.git') }
372
+
373
+ before do
374
+ allow(File).to(receive(:directory?).with(path).and_return(true))
375
+ allow(Git).to(receive(:open)).with(path).and_return(local_git)
376
+ allow(local_git).to(receive(:remotes)).and_return([remote])
377
+ end
378
+
379
+ it 'returns the origin remote url' do
380
+ expect(resolved_url).to(eq('https://gitlab.example.com/repo.git'))
381
+ end
382
+
383
+ it 'queries File.directory?' do
384
+ resolved_url
385
+ expect(File).to(have_received(:directory?).with(path))
386
+ end
387
+ end
388
+
389
+ context 'when the path is a directory but does not have an origin remote' do
390
+ let(:path) { '/path/to/local/repo' }
391
+ let(:local_git) { instance_double(Git::Base) }
392
+ let(:remote) { instance_double(Git::Remote, name: 'upstream', url: 'https://gitlab.example.com/repo.git') }
393
+
394
+ before do
395
+ allow(File).to(receive(:directory?).with(path).and_return(true))
396
+ allow(Git).to(receive(:open)).with(path).and_return(local_git)
397
+ allow(local_git).to(receive(:remotes)).and_return([remote])
398
+ end
399
+
400
+ it 'returns the path itself' do
401
+ expect(resolved_url).to(eq(path))
402
+ end
403
+ end
404
+
405
+ context 'when Git.open raises an ArgumentError' do
406
+ let(:path) { '/path/to/local/repo' }
407
+
408
+ before do
409
+ allow(File).to(receive(:directory?).with(path).and_return(true))
410
+ allow(Git).to(receive(:open)).with(path).and_raise(ArgumentError)
411
+ end
412
+
413
+ it 'returns the path itself' do
414
+ expect(resolved_url).to(eq(path))
415
+ end
416
+ end
417
+ end
418
+
239
419
  describe '#replace_reference' do
240
420
  subject(:modifier) { described_class.new(def_type: 'requirement', first_version: 'a') }
241
421
 
@@ -323,5 +503,127 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
323
503
  end
324
504
  end
325
505
  end
506
+
507
+ context 'when force_version is provided' do
508
+ subject(:modifier) { described_class.new(def_type: 'requirement', force_version: '42') }
509
+
510
+ before do
511
+ allow(document).to(receive(:ref_to_def).with('REFERENCE').and_return(definition))
512
+ allow(definition).to(receive(:sha256_short).and_return(+'~abcd1234'))
513
+ end
514
+
515
+ context 'when definition has NOT changed' do
516
+ before do
517
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(ref_definition))
518
+ allow(ref_definition).to(receive(:sha256_short).and_return(+'~abcd1234'))
519
+ end
520
+
521
+ it 'retains the previous reference version if it had one' do
522
+ allow(ref_definition).to(receive(:explicit_version).and_return('3'))
523
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
524
+ .to(eq('[define,requirement,REFERENCE(3)]'))
525
+ end
526
+
527
+ it 'does not add a version if it had none' do
528
+ allow(ref_definition).to(receive(:explicit_version).and_return(nil))
529
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
530
+ .to(eq('[define,requirement,REFERENCE]'))
531
+ end
532
+ end
533
+
534
+ context 'when definition has changed' do
535
+ before do
536
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(ref_definition))
537
+ allow(ref_definition).to(receive_messages(sha256_short: +'~4321aaaa', reference: 'REFERENCE'))
538
+ end
539
+
540
+ it 'sets the version to the forced version if it had a previous version' do
541
+ allow(ref_definition).to(receive(:explicit_version).and_return('3'))
542
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
543
+ .to(eq('[define,requirement,REFERENCE(42)]'))
544
+ end
545
+
546
+ it 'sets the version to the forced version if it had no previous version' do
547
+ allow(ref_definition).to(receive(:explicit_version).and_return(nil))
548
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
549
+ .to(eq('[define,requirement,REFERENCE(42)]'))
550
+ end
551
+
552
+ it 'raises an error if the previous version is already equal to the forced version' do
553
+ allow(ref_definition).to(receive(:explicit_version).and_return('42'))
554
+ msg = 'REFERENCE has changed but its version in reference document is already at force_version (42)'
555
+ expect { modifier.replace_reference('', '[define,requirement,REFERENCE]') }
556
+ .to(raise_error(ArgumentError, msg))
557
+ end
558
+ end
559
+
560
+ context 'when definition is new' do
561
+ before do
562
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(nil))
563
+ end
564
+
565
+ it 'sets the version to the forced version' do
566
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
567
+ .to(eq('[define,requirement,REFERENCE(42)]'))
568
+ end
569
+ end
570
+ end
571
+
572
+ context 'when force_version is an integer' do
573
+ subject(:modifier) { described_class.new(def_type: 'requirement', force_version: 42) }
574
+
575
+ before do
576
+ allow(document).to(receive(:ref_to_def).with('REFERENCE').and_return(definition))
577
+ allow(definition).to(receive(:sha256_short).and_return(+'~abcd1234'))
578
+ end
579
+
580
+ context 'when definition is new' do
581
+ before do
582
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(nil))
583
+ end
584
+
585
+ it 'sets the version to the string representation' do
586
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
587
+ .to(eq('[define,requirement,REFERENCE(42)]'))
588
+ end
589
+ end
590
+
591
+ context 'when definition has changed' do
592
+ before do
593
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(ref_definition))
594
+ allow(ref_definition).to(receive_messages(sha256_short: +'~4321aaaa', reference: 'REFERENCE'))
595
+ end
596
+
597
+ it 'converts force_version to string' do
598
+ allow(ref_definition).to(receive(:explicit_version).and_return('3'))
599
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
600
+ .to(eq('[define,requirement,REFERENCE(42)]'))
601
+ end
602
+ end
603
+ end
604
+
605
+ context 'when force_version is nil' do
606
+ subject(:modifier) { described_class.new(def_type: 'requirement', force_version: nil) }
607
+
608
+ before do
609
+ allow(document).to(receive(:ref_to_def).with('REFERENCE').and_return(definition))
610
+ allow(definition).to(receive(:sha256_short).and_return(+'~abcd1234'))
611
+ allow(ref_document).to(receive(:ref_to_def).with('REFERENCE').and_return(nil))
612
+ end
613
+
614
+ it 'does not add a version if the definition is new' do
615
+ expect(modifier.replace_reference('', '[define,requirement,REFERENCE]'))
616
+ .to(eq('[define,requirement,REFERENCE]'))
617
+ end
618
+ end
619
+
620
+ context 'when force_version is missing from config' do
621
+ it 'raises a KeyError' do
622
+ obj = described_class.new(def_type: 'requirement')
623
+ allow(obj).to(receive(:config).and_return({}))
624
+ expect { obj.__send__(:force_version_for_new) }
625
+ .to(raise_error(KeyError))
626
+ end
627
+ end
326
628
  end
327
629
  end
@@ -29,23 +29,26 @@ RSpec.describe(Defmastership::Modifier::UpdateIrefChecksum) do
29
29
  allow(Defmastership::Document).to(receive(:new).and_return(document))
30
30
  allow(document).to(receive(:parse_file_with_preprocessor))
31
31
  allow_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).and_return(adoc_sources))
32
+ end
32
33
 
34
+ it 'creates a new document' do
33
35
  modifier.do_modifications(adoc_sources)
36
+ expect(Defmastership::Document).to(have_received(:new))
34
37
  end
35
38
 
36
- it { expect(Defmastership::Document).to(have_received(:new)) }
39
+ it 'parses the first adoc file with preprocessor' do
40
+ modifier.do_modifications(adoc_sources)
41
+ expect(document).to(have_received(:parse_file_with_preprocessor).with('file1.adoc'))
42
+ end
37
43
 
38
- it do
39
- expect(document).to(
40
- have_received(:parse_file_with_preprocessor)
41
- .once.with('file1.adoc')
42
- .once.with('file2.adoc')
43
- )
44
+ it 'parses the second adoc file with preprocessor' do
45
+ modifier.do_modifications(adoc_sources)
46
+ expect(document).to(have_received(:parse_file_with_preprocessor).with('file2.adoc'))
44
47
  end
45
48
 
46
49
  it { expect(modifier.do_modifications(adoc_sources)).to(eq(adoc_sources)) }
47
50
 
48
- it 'call the parent method' do
51
+ it 'call the parent method with arguments' do
49
52
  expect_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).with(adoc_sources))
50
53
  modifier.do_modifications(adoc_sources)
51
54
  end
@@ -29,23 +29,26 @@ RSpec.describe(Defmastership::Modifier::UpdateIrefVersion) do
29
29
  allow(Defmastership::Document).to(receive(:new).and_return(document))
30
30
  allow(document).to(receive(:parse_file_with_preprocessor))
31
31
  allow_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).and_return(adoc_sources))
32
+ end
32
33
 
34
+ it 'creates a new document' do
33
35
  modifier.do_modifications(adoc_sources)
36
+ expect(Defmastership::Document).to(have_received(:new))
34
37
  end
35
38
 
36
- it { expect(Defmastership::Document).to(have_received(:new)) }
39
+ it 'parses the first adoc file with preprocessor' do
40
+ modifier.do_modifications(adoc_sources)
41
+ expect(document).to(have_received(:parse_file_with_preprocessor).with('file1.adoc'))
42
+ end
37
43
 
38
- it do
39
- expect(document).to(
40
- have_received(:parse_file_with_preprocessor)
41
- .once.with('file1.adoc')
42
- .once.with('file2.adoc')
43
- )
44
+ it 'parses the second adoc file with preprocessor' do
45
+ modifier.do_modifications(adoc_sources)
46
+ expect(document).to(have_received(:parse_file_with_preprocessor).with('file2.adoc'))
44
47
  end
45
48
 
46
49
  it { expect(modifier.do_modifications(adoc_sources)).to(eq(adoc_sources)) }
47
50
 
48
- it 'call the parent method' do
51
+ it 'call the parent method with arguments' do
49
52
  expect_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).with(adoc_sources))
50
53
  modifier.do_modifications(adoc_sources)
51
54
  end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2023 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
- # rubocop:disable Metrics/BlockLength
4
+ # rubocop:disable-next Metrics/BlockLength
5
5
  namespace 'quality' do
6
6
  begin
7
7
  require('rubocop/rake_task')
@@ -58,7 +58,6 @@ namespace 'quality' do
58
58
  desc 'Runs all quality code check'
59
59
  task(all: ['quality:rubocop', 'quality:reek', 'quality:flay'])
60
60
  end
61
- # rubocop:enable Metrics/BlockLength
62
61
 
63
62
  desc 'Synonym for quality:rubocop'
64
63
  task(rubocop: 'quality:rubocop')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: defmastership
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.6
4
+ version: 1.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jérôme Arbez-Gindre
@@ -272,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
272
  - !ruby/object:Gem::Version
273
273
  version: '0'
274
274
  requirements: []
275
- rubygems_version: 4.0.9
275
+ rubygems_version: 4.0.21
276
276
  specification_version: 4
277
277
  summary: Handling of references and definitions with asciidoctor
278
278
  test_files: []