neocities-red 1.1.2 → 1.2.0

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +29 -15
  3. data/.gitignore +4 -0
  4. data/CHANGELOG.md +95 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +9 -6
  7. data/README.md +6 -0
  8. data/lib/neocities_red/cli.rb +156 -31
  9. data/lib/neocities_red/cli_display.rb +200 -5
  10. data/lib/neocities_red/client.rb +84 -77
  11. data/lib/neocities_red/errors.rb +20 -0
  12. data/lib/neocities_red/services/common/exclusions.rb +69 -0
  13. data/lib/neocities_red/services/common/pizza.rb +34 -21
  14. data/lib/neocities_red/services/common/worker_pool.rb +54 -0
  15. data/lib/neocities_red/services/file/folder_uploader.rb +39 -25
  16. data/lib/neocities_red/services/file/list.rb +60 -30
  17. data/lib/neocities_red/services/file/remover.rb +27 -12
  18. data/lib/neocities_red/services/file/uploader.rb +33 -13
  19. data/lib/neocities_red/services/site/differencer.rb +42 -12
  20. data/lib/neocities_red/services/site/exporter.rb +120 -7
  21. data/lib/neocities_red/services/site/informer.rb +29 -4
  22. data/lib/neocities_red/services/site/pusher.rb +74 -38
  23. data/lib/neocities_red/version.rb +2 -1
  24. data/lib/neocities_red.rb +32 -13
  25. data/neocities-red.gemspec +11 -6
  26. data/spec/neocities_red/cli_display_spec.rb +0 -6
  27. data/spec/neocities_red/cli_spec.rb +85 -0
  28. data/spec/neocities_red/client_spec.rb +7 -50
  29. data/spec/neocities_red/services/common/exclusions_spec.rb +47 -0
  30. data/spec/neocities_red/services/common/worker_pool_spec.rb +48 -0
  31. data/spec/neocities_red/services/file/folder_uploader_spec.rb +8 -6
  32. data/spec/neocities_red/services/file/list_spec.rb +13 -10
  33. data/spec/neocities_red/services/file/remover_spec.rb +15 -21
  34. data/spec/neocities_red/services/file/uploader_spec.rb +25 -20
  35. data/spec/neocities_red/services/site/differencer_spec.rb +32 -6
  36. data/spec/neocities_red/services/site/exporter_spec.rb +105 -38
  37. data/spec/neocities_red/services/site/informer_spec.rb +3 -3
  38. data/spec/neocities_red/services/site/pusher_spec.rb +1 -1
  39. data/spec/spec_helper.rb +1 -1
  40. metadata +11 -25
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "fileutils"
5
+ require "tmpdir"
6
+
7
+ RSpec.describe NeocitiesRed::Services::Common::Exclusions do
8
+ let(:tmp_root) { Dir.mktmpdir("exclusions_spec") }
9
+
10
+ before do
11
+ FileUtils.mkdir_p(File.join(tmp_root, "node_modules"))
12
+ File.write(File.join(tmp_root, "node_modules", "dep.js"), "x")
13
+ File.write(File.join(tmp_root, "secret.txt"), "x")
14
+ File.write(File.join(tmp_root, "keep.txt"), "x")
15
+ end
16
+
17
+ after do
18
+ FileUtils.rm_rf(tmp_root)
19
+ end
20
+
21
+ describe ".build" do
22
+ it "returns an empty list for entries that do not exist" do
23
+ expect(described_class.build([File.join(tmp_root, "nope")])).to eq([])
24
+ end
25
+
26
+ it "returns the path for an existing file" do
27
+ expect(described_class.build([File.join(tmp_root, "secret.txt")]))
28
+ .to eq([File.join(tmp_root, "secret.txt")])
29
+ end
30
+
31
+ it "returns the directory and all of its children for an existing directory" do
32
+ entries = described_class.build([File.join(tmp_root, "node_modules")])
33
+
34
+ expect(entries).to include(File.join(tmp_root, "node_modules"))
35
+ expect(entries).to include(File.join(tmp_root, "node_modules", "dep.js"))
36
+ end
37
+
38
+ it "normalizes paths relative to base_path when given" do
39
+ entries = described_class.build(
40
+ [File.join(tmp_root, "secret.txt"), File.join(tmp_root, "node_modules")],
41
+ base_path: tmp_root
42
+ )
43
+
44
+ expect(entries).to contain_exactly("secret.txt", "node_modules", "node_modules/dep.js")
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe NeocitiesRed::Services::Common::WorkerPool do
6
+ let(:result) { [] }
7
+ let(:mutex) { Mutex.new }
8
+
9
+ def pool_of(size)
10
+ described_class.new(size) do |item|
11
+ mutex.synchronize { result << item }
12
+ end
13
+ end
14
+
15
+ describe "#process" do
16
+ it "calls the block for each item" do
17
+ pool_of(3).process([1, 2, 3, 4, 5])
18
+
19
+ expect(result.sort).to eq([1, 2, 3, 4, 5])
20
+ end
21
+
22
+ it "processes items across multiple threads" do
23
+ threads_seen = []
24
+ pool = described_class.new(4) do |item|
25
+ sleep 0.002
26
+ threads_seen << Thread.current.object_id
27
+ result << item
28
+ end
29
+
30
+ pool.process(Array.new(20, :work))
31
+
32
+ expect(threads_seen.uniq.size).to be > 1
33
+ expect(result.size).to eq(20)
34
+ end
35
+
36
+ it "works with a single worker" do
37
+ pool_of(1).process(%w[a b c])
38
+
39
+ expect(result).to eq(%w[a b c])
40
+ end
41
+
42
+ it "returns immediately for an empty list" do
43
+ expect { pool_of(2).process([]) }.not_to raise_error
44
+
45
+ expect(result).to be_empty
46
+ end
47
+ end
48
+ end
@@ -6,6 +6,7 @@ require "fileutils"
6
6
  RSpec.describe NeocitiesRed::Services::File::FolderUploader do
7
7
  let(:client) { instance_double(NeocitiesRed::Client) }
8
8
  let(:remote_path) { "ext/" }
9
+ let(:display) { instance_double(NeocitiesRed::CliDisplay, display_skip_file: nil) }
9
10
 
10
11
  let(:spec_root) { File.expand_path("..", __dir__) } # => ./spec
11
12
  let(:tmp_root) { File.join(spec_root, "tmp", "folder_uploader_spec") }
@@ -26,9 +27,9 @@ RSpec.describe NeocitiesRed::Services::File::FolderUploader do
26
27
  end
27
28
 
28
29
  describe "#files" do
29
- it "raises FileIsNotExists when the path does not exist" do
30
- uploader = described_class.new(client, File.join(tmp_root, "nope"), remote_path)
31
- expect { uploader.files }.to raise_error(NeocitiesRed::Services::File::FileIsNotExists)
30
+ it "raises FileNotFoundError when the path does not exist" do
31
+ uploader = described_class.new(client, File.join(tmp_root, "nope"), remote_path, display: display)
32
+ expect { uploader.files }.to raise_error(NeocitiesRed::FileNotFoundError)
32
33
  end
33
34
 
34
35
  it "returns all files under the directory as relative paths, including dotfiles, excluding directories" do
@@ -40,7 +41,7 @@ RSpec.describe NeocitiesRed::Services::File::FolderUploader do
40
41
  FileUtils.mkdir_p(File.join(tmp_root, "ext/empty_dir"))
41
42
  FileUtils.mkdir_p(File.join(tmp_root, "ext/.hiddendir"))
42
43
 
43
- uploader = described_class.new(client, File.join(tmp_root, "ext"), remote_path)
44
+ uploader = described_class.new(client, File.join(tmp_root, "ext"), remote_path, display: display)
44
45
  expect(uploader.files).to contain_exactly("a.txt", "sub/b.txt", ".env", "sub/.keep")
45
46
  end
46
47
 
@@ -49,16 +50,17 @@ RSpec.describe NeocitiesRed::Services::File::FolderUploader do
49
50
  write_file("tmp_ext/sub/nested.rb", content: "puts :ok")
50
51
 
51
52
  Dir.chdir(tmp_root) do
52
- uploader = described_class.new(client, "./tmp_ext/", remote_path)
53
+ uploader = described_class.new(client, "./tmp_ext/", remote_path, display: display)
53
54
  expect(uploader.files).to contain_exactly("root.rb", "sub/nested.rb")
54
55
  end
55
56
  end
56
57
 
57
58
  it "returns nil when filepath is a file (not a directory)" do
58
59
  file_path = write_file("not_a_dir.txt", content: "hello")
59
- uploader = described_class.new(client, file_path, remote_path)
60
+ uploader = described_class.new(client, file_path, remote_path, display: display)
60
61
 
61
62
  expect(uploader.files).to be_nil
63
+ expect(display).to have_received(:display_skip_file)
62
64
  end
63
65
  end
64
66
  end
@@ -7,7 +7,8 @@ RSpec.describe NeocitiesRed::Services::File::List do
7
7
  let(:client) { instance_double(NeocitiesRed::Client) }
8
8
  let(:path) { nil }
9
9
  let(:detail) { false }
10
- let(:file_list) { described_class.new(client, path, detail) }
10
+ let(:display) { instance_double(NeocitiesRed::CliDisplay, display_list_table: nil) }
11
+ let(:file_list) { described_class.new(client, path, detail, display: display) }
11
12
 
12
13
  describe "#list" do
13
14
  context "when successful" do
@@ -58,11 +59,10 @@ RSpec.describe NeocitiesRed::Services::File::List do
58
59
 
59
60
  before do
60
61
  allow(client).to receive(:list).and_return(error_response)
61
- allow($stdout).to receive(:puts)
62
62
  end
63
63
 
64
- it "displays the error and exits" do
65
- expect { file_list.list }.to raise_error(SystemExit)
64
+ it "raises APIError with the message" do
65
+ expect { file_list.list }.to raise_error(NeocitiesRed::APIError, /Invalid path/)
66
66
  end
67
67
  end
68
68
  end
@@ -81,7 +81,6 @@ RSpec.describe NeocitiesRed::Services::File::List do
81
81
 
82
82
  before do
83
83
  allow(client).to receive(:list).with(path).and_return(files_response)
84
- allow($stdout).to receive(:puts)
85
84
  end
86
85
 
87
86
  it "returns an array of files" do
@@ -119,7 +118,6 @@ RSpec.describe NeocitiesRed::Services::File::List do
119
118
  allow(pastel).to receive_messages(blue: pastel, green: pastel)
120
119
  allow(TTY::Table).to receive(:new).and_return(table)
121
120
  allow(table).to receive(:to_s).and_return("table output")
122
- allow($stdout).to receive(:puts)
123
121
  end
124
122
 
125
123
  it "returns files with detailed information" do
@@ -142,6 +140,12 @@ RSpec.describe NeocitiesRed::Services::File::List do
142
140
 
143
141
  expect(pastel).to have_received(:green).at_least(:once)
144
142
  end
143
+
144
+ it "renders the table through the display" do
145
+ file_list.show
146
+
147
+ expect(display).to have_received(:display_list_table).with(table)
148
+ end
145
149
  end
146
150
 
147
151
  context "when API returns an error" do
@@ -149,11 +153,10 @@ RSpec.describe NeocitiesRed::Services::File::List do
149
153
 
150
154
  before do
151
155
  allow(client).to receive(:list).and_return(error_response)
152
- allow($stdout).to receive(:puts)
153
156
  end
154
157
 
155
- it "displays the error and exits" do
156
- expect { file_list.show }.to raise_error(SystemExit)
158
+ it "raises APIError with the message" do
159
+ expect { file_list.show }.to raise_error(NeocitiesRed::APIError, /Path not found/)
157
160
  end
158
161
  end
159
162
  end
@@ -166,7 +169,7 @@ RSpec.describe NeocitiesRed::Services::File::List do
166
169
  end
167
170
 
168
171
  it "handles nil detail as false" do
169
- file_list_nil_detail = described_class.new(client, path, nil)
172
+ file_list_nil_detail = described_class.new(client, path, nil, display: display)
170
173
  expect(file_list_nil_detail.instance_variable_get(:@detail)).to be(false)
171
174
  end
172
175
 
@@ -1,21 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
- require "stringio"
5
4
 
6
5
  RSpec.describe NeocitiesRed::Services::File::Remover do
7
- subject(:remover) { described_class.new(client, filepath) }
6
+ subject(:remover) { described_class.new(client, filepath, display: display) }
8
7
 
9
8
  let(:client) { instance_double(NeocitiesRed::Client) }
10
9
  let(:filepath) { "test_file.txt" }
11
- let(:io) { StringIO.new }
12
- let(:pastel) { object_double(Pastel.new(eachline: "\n")) }
13
-
14
- before do
15
- allow(Pastel).to receive(:new).with(eachline: "\n").and_return(pastel)
16
- allow(pastel).to receive(:bold) { |msg| msg }
17
- allow(pastel).to receive_messages(green: pastel, yellow: pastel)
18
- allow($stdout).to receive_messages(puts: nil, print: nil)
10
+ let(:display) do
11
+ instance_double(
12
+ NeocitiesRed::CliDisplay,
13
+ display_delete_progress: nil,
14
+ display_delete_success: nil,
15
+ display_delete_error: nil
16
+ )
19
17
  end
20
18
 
21
19
  describe "#initialize" do
@@ -46,14 +44,10 @@ RSpec.describe NeocitiesRed::Services::File::Remover do
46
44
  expect(client).to have_received(:delete).with(filepath)
47
45
  end
48
46
 
49
- it "prints deletion progress message" do
47
+ it "displays delete progress and success" do
50
48
  remover.remove
51
- expect(pastel).to have_received(:bold).with("Deleting #{filepath} ...")
52
- end
53
-
54
- it "prints SUCCESS message" do
55
- remover.remove
56
- expect(pastel).to have_received(:green)
49
+ expect(display).to have_received(:display_delete_progress).with(filepath)
50
+ expect(display).to have_received(:display_delete_success)
57
51
  end
58
52
 
59
53
  it "returns the success response" do
@@ -76,9 +70,9 @@ RSpec.describe NeocitiesRed::Services::File::Remover do
76
70
  expect(client).to have_received(:delete).with(filepath)
77
71
  end
78
72
 
79
- it "prints error message" do
73
+ it "displays delete error" do
80
74
  remover.remove
81
- expect(pastel).to have_received(:bold).with("File not found")
75
+ expect(display).to have_received(:display_delete_error).with(error_response)
82
76
  end
83
77
 
84
78
  it "returns the error response" do
@@ -96,9 +90,9 @@ RSpec.describe NeocitiesRed::Services::File::Remover do
96
90
  allow(client).to receive(:delete).with(filepath).and_return(exists_response)
97
91
  end
98
92
 
99
- it "prints EXISTS message" do
93
+ it "displays delete error" do
100
94
  remover.remove
101
- expect(pastel).to have_received(:yellow)
95
+ expect(display).to have_received(:display_delete_error).with(exists_response)
102
96
  end
103
97
 
104
98
  it "returns the error response" do
@@ -1,13 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fileutils"
4
3
  require "spec_helper"
5
4
 
6
5
  RSpec.describe NeocitiesRed::Services::File::Uploader do
7
6
  let(:client) { instance_double(NeocitiesRed::Client) }
8
7
  let(:filepath) { "/path/to/file.txt" }
9
8
  let(:remote_path) { "file.txt" }
10
- let(:uploader) { described_class.new(client, filepath, remote_path) }
9
+ let(:display) do
10
+ instance_double(
11
+ NeocitiesRed::CliDisplay,
12
+ display_skip_directory: nil,
13
+ display_upload_progress: nil,
14
+ display_upload_success: nil,
15
+ display_upload_exists: nil,
16
+ display_response: nil
17
+ )
18
+ end
19
+ let(:uploader) { described_class.new(client, filepath, remote_path, display: display) }
11
20
 
12
21
  describe "#upload" do
13
22
  context "when the file does not exist" do
@@ -15,9 +24,9 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
15
24
  allow(Pathname).to receive(:new).with(filepath).and_return(instance_double(Pathname, exist?: false))
16
25
  end
17
26
 
18
- it "raises FileIsNotExists error" do
27
+ it "raises FileNotFoundError" do
19
28
  expect { uploader.upload }.to raise_error(
20
- NeocitiesRed::Services::File::FileIsNotExists,
29
+ NeocitiesRed::FileNotFoundError,
21
30
  /does not exist locally/
22
31
  )
