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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +29 -15
- data/.gitignore +4 -0
- data/CHANGELOG.md +95 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +9 -6
- data/README.md +6 -0
- data/lib/neocities_red/cli.rb +156 -31
- data/lib/neocities_red/cli_display.rb +200 -5
- data/lib/neocities_red/client.rb +84 -77
- data/lib/neocities_red/errors.rb +20 -0
- data/lib/neocities_red/services/common/exclusions.rb +69 -0
- data/lib/neocities_red/services/common/pizza.rb +34 -21
- data/lib/neocities_red/services/common/worker_pool.rb +54 -0
- data/lib/neocities_red/services/file/folder_uploader.rb +39 -25
- data/lib/neocities_red/services/file/list.rb +60 -30
- data/lib/neocities_red/services/file/remover.rb +27 -12
- data/lib/neocities_red/services/file/uploader.rb +33 -13
- data/lib/neocities_red/services/site/differencer.rb +42 -12
- data/lib/neocities_red/services/site/exporter.rb +120 -7
- data/lib/neocities_red/services/site/informer.rb +29 -4
- data/lib/neocities_red/services/site/pusher.rb +74 -38
- data/lib/neocities_red/version.rb +2 -1
- data/lib/neocities_red.rb +32 -13
- data/neocities-red.gemspec +11 -6
- data/spec/neocities_red/cli_display_spec.rb +0 -6
- data/spec/neocities_red/cli_spec.rb +85 -0
- data/spec/neocities_red/client_spec.rb +7 -50
- data/spec/neocities_red/services/common/exclusions_spec.rb +47 -0
- data/spec/neocities_red/services/common/worker_pool_spec.rb +48 -0
- data/spec/neocities_red/services/file/folder_uploader_spec.rb +8 -6
- data/spec/neocities_red/services/file/list_spec.rb +13 -10
- data/spec/neocities_red/services/file/remover_spec.rb +15 -21
- data/spec/neocities_red/services/file/uploader_spec.rb +25 -20
- data/spec/neocities_red/services/site/differencer_spec.rb +32 -6
- data/spec/neocities_red/services/site/exporter_spec.rb +105 -38
- data/spec/neocities_red/services/site/informer_spec.rb +3 -3
- data/spec/neocities_red/services/site/pusher_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +11 -25
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
require "json"
|
|
5
5
|
require "fileutils"
|
|
6
|
+
require "time"
|
|
6
7
|
|
|
7
8
|
RSpec.describe NeocitiesRed::Services::Site::Exporter do
|
|
8
9
|
let(:client) { instance_double(NeocitiesRed::Client) }
|
|
@@ -11,29 +12,42 @@ RSpec.describe NeocitiesRed::Services::Site::Exporter do
|
|
|
11
12
|
let(:tmp_root) { File.join(spec_root, "tmp", "site_exporter_spec") }
|
|
12
13
|
let(:config_path) { File.join(tmp_root, "config.json") }
|
|
13
14
|
let(:data) { { "LAST_PULL" => { "time" => nil, "loc" => nil } } }
|
|
15
|
+
let(:display) do
|
|
16
|
+
instance_double(
|
|
17
|
+
NeocitiesRed::CliDisplay,
|
|
18
|
+
display_pull_progress: nil,
|
|
19
|
+
display_pull_no_updates: nil,
|
|
20
|
+
display_pull_success: nil,
|
|
21
|
+
display_pull_failure: nil,
|
|
22
|
+
display_pull_stats: nil
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
let(:exporter) { described_class.new(client, sitename, data, config_path, display: display) }
|
|
26
|
+
let(:info_response) { { result: "success", info: { domain: nil } } }
|
|
27
|
+
let(:list_response) { { result: "success", files: [] } }
|
|
14
28
|
|
|
15
|
-
|
|
29
|
+
around do |example|
|
|
16
30
|
FileUtils.rm_rf(tmp_root)
|
|
17
31
|
FileUtils.mkdir_p(tmp_root)
|
|
18
32
|
File.write(config_path, data.to_json)
|
|
19
|
-
end
|
|
20
33
|
|
|
21
|
-
|
|
34
|
+
original_dir = Dir.pwd
|
|
35
|
+
Dir.chdir(tmp_root)
|
|
36
|
+
example.run
|
|
37
|
+
ensure
|
|
38
|
+
Dir.chdir(original_dir)
|
|
22
39
|
FileUtils.rm_rf(tmp_root)
|
|
23
40
|
end
|
|
24
41
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
before do
|
|
30
|
-
allow(client).to receive(:pull).and_return(nil)
|
|
31
|
-
end
|
|
42
|
+
before do
|
|
43
|
+
allow(client).to receive_messages(info: info_response, list: list_response)
|
|
44
|
+
end
|
|
32
45
|
|
|
33
|
-
|
|
46
|
+
describe "#export" do
|
|
47
|
+
context "when the site has no files" do
|
|
48
|
+
it "updates the config file with last pull data" do
|
|
34
49
|
expect { exporter.export(quiet: true, last_pull_time: nil, last_pull_loc: nil) }.not_to raise_error
|
|
35
50
|
|
|
36
|
-
expect(File.exist?(config_path)).to be(true)
|
|
37
51
|
updated_data = JSON.parse(File.read(config_path))
|
|
38
52
|
expect(updated_data["LAST_PULL"]).to have_key("time")
|
|
39
53
|
expect(updated_data["LAST_PULL"]).to have_key("loc")
|
|
@@ -62,51 +76,104 @@ RSpec.describe NeocitiesRed::Services::Site::Exporter do
|
|
|
62
76
|
expect(Whirly).not_to have_received(:stop)
|
|
63
77
|
end
|
|
64
78
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
it "displays pull stats" do
|
|
80
|
+
exporter.export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
|
|
81
|
+
|
|
82
|
+
expect(display).to have_received(:display_pull_stats).with(0, anything)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "when the site has files" do
|
|
87
|
+
let(:list_response) do
|
|
88
|
+
{
|
|
89
|
+
result: "success",
|
|
90
|
+
files: [
|
|
91
|
+
{ path: "index.html", is_directory: false, updated_at: "2024-01-01T00:00:00Z" },
|
|
92
|
+
{ path: "assets/", is_directory: true, updated_at: "2024-01-01T00:00:00Z" }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
let(:file_response) { instance_double(Faraday::Response, status: 200, body: "<h1>Hello</h1>") }
|
|
97
|
+
|
|
98
|
+
it "downloads files and writes them locally" do
|
|
99
|
+
allow(client).to receive(:download).with("https://test-site.neocities.org/index.html").and_return(file_response)
|
|
100
|
+
|
|
101
|
+
exporter.export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
|
|
102
|
+
|
|
103
|
+
expect(File.read(File.join(tmp_root, "index.html"))).to eq("<h1>Hello</h1>")
|
|
104
|
+
expect(File.directory?(File.join(tmp_root, "assets"))).to be(true)
|
|
105
|
+
expect(display).to have_received(:display_pull_success)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "uses the custom domain when present" do
|
|
109
|
+
allow(client).to receive(:info).and_return(result: "success", info: { domain: "example.com" })
|
|
110
|
+
allow(client).to receive(:download).with("https://example.com/index.html").and_return(file_response)
|
|
111
|
+
|
|
112
|
+
exporter.export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
|
|
113
|
+
|
|
114
|
+
expect(client).to have_received(:download).with("https://example.com/index.html")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "skips download when the file has not changed since last pull" do
|
|
118
|
+
allow(client).to receive(:download)
|
|
119
|
+
File.write(File.join(tmp_root, "index.html"), "existing content")
|
|
120
|
+
|
|
121
|
+
last_pull_time = Time.now.iso8601
|
|
122
|
+
exporter.export(quiet: false, last_pull_time: last_pull_time, last_pull_loc: Dir.pwd)
|
|
123
|
+
|
|
124
|
+
expect(display).to have_received(:display_pull_no_updates)
|
|
125
|
+
expect(client).not_to have_received(:download)
|
|
126
|
+
expect(File.read(File.join(tmp_root, "index.html"))).to eq("existing content")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "reports failure when the download fails" do
|
|
130
|
+
allow(client).to receive(:download).with("https://test-site.neocities.org/index.html").and_return(
|
|
131
|
+
instance_double(Faraday::Response, status: 500, body: "")
|
|
132
|
+
)
|
|
68
133
|
|
|
69
|
-
|
|
70
|
-
expect { exporter.export(quiet: true, last_pull_time: last_pull_time, last_pull_loc: last_pull_loc) }.not_to raise_error
|
|
134
|
+
exporter.export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
|
|
71
135
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
)
|
|
75
|
-
end
|
|
136
|
+
expect(display).to have_received(:display_pull_failure)
|
|
137
|
+
expect(File.exist?(File.join(tmp_root, "index.html"))).to be(false)
|
|
76
138
|
end
|
|
77
139
|
end
|
|
78
140
|
|
|
79
|
-
context "when
|
|
80
|
-
let(:
|
|
141
|
+
context "when the API returns an error for info" do
|
|
142
|
+
let(:info_response) { { result: "error", message: "Site not found" } }
|
|
81
143
|
|
|
82
|
-
it "
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
144
|
+
it "raises APIError" do
|
|
145
|
+
expect do
|
|
146
|
+
exporter.export(quiet: true, last_pull_time: nil, last_pull_loc: nil)
|
|
147
|
+
end.to raise_error(NeocitiesRed::APIError, /Site not found/)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
86
150
|
|
|
87
|
-
|
|
151
|
+
context "when the API returns an error for list" do
|
|
152
|
+
let(:list_response) { { result: "error", message: "List failed" } }
|
|
88
153
|
|
|
89
|
-
|
|
90
|
-
expect
|
|
91
|
-
|
|
154
|
+
it "raises APIError" do
|
|
155
|
+
expect do
|
|
156
|
+
exporter.export(quiet: true, last_pull_time: nil, last_pull_loc: nil)
|
|
157
|
+
end.to raise_error(NeocitiesRed::APIError, /List failed/)
|
|
92
158
|
end
|
|
159
|
+
end
|
|
93
160
|
|
|
94
|
-
|
|
161
|
+
context "when fetching raises an error" do
|
|
162
|
+
it "propagates the error and stops Whirly" do
|
|
163
|
+
allow(client).to receive(:info).and_raise(StandardError.new("network error"))
|
|
95
164
|
allow(Whirly).to receive(:start)
|
|
96
165
|
allow(Whirly).to receive(:stop)
|
|
97
|
-
allow(client).to receive(:pull).and_raise(StandardError.new("network error"))
|
|
98
166
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
167
|
+
expect do
|
|
168
|
+
exporter.export(quiet: true, last_pull_time: nil, last_pull_loc: nil)
|
|
169
|
+
end.to raise_error(StandardError, "network error")
|
|
170
|
+
expect(Whirly).to have_received(:stop)
|
|
102
171
|
end
|
|
103
172
|
end
|
|
104
173
|
end
|
|
105
174
|
|
|
106
175
|
describe "#initialize" do
|
|
107
176
|
it "stores client, sitename, data, and app_config_path" do
|
|
108
|
-
exporter = described_class.new(client, sitename, data, config_path)
|
|
109
|
-
|
|
110
177
|
expect(exporter.client).to eq(client)
|
|
111
178
|
expect(exporter.sitename).to eq(sitename)
|
|
112
179
|
expect(exporter.data).to eq(data)
|
|
@@ -54,10 +54,10 @@ RSpec.describe NeocitiesRed::Services::Site::Informer do
|
|
|
54
54
|
allow(client).to receive(:info).and_return(error_response)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
it "raises
|
|
57
|
+
it "raises APIError with the message" do
|
|
58
58
|
expect { profile_info.stats }.to raise_error(
|
|
59
|
-
NeocitiesRed::
|
|
60
|
-
/
|
|
59
|
+
NeocitiesRed::APIError,
|
|
60
|
+
/could not find site nonexistent/
|
|
61
61
|
)
|
|
62
62
|
end
|
|
63
63
|
end
|
|
@@ -47,7 +47,7 @@ RSpec.describe NeocitiesRed::Services::Site::Pusher do
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
before do
|
|
50
|
-
allow(NeocitiesRed::Services::File::Uploader).to receive(:new) do |_client, filepath, remote_path|
|
|
50
|
+
allow(NeocitiesRed::Services::File::Uploader).to receive(:new) do |_client, filepath, remote_path, _display|
|
|
51
51
|
upload_calls << [filepath.to_s, remote_path.to_s]
|
|
52
52
|
uploader_instance
|
|
53
53
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: neocities-red
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kyle Drake
|
|
@@ -84,9 +84,6 @@ dependencies:
|
|
|
84
84
|
name: pastel
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0.8'
|
|
90
87
|
- - '='
|
|
91
88
|
- !ruby/object:Gem::Version
|
|
92
89
|
version: 0.8.0
|
|
@@ -94,9 +91,6 @@ dependencies:
|
|
|
94
91
|
prerelease: false
|
|
95
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
96
93
|
requirements:
|
|
97
|
-
- - "~>"
|
|
98
|
-
- !ruby/object:Gem::Version
|
|
99
|
-
version: '0.8'
|
|
100
94
|
- - '='
|
|
101
95
|
- !ruby/object:Gem::Version
|
|
102
96
|
version: 0.8.0
|
|
@@ -107,9 +101,6 @@ dependencies:
|
|
|
107
101
|
- - "~>"
|
|
108
102
|
- !ruby/object:Gem::Version
|
|
109
103
|
version: '13'
|
|
110
|
-
- - ">="
|
|
111
|
-
- !ruby/object:Gem::Version
|
|
112
|
-
version: 13.3.0
|
|
113
104
|
type: :runtime
|
|
114
105
|
prerelease: false
|
|
115
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -117,9 +108,6 @@ dependencies:
|
|
|
117
108
|
- - "~>"
|
|
118
109
|
- !ruby/object:Gem::Version
|
|
119
110
|
version: '13'
|
|
120
|
-
- - ">="
|
|
121
|
-
- !ruby/object:Gem::Version
|
|
122
|
-
version: 13.3.0
|
|
123
111
|
- !ruby/object:Gem::Dependency
|
|
124
112
|
name: thor
|
|
125
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,9 +132,6 @@ dependencies:
|
|
|
144
132
|
name: tty-prompt
|
|
145
133
|
requirement: !ruby/object:Gem::Requirement
|
|
146
134
|
requirements:
|
|
147
|
-
- - "~>"
|
|
148
|
-
- !ruby/object:Gem::Version
|
|
149
|
-
version: '0.23'
|
|
150
135
|
- - '='
|
|
151
136
|
- !ruby/object:Gem::Version
|
|
152
137
|
version: 0.23.1
|
|
@@ -154,9 +139,6 @@ dependencies:
|
|
|
154
139
|
prerelease: false
|
|
155
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
156
141
|
requirements:
|
|
157
|
-
- - "~>"
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0.23'
|
|
160
142
|
- - '='
|
|
161
143
|
- !ruby/object:Gem::Version
|
|
162
144
|
version: 0.23.1
|
|
@@ -164,9 +146,6 @@ dependencies:
|
|
|
164
146
|
name: tty-table
|
|
165
147
|
requirement: !ruby/object:Gem::Requirement
|
|
166
148
|
requirements:
|
|
167
|
-
- - "~>"
|
|
168
|
-
- !ruby/object:Gem::Version
|
|
169
|
-
version: '0.12'
|
|
170
149
|
- - '='
|
|
171
150
|
- !ruby/object:Gem::Version
|
|
172
151
|
version: 0.12.0
|
|
@@ -174,9 +153,6 @@ dependencies:
|
|
|
174
153
|
prerelease: false
|
|
175
154
|
version_requirements: !ruby/object:Gem::Requirement
|
|
176
155
|
requirements:
|
|
177
|
-
- - "~>"
|
|
178
|
-
- !ruby/object:Gem::Version
|
|
179
|
-
version: '0.12'
|
|
180
156
|
- - '='
|
|
181
157
|
- !ruby/object:Gem::Version
|
|
182
158
|
version: 0.12.0
|
|
@@ -213,6 +189,7 @@ files:
|
|
|
213
189
|
- ".gitignore"
|
|
214
190
|
- ".rspec"
|
|
215
191
|
- ".rubocop.yml"
|
|
192
|
+
- CHANGELOG.md
|
|
216
193
|
- CODE_OF_CONDUCT.md
|
|
217
194
|
- CONTRIBUTING.md
|
|
218
195
|
- Gemfile
|
|
@@ -226,7 +203,10 @@ files:
|
|
|
226
203
|
- lib/neocities_red/cli.rb
|
|
227
204
|
- lib/neocities_red/cli_display.rb
|
|
228
205
|
- lib/neocities_red/client.rb
|
|
206
|
+
- lib/neocities_red/errors.rb
|
|
207
|
+
- lib/neocities_red/services/common/exclusions.rb
|
|
229
208
|
- lib/neocities_red/services/common/pizza.rb
|
|
209
|
+
- lib/neocities_red/services/common/worker_pool.rb
|
|
230
210
|
- lib/neocities_red/services/file/folder_uploader.rb
|
|
231
211
|
- lib/neocities_red/services/file/list.rb
|
|
232
212
|
- lib/neocities_red/services/file/remover.rb
|
|
@@ -240,7 +220,9 @@ files:
|
|
|
240
220
|
- spec/neocities_red/cli_display_spec.rb
|
|
241
221
|
- spec/neocities_red/cli_spec.rb
|
|
242
222
|
- spec/neocities_red/client_spec.rb
|
|
223
|
+
- spec/neocities_red/services/common/exclusions_spec.rb
|
|
243
224
|
- spec/neocities_red/services/common/pizza_spec.rb
|
|
225
|
+
- spec/neocities_red/services/common/worker_pool_spec.rb
|
|
244
226
|
- spec/neocities_red/services/file/folder_uploader_spec.rb
|
|
245
227
|
- spec/neocities_red/services/file/list_spec.rb
|
|
246
228
|
- spec/neocities_red/services/file/remover_spec.rb
|
|
@@ -255,6 +237,10 @@ licenses:
|
|
|
255
237
|
- MIT
|
|
256
238
|
metadata:
|
|
257
239
|
rubygems_mfa_required: 'true'
|
|
240
|
+
homepage_uri: https://github.com/o-200/neocities-red
|
|
241
|
+
source_code_uri: https://github.com/o-200/neocities-red
|
|
242
|
+
changelog_uri: https://github.com/o-200/neocities-red/blob/main/CHANGELOG.md
|
|
243
|
+
documentation_uri: https://github.com/o-200/neocities-red#readme
|
|
258
244
|
rdoc_options: []
|
|
259
245
|
require_paths:
|
|
260
246
|
- lib
|