bookbindery 8.5.0 → 9.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bookbinder.gemspec +1 -1
- data/lib/bookbinder/cli.rb +36 -55
- data/lib/bookbinder/commands/bind.rb +3 -19
- data/lib/bookbinder/commands/collection.rb +33 -73
- data/lib/bookbinder/commands/components/command_options.rb +3 -22
- data/lib/bookbinder/commands/generate.rb +0 -11
- data/lib/bookbinder/commands/imprint.rb +3 -10
- data/lib/bookbinder/commands/punch.rb +0 -11
- data/lib/bookbinder/commands/update_local_doc_repos.rb +1 -9
- data/lib/bookbinder/commands/watch.rb +1 -10
- data/lib/bookbinder/config/fetcher.rb +2 -18
- data/lib/bookbinder/preprocessing/dita_html_preprocessor.rb +3 -6
- data/lib/bookbinder/preprocessing/dita_pdf_preprocessor.rb +3 -5
- data/lib/bookbinder/terminal.rb +0 -1
- metadata +3 -31
- data/lib/bookbinder/cf_command_runner.rb +0 -123
- data/lib/bookbinder/command_runner.rb +0 -23
- data/lib/bookbinder/command_validator.rb +0 -51
- data/lib/bookbinder/commands/build_and_push_tarball.rb +0 -38
- data/lib/bookbinder/commands/chain.rb +0 -11
- data/lib/bookbinder/commands/help.rb +0 -70
- data/lib/bookbinder/commands/naming.rb +0 -29
- data/lib/bookbinder/commands/push_from_local.rb +0 -132
- data/lib/bookbinder/commands/push_to_prod.rb +0 -66
- data/lib/bookbinder/commands/run_publish_ci.rb +0 -37
- data/lib/bookbinder/commands/version.rb +0 -29
- data/lib/bookbinder/config/aws_credentials.rb +0 -21
- data/lib/bookbinder/config/cf_credentials.rb +0 -62
- data/lib/bookbinder/config/remote_yaml_credential_provider.rb +0 -22
- data/lib/bookbinder/deploy/app_fetcher.rb +0 -36
- data/lib/bookbinder/deploy/archive.rb +0 -102
- data/lib/bookbinder/deploy/artifact.rb +0 -26
- data/lib/bookbinder/deploy/blue_green_app.rb +0 -29
- data/lib/bookbinder/deploy/cf_routes.rb +0 -32
- data/lib/bookbinder/deploy/deployment.rb +0 -55
- data/lib/bookbinder/deploy/distributor.rb +0 -76
- data/lib/bookbinder/deploy/failure.rb +0 -15
- data/lib/bookbinder/deploy/pusher.rb +0 -34
- data/lib/bookbinder/deploy/success.rb +0 -16
- data/lib/bookbinder/deprecated_logger.rb +0 -33
- data/lib/bookbinder/errors/cli_error.rb +0 -6
- data/lib/bookbinder/legacy/cli.rb +0 -71
- data/lib/bookbinder/preprocessing/dita_preprocessor.rb +0 -17
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require 'ansi/code'
|
3
|
-
|
4
|
-
module Bookbinder
|
5
|
-
module Config
|
6
|
-
class RemoteYamlCredentialProvider
|
7
|
-
def initialize(logger, version_control_system)
|
8
|
-
@logger = logger
|
9
|
-
@version_control_system = version_control_system
|
10
|
-
end
|
11
|
-
|
12
|
-
def credentials(repo_url)
|
13
|
-
logger.log "Processing #{ANSI.cyan{repo_url}}"
|
14
|
-
YAML.load(version_control_system.read_file("credentials.yml", from_repo: repo_url))
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
attr_reader :logger, :version_control_system
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require_relative 'blue_green_app'
|
2
|
-
require_relative 'cf_routes'
|
3
|
-
|
4
|
-
module Bookbinder
|
5
|
-
module Deploy
|
6
|
-
class AppFetcher
|
7
|
-
def initialize(routes_to_search, cf_command_runner)
|
8
|
-
@routes_to_search = routes_to_search
|
9
|
-
@cf_command_runner = cf_command_runner
|
10
|
-
end
|
11
|
-
|
12
|
-
def fetch_current_app
|
13
|
-
raw_cf_routes = cf_command_runner.cf_routes_output
|
14
|
-
cf_routes = CfRoutes.new(raw_cf_routes)
|
15
|
-
|
16
|
-
existing_hosts = routes_to_search.select do |domain, host|
|
17
|
-
cf_routes.apps_by_host_and_domain.has_key?([host, domain])
|
18
|
-
end
|
19
|
-
|
20
|
-
return nil if existing_hosts.empty?
|
21
|
-
app_groups = existing_hosts.map { |domain, host| apps_for_host(cf_routes, domain, host) }
|
22
|
-
apps_for_existing_routes = app_groups.first
|
23
|
-
apps_for_existing_routes.first
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
attr_reader :routes_to_search, :cf_command_runner
|
29
|
-
|
30
|
-
def apps_for_host(routes_from_cf, domain, host)
|
31
|
-
routes_from_cf.apps_by_host_and_domain.fetch([host, domain], []).
|
32
|
-
map &BlueGreenApp.method(:new)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'fog/aws'
|
2
|
-
require 'tmpdir'
|
3
|
-
require_relative '../deprecated_logger'
|
4
|
-
require_relative 'artifact'
|
5
|
-
require_relative 'success'
|
6
|
-
|
7
|
-
module Bookbinder
|
8
|
-
module Deploy
|
9
|
-
class Archive
|
10
|
-
class FileDoesNotExist < StandardError; end
|
11
|
-
class NoNamespaceGiven < StandardError; end
|
12
|
-
|
13
|
-
def initialize(logger: nil, key: '', secret: '')
|
14
|
-
@logger = logger
|
15
|
-
@aws_key = key
|
16
|
-
@aws_secret_key = secret
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_and_upload_tarball(
|
20
|
-
app_dir: 'final_app',
|
21
|
-
bucket: '',
|
22
|
-
build_number: nil,
|
23
|
-
namespace: nil
|
24
|
-
)
|
25
|
-
tarball_filename, tarball_path = create_tarball(app_dir, build_number, namespace)
|
26
|
-
upload_file(bucket, tarball_filename, tarball_path)
|
27
|
-
Success.new("Green build ##{build_number} has been uploaded to S3 for #{namespace}")
|
28
|
-
end
|
29
|
-
|
30
|
-
def upload_file(bucket, name, source_path)
|
31
|
-
find_or_create_directory(bucket).
|
32
|
-
files.create(key: name,
|
33
|
-
body: File.read(source_path),
|
34
|
-
public: true)
|
35
|
-
end
|
36
|
-
|
37
|
-
def download(download_dir: nil, bucket: nil, build_number: nil, namespace: nil)
|
38
|
-
raise NoNamespaceGiven, 'One must specify a namespace to find files in this bucket' unless namespace
|
39
|
-
|
40
|
-
directory = connection.directories.get bucket
|
41
|
-
build_number ||= latest_build_number_for_namespace(directory, namespace)
|
42
|
-
filename = Artifact.new(namespace, build_number, 'tgz').filename
|
43
|
-
|
44
|
-
s3_file = directory.files.get(filename)
|
45
|
-
raise FileDoesNotExist, "Unable to find tarball on AWS for book '#{namespace}', build number: #{build_number}" unless s3_file
|
46
|
-
|
47
|
-
downloaded_file = File.join(Dir.mktmpdir, 'downloaded.tgz')
|
48
|
-
File.open(downloaded_file, 'wb') { |f| f.write(s3_file.body) }
|
49
|
-
Dir.chdir(download_dir) { `tar xzf #{downloaded_file}` }
|
50
|
-
|
51
|
-
@logger.log "Green build ##{build_number.to_s.green} has been downloaded from S3 and untarred into #{download_dir.to_s.cyan}"
|
52
|
-
end
|
53
|
-
|
54
|
-
def tarball_name_regex(namespace)
|
55
|
-
/^#{namespace}-(\d+_?\d*)\.tgz/
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def find_or_create_directory(name)
|
61
|
-
connection.directories.create(key: name)
|
62
|
-
rescue Excon::Errors::Conflict
|
63
|
-
connection.directories.get(name)
|
64
|
-
end
|
65
|
-
|
66
|
-
def create_tarball(app_dir, build_number, namespace)
|
67
|
-
tarball_filename = Artifact.new(namespace, build_number, 'tgz').filename
|
68
|
-
tarball_path = File.join(Dir.mktmpdir, tarball_filename)
|
69
|
-
|
70
|
-
Dir.chdir(app_dir) { `tar czf #{tarball_path} *` }
|
71
|
-
return tarball_filename, tarball_path
|
72
|
-
end
|
73
|
-
|
74
|
-
def latest_build_number_for_namespace(directory, namespace)
|
75
|
-
all_files = all_files_workaround_for_fog_map_limitation(directory.files)
|
76
|
-
|
77
|
-
all_files_with_namespace = all_files.map do |file|
|
78
|
-
filename = file.key
|
79
|
-
file if filename[tarball_name_regex(namespace)]
|
80
|
-
end.compact
|
81
|
-
|
82
|
-
return nil if all_files_with_namespace.empty?
|
83
|
-
most_recent_file = all_files_with_namespace.sort_by { |file| file.last_modified }.last
|
84
|
-
|
85
|
-
most_recent_filename = most_recent_file.key
|
86
|
-
most_recent_filename[tarball_name_regex(namespace), 1]
|
87
|
-
end
|
88
|
-
|
89
|
-
def connection
|
90
|
-
@connection ||= Fog::Storage.new :provider => 'AWS',
|
91
|
-
:aws_access_key_id => @aws_key,
|
92
|
-
:aws_secret_access_key => @aws_secret_key
|
93
|
-
end
|
94
|
-
|
95
|
-
def all_files_workaround_for_fog_map_limitation(files)
|
96
|
-
all_files = []
|
97
|
-
files.each { |f| all_files << f }
|
98
|
-
all_files
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Bookbinder
|
2
|
-
module Deploy
|
3
|
-
class Artifact
|
4
|
-
attr_reader :namespace
|
5
|
-
|
6
|
-
def initialize(namespace, build_number, extension, path = '.')
|
7
|
-
@namespace = namespace
|
8
|
-
@build_number = build_number
|
9
|
-
@path = path
|
10
|
-
@extension = extension
|
11
|
-
end
|
12
|
-
|
13
|
-
def full_path
|
14
|
-
File.join(path, filename)
|
15
|
-
end
|
16
|
-
|
17
|
-
def filename
|
18
|
-
"#{namespace}-#{build_number}.#{extension}"
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
attr_reader :build_number, :path, :extension
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Bookbinder
|
2
|
-
module Deploy
|
3
|
-
class BlueGreenApp
|
4
|
-
def initialize(name)
|
5
|
-
@name = name.strip
|
6
|
-
end
|
7
|
-
|
8
|
-
def ==(other)
|
9
|
-
to_s == other.to_s
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
name
|
14
|
-
end
|
15
|
-
|
16
|
-
def with_flipped_name
|
17
|
-
if name.match(/green$/)
|
18
|
-
BlueGreenApp.new(name.sub(/green$/, 'blue'))
|
19
|
-
else
|
20
|
-
BlueGreenApp.new(name.sub(/blue$/, 'green'))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
attr_reader :name
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Bookbinder
|
2
|
-
module Deploy
|
3
|
-
class CfRoutes
|
4
|
-
def initialize(raw_routes)
|
5
|
-
@raw_routes = raw_routes
|
6
|
-
end
|
7
|
-
|
8
|
-
def apps_by_host_and_domain
|
9
|
-
@apps_by_host_and_domain ||= data(raw_routes).reduce({}) {|acc, row|
|
10
|
-
parsed_row = Hash[headers(raw_routes).zip(row)]
|
11
|
-
acc.merge(parsed_row.values_at('host', 'domain') => parse_apps(parsed_row['apps']))
|
12
|
-
}
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
attr_reader :raw_routes
|
18
|
-
|
19
|
-
def parse_apps(apps)
|
20
|
-
apps.split(',').map(&:strip) unless apps.nil?
|
21
|
-
end
|
22
|
-
|
23
|
-
def headers(raw)
|
24
|
-
raw.lines[2].split(/\s+/)
|
25
|
-
end
|
26
|
-
|
27
|
-
def data(raw)
|
28
|
-
raw.lines[3..-1].map {|line| line.split(/\s+/, headers(raw).size)}
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module Bookbinder
|
2
|
-
module Deploy
|
3
|
-
class Deployment
|
4
|
-
attr_reader :app_dir, :build_number, :cf_credentials
|
5
|
-
|
6
|
-
def initialize(app_dir: nil,
|
7
|
-
aws_credentials: nil,
|
8
|
-
book_repo: nil,
|
9
|
-
build_number: nil,
|
10
|
-
cf_credentials: nil)
|
11
|
-
@app_dir = app_dir
|
12
|
-
@aws_credentials = aws_credentials
|
13
|
-
@book_repo = book_repo
|
14
|
-
@build_number = build_number
|
15
|
-
@cf_credentials = cf_credentials
|
16
|
-
end
|
17
|
-
|
18
|
-
def artifact_filename
|
19
|
-
artifact.filename
|
20
|
-
end
|
21
|
-
|
22
|
-
def artifact_full_path
|
23
|
-
artifact.full_path
|
24
|
-
end
|
25
|
-
|
26
|
-
def aws_access_key
|
27
|
-
aws_credentials.access_key
|
28
|
-
end
|
29
|
-
|
30
|
-
def aws_secret_key
|
31
|
-
aws_credentials.secret_key
|
32
|
-
end
|
33
|
-
|
34
|
-
def flat_routes
|
35
|
-
cf_credentials.flat_routes
|
36
|
-
end
|
37
|
-
|
38
|
-
def green_builds_bucket
|
39
|
-
aws_credentials.green_builds_bucket
|
40
|
-
end
|
41
|
-
|
42
|
-
def namespace
|
43
|
-
Ingest::DestinationDirectory.new(book_repo)
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
attr_reader :aws_credentials, :book_repo
|
49
|
-
|
50
|
-
def artifact
|
51
|
-
Artifact.new(namespace, build_number, 'log', '/tmp')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require_relative '../cf_command_runner'
|
2
|
-
require_relative '../ingest/destination_directory'
|
3
|
-
require_relative '../sheller'
|
4
|
-
require_relative 'app_fetcher'
|
5
|
-
require_relative 'archive'
|
6
|
-
require_relative 'artifact'
|
7
|
-
require_relative 'pusher'
|
8
|
-
|
9
|
-
module Bookbinder
|
10
|
-
module Deploy
|
11
|
-
class Distributor
|
12
|
-
EXPIRATION_HOURS = 2
|
13
|
-
|
14
|
-
def self.build(streams, archive, deployment)
|
15
|
-
cf_command_runner = CfCommandRunner.new(streams, Sheller.new, deployment.cf_credentials, deployment.artifact_full_path)
|
16
|
-
cf_app_fetcher = AppFetcher.new(deployment.flat_routes, cf_command_runner)
|
17
|
-
pusher = Pusher.new(cf_command_runner, cf_app_fetcher)
|
18
|
-
new(streams, archive, pusher, deployment)
|
19
|
-
end
|
20
|
-
|
21
|
-
def initialize(streams, archive, pusher, deployment)
|
22
|
-
@streams = streams
|
23
|
-
@archive = archive
|
24
|
-
@pusher = pusher
|
25
|
-
@deployment = deployment
|
26
|
-
end
|
27
|
-
|
28
|
-
def distribute
|
29
|
-
push_app
|
30
|
-
nil
|
31
|
-
rescue => e
|
32
|
-
streams[:err].puts(<<-ERROR.chomp)
|
33
|
-
[ERROR] #{e.message}
|
34
|
-
[DEBUG INFO]
|
35
|
-
CF organization: #{cf_credentials.organization}
|
36
|
-
CF space: #{cf_credentials.space}
|
37
|
-
CF account: #{cf_credentials.username}
|
38
|
-
routes: #{cf_credentials.routes}
|
39
|
-
ERROR
|
40
|
-
raise
|
41
|
-
ensure
|
42
|
-
upload_trace
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
attr_reader :archive, :deployment, :pusher, :streams
|
48
|
-
|
49
|
-
def push_app
|
50
|
-
pusher.push(deployment.app_dir)
|
51
|
-
end
|
52
|
-
|
53
|
-
def upload_trace
|
54
|
-
uploaded_file = archive.upload_file(deployment.green_builds_bucket, deployment.artifact_filename, deployment.artifact_full_path)
|
55
|
-
log_success(
|
56
|
-
["Your cf trace file is available at: #{uploaded_file.url(Time.now.to_i + EXPIRATION_HOURS*60*60)}",
|
57
|
-
"This URL will expire in #{EXPIRATION_HOURS} hours, so if you need to share it, make sure to save a copy now."]
|
58
|
-
)
|
59
|
-
rescue Errno::ENOENT
|
60
|
-
log_error("Could not find CF trace file: #{deployment.artifact_full_path}")
|
61
|
-
end
|
62
|
-
|
63
|
-
def cf_credentials
|
64
|
-
deployment.cf_credentials
|
65
|
-
end
|
66
|
-
|
67
|
-
def log_success(message)
|
68
|
-
streams[:success].puts(message)
|
69
|
-
end
|
70
|
-
|
71
|
-
def log_error(message)
|
72
|
-
streams[:err].puts(message)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Bookbinder
|
2
|
-
module Deploy
|
3
|
-
class Pusher
|
4
|
-
def initialize(cf_cli, app_fetcher)
|
5
|
-
@cf_cli = cf_cli
|
6
|
-
@app_fetcher = app_fetcher
|
7
|
-
end
|
8
|
-
|
9
|
-
def push(app_dir)
|
10
|
-
Dir.chdir(app_dir) do
|
11
|
-
cf_cli.login
|
12
|
-
|
13
|
-
old_app = app_fetcher.fetch_current_app
|
14
|
-
|
15
|
-
if old_app
|
16
|
-
new_app = old_app.with_flipped_name
|
17
|
-
cf_cli.start(new_app)
|
18
|
-
cf_cli.push(new_app)
|
19
|
-
cf_cli.map_routes(new_app)
|
20
|
-
cf_cli.takedown_old_target_app(old_app)
|
21
|
-
else
|
22
|
-
new_app = cf_cli.new_app
|
23
|
-
cf_cli.push(new_app)
|
24
|
-
cf_cli.map_routes(new_app)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
attr_reader :cf_cli, :app_fetcher
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|