23
32
  end
@@ -29,13 +38,12 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
29
38
  before do
30
39
  allow(Pathname).to receive(:new).with(filepath).and_return(path_double)
31
40
  allow(client).to receive(:upload)
32
- allow($stdout).to receive(:puts)
33
41
  end
34
42
 
35
- it "prints a message and returns without uploading" do
43
+ it "displays a skip message and returns without uploading" do
36
44
  uploader.upload
37
45
 
38
- expect($stdout).to have_received(:puts).with(match(/#{Regexp.escape(filepath)} is a directory, skipping/))
46
+ expect(display).to have_received(:display_skip_directory).with(path_double)
39
47
  expect(client).not_to have_received(:upload)
40
48
  end
41
49
  end
@@ -46,7 +54,6 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
46
54
 
47
55
  before do
48
56
  allow(Pathname).to receive(:new).with(filepath).and_return(path_double)
49
- allow($stdout).to receive(:puts)
50
57
  end
51
58
 
52
59
  context "when upload is successful" do
@@ -60,10 +67,11 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
60
67
  expect(client).to have_received(:upload).with(path_double, remote_path)
61
68
  end
62
69
 
63
- it "prints success message" do
70
+ it "displays progress and success" do
64
71
  uploader.upload
65
72
 
66
- expect($stdout).to have_received(:puts).with(/SUCCESS/)
73
+ expect(display).to have_received(:display_upload_progress).with(path_double, remote_path)
74
+ expect(display).to have_received(:display_upload_success)
67
75
  end
68
76
 
69
77
  it "returns the success response" do
@@ -86,10 +94,10 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
86
94
  allow(client).to receive(:upload).with(path_double, remote_path).and_return(exists_response)
87
95
  end
88
96
 
89
- it "prints exists message" do
97
+ it "displays exists message" do
90
98
  uploader.upload
91
99
 
92
- expect($stdout).to have_received(:puts).with(/EXISTS/)
100
+ expect(display).to have_received(:display_upload_exists)
93
101
  end
94
102
 
95
103
  it "returns the error response" do
@@ -108,12 +116,10 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
108
116
  allow(client).to receive(:upload).with(path_double, remote_path).and_return(error_response)
109
117
  end
110
118
 
111
- it "prints error message" do
119
+ it "displays the error response" do
112
120
  uploader.upload
113
121
 
114
- expect($stdout).to have_received(:puts).with(
115
- hash_including(result: "error", error_type: "upload_failed", message: "Upload failed")
116
- )
122
+ expect(display).to have_received(:display_response).with(error_response)
117
123
  end
118
124
 
119
125
  it "returns the error response" do
@@ -127,13 +133,12 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
127
133
  context "with custom remote path" do
128
134
  let(:custom_remote_path) { "custom/path/file.txt" }
129
135
  let(:path_double) { instance_double(Pathname, exist?: true, directory?: false, to_s: filepath) }
130
- let(:custom_uploader) { described_class.new(client, filepath, custom_remote_path) }
136
+ let(:custom_uploader) { described_class.new(client, filepath, custom_remote_path, display: display) }
131
137
  let(:success_response) { { result: "success", message: "File uploaded successfully" } }
132
138
 
133
139
  before do
134
140
  allow(Pathname).to receive(:new).with(filepath).and_return(path_double)
135
141
  allow(client).to receive(:upload).with(path_double, custom_remote_path).and_return(success_response)
136
- allow($stdout).to receive(:puts)
137
142
  end
138
143
 
139
144
  it "uses the custom remote path" do
@@ -151,8 +156,8 @@ RSpec.describe NeocitiesRed::Services::File::Uploader do
151
156
  expect(uploader.instance_variable_get(:@remote_path)).to eq(remote_path)
152
157
  end
153
158
 
154
- it "creates a Pastel instance" do
155
- expect(uploader.instance_variable_get(:@pastel)).to be_a(Pastel::Delegator)
159
+ it "stores the display" do
160
+ expect(uploader.instance_variable_get(:@display)).to eq(display)
156
161
  end
157
162
  end
158
163
  end
@@ -72,6 +72,7 @@ RSpec.describe NeocitiesRed::Services::Site::Differencer do
72
72
  .with(File.join("**", "*"), File::FNM_DOTMATCH)
73
73
  .and_return(globbed_paths)
74
74
 
75
+ allow(File).to receive(:file?).and_return(false)
75
76
  allow(File).to receive(:file?).with("index.html").and_return(true)
76
77
  allow(File).to receive(:file?).with("about.html").and_return(true)
77
78
  allow(File).to receive(:file?).with("contact.html").and_return(true)
@@ -88,7 +89,7 @@ RSpec.describe NeocitiesRed::Services::Site::Differencer do
88
89
  it "returns added, modified and removed paths" do
89
90
  added_paths, modified_paths, removed_paths = service.show
90
91
 
91
- expect(added_paths).to eq(["GREEN(contact.html)", "GREEN(assets)"])
92
+ expect(added_paths).to eq(["GREEN(contact.html)", "GREEN(assets)", "GREEN(.git)", "GREEN(.env)"])
92
93
  expect(modified_paths).to eq(["YELLOW(about.html)"])
93
94
  expect(removed_paths).to eq(["RED(old.html)"])
94
95
  end
@@ -110,11 +111,11 @@ RSpec.describe NeocitiesRed::Services::Site::Differencer do
110
111
  expect(Digest::SHA1).not_to have_received(:file).with("assets")
111
112
  end
112
113
 
113
- it "always excludes dotfiles and dot-directories from local paths" do
114
+ it "includes dotfiles and dot-directories by default" do
114
115
  added_paths, = service.show
115
116
 
116
- expect(added_paths).not_to include("GREEN(.git)")
117
- expect(added_paths).not_to include("GREEN(.env)")
117
+ expect(added_paths).to include("GREEN(.git)")
118
+ expect(added_paths).to include("GREEN(.env)")
118
119
  end
119
120
 
120
121
  context "when exclude is provided" do
@@ -123,7 +124,7 @@ RSpec.describe NeocitiesRed::Services::Site::Differencer do
123
124
  it "excludes paths from diff" do
124
125
  added_paths, modified_paths, removed_paths = service.show
125
126
 
126
- expect(added_paths).to eq(["GREEN(assets)"])
127
+ expect(added_paths).to eq(["GREEN(assets)", "GREEN(.git)", "GREEN(.env)"])
127
128
  expect(modified_paths).to eq(["YELLOW(about.html)"])
128
129
  expect(removed_paths).to eq([])
129
130
  end
@@ -132,13 +133,38 @@ RSpec.describe NeocitiesRed::Services::Site::Differencer do
132
133
  context "when ignore_dotfiles is true" do
133
134
  let(:ignore_dotfiles) { true }
134
135
 
135
- it "still returns the same result because dotfiles are already filtered earlier" do
136
+ it "excludes dotfiles and dot-directories" do
136
137
  added_paths, modified_paths, removed_paths = service.show
137
138
 
138
139
  expect(added_paths).to eq(["GREEN(contact.html)", "GREEN(assets)"])
140
+ expect(added_paths).not_to include("GREEN(.git)")
141
+ expect(added_paths).not_to include("GREEN(.env)")
139
142
  expect(modified_paths).to eq(["YELLOW(about.html)"])
140
143
  expect(removed_paths).to eq(["RED(old.html)"])
141
144
  end
145
+
146
+ it "does not hash dotfiles" do
147
+ service.show
148
+
149
+ expect(Digest::SHA1).not_to have_received(:file).with(".env")
150
+ end
151
+ end
152
+
153
+ context "when server has directories" do
154
+ let(:server_files) do
155
+ [
156
+ { path: "index.html", sha1_hash: "server-index-sha", is_directory: false },
157
+ { path: "assets", is_directory: true },
158
+ { path: "old.html", sha1_hash: "server-old-sha", is_directory: false }
159
+ ]
160
+ end
161
+
162
+ it "does not list server directories as removed" do
163
+ _, _, removed_paths = service.show
164
+
165
+ expect(removed_paths).to eq(["RED(old.html)"])
166
+ expect(removed_paths).not_to include("RED(assets)")
167
+ end
142
168
  end
143
169
  end
144
170