IDPROD-2142 part2: generate docs index.html page (#302)
Now generating a `docs/index.html` page that links to the documentation for all of the modules in the repo that have documentation enabled (`Stripe` & `StripeIdentity`). The index page reuses the same html template as the Jazzy theme we use to generate our docs. The descriptions that display for each module are populated by the summary in their podspec file. With the next deploy, this page will be visible at https://stripe.dev/stripe-ios.
This commit is contained in:
parent
987a7d0dcc
commit
702e8df394
|
@ -8,4 +8,4 @@ github_url: https://github.com/stripe/stripe-ios
|
|||
github_file_prefix: https://github.com/stripe/stripe-ios/tree/master
|
||||
skip_undocumented: true
|
||||
hide_documentation_coverage: true
|
||||
theme: fullwidth
|
||||
theme: .jazzy/theme
|
||||
|
|
|
@ -31,9 +31,16 @@
|
|||
{{> header}}
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="{{path_to_root}}index.html">{{module_name}} Reference</a>
|
||||
{{#is_root_index}}
|
||||
<a class="breadcrumb" href="{{path_to_root}}index.html">Stripe iOS SDKs</a>
|
||||
{{/is_root_index}}
|
||||
{{^is_root_index}}
|
||||
<a class="breadcrumb" href="{{path_to_root}}../index.html">Stripe iOS SDKs</a>
|
||||
<img class="carat" src="{{path_to_root}}img/carat.png" />
|
||||
<a class="breadcrumb" href="{{path_to_root}}index.html">{{module_name}}</a>
|
||||
<img class="carat" src="{{path_to_root}}img/carat.png" />
|
||||
{{name}} {{kind}} Reference
|
||||
{{/is_root_index}}
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
{{#is_root_index}}
|
||||
<a class="header-link" href="{{path_to_root}}index.html">
|
||||
{{/is_root_index}}
|
||||
{{^is_root_index}}
|
||||
<a class="header-link" href="{{path_to_root}}../index.html">
|
||||
{{/is_root_index}}
|
||||
{{docs_title}}
|
||||
</a>
|
||||
{{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
{{#modules}}
|
||||
<a href="{{path_to_root}}{{directory}}/index.html"><h2 class="heading">{{name}}</h2></a>
|
||||
{{summary}}
|
||||
{{/modules}}
|
3
Gemfile
3
Gemfile
|
@ -3,6 +3,7 @@ source "https://rubygems.org"
|
|||
gem "fastlane"
|
||||
gem "cocoapods"
|
||||
|
||||
gem "jazzy", "~> 0.13.6"
|
||||
gem "jazzy", "~> 0.13.7"
|
||||
gem "mustache", "~> 1.1.1"
|
||||
|
||||
gem "xcode-install", "~> 2.6"
|
||||
|
|
|
@ -188,7 +188,7 @@ GEM
|
|||
httpclient (2.8.3)
|
||||
i18n (1.8.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jazzy (0.13.6)
|
||||
jazzy (0.13.7)
|
||||
cocoapods (~> 1.5)
|
||||
mustache (~> 1.1)
|
||||
open4
|
||||
|
@ -283,7 +283,8 @@ PLATFORMS
|
|||
DEPENDENCIES
|
||||
cocoapods
|
||||
fastlane
|
||||
jazzy (~> 0.13.6)
|
||||
jazzy (~> 0.13.7)
|
||||
mustache (~> 1.1.1)
|
||||
xcode-install (~> 2.6)
|
||||
|
||||
BUNDLED WITH
|
||||
|
|
|
@ -5,12 +5,12 @@ Pod::Spec.new do |s|
|
|||
# Instead, update the VERSION file and run ./ci_scripts/update_version.sh
|
||||
s.version = '21.7.0'
|
||||
|
||||
s.summary = 'Stripe is a web-based API for accepting payments online.'
|
||||
s.summary = 'Accept online payments using Stripe.'
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.homepage = 'https://stripe.com/docs/mobile/ios'
|
||||
s.authors = { 'Stripe' => 'support+github@stripe.com' }
|
||||
s.source = { :git => 'https://github.com/stripe/stripe-ios.git', :tag => "#{s.version}" }
|
||||
s.frameworks = 'Foundation', 'Security', 'WebKit', 'PassKit', 'Contacts', 'CoreLocation'
|
||||
s.frameworks = 'Foundation', 'Security', 'WebKit', 'PassKit', 'Contacts', 'CoreLocation', 'UIKit'
|
||||
s.requires_arc = true
|
||||
s.platform = :ios
|
||||
s.ios.deployment_target = '11.0'
|
||||
|
|
|
@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
|||
s.homepage = 'https://stripe.com/docs/mobile/ios'
|
||||
s.authors = { 'Stripe' => 'support+github@stripe.com' }
|
||||
s.source = { :git => 'https://github.com/stripe/stripe-ios.git', :tag => "#{s.version}" }
|
||||
s.frameworks = 'Foundation', 'Security', 'WebKit', 'PassKit', 'Contacts', 'CoreLocation'
|
||||
s.frameworks = 'Foundation', 'UIKit'
|
||||
s.requires_arc = true
|
||||
s.platform = :ios
|
||||
s.ios.deployment_target = '11.0'
|
||||
|
|
|
@ -5,12 +5,12 @@ Pod::Spec.new do |s|
|
|||
# Instead, update the VERSION file and run ./ci_scripts/update_version.sh
|
||||
s.version = '21.7.0'
|
||||
|
||||
s.summary = 'StripeIdentity is a web-based API that confirms the identity of global users.'
|
||||
s.summary = 'Securely capture ID documents and selfies on iOS for use with Stripe\'s Identity API to confirm the identity of global users.'
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.homepage = 'https://stripe.com/docs/mobile/ios'
|
||||
s.homepage = 'https://stripe.com/identity'
|
||||
s.authors = { 'Stripe' => 'support+github@stripe.com' }
|
||||
s.source = { :git => 'https://github.com/stripe/stripe-ios.git', :tag => "#{s.version}" }
|
||||
s.frameworks = 'Foundation', 'Security', 'WebKit', 'PassKit', 'Contacts', 'CoreLocation'
|
||||
s.frameworks = 'Foundation', 'WebKit', 'UIKit'
|
||||
s.requires_arc = true
|
||||
s.platform = :ios
|
||||
s.ios.deployment_target = '11.0'
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rubygems/dependency_installer.rb'
|
||||
require 'cocoapods'
|
||||
require 'jazzy'
|
||||
require 'fileutils'
|
||||
require 'mustache'
|
||||
require 'optparse'
|
||||
require 'pathname'
|
||||
require 'yaml'
|
||||
|
||||
script_dir = __dir__
|
||||
|
||||
def info(string)
|
||||
puts "[#{File.basename(__FILE__)}] [INFO] #{string}"
|
||||
end
|
||||
|
@ -16,116 +16,224 @@ def die(string)
|
|||
abort "[#{File.basename(__FILE__)}] [ERROR] #{string}"
|
||||
end
|
||||
|
||||
def install_jazzy(version = Gem::Requirement.default)
|
||||
begin
|
||||
installer = Gem::DependencyInstaller.new
|
||||
installer.install("jazzy", version)
|
||||
rescue
|
||||
die "Executing \`gem install jazzy\` failed"
|
||||
# Joins the given strings. If one or more arguments is nil or empty, an exception is raised.
|
||||
def File.join_if_safe(arg1, *otherArgs)
|
||||
args = [arg1] + otherArgs
|
||||
|
||||
# Check for empty or nil strings
|
||||
args.each do |arg|
|
||||
raise "Cannot join nil or empty string." if arg.nil? || arg.empty?
|
||||
end
|
||||
|
||||
return File.join(args)
|
||||
end
|
||||
|
||||
# MARK: - constants
|
||||
|
||||
$SCRIPT_DIR = __dir__
|
||||
$ROOT_DIR = File.expand_path("..", $SCRIPT_DIR)
|
||||
$JAZZY_CONFIG_FILE = File.join_if_safe($ROOT_DIR, ".jazzy.yaml")
|
||||
$JAZZY_CONFIG = YAML.load_file($JAZZY_CONFIG_FILE)
|
||||
|
||||
# MARK: - build docs
|
||||
|
||||
# Note(mludowise): When `check_documentation.sh` locally, we want to save docs
|
||||
# to a temp directory so we can check undocumented.json and grep for `@_spi`,
|
||||
# without unintentially committing changes to the `/docs` folder.
|
||||
docs_root_directory = File.expand_path("#{script_dir}/..", Dir.getwd)
|
||||
OptionParser.new do |opts|
|
||||
opts.on("--docs-root-dir DIRECTORY", "Generate docs to this directory instead of the repo's root directory.") do |dir|
|
||||
docs_root_directory = File.expand_path(dir, Dir.getwd)
|
||||
end
|
||||
end.parse!
|
||||
def get_docs_root_directory
|
||||
docs_root_directory = $ROOT_DIR
|
||||
|
||||
# Verify jazzy is installed
|
||||
begin
|
||||
Gem::Specification.find_by_name('jazzy')
|
||||
rescue
|
||||
if ENV["CI"] != 'true'
|
||||
die "Please install jazzy: https://github.com/realm/jazzy#installation"
|
||||
end
|
||||
OptionParser.new do |opts|
|
||||
opts.on("--docs-root-dir DIRECTORY", "Generate docs to this directory instead of the repo's root directory.") do |dir|
|
||||
docs_root_directory = File.expand_path(dir, Dir.getwd)
|
||||
end
|
||||
end.parse!
|
||||
|
||||
info "Installing jazzy..."
|
||||
install_jazzy
|
||||
end
|
||||
|
||||
# Verify jazzy is up to date
|
||||
jazzy_version_local = Gem::Specification.find_by_name('jazzy').version
|
||||
fetcher = Gem::SpecFetcher.fetcher
|
||||
newer_jazzy_dependency = Gem::Dependency.new "jazzy", "> #{jazzy_version_local}"
|
||||
newer_jazzy_remotes, = fetcher.search_for_dependency newer_jazzy_dependency
|
||||
unless newer_jazzy_remotes.empty?
|
||||
jazzy_version_remote = newer_jazzy_remotes.map { |n, _| n.version }.sort.last
|
||||
info "Current jazzy version: #{jazzy_version_local}"
|
||||
|
||||
if ENV["CI"] != 'true'
|
||||
die "Please update jazzy: \`gem update jazzy\`"
|
||||
end
|
||||
|
||||
info "Updating jazzy to version #{jazzy_version_remote}..."
|
||||
install_jazzy ">= #{jazzy_version_remote}"
|
||||
return docs_root_directory
|
||||
end
|
||||
|
||||
# Create temp podspec directory
|
||||
# NOTE(mludowise|https://github.com/realm/jazzy/issues/1262):
|
||||
# This won't be needed if jazzy ever allows for multiple development pods
|
||||
make_dir_output = `#{script_dir}/make_temp_spec_repo.sh`
|
||||
make_dir_status=$?.exitstatus
|
||||
def make_temp_spec_repo
|
||||
make_spec_repo_output = `#{$SCRIPT_DIR}/make_temp_spec_repo.sh`
|
||||
make_spec_repo_status=$?.exitstatus
|
||||
|
||||
unless make_dir_status == 0
|
||||
die temp_spec_dir
|
||||
unless make_spec_repo_status == 0
|
||||
die "Unable to create pod spec repo."
|
||||
end
|
||||
|
||||
temp_spec_dir = make_spec_repo_output.lines.last.strip
|
||||
info "Sucessfully created podspec repo at \`#{temp_spec_dir}\`"
|
||||
return temp_spec_dir
|
||||
end
|
||||
|
||||
temp_spec_dir = `#{script_dir}/make_temp_spec_repo.sh`.lines.last.strip
|
||||
info "Sucessfully created podspec repo at \`#{temp_spec_dir}\`"
|
||||
|
||||
# Clean pod cache to always use latest local copy of pod dependencies
|
||||
# NOTE(mludowise|https://github.com/realm/jazzy/issues/1262):
|
||||
# This won't be needed if jazzy ever allows for multiple development pods
|
||||
info "Cleaning pod cache..."
|
||||
Dir.glob("#{script_dir}/../*.podspec").each do |file|
|
||||
podspec = Pod::Specification.from_file(file)
|
||||
cmd = Pod::Command::Cache::Clean.new(CLAide::ARGV.new([podspec.name, '--all']))
|
||||
cmd.run
|
||||
def clean_pod_cache
|
||||
info "Cleaning pod cache..."
|
||||
Dir.glob("#{$ROOT_DIR}/*.podspec").each do |file|
|
||||
podspec = Pod::Specification.from_file(file)
|
||||
cmd = Pod::Command::Cache::Clean.new(CLAide::ARGV.new([podspec.name, '--all']))
|
||||
cmd.run
|
||||
end
|
||||
end
|
||||
|
||||
def docs_title(release_version)
|
||||
return "Stripe iOS SDKs #{release_version}"
|
||||
end
|
||||
|
||||
# Execute jazzy
|
||||
modules = YAML.load_file("modules.yaml")['modules']
|
||||
release_version = `cat "#{script_dir}/../VERSION"`.strip
|
||||
jazzy_exit_code = 0
|
||||
def build_module_docs(modules, release_version, docs_root_directory, temp_spec_dir)
|
||||
jazzy_exit_code = 0
|
||||
|
||||
modules.each do |m|
|
||||
docs_config = m['docs']
|
||||
if docs_config.nil?
|
||||
next
|
||||
modules.each do |m|
|
||||
|
||||
# Note: If we don't check for empty string/nil, then jazzy will silently
|
||||
# overwrite the entire git repo directory.
|
||||
output = m['docs']['output'].to_s
|
||||
if output.empty?
|
||||
die "Missing required docs config \`output\`. Update modules.yaml."
|
||||
end
|
||||
|
||||
# Prepend `docs_root_directory`
|
||||
output = File.expand_path(output, docs_root_directory).to_s
|
||||
|
||||
info "Executing jazzy for #{m['podspec']}..."
|
||||
`jazzy \
|
||||
--config "#{$JAZZY_CONFIG_FILE}" \
|
||||
--output "#{output}" \
|
||||
--github-file-prefix "https://github.com/stripe/stripe-ios/tree/#{release_version}" \
|
||||
--title "#{docs_title(release_version)}" \
|
||||
--podspec "#{File.join_if_safe($ROOT_DIR, m['podspec'])}" \
|
||||
--pod-sources "file://#{temp_spec_dir}"`
|
||||
|
||||
# Verify jazzy exit code
|
||||
jazzy_exit_code=$?.exitstatus
|
||||
|
||||
if jazzy_exit_code != 0
|
||||
die "Executing jazzy failed with status code: #{jazzy_exit_code}"
|
||||
end
|
||||
end
|
||||
|
||||
# Note: If we don't check for empty string/nil, then jazzy will silently
|
||||
# overwrite the entire git repo directory.
|
||||
output = docs_config['output'].to_s
|
||||
if output.empty?
|
||||
die "Missing required docs config \`output\`. Update modules.yaml."
|
||||
end
|
||||
|
||||
# Prepend `docs_root_directory`
|
||||
output = File.expand_path(output, docs_root_directory).to_s
|
||||
|
||||
info "Executing jazzy for #{m['podspec']}..."
|
||||
`jazzy \
|
||||
--config "#{script_dir}/../.jazzy.yaml" \
|
||||
--output "#{output}" \
|
||||
--github-file-prefix "https://github.com/stripe/stripe-ios/tree/#{release_version}" \
|
||||
--podspec "#{script_dir}/../#{m['podspec']}" \
|
||||
--pod-sources "file://#{temp_spec_dir}"`
|
||||
|
||||
# Verify jazzy exit code
|
||||
jazzy_exit_code=$?.exitstatus
|
||||
|
||||
break if jazzy_exit_code != 0
|
||||
|
||||
end
|
||||
|
||||
# Cleanup temp podspec directory
|
||||
FileUtils.rm_rf(temp_spec_dir)
|
||||
# Creates html that lists all modules with docs enabled and links to their docs
|
||||
# directory. The descriptions of the modules are from their podspec summaries.
|
||||
def index_page_content(modules)
|
||||
view = Mustache.new
|
||||
view.template_file = File.join_if_safe($ROOT_DIR, $JAZZY_CONFIG['theme'], "templates", "index.mustache")
|
||||
|
||||
if jazzy_exit_code != 0
|
||||
die "Executing jazzy failed with status code: #{jazzy_exit_code}"
|
||||
view[:modules] = modules.map do |m|
|
||||
# Get get module's docs output relative to `docs` folder
|
||||
relative_path = Pathname.new(m['docs']['output']).relative_path_from(Pathname.new('docs'))
|
||||
|
||||
# Load podspec to get module name and summary
|
||||
podspec = Pod::Specification.from_file(File.join_if_safe($ROOT_DIR, m['podspec']))
|
||||
|
||||
props={}
|
||||
props[:name] = podspec.name
|
||||
props[:summary] = podspec.summary
|
||||
props[:directory] = relative_path.to_s
|
||||
props
|
||||
end
|
||||
|
||||
return view.render
|
||||
end
|
||||
|
||||
# Builds the `/docs/index.html` page
|
||||
def build_index_page(modules, release_version, docs_root_directory)
|
||||
info "Building index page..."
|
||||
|
||||
# Reuse Jazzy theme so it's visually consistent with the reset of the docs
|
||||
view = Mustache.new
|
||||
view.template_name = "doc"
|
||||
view.template_path = File.join_if_safe($ROOT_DIR, $JAZZY_CONFIG['theme'], "templates")
|
||||
|
||||
# Add properties expected by template
|
||||
# Copied & modified from https://github.com/realm/jazzy
|
||||
config = YAML.load_file(File.join_if_safe($ROOT_DIR, ".jazzy.yaml"))
|
||||
view[:copyright] = (
|
||||
date = DateTime.now.strftime('%Y-%m-%d')
|
||||
year = date[0..3]
|
||||
"© #{year} <a class=\"link\" href=\"#{$JAZZY_CONFIG['author_url']}\"" \
|
||||
"target=\"_blank\" rel=\"external\">#{$JAZZY_CONFIG['author']}</a>. " \
|
||||
"All rights reserved. (Last updated: #{date})"
|
||||
)
|
||||
view[:jazzy_version] = Jazzy::VERSION
|
||||
view[:objc_first] = false
|
||||
view[:language_stub] = 'swift'
|
||||
view[:disable_search] = false
|
||||
view[:docs_title] = docs_title(release_version)
|
||||
view[:module_version] = release_version
|
||||
view[:github_url] = $JAZZY_CONFIG['github_url']
|
||||
view[:name] = docs_title(release_version)
|
||||
|
||||
# Don't render search since it won't work for the index page
|
||||
view[:disable_search] = true
|
||||
|
||||
# Custom template var for our theme to disable some html for the root index page
|
||||
view[:is_root_index] = true
|
||||
|
||||
# Insert generated html
|
||||
view[:overview] = index_page_content(modules)
|
||||
|
||||
# Write to docs/index.html
|
||||
output_file = File.join_if_safe(docs_root_directory, "docs", "index.html")
|
||||
File.open(output_file, 'w') { |file| file.write(view.render) }
|
||||
end
|
||||
|
||||
# Jazzy compiles assets from the theme's assets directory and saves them to each
|
||||
# module's docs directory. We're going to move one set of them to the docs/ root
|
||||
# directory and symlink the rest. It's a bit hacky but it reduces duplicate
|
||||
# css/js/images in our repo and moves it to an expected location that
|
||||
# docs/index.html wants.
|
||||
def fix_assets(modules, docs_root_directory)
|
||||
docs_dir = File.expand_path('docs', docs_root_directory)
|
||||
|
||||
# Get list of assets used by theme (js, img, css, etc)
|
||||
Dir.glob(File.join_if_safe($ROOT_DIR, $JAZZY_CONFIG['theme'], "assets", "*")).each do |asset_file|
|
||||
asset_base_name = File.basename(asset_file)
|
||||
|
||||
# Delete old asset copies from /docs directory
|
||||
FileUtils.rm_rf(File.join_if_safe(docs_dir, asset_base_name))
|
||||
|
||||
modules.each_with_index do |m, index|
|
||||
module_docs_dir = File.join_if_safe(docs_root_directory, m['docs']['output'])
|
||||
compiled_asset_path = File.join_if_safe(module_docs_dir, asset_base_name)
|
||||
|
||||
if index == 0
|
||||
# Move the compiled asset from the module's docs folder into `/docs` so index.html can use it
|
||||
FileUtils.mv(compiled_asset_path, File.join_if_safe(docs_dir, asset_base_name))
|
||||
else
|
||||
# Delete the compiled asset from the module's docs folder
|
||||
FileUtils.rm_rf(compiled_asset_path)
|
||||
end
|
||||
|
||||
# Symlink so each module's docs folder can use root `/docs` folder's assets
|
||||
Dir.chdir(module_docs_dir){
|
||||
File.symlink(File.join_if_safe(docs_dir, asset_base_name), compiled_asset_path)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# MARK: - main
|
||||
|
||||
temp_spec_dir = make_temp_spec_repo()
|
||||
|
||||
begin
|
||||
clean_pod_cache()
|
||||
docs_root_directory = get_docs_root_directory()
|
||||
|
||||
# Load modules from yaml and filter out any which don't have docs configured
|
||||
modules = YAML.load_file(File.join_if_safe($ROOT_DIR, "modules.yaml"))['modules'].select { |m| !m['docs'].nil? }
|
||||
release_version = `cat "#{$ROOT_DIR}/VERSION"`.strip
|
||||
build_module_docs(modules, release_version, docs_root_directory, temp_spec_dir)
|
||||
build_index_page(modules, release_version, docs_root_directory)
|
||||
fix_assets(modules, docs_root_directory)
|
||||
ensure
|
||||
# Always cleanup temp podspec directory
|
||||
info "Deleting podspec repo at `#{temp_spec_dir}`"
|
||||
FileUtils.rm_rf(temp_spec_dir)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue