bard 1.7.2 → 1.7.4
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/lib/bard/github_pages.rb +49 -28
- data/lib/bard/ping.rb +37 -6
- data/lib/bard/version.rb +1 -1
- data/spec/bard/github_pages_spec.rb +64 -1
- data/spec/bard/ping_spec.rb +41 -12
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d1e8b7a7dc083d479b5322405ddbfc58ecab56967433c5f2a543c7637a86ce28
|
|
4
|
+
data.tar.gz: 3c09e62579e85fa615e2005ed6f5cc2d0068576eba46255791523a211b7c0387
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ab06301b535cfe5eb37bb3da892fc6e8a66cb46c6c346bfb0d8279bfd37bba9c495f3c9fc9ffda8663881b7fe333186820cc4c57d36f086c524191dc953da14
|
|
7
|
+
data.tar.gz: 0f55ad3b8d94900354005227d73b86ba3ab25847eb7d88242f89e28fafbd281256755a802a7ca10092bd1571040335a3a4d8de845406af94b4d5a10edd1e9e16
|
data/lib/bard/github_pages.rb
CHANGED
|
@@ -22,34 +22,55 @@ module Bard
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
def build_site
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
25
|
+
with_locked_port do |port|
|
|
26
|
+
system "rm -rf #{@build_dir.sub(@sha, "*")}"
|
|
27
|
+
run! <<~SH
|
|
28
|
+
set -e
|
|
29
|
+
RAILS_ENV=production bundle exec rails s -p #{port} -d --pid tmp/pids/server.pid
|
|
30
|
+
OUTPUT=$(bundle exec rake assets:clean assets:precompile 2>&1) || echo "$OUTPUT"
|
|
31
|
+
|
|
32
|
+
# Create the output directory and enter it
|
|
33
|
+
BUILD=#{@build_dir}
|
|
34
|
+
rm -rf $BUILD
|
|
35
|
+
mkdir -p $BUILD
|
|
36
|
+
cp -R public/assets $BUILD/
|
|
37
|
+
cd $BUILD
|
|
38
|
+
|
|
39
|
+
# wait until server responds
|
|
40
|
+
echo waiting...
|
|
41
|
+
curl -s --retry 5 --retry-delay 2 http://localhost:#{port} >/dev/null 2>&1
|
|
42
|
+
|
|
43
|
+
echo copying...
|
|
44
|
+
# Mirror the site to the build folder, ignoring links with query params
|
|
45
|
+
wget -nv -r -l inf --no-remove-listing -FEnH --reject-regex "(\\.*)\\?(.*)" http://localhost:#{port}/ 2>&1
|
|
46
|
+
|
|
47
|
+
echo #{@domain} > CNAME
|
|
48
|
+
SH
|
|
49
|
+
ensure # cleanup
|
|
50
|
+
run! <<~SH
|
|
51
|
+
cat tmp/pids/server.pid | xargs -I {} kill {}
|
|
52
|
+
rm -rf public/assets
|
|
53
|
+
SH
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def with_locked_port
|
|
58
|
+
(3000..3020).each do |port|
|
|
59
|
+
lock_file = "/tmp/bard_github_pages_#{port}.lock"
|
|
60
|
+
file = File.open(lock_file, File::RDWR | File::CREAT, 0644)
|
|
61
|
+
if file.flock(File::LOCK_EX | File::LOCK_NB)
|
|
62
|
+
begin
|
|
63
|
+
yield port
|
|
64
|
+
return
|
|
65
|
+
ensure
|
|
66
|
+
file.flock(File::LOCK_UN)
|
|
67
|
+
file.close
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
file.close
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
raise "Could not find an available port for GitHub Pages deployment (checked 3000-3020)."
|
|
53
74
|
end
|
|
54
75
|
|
|
55
76
|
def create_tree_from_build
|
data/lib/bard/ping.rb
CHANGED
|
@@ -8,16 +8,26 @@ module Bard
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def call
|
|
11
|
-
server.ping.reject
|
|
12
|
-
response = get_response_with_redirect(url) rescue nil
|
|
13
|
-
response.is_a?(Net::HTTPSuccess)
|
|
14
|
-
end
|
|
11
|
+
server.ping.reject { |url| reachable?(url) }
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
private
|
|
18
15
|
|
|
16
|
+
def reachable?(url)
|
|
17
|
+
attempts = 0
|
|
18
|
+
begin
|
|
19
|
+
attempts += 1
|
|
20
|
+
response = get_response_with_redirect(url)
|
|
21
|
+
response.is_a?(Net::HTTPSuccess)
|
|
22
|
+
rescue StandardError
|
|
23
|
+
retry if attempts < 2
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
19
28
|
def get_response_with_redirect uri_str, limit=5
|
|
20
|
-
|
|
29
|
+
uri = URI(uri_str)
|
|
30
|
+
response = http_get(uri)
|
|
21
31
|
|
|
22
32
|
case response
|
|
23
33
|
when Net::HTTPRedirection
|
|
@@ -25,11 +35,32 @@ module Bard
|
|
|
25
35
|
puts "too many HTTP redirects"
|
|
26
36
|
response
|
|
27
37
|
else
|
|
28
|
-
|
|
38
|
+
location = response["location"]
|
|
39
|
+
return response unless location
|
|
40
|
+
|
|
41
|
+
next_uri = begin
|
|
42
|
+
uri + location
|
|
43
|
+
rescue URI::InvalidURIError
|
|
44
|
+
URI(location)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
get_response_with_redirect(next_uri, limit - 1)
|
|
29
48
|
end
|
|
30
49
|
else
|
|
31
50
|
response
|
|
32
51
|
end
|
|
33
52
|
end
|
|
53
|
+
|
|
54
|
+
def http_get(uri)
|
|
55
|
+
Net::HTTP.start(
|
|
56
|
+
uri.host,
|
|
57
|
+
uri.port,
|
|
58
|
+
use_ssl: uri.scheme == "https",
|
|
59
|
+
open_timeout: 5,
|
|
60
|
+
read_timeout: 5,
|
|
61
|
+
) do |http|
|
|
62
|
+
http.get(uri.request_uri)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
34
65
|
end
|
|
35
66
|
end
|
data/lib/bard/version.rb
CHANGED
|
@@ -38,6 +38,69 @@ describe Bard::GithubPages do
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
describe "#build_site" do
|
|
42
|
+
it "uses the locked port" do
|
|
43
|
+
github_pages.instance_variable_set(:@sha, "abc123")
|
|
44
|
+
github_pages.instance_variable_set(:@build_dir, "tmp/github-build-abc123")
|
|
45
|
+
github_pages.instance_variable_set(:@domain, "example.com")
|
|
46
|
+
|
|
47
|
+
allow(github_pages).to receive(:with_locked_port).and_yield(3005)
|
|
48
|
+
|
|
49
|
+
expect(github_pages).to receive(:run!).with(satisfy { |cmd|
|
|
50
|
+
cmd.include?("rails s -p 3005") && cmd.include?("http://localhost:3005")
|
|
51
|
+
}).ordered
|
|
52
|
+
|
|
53
|
+
expect(github_pages).to receive(:run!).with(include("kill")).ordered
|
|
54
|
+
|
|
55
|
+
github_pages.send(:build_site)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "#with_locked_port" do
|
|
60
|
+
let(:file_mock) { double("file", close: true) }
|
|
61
|
+
|
|
62
|
+
before do
|
|
63
|
+
allow(File).to receive(:open).and_return(file_mock)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "yields the first available port" do
|
|
67
|
+
allow(file_mock).to receive(:flock).and_return(true)
|
|
68
|
+
|
|
69
|
+
expect(File).to receive(:open).with("/tmp/bard_github_pages_3000.lock", anything, anything)
|
|
70
|
+
|
|
71
|
+
yielded_port = nil
|
|
72
|
+
github_pages.send(:with_locked_port) { |p| yielded_port = p }
|
|
73
|
+
expect(yielded_port).to eq(3000)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "retries if the first port is locked" do
|
|
77
|
+
# 1. Try port 3000
|
|
78
|
+
expect(File).to receive(:open).with("/tmp/bard_github_pages_3000.lock", anything, anything).ordered
|
|
79
|
+
expect(file_mock).to receive(:flock).with(File::LOCK_EX | File::LOCK_NB).and_return(false).ordered
|
|
80
|
+
expect(file_mock).to receive(:close).ordered
|
|
81
|
+
|
|
82
|
+
# 2. Try port 3001
|
|
83
|
+
expect(File).to receive(:open).with("/tmp/bard_github_pages_3001.lock", anything, anything).ordered
|
|
84
|
+
expect(file_mock).to receive(:flock).with(File::LOCK_EX | File::LOCK_NB).and_return(true).ordered
|
|
85
|
+
|
|
86
|
+
# 3. Cleanup after yielding
|
|
87
|
+
expect(file_mock).to receive(:flock).with(File::LOCK_UN).ordered
|
|
88
|
+
expect(file_mock).to receive(:close).ordered
|
|
89
|
+
|
|
90
|
+
yielded_port = nil
|
|
91
|
+
github_pages.send(:with_locked_port) { |p| yielded_port = p }
|
|
92
|
+
expect(yielded_port).to eq(3001)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "raises an error if no ports are available" do
|
|
96
|
+
allow(file_mock).to receive(:flock).and_return(false)
|
|
97
|
+
|
|
98
|
+
expect {
|
|
99
|
+
github_pages.send(:with_locked_port) {}
|
|
100
|
+
}.to raise_error(/Could not find an available port/)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
41
104
|
describe "#get_parent_commit" do
|
|
42
105
|
it "returns the sha of the gh-pages branch" do
|
|
43
106
|
github_pages.instance_variable_set(:@branch, "gh-pages")
|
|
@@ -77,4 +140,4 @@ describe Bard::GithubPages do
|
|
|
77
140
|
end
|
|
78
141
|
end
|
|
79
142
|
end
|
|
80
|
-
end
|
|
143
|
+
end
|
data/spec/bard/ping_spec.rb
CHANGED
|
@@ -3,29 +3,58 @@ require "bard/ping"
|
|
|
3
3
|
|
|
4
4
|
describe Bard::Ping do
|
|
5
5
|
let(:server) { double("server", ping: ["http://example.com"]) }
|
|
6
|
+
let(:ping) { described_class.new(server) }
|
|
7
|
+
|
|
8
|
+
def success_response
|
|
9
|
+
Net::HTTPSuccess.new(1.0, "200", "OK")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def not_found_response
|
|
13
|
+
Net::HTTPNotFound.new(1.0, "404", "Not Found")
|
|
14
|
+
end
|
|
6
15
|
|
|
7
16
|
context "when the server is reachable" do
|
|
8
|
-
it "
|
|
9
|
-
allow(
|
|
10
|
-
expect(
|
|
17
|
+
it "returns an empty array" do
|
|
18
|
+
allow(ping).to receive(:http_get).and_return(success_response)
|
|
19
|
+
expect(ping.call).to be_empty
|
|
11
20
|
end
|
|
12
21
|
end
|
|
13
22
|
|
|
14
23
|
context "when the server is not reachable" do
|
|
15
|
-
it "
|
|
16
|
-
allow(
|
|
17
|
-
expect(
|
|
24
|
+
it "returns the url" do
|
|
25
|
+
allow(ping).to receive(:http_get).and_return(not_found_response)
|
|
26
|
+
expect(ping.call).to eq(["http://example.com"])
|
|
18
27
|
end
|
|
19
28
|
end
|
|
20
29
|
|
|
21
30
|
context "when there is a redirect" do
|
|
22
|
-
it "
|
|
31
|
+
it "follows the redirect and returns an empty array" do
|
|
23
32
|
redirect_response = Net::HTTPRedirection.new(1.0, "301", "Moved Permanently")
|
|
24
|
-
redirect_response["location"] = "
|
|
25
|
-
|
|
26
|
-
allow(
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
redirect_response["location"] = "/new"
|
|
34
|
+
allow(ping).to receive(:http_get).with(URI("http://example.com")).and_return(redirect_response)
|
|
35
|
+
allow(ping).to receive(:http_get).with(URI("http://example.com/new")).and_return(success_response)
|
|
36
|
+
expect(ping.call).to be_empty
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "when a transient error occurs" do
|
|
41
|
+
it "retries once before marking down" do
|
|
42
|
+
calls = 0
|
|
43
|
+
allow(ping).to receive(:http_get) do
|
|
44
|
+
calls += 1
|
|
45
|
+
raise Errno::ECONNRESET if calls == 1
|
|
46
|
+
|
|
47
|
+
success_response
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
expect(ping.call).to be_empty
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when errors persist across retries" do
|
|
55
|
+
it "returns the url" do
|
|
56
|
+
allow(ping).to receive(:http_get).and_raise(Errno::ECONNREFUSED)
|
|
57
|
+
expect(ping.call).to eq(["http://example.com"])
|
|
29
58
|
end
|
|
30
59
|
end
|
|
31
60
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Micah Geisel
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-12-
|
|
10
|
+
date: 2025-12-16 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: thor
|