Skip to content

Commit 8a0dc23

Browse files
committed
Merge pull request #7 from nhr/distro_handling
Doc'ed distro handling and added distro support to builder
2 parents 26a7fd7 + 2438305 commit 8a0dc23

File tree

3 files changed

+240
-34
lines changed

3 files changed

+240
-34
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
source "https://rubygems.org"
22

33
gem 'asciidoctor'
4+
gem 'git'
45
gem 'guard'
56
gem 'guard-shell'
67
gem 'guard-livereload'

README.adoc

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,6 @@ This repo contains the documentation for
88
99
The documentation is sourced in http://www.methods.co.nz/asciidoc/[AsciiDoc] and transformed into HTML/CSS and other formats through http://asciidoctor.org/[AsciiDoctor]-based automation.
1010

11-
== Branches
12-
13-
Documentation for different OpenShift distributions is handled on different branches.
14-
15-
* `master` - OpenShift Origin latest code
16-
* `openshift-origin-release-N` - OpenShift Origin most recent stable release
17-
* `openshift-online` - OpenShift Online most recent release
18-
* `enterprise-N.N` - OpenShift Enterprise support releases
19-
2011
== Repo Organization
2112

2213
Each directory of the repo represents a different collection of topics (you can think of directories as books). The exception is the `build_system` directory, which contains the code used to generate the finished documentation. Within each 'book' directory, topics exist as separate asciidoc files and an `images` directory contains any images that are included in the topics.
@@ -33,27 +24,101 @@ Each directory of the repo represents a different collection of topics (you can
3324
/bookN
3425
----
3526

36-
== Metadata
27+
== Version Management
28+
The overlap of documentation across OpenShifts Origin, Online and Enterprise is no less than 80%. In many cases, this means that individual topics may need to include or exclude individual paragraphs with respect to a specific OpenShift distribution. While it is _possible_ to accomplish this solely by using git branches to maintain slightly different versions of a given topic, doing so would make the task of maintaining internal consistency extrememely difficult for content contributors.
29+
30+
Git branching is still extremely valuable, and serves the important role of tracking the release versions of documentation for the various OpenShift distributions.
31+
32+
=== Distribution-Specific Conditionals
33+
OpenShift documentation uses AsciiDoc's `ifdef/endif` macro to conditionalize document segments for specific OpenShift distributions down to the single-line level.
34+
35+
The supported distribution attributes used in the OpenShift document generator are:
36+
37+
* `openshift-origin`
38+
* `openshift-online`
39+
* `openshift-enterprise`
40+
41+
These attributes can be used alone or together to conditionalize text within a topic document.
42+
43+
Here is an example of this concept in use:
44+
45+
----
46+
This first line is unconditionalized, and will appear for all versions.
47+
48+
\ifdef::openshift-online[]
49+
This line will only appear for OpenShift Online.
50+
\endif::[]
51+
52+
\ifdef::openshift-enterprise[]
53+
This line will only appear for OpenShift Enterprise.
54+
\endif::[]
55+
56+
\ifdef::openshift-origin,openshift-enterprise[]
57+
This line will appear for OpenShift Origin and Enterprise, but not for OpenShift Online.
58+
\endif::[]
59+
----
60+
61+
Two important points to keep in mind:
62+
63+
* The `ifdef/endif` blocks have no size limit, however they should _not_ be used to conditionalize an entire topic. If an entire topic file is specific to a given OpenShift distribution, refer to the link:#document-set-metadata[Document Set Metadata] section for information on how to conditionalize at the whole-topic level.
64+
65+
* The `ifdef/endif` blocks _cannot be nested_. In other words, one conditional block cannot contain other conditional blocks.
66+
67+
=== Release Branches
68+
Through the use of link:#distribution-specific-conditionals[Distribution-Specific Conditionals] and link:#document-set-metadata[Document Set Metadata], the master branch of this repository always contains a complete set of documentation that includes all of the OpenShift distributions. However, when and as new versions of the OpenShift distros are released, the master branch is merged down to new or existing release branches. Here is the general naming scheme used in the branches:
69+
70+
* `master` - OpenShift Origin latest code
71+
* `origin-N.N` - OpenShift Origin most recent stable release
72+
* `online` - OpenShift Online most recent release
73+
* `enterprise-N.N` - OpenShift Enterprise support releases
74+
75+
On a nightly basis, the documentation is rebuilt for each of these branches. In this manner, documentation for released versions of OpenShift will remain the same even as development continues on master. Additionally, any corrections or additions that are "cherry-picked" into the release branches will show up in the release documentation the next day.
76+
77+
== Document Set Metadata
78+
In order to construct the documentation site from these sources, the build system looks at the `_build_cfg.yml` metdata file. The build system _only_ looks in this file for information on which files to include, so any new file submissions must be accompanied by an update to this metadata file.
3779

38-
In order to construct the documentation site from these sources, the build system looks at the `_build_cfg.yml` metdata file. The format of this files is as indicated:
80+
=== File Format
81+
The format of this file is as indicated:
3982

4083
----
4184
--- <1>
4285
Name: Origin of the Species <2>
4386
Dir: origin_of_the_species <3>
87+
Distros: all <4>
4488
Topics:
45-
- Name: The Majestic Marmoset <4>
46-
File: the_majestic_marmoset <5>
89+
- Name: The Majestic Marmoset <5>
90+
File: the_majestic_marmoset <6>
91+
Distros: all
4792
- Name: The Curious Crocodile
4893
File: the_curious_crocodile
94+
Distros: openshift-online,openshift-enterprise <7>
4995
----
5096
<1> Record separator at the top of each topic group
5197
<2> Display name of topic group
5298
<3> Directory name of topic group
53-
<4> Topic name
54-
<5> Topic file under the topic group dir withour without '.adoc'
99+
<4> Which OpenShift versions this topic group is part of
100+
<5> Topic name
101+
<6> Topic file under the topic group dir without '.adoc'
102+
<7> Which OpenShift versions this topic is part of
103+
104+
=== Notes on "Distros"
105+
106+
* The "Distros" setting is optional for topic groups and topic items. When the "Distros" setting is absent, the system treats the topic group or topic as though the user had set "Distros: all".
107+
* The "all" value for "Distros" is a synonym for "openshift-origin,openshift-enterprise,openshift-online".
108+
* The "all" value trumps other values, so "openshift-online,all" is treated as "all"
109+
110+
== Understanding the Complete Distribution Condition Chain
111+
It is important to understand the ordering of distribution conditionals in determining whether or not a specific piece of content appears in the documentation set. The hierarchy is fairly straightforward:
112+
113+
1. Topic group "Distros" setting from `_build_cfg.yml`
114+
2. Topic item "Distros" setting from `_build_cfg.yml`
115+
3. Document-level `ifdef/endif` blocks
116+
117+
In this manner:
118+
119+
* If a topic group is configured with "Distros: openshift-online", the entire group will be skipped for OpenShift Enterprise and OpenShift Origin, regardless of the Topic-level and document-level content rules within that group.
55120

56-
The build system only looks in this file for information on which files to include, so any new file submissions must be accompanied by an update to this metadata file.
121+
* When a topic group is available to all Distros, but a specific topic item is limited, the topic group will appear for all distros and the specific topic item will only appear for the indicated distros.
57122

58123
== Live Editing
59124
If you would like to work on one of the documentation files in an editing environment that automatically redraws the resulting HTML, follow these steps.

Rakefile

Lines changed: 158 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
require 'asciidoctor'
2+
require 'git'
3+
require 'logger'
24
require 'pandoc-ruby'
35
require 'pathname'
46
require 'rake'
@@ -38,6 +40,27 @@ def package_dir
3840
end
3941
end
4042

43+
def git
44+
@git ||= Git.open(source_dir)
45+
end
46+
47+
def git_checkout branch_name
48+
target_branch = git.branches.local.select{ |b| b.name == branch_name }[0]
49+
if not target_branch.current
50+
target_branch.checkout
51+
end
52+
end
53+
54+
# Returns the local git branches; current branch is always first
55+
def local_branches
56+
@local_branches ||= begin
57+
branches = []
58+
branches << git.branches.local.select{ |b| b.current }[0].name
59+
branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
60+
branches.flatten
61+
end
62+
end
63+
4164
def build_config_file
4265
@build_config_file ||= File.join(source_dir,BUILD_FILENAME)
4366
end
@@ -46,6 +69,63 @@ def build_config
4669
@build_config ||= validate_config(YAML.load_stream(open(build_config_file)))
4770
end
4871

72+
def distro_map
73+
@distro_map ||= begin
74+
{ 'openshift-origin' => {
75+
:name => 'OpenShift Origin',
76+
:branches => {
77+
'master' => {
78+
:name => 'Nightly Build',
79+
:dir => 'latest',
80+
},
81+
'origin-4' => {
82+
:name => 'Version 4',
83+
:dir => 'stable',
84+
},
85+
},
86+
},
87+
'openshift-online' => {
88+
:name => 'OpenShift Online',
89+
:branches => {
90+
'online' => {
91+
:name => 'Latest Release',
92+
:dir => 'online',
93+
},
94+
},
95+
},
96+
'openshift-enterprise' => {
97+
:name => 'OpenShift Enterprise',
98+
:branches => {
99+
'enterprise-2.2' => {
100+
:name => 'Version 2.2',
101+
:dir => 'enterprise/v2.2',
102+
},
103+
},
104+
}
105+
}
106+
end
107+
end
108+
109+
def distro_branches
110+
@distro_branches ||= distro_map.map{ |distro,dconfig| dconfig[:branches].keys }.flatten
111+
end
112+
113+
def parse_distros distros_string, for_validation=false
114+
values = distros_string.split(',').map{ |v| v.strip }
115+
return values if for_validation
116+
return distro_map.keys if values.include?('all')
117+
return values.uniq
118+
end
119+
120+
def validate_distros distros_string
121+
return false if not distros_string.is_a?(String)
122+
values = parse_distros(distros_string, true)
123+
values.each do |v|
124+
return false if not v == 'all' or not distro_map.keys.include?(v)
125+
end
126+
return true
127+
end
128+
49129
def validate_config config_data
50130
# Validate/normalize the config file straight away
51131
if not config_data.is_a?(Array)
@@ -70,6 +150,16 @@ def validate_config config_data
70150
if not File.exists?(File.join(source_dir,topic_group['Dir']))
71151
raise "In #{build_config_file}, the directory #{topic_group['Dir']} for topic group #{topic_group['Name']} does not exist under #{source_dir}"
72152
end
153+
# Validate the Distros setting
154+
if topic_group.has_key?('Distros')
155+
if not validate_distros(topic_group['Distros'])
156+
key_list = distro_map.keys.map{ |k| "'#{k.to_s}'" }.sort.join(', ')
157+
raise "In #{build_config_file}, the Distros value #{topic_group['Distros'].inspect} for topic group #{topic_group['Name']} is not valid. Legal values are 'all', #{key_list}, or a comma-separated list of legal values."
158+
end
159+
topic_group['Distros'] = parse_distros(topic_group['Distros'])
160+
else
161+
topic_group['Distros'] = parse_distros('all')
162+
end
73163
if not topic_group['Topics'].is_a?(Array)
74164
raise "The #{topic_group['Name']} topic group in #{build_config_file} is malformed; the build system is expecting an array of 'Topic' definitions."
75165
end
@@ -90,17 +180,29 @@ def validate_config config_data
90180
if not File.exists?(File.join(source_dir,topic_group['Dir'],"#{topic['File']}.adoc"))
91181
raise "In #{build_config_file}, could not find file #{topic['File']} under directory #{topic_group['Dir']} for topic #{topic['Name']} in topic group #{topic_group['Name']}."
92182
end
183+
if topic.has_key?('Distros')
184+
if not validate_distros(topic['Distros'])
185+
key_list = distro_map.keys.map{ |k| "'#{k.to_s}'" }.sort.join(', ')
186+
raise "In #{build_config_file}, the Distros value #{topic_group['Distros'].inspect} for topic item #{topic['Name']} in topic group #{topic_group['Name']} is not valid. Legal values are 'all', #{key_list}, or a comma-separated list of legal values."
187+
end
188+
topic['Distros'] = parse_distros(topic['Distros'])
189+
else
190+
topic['Distros'] = parse_distros('all')
191+
end
93192
end
94193
end
95194
config_data
96195
end
97196

98-
def nav_tree
197+
def nav_tree distro
99198
@nav_tree ||= begin
100199
navigation = []
101200
build_config.each do |topic_group|
201+
next if not topic_group['Distros'].include?(distro)
202+
next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
102203
topic_list = []
103204
topic_group['Topics'].each do |topic|
205+
next if not topic['Distros'].include?(distro)
104206
topic_list << ["#{topic_group['Dir']}/#{topic['File']}.html",topic['Name']]
105207
end
106208
navigation << { :title => topic_group['Name'], :topics => topic_list }
@@ -110,25 +212,63 @@ def nav_tree
110212
end
111213

112214
task :build do
113-
# Copy stylesheets into preview area
114-
system("cp -r _stylesheets #{preview_dir}/stylesheets")
115-
# Build the topic files
116-
build_config.each do |topic_group|
117-
src_group_path = File.join(source_dir,topic_group['Dir'])
118-
tgt_group_path = File.join(preview_dir,topic_group['Dir'])
119-
if not File.exists?(tgt_group_path)
120-
Dir.mkdir(tgt_group_path)
215+
# First, notify the user of missing local branches
216+
missing_branches = []
217+
distro_branches.sort.each do |dbranch|
218+
next if local_branches.include?(dbranch)
219+
missing_branches << dbranch
220+
end
221+
if missing_branches.length > 0
222+
puts "\nNOTE: The following branches do not exist in your local git repo:"
223+
missing_branches.each do |mbranch|
224+
puts "- #{mbranch}"
121225
end
122-
#if File.exists?(File.join(src_group_path,'images'))
123-
# system("cp -r #{src_group_path}/images #{tgt_group_path}")
124-
#end
125-
topic_group['Topics'].each do |topic|
126-
src_file_path = File.join(src_group_path,"#{topic['File']}.adoc")
127-
tgt_file_path = File.join(tgt_group_path,"#{topic['File']}.adoc")
128-
system('cp', src_file_path, tgt_file_path)
129-
Asciidoctor.render_file tgt_file_path, :in_place => true, :safe => :unsafe, :template_dir => template_dir, :attributes => ['source-highlighter=coderay','coderay-css=style',"stylesdir=#{preview_dir}/stylesheets","imagesdir=#{src_group_path}/images",'stylesheet=origin.css','linkcss!','icons=font','idprefix=','idseparator=-','sectanchors']
130-
system('rm', tgt_file_path)
226+
puts "The build will proceed but these branches will not be generated."
227+
end
228+
distro_map.each do |distro,distro_config|
229+
puts "\n\nBuilding #{distro_config[:name]}"
230+
distro_config[:branches].each do |branch,branch_config|
231+
if missing_branches.include?(branch)
232+
puts "- skipping #{branch}"
233+
next
234+
end
235+
puts "- building #{branch}"
236+
237+
# Put us on the correct branch
238+
git_checkout(branch)
239+
240+
# Create the target dir
241+
branch_path = "#{preview_dir}/#{branch_config[:dir]}"
242+
system("mkdir -p #{branch_path}")
243+
244+
# Copy stylesheets into preview area
245+
system("cp -r _stylesheets #{branch_path}/stylesheets")
246+
247+
# Build the nav tree
248+
navigation = nav_tree(distro)
249+
250+
# Build the topic files
251+
build_config.each do |topic_group|
252+
next if not topic_group['Distros'].include?(distro)
253+
next if topic_group['Topics'].select{ |t| t['Distros'].include?(distro) }.length == 0
254+
src_group_path = File.join(source_dir,topic_group['Dir'])
255+
tgt_group_path = File.join(branch_path,topic_group['Dir'])
256+
if not File.exists?(tgt_group_path)
257+
Dir.mkdir(tgt_group_path)
258+
end
259+
topic_group['Topics'].each do |topic|
260+
next if not topic['Distros'].include?(distro)
261+
src_file_path = File.join(src_group_path,"#{topic['File']}.adoc")
262+
tgt_file_path = File.join(tgt_group_path,"#{topic['File']}.adoc")
263+
system('cp', src_file_path, tgt_file_path)
264+
Asciidoctor.render_file tgt_file_path, :in_place => true, :safe => :unsafe, :template_dir => template_dir, :attributes => ['source-highlighter=coderay','coderay-css=style',"stylesdir=#{branch_path}/stylesheets","imagesdir=#{src_group_path}/images",'stylesheet=origin.css','linkcss!','icons=font','idprefix=','idseparator=-','sectanchors', distro, "product-title=#{distro_config[:name]}", "product-version=#{branch_config[:name]}"]
265+
system('rm', tgt_file_path)
266+
end
267+
end
131268
end
269+
270+
# Return to the original branch
271+
git_checkout(local_branches[0])
132272
end
133273
end
134274

0 commit comments

Comments
 (0)