bookbindery 1.0.0 → 2.0.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/lib/bookbinder/archive.rb +1 -1
- data/lib/bookbinder/archive_menu_configuration.rb +34 -0
- data/lib/bookbinder/book.rb +17 -17
- data/lib/bookbinder/cli.rb +25 -36
- data/lib/bookbinder/code_example.rb +5 -38
- data/lib/bookbinder/code_example_reader.rb +40 -0
- data/lib/bookbinder/colorizer.rb +14 -0
- data/lib/bookbinder/command_runner.rb +9 -16
- data/lib/bookbinder/command_validator.rb +14 -7
- data/lib/bookbinder/commands/bind.rb +321 -0
- data/lib/bookbinder/commands/build_and_push_tarball.rb +7 -6
- data/lib/bookbinder/commands/chain.rb +11 -0
- data/lib/bookbinder/commands/generate_pdf.rb +4 -3
- data/lib/bookbinder/commands/help.rb +49 -10
- data/lib/bookbinder/commands/naming.rb +9 -1
- data/lib/bookbinder/commands/push_local_to_staging.rb +4 -3
- data/lib/bookbinder/commands/push_to_prod.rb +36 -4
- data/lib/bookbinder/commands/run_publish_ci.rb +21 -24
- data/lib/bookbinder/commands/tag.rb +3 -3
- data/lib/bookbinder/commands/update_local_doc_repos.rb +5 -4
- data/lib/bookbinder/commands/version.rb +11 -8
- data/lib/bookbinder/configuration.rb +8 -3
- data/lib/bookbinder/configuration_fetcher.rb +7 -25
- data/lib/bookbinder/configuration_validator.rb +21 -0
- data/lib/bookbinder/distributor.rb +1 -1
- data/lib/bookbinder/dita_html_to_middleman_formatter.rb +37 -0
- data/lib/bookbinder/dita_section.rb +7 -0
- data/lib/bookbinder/dita_section_gatherer.rb +28 -0
- data/lib/bookbinder/git_accessor.rb +17 -0
- data/lib/bookbinder/git_client.rb +10 -7
- data/lib/bookbinder/git_hub_repository.rb +46 -41
- data/lib/bookbinder/local_dita_preprocessor.rb +27 -0
- data/lib/bookbinder/local_dita_to_html_converter.rb +49 -0
- data/lib/bookbinder/local_file_system_accessor.rb +68 -0
- data/lib/bookbinder/middleman_runner.rb +30 -17
- data/lib/bookbinder/pdf_generator.rb +1 -1
- data/lib/bookbinder/publisher.rb +16 -80
- data/lib/bookbinder/remote_yaml_credential_provider.rb +2 -3
- data/lib/bookbinder/repositories/command_repository.rb +156 -0
- data/lib/bookbinder/repositories/section_repository.rb +31 -0
- data/lib/bookbinder/section.rb +5 -67
- data/lib/bookbinder/shell_out.rb +1 -0
- data/lib/bookbinder/sheller.rb +19 -0
- data/lib/bookbinder/sieve.rb +6 -1
- data/lib/bookbinder/stabilimentum.rb +5 -1
- data/lib/bookbinder/terminal.rb +10 -0
- data/lib/bookbinder/user_message.rb +6 -0
- data/lib/bookbinder/user_message_presenter.rb +21 -0
- data/lib/bookbinder/yaml_loader.rb +18 -7
- data/lib/bookbinder.rb +2 -9
- data/master_middleman/archive_drop_down_menu.rb +46 -0
- data/master_middleman/bookbinder_helpers.rb +47 -40
- data/master_middleman/quicklinks_renderer.rb +1 -1
- metadata +33 -87
- data/lib/bookbinder/commands/publish.rb +0 -138
- data/lib/bookbinder/usage_messenger.rb +0 -33
- /data/{bin → install_bin}/bookbinder +0 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
require_relative '../archive_menu_configuration'
|
|
2
|
+
require_relative '../book'
|
|
3
|
+
require_relative '../cli_error'
|
|
4
|
+
require_relative '../directory_helpers'
|
|
5
|
+
require_relative '../publisher'
|
|
6
|
+
require_relative '../section'
|
|
7
|
+
require_relative '../dita_section'
|
|
8
|
+
require_relative '../dita_section_gatherer'
|
|
9
|
+
require_relative 'naming'
|
|
10
|
+
|
|
11
|
+
module Bookbinder
|
|
12
|
+
module Commands
|
|
13
|
+
class Bind
|
|
14
|
+
VersionUnsupportedError = Class.new(RuntimeError)
|
|
15
|
+
|
|
16
|
+
include Bookbinder::DirectoryHelperMethods
|
|
17
|
+
include Commands::Naming
|
|
18
|
+
|
|
19
|
+
def initialize(logger,
|
|
20
|
+
config_fetcher,
|
|
21
|
+
archive_menu_config,
|
|
22
|
+
version_control_system,
|
|
23
|
+
file_system_accessor,
|
|
24
|
+
static_site_generator,
|
|
25
|
+
sitemap_generator,
|
|
26
|
+
final_app_directory,
|
|
27
|
+
server_director,
|
|
28
|
+
context_dir,
|
|
29
|
+
dita_preprocessor)
|
|
30
|
+
@logger = logger
|
|
31
|
+
@config_fetcher = config_fetcher
|
|
32
|
+
@archive_menu_config = archive_menu_config
|
|
33
|
+
@version_control_system = version_control_system
|
|
34
|
+
@file_system_accessor = file_system_accessor
|
|
35
|
+
@static_site_generator = static_site_generator
|
|
36
|
+
@sitemap_generator = sitemap_generator
|
|
37
|
+
@final_app_directory = final_app_directory
|
|
38
|
+
@server_director = server_director
|
|
39
|
+
@context_dir = context_dir
|
|
40
|
+
@dita_preprocessor = dita_preprocessor
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def usage
|
|
44
|
+
["bind <local|github> [--verbose]",
|
|
45
|
+
"Bind the sections specified in config.yml from <local> or <github> into the final_app directory"]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def command_for?(test_command_name)
|
|
49
|
+
%w(bind publish).include?(test_command_name)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def deprecated_command_for?(command_name)
|
|
53
|
+
%w(publish).include?(command_name)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def run(cli_arguments)
|
|
57
|
+
raise CliError::InvalidArguments unless arguments_are_valid?(cli_arguments)
|
|
58
|
+
@section_repository = Repositories::SectionRepository.new(logger)
|
|
59
|
+
@gem_root = File.expand_path('../../../../', __FILE__)
|
|
60
|
+
|
|
61
|
+
@publisher = Publisher.new(logger, sitemap_generator, static_site_generator, server_director, file_system_accessor)
|
|
62
|
+
|
|
63
|
+
location = cli_arguments[0]
|
|
64
|
+
|
|
65
|
+
output_paths = output_directory_paths(location)
|
|
66
|
+
publish_config = publish_config(location)
|
|
67
|
+
@versions = publish_config.fetch(:versions, [])
|
|
68
|
+
@book_repo = publish_config[:book_repo]
|
|
69
|
+
|
|
70
|
+
master_middleman_dir = output_paths.fetch(:master_middleman_dir)
|
|
71
|
+
output_dir = output_paths.fetch(:output_dir)
|
|
72
|
+
|
|
73
|
+
dita_processing_dir = File.join output_dir, 'dita'
|
|
74
|
+
dita_section_dir = File.join dita_processing_dir, 'dita_sections'
|
|
75
|
+
dita_processed_dir = File.join dita_processing_dir, 'html_from_dita'
|
|
76
|
+
formatted_dir = File.join dita_processing_dir, 'site_generator_ready'
|
|
77
|
+
|
|
78
|
+
master_dir = File.join output_dir, 'master_middleman'
|
|
79
|
+
workspace_dir = File.join master_dir, 'source'
|
|
80
|
+
prepare_directories(final_app_directory,
|
|
81
|
+
output_dir,
|
|
82
|
+
workspace_dir,
|
|
83
|
+
master_middleman_dir,
|
|
84
|
+
master_dir,
|
|
85
|
+
dita_processing_dir,
|
|
86
|
+
formatted_dir)
|
|
87
|
+
|
|
88
|
+
dita_section_config_hash = config.dita_sections || {}
|
|
89
|
+
dita_sections = dita_section_config_hash.map do |dita_section_config|
|
|
90
|
+
relative_path_to_dita_map = dita_section_config['ditamap_location']
|
|
91
|
+
full_name = dita_section_config.fetch('repository', {}).fetch('name')
|
|
92
|
+
target_ref = dita_section_config.fetch('repository', {})['ref']
|
|
93
|
+
directory = dita_section_config['directory']
|
|
94
|
+
|
|
95
|
+
DitaSection.new(nil, relative_path_to_dita_map, full_name, target_ref, directory)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if location == 'github'
|
|
99
|
+
dita_section_gatherer = DitaSectionGatherer.new(version_control_system, logger)
|
|
100
|
+
final_dita_sections = dita_section_gatherer.gather(dita_sections, to: dita_section_dir)
|
|
101
|
+
else
|
|
102
|
+
final_dita_sections = dita_sections.map do |dita_section|
|
|
103
|
+
relative_path_to_dita_map = dita_section.ditamap_location
|
|
104
|
+
full_name = dita_section.full_name
|
|
105
|
+
target_ref = dita_section.target_ref
|
|
106
|
+
directory = dita_section.directory
|
|
107
|
+
|
|
108
|
+
path_to_local_copy = File.join output_paths[:local_repo_dir], directory
|
|
109
|
+
|
|
110
|
+
DitaSection.new(path_to_local_copy, relative_path_to_dita_map, full_name, target_ref, directory)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
dita_preprocessor.preprocess final_dita_sections, dita_processed_dir, formatted_dir, workspace_dir
|
|
115
|
+
|
|
116
|
+
sections = gather_sections(workspace_dir, output_paths)
|
|
117
|
+
|
|
118
|
+
subnavs = subnavs_by_dir_name(sections)
|
|
119
|
+
|
|
120
|
+
success = publisher.publish(
|
|
121
|
+
subnavs,
|
|
122
|
+
{verbose: cli_arguments.include?('--verbose')},
|
|
123
|
+
output_paths,
|
|
124
|
+
archive_menu_config.generate(publish_config, sections)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
success ? 0 : 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
attr_reader :publisher,
|
|
133
|
+
:version_control_system,
|
|
134
|
+
:config_fetcher,
|
|
135
|
+
:archive_menu_config,
|
|
136
|
+
:logger,
|
|
137
|
+
:file_system_accessor,
|
|
138
|
+
:static_site_generator,
|
|
139
|
+
:final_app_directory,
|
|
140
|
+
:sitemap_generator,
|
|
141
|
+
:server_director,
|
|
142
|
+
:context_dir,
|
|
143
|
+
:dita_preprocessor
|
|
144
|
+
|
|
145
|
+
def gather_sections(workspace, output_paths)
|
|
146
|
+
config.sections.map do |attributes|
|
|
147
|
+
|
|
148
|
+
local_repo_dir = output_paths[:local_repo_dir]
|
|
149
|
+
vcs_repo =
|
|
150
|
+
if local_repo_dir
|
|
151
|
+
GitHubRepository.
|
|
152
|
+
build_from_local(logger, attributes, local_repo_dir, version_control_system).
|
|
153
|
+
tap { |repo| repo.copy_from_local(workspace) }
|
|
154
|
+
else
|
|
155
|
+
GitHubRepository.
|
|
156
|
+
build_from_remote(logger, attributes, nil, version_control_system).
|
|
157
|
+
tap { |repo| repo.copy_from_remote(workspace) }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
@section_repository.get_instance(attributes,
|
|
161
|
+
vcs_repo: vcs_repo,
|
|
162
|
+
destination_dir: workspace,
|
|
163
|
+
build: ->(*args) { Section.new(*args) })
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def prepare_directories(final_app,
|
|
168
|
+
output_dir,
|
|
169
|
+
middleman_source,
|
|
170
|
+
master_middleman_dir,
|
|
171
|
+
middleman_dir,
|
|
172
|
+
dita_processing_dir,
|
|
173
|
+
formatted_dir)
|
|
174
|
+
forget_sections(output_dir)
|
|
175
|
+
file_system_accessor.remove_directory File.join final_app, '.'
|
|
176
|
+
file_system_accessor.remove_directory dita_processing_dir
|
|
177
|
+
file_system_accessor.make_directory output_dir
|
|
178
|
+
file_system_accessor.make_directory formatted_dir
|
|
179
|
+
file_system_accessor.make_directory File.join dita_processing_dir, 'dita_sections'
|
|
180
|
+
file_system_accessor.make_directory File.join final_app, 'public'
|
|
181
|
+
file_system_accessor.make_directory middleman_source
|
|
182
|
+
|
|
183
|
+
copy_directory_from_gem 'template_app', final_app
|
|
184
|
+
copy_directory_from_gem 'master_middleman', middleman_dir
|
|
185
|
+
file_system_accessor.copy File.join(master_middleman_dir, '.'), middleman_dir
|
|
186
|
+
|
|
187
|
+
copy_version_master_middleman(middleman_source)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def forget_sections(middleman_scratch)
|
|
191
|
+
file_system_accessor.remove_directory File.join middleman_scratch, '.'
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def copy_directory_from_gem(dir, output_dir)
|
|
195
|
+
file_system_accessor.copy File.join(@gem_root, "#{dir}/."), output_dir
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Copy the index file from each version into the version's directory. Because version
|
|
199
|
+
# subdirectories are sections, this is the only way they get content from their master
|
|
200
|
+
# middleman directory.
|
|
201
|
+
def copy_version_master_middleman(dest_dir)
|
|
202
|
+
@versions.each do |version|
|
|
203
|
+
Dir.mktmpdir(version) do |tmpdir|
|
|
204
|
+
book = Book.from_remote(logger: logger,
|
|
205
|
+
full_name: @book_repo,
|
|
206
|
+
destination_dir: tmpdir,
|
|
207
|
+
ref: version,
|
|
208
|
+
git_accessor: version_control_system)
|
|
209
|
+
index_source_dir = File.join(tmpdir, book.directory, 'master_middleman', source_dir_name)
|
|
210
|
+
index_dest_dir = File.join(dest_dir, version)
|
|
211
|
+
file_system_accessor.make_directory(index_dest_dir)
|
|
212
|
+
|
|
213
|
+
Dir.glob(File.join(index_source_dir, 'index.*')) do |f|
|
|
214
|
+
file_system_accessor.copy(File.expand_path(f), index_dest_dir)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def output_directory_paths(location)
|
|
221
|
+
local_repo_dir = (location == 'local') ? File.expand_path('..', context_dir) : nil
|
|
222
|
+
|
|
223
|
+
{
|
|
224
|
+
final_app_dir: final_app_directory,
|
|
225
|
+
local_repo_dir: local_repo_dir,
|
|
226
|
+
output_dir: File.join(context_dir, output_dir_name),
|
|
227
|
+
master_middleman_dir: layout_repo_path(local_repo_dir)
|
|
228
|
+
}
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def publish_config(location)
|
|
232
|
+
arguments = {
|
|
233
|
+
sections: config.sections,
|
|
234
|
+
book_repo: config.book_repo,
|
|
235
|
+
host_for_sitemap: config.public_host,
|
|
236
|
+
archive_menu: config.archive_menu
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
optional_arguments = {}
|
|
240
|
+
optional_arguments.merge!(template_variables: config.template_variables) if config.respond_to?(:template_variables)
|
|
241
|
+
if publishing_to_github? location
|
|
242
|
+
config.versions.each { |version| arguments[:sections].concat sections_from version }
|
|
243
|
+
optional_arguments.merge!(versions: config.versions)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
arguments.merge! optional_arguments
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def config
|
|
250
|
+
config_fetcher.fetch_config
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def sections_from(version)
|
|
254
|
+
Dir.mktmpdir('book_checkout') do |temp_workspace|
|
|
255
|
+
book = Book.from_remote(logger: logger,
|
|
256
|
+
full_name: config.book_repo,
|
|
257
|
+
destination_dir: temp_workspace,
|
|
258
|
+
ref: version,
|
|
259
|
+
git_accessor: version_control_system,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
book_checkout_value = File.join temp_workspace, book.directory
|
|
263
|
+
config_file = File.join book_checkout_value, 'config.yml'
|
|
264
|
+
attrs = YAML.load(File.read(config_file))['sections']
|
|
265
|
+
raise VersionUnsupportedError.new(version) if attrs.nil?
|
|
266
|
+
|
|
267
|
+
attrs.map do |section_hash|
|
|
268
|
+
section_hash['repository']['ref'] = version
|
|
269
|
+
section_hash['directory'] = File.join(version, section_hash['directory'])
|
|
270
|
+
section_hash
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def layout_repo_path(local_repo_dir)
|
|
276
|
+
if config.has_option?('layout_repo')
|
|
277
|
+
if local_repo_dir
|
|
278
|
+
File.join(local_repo_dir, config.layout_repo.split('/').last)
|
|
279
|
+
else
|
|
280
|
+
section = {'repository' => {'name' => config.layout_repo}}
|
|
281
|
+
destination_dir = Dir.mktmpdir
|
|
282
|
+
repository = GitHubRepository.build_from_remote(logger,
|
|
283
|
+
section,
|
|
284
|
+
'master',
|
|
285
|
+
version_control_system)
|
|
286
|
+
repository.copy_from_remote(destination_dir)
|
|
287
|
+
if repository
|
|
288
|
+
File.join(destination_dir, repository.directory)
|
|
289
|
+
else
|
|
290
|
+
raise 'failed to fetch repository'
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
else
|
|
294
|
+
File.absolute_path('master_middleman')
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def arguments_are_valid?(arguments)
|
|
299
|
+
return false unless arguments.any?
|
|
300
|
+
verbose = arguments[1] && arguments[1..-1].include?('--verbose')
|
|
301
|
+
tag_provided = arguments[1] && (arguments[1..-1] - ['--verbose']).any?
|
|
302
|
+
nothing_special = arguments[1..-1].empty?
|
|
303
|
+
|
|
304
|
+
%w(local github).include?(arguments[0]) && (tag_provided || verbose || nothing_special)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def publishing_to_github?(publish_location)
|
|
308
|
+
config.has_option?('versions') && publish_location != 'local'
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def subnavs_by_dir_name(sections)
|
|
312
|
+
sections.reduce({}) do |subnavs, section|
|
|
313
|
+
namespace = section.directory.gsub('/', '_')
|
|
314
|
+
template = section.subnav_template || 'default'
|
|
315
|
+
|
|
316
|
+
subnavs.merge(namespace => template)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -5,7 +5,7 @@ require_relative '../archive'
|
|
|
5
5
|
module Bookbinder
|
|
6
6
|
module Commands
|
|
7
7
|
class BuildAndPushTarball < BookbinderCommand
|
|
8
|
-
|
|
8
|
+
include Commands::Naming
|
|
9
9
|
|
|
10
10
|
class MissingBuildNumber < StandardError
|
|
11
11
|
def initialize
|
|
@@ -13,17 +13,18 @@ module Bookbinder
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def
|
|
17
|
-
|
|
16
|
+
def usage
|
|
17
|
+
[command_name,
|
|
18
|
+
"Create a tarball from the final_app directory and push to the S3 bucket specified in your credentials.yml"]
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def run(_)
|
|
21
22
|
raise MissingBuildNumber unless ENV['BUILD_NUMBER']
|
|
22
23
|
config = configuration_fetcher.fetch_config
|
|
23
24
|
aws_credentials = config.aws_credentials
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
archive = Archive.new(logger: @logger, key: aws_credentials.access_key, secret: aws_credentials.secret_key)
|
|
26
|
+
archive.create_and_upload_tarball(build_number: ENV['BUILD_NUMBER'], bucket: aws_credentials.green_builds_bucket,
|
|
27
|
+
namespace: GitHubRepository.new(logger: @logger, full_name: config.book_repo, git_accessor: Git).short_name)
|
|
27
28
|
0
|
|
28
29
|
end
|
|
29
30
|
end
|
|
@@ -6,7 +6,7 @@ require_relative 'naming'
|
|
|
6
6
|
module Bookbinder
|
|
7
7
|
module Commands
|
|
8
8
|
class GeneratePDF < BookbinderCommand
|
|
9
|
-
|
|
9
|
+
include Commands::Naming
|
|
10
10
|
|
|
11
11
|
class AppNotPublished < StandardError
|
|
12
12
|
def initialize(msg='You must publish locally before you generate a PDF.')
|
|
@@ -32,8 +32,9 @@ module Bookbinder
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def
|
|
36
|
-
"generate_pdf [<file_name>.yml]
|
|
35
|
+
def usage
|
|
36
|
+
["generate_pdf [<file_name>.yml]",
|
|
37
|
+
"Generate a PDF from the files specified in <file_name.yml>"]
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
def run(params)
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
require_relative 'naming'
|
|
2
|
+
|
|
1
3
|
module Bookbinder
|
|
2
4
|
module Commands
|
|
3
5
|
class Help
|
|
4
|
-
|
|
5
|
-
@logger = logger
|
|
6
|
-
@usage_message = usage_message
|
|
7
|
-
end
|
|
6
|
+
include Commands::Naming
|
|
8
7
|
|
|
9
|
-
def
|
|
10
|
-
|
|
8
|
+
def initialize(logger, other_commands)
|
|
9
|
+
@logger = logger
|
|
10
|
+
@other_commands = other_commands
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def
|
|
13
|
+
def command_name
|
|
14
14
|
'--help'
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def
|
|
18
|
-
"
|
|
17
|
+
def usage
|
|
18
|
+
[command_name, "Print this message"]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def run(*)
|
|
@@ -23,9 +23,48 @@ module Bookbinder
|
|
|
23
23
|
0
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def usage_message
|
|
27
|
+
[usage_header, command_usage_messages].join("\n")
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
private
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
def command_usage_messages
|
|
33
|
+
(flags + standard_commands).reduce('') { |message, command|
|
|
34
|
+
"#{message}#{usage_indent}#{formatted_usage(command)}\n"
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def formatted_usage(command)
|
|
39
|
+
"#{command.usage[0].ljust(chars_for_usage_definition)}#{command.usage[1]}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def usage_indent
|
|
43
|
+
" " * 4
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def chars_for_usage_definition
|
|
47
|
+
33
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def flags
|
|
51
|
+
other_commands.select(&:flag?) + [self]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def standard_commands
|
|
55
|
+
other_commands.reject(&:flag?)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def usage_header
|
|
59
|
+
<<TEXT
|
|
60
|
+
|
|
61
|
+
\e[1;39;49mDocumentation\e[0m: https://github.com/pivotal-cf/docs-bookbinder
|
|
62
|
+
|
|
63
|
+
\e[1;39;49mUsage\e[0m: bookbinder <command|flag> [args]
|
|
64
|
+
TEXT
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
attr_reader :logger, :other_commands
|
|
29
68
|
end
|
|
30
69
|
end
|
|
31
70
|
end
|
|
@@ -2,7 +2,15 @@ module Bookbinder
|
|
|
2
2
|
module Commands
|
|
3
3
|
module Naming
|
|
4
4
|
def command_name
|
|
5
|
-
name.demodulize.underscore
|
|
5
|
+
self.class.name.demodulize.underscore
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def command_for?(test_command_name)
|
|
9
|
+
command_name == test_command_name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def flag?
|
|
13
|
+
command_name.match(/^--/)
|
|
6
14
|
end
|
|
7
15
|
end
|
|
8
16
|
end
|
|
@@ -5,10 +5,11 @@ require_relative 'naming'
|
|
|
5
5
|
module Bookbinder
|
|
6
6
|
module Commands
|
|
7
7
|
class PushLocalToStaging < BookbinderCommand
|
|
8
|
-
|
|
8
|
+
include Commands::Naming
|
|
9
9
|
|
|
10
|
-
def
|
|
11
|
-
|
|
10
|
+
def usage
|
|
11
|
+
[command_name,
|
|
12
|
+
"Push the contents of final_app to the staging host specified in credentials.yml"]
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def run(_)
|
|
@@ -3,21 +3,35 @@ require_relative 'bookbinder_command'
|
|
|
3
3
|
require_relative 'naming'
|
|
4
4
|
|
|
5
5
|
module Bookbinder
|
|
6
|
+
class PushToProdValidator
|
|
7
|
+
MissingRequiredKeyError = Class.new(RuntimeError)
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
module Commands
|
|
7
|
-
class PushToProd
|
|
8
|
-
|
|
11
|
+
class PushToProd
|
|
12
|
+
include Commands::Naming
|
|
13
|
+
CONFIG_REQUIRED_KEYS = %w(cred_repo)
|
|
14
|
+
|
|
15
|
+
def initialize(logger, configuration_fetcher)
|
|
16
|
+
@logger = logger
|
|
17
|
+
@configuration_fetcher = configuration_fetcher
|
|
18
|
+
end
|
|
9
19
|
|
|
10
|
-
def
|
|
11
|
-
"push_to_prod [build_#]
|
|
20
|
+
def usage
|
|
21
|
+
["push_to_prod [build_#]",
|
|
22
|
+
"Push latest or <build_#> from your S3 bucket to the production host specified in credentials.yml"]
|
|
12
23
|
end
|
|
13
24
|
|
|
14
25
|
def run(arguments)
|
|
26
|
+
validate
|
|
15
27
|
Distributor.build(@logger, options(arguments)).distribute
|
|
16
28
|
0
|
|
17
29
|
end
|
|
18
30
|
|
|
19
31
|
private
|
|
20
32
|
|
|
33
|
+
attr_reader :configuration_fetcher
|
|
34
|
+
|
|
21
35
|
def options(arguments)
|
|
22
36
|
{
|
|
23
37
|
app_dir: Dir.mktmpdir,
|
|
@@ -30,6 +44,24 @@ module Bookbinder
|
|
|
30
44
|
production: true
|
|
31
45
|
}
|
|
32
46
|
end
|
|
47
|
+
|
|
48
|
+
def config
|
|
49
|
+
@config ||= configuration_fetcher.fetch_config
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def validate
|
|
53
|
+
missing_keys = []
|
|
54
|
+
CONFIG_REQUIRED_KEYS.map do |required_key|
|
|
55
|
+
unless config.has_option?(required_key)
|
|
56
|
+
missing_keys.push(required_key)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if missing_keys.length > 0
|
|
61
|
+
raise PushToProdValidator::MissingRequiredKeyError.new "Your config.yml is missing required key(s). The require keys for this commands are " + missing_keys.join(", ")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
33
65
|
end
|
|
34
66
|
end
|
|
35
67
|
end
|
|
@@ -1,42 +1,39 @@
|
|
|
1
|
-
require_relative '
|
|
1
|
+
require_relative 'bind'
|
|
2
|
+
require_relative 'build_and_push_tarball'
|
|
3
|
+
require_relative 'chain'
|
|
2
4
|
require_relative 'naming'
|
|
3
|
-
require_relative 'publish'
|
|
4
5
|
require_relative 'push_local_to_staging'
|
|
5
|
-
require_relative 'build_and_push_tarball'
|
|
6
6
|
|
|
7
7
|
module Bookbinder
|
|
8
8
|
module Commands
|
|
9
|
-
class RunPublishCI
|
|
10
|
-
|
|
9
|
+
class RunPublishCI
|
|
10
|
+
include Commands::Naming
|
|
11
|
+
include Commands::Chain
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
-
|
|
13
|
+
def usage
|
|
14
|
+
[command_name,
|
|
15
|
+
"Run publish, push_local_to_staging, and build_and_push_tarball for CI purposes"]
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
def
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
def initialize(publish_command, push_local_to_staging_command, build_and_push_tarball_command)
|
|
19
|
+
@publish_command = publish_command
|
|
20
|
+
@push_local_to_staging_command = push_local_to_staging_command
|
|
21
|
+
@build_and_push_tarball_command = build_and_push_tarball_command
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def check_params
|
|
24
|
+
def run(cli_args)
|
|
25
25
|
raise BuildAndPushTarball::MissingBuildNumber unless ENV['BUILD_NUMBER']
|
|
26
|
-
config.book_repo
|
|
27
|
-
end
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
command_chain(
|
|
28
|
+
->{publish_command.run(['github'] + cli_args)},
|
|
29
|
+
->{push_local_to_staging_command.run([])},
|
|
30
|
+
->{build_and_push_tarball_command.run([])}
|
|
31
|
+
)
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
PushLocalToStaging.new(@logger, @configuration_fetcher).run []
|
|
35
|
-
end
|
|
34
|
+
private
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
BuildAndPushTarball.new(@logger, @configuration_fetcher).run []
|
|
39
|
-
end
|
|
36
|
+
attr_reader :publish_command, :push_local_to_staging_command, :build_and_push_tarball_command
|
|
40
37
|
end
|
|
41
38
|
end
|
|
42
39
|
end
|
|
@@ -8,10 +8,10 @@ require_relative 'naming'
|
|
|
8
8
|
module Bookbinder
|
|
9
9
|
module Commands
|
|
10
10
|
class Tag < BookbinderCommand
|
|
11
|
-
|
|
11
|
+
include Commands::Naming
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
"tag <git tag>
|
|
13
|
+
def usage
|
|
14
|
+
["tag <git tag>", "Apply the specified <git tag> to your book and all sections of your book"]
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def run(params)
|
|
@@ -4,10 +4,11 @@ require_relative 'naming'
|
|
|
4
4
|
module Bookbinder
|
|
5
5
|
module Commands
|
|
6
6
|
class UpdateLocalDocRepos < BookbinderCommand
|
|
7
|
-
|
|
7
|
+
include Commands::Naming
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
|
|
9
|
+
def usage
|
|
10
|
+
[command_name,
|
|
11
|
+
"Run `git pull` on all sections that exist at the same directory level as your book directory"]
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def run(_)
|
|
@@ -20,7 +21,7 @@ module Bookbinder
|
|
|
20
21
|
def repo_for(section_config)
|
|
21
22
|
local_repo_dir = File.absolute_path('../')
|
|
22
23
|
GitHubRepository.new(logger: @logger, full_name: section_config['repository']['name'],
|
|
23
|
-
local_repo_dir: local_repo_dir)
|
|
24
|
+
local_repo_dir: local_repo_dir, git_accessor: Git)
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
end
|