From da5cad7cb1d502a34bc9271493c469324cb71954 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Fri, 2 Mar 2018 16:15:09 -0800 Subject: [PATCH] (PDOC-228) puppet plans support Currently, Puppet Strings only supports Puppet Tasks. Since Plans are sort of connected to Tasks, it seemed right that Strings should also support Plans. That and Plans are a thing that needs to be documented. First, the Puppet[:tasks] setting needs to be set to add the 'plan' keyword to the Puppet Parser's lexicon, so this sets it in the Strings parser if the setting exists. If it does not exist and Puppet.version is less than 5.0.0, Strings will error out. Second, processing for the Plans themselves is set up. Plans are very similar to other Puppet objects like defined types and classes, so this involved some serious copy-pasta. Third, all the template/to_hash scaffolding for the different outputs is in place (HTML, JSON, Markdown). Yey. --- lib/puppet-strings.rb | 5 + lib/puppet-strings/json.rb | 1 + lib/puppet-strings/markdown.rb | 2 + lib/puppet-strings/markdown/puppet_plan.rb | 14 + lib/puppet-strings/markdown/puppet_plans.rb | 37 + lib/puppet-strings/yard.rb | 8 +- lib/puppet-strings/yard/code_objects.rb | 1 + lib/puppet-strings/yard/code_objects/plan.rb | 56 ++ lib/puppet-strings/yard/handlers.rb | 1 + .../yard/handlers/puppet/plan_handler.rb | 27 + .../yard/parsers/puppet/parser.rb | 11 + .../yard/parsers/puppet/statement.rb | 14 + .../fulldoc/html/full_list_puppet_plan.erb | 9 + .../templates/default/fulldoc/html/setup.rb | 9 + .../templates/default/layout/html/setup.rb | 19 +- .../default/puppet_plan/html/box_info.erb | 10 + .../default/puppet_plan/html/header.erb | 1 + .../default/puppet_plan/html/overview.erb | 6 + .../default/puppet_plan/html/setup.rb | 11 + .../default/puppet_plan/html/source.erb | 12 + .../default/puppet_plan/html/summary.erb | 4 + .../yard/templates/default/tags/setup.rb | 3 +- spec/fixtures/unit/json/output.json | 3 + spec/fixtures/unit/json/output_with_plan.json | 689 ++++++++++++++++++ .../unit/markdown/output_with_plan.md | 451 ++++++++++++ spec/spec_helper.rb | 7 +- spec/unit/puppet-strings/json_spec.rb | 17 +- spec/unit/puppet-strings/markdown_spec.rb | 36 +- 28 files changed, 1435 insertions(+), 29 deletions(-) create mode 100644 lib/puppet-strings/markdown/puppet_plan.rb create mode 100644 lib/puppet-strings/markdown/puppet_plans.rb create mode 100644 lib/puppet-strings/yard/code_objects/plan.rb create mode 100644 lib/puppet-strings/yard/handlers/puppet/plan_handler.rb create mode 100644 lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_plan.erb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/box_info.erb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/header.erb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/overview.erb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/setup.rb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/source.erb create mode 100644 lib/puppet-strings/yard/templates/default/puppet_plan/html/summary.erb create mode 100644 spec/fixtures/unit/json/output_with_plan.json create mode 100644 spec/fixtures/unit/markdown/output_with_plan.md diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index b8b84bb..3c7958d 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -7,6 +7,7 @@ module PuppetStrings types/**/*.pp lib/**/*.rb tasks/*.json + plans/*.pp ).freeze # Generates documentation. @@ -62,6 +63,10 @@ module PuppetStrings end end + def self.puppet_5? + Puppet::Util::Package.versioncmp(Puppet.version, "5.0.0") >= 0 + end + def self.render_json(path) require 'puppet-strings/json' PuppetStrings::Json.render(path) diff --git a/lib/puppet-strings/json.rb b/lib/puppet-strings/json.rb index 85491e5..e0ac1fb 100644 --- a/lib/puppet-strings/json.rb +++ b/lib/puppet-strings/json.rb @@ -13,6 +13,7 @@ module PuppetStrings::Json providers: YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash), puppet_functions: YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash), puppet_tasks: YARD::Registry.all(:puppet_task).sort_by!(&:name).map!(&:to_hash), + puppet_plans: YARD::Registry.all(:puppet_plan).sort_by!(&:name).map!(&:to_hash) # TODO: Need Ruby documentation? } diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb index e5b0d49..c3cebee 100644 --- a/lib/puppet-strings/markdown.rb +++ b/lib/puppet-strings/markdown.rb @@ -7,6 +7,7 @@ module PuppetStrings::Markdown require_relative 'markdown/defined_types' require_relative 'markdown/resource_types' require_relative 'markdown/puppet_tasks' + require_relative 'markdown/puppet_plans' require_relative 'markdown/table_of_contents' # generates markdown documentation @@ -19,6 +20,7 @@ module PuppetStrings::Markdown final << PuppetStrings::Markdown::ResourceTypes.render final << PuppetStrings::Markdown::Functions.render final << PuppetStrings::Markdown::PuppetTasks.render + final << PuppetStrings::Markdown::PuppetPlans.render final end diff --git a/lib/puppet-strings/markdown/puppet_plan.rb b/lib/puppet-strings/markdown/puppet_plan.rb new file mode 100644 index 0000000..e4e62e3 --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_plan.rb @@ -0,0 +1,14 @@ +require 'puppet-strings/markdown/base' + +module PuppetStrings::Markdown + class PuppetPlan < Base + def initialize(registry) + @template = 'classes_and_defines.erb' + super(registry, 'plan') + end + + def render + super(@template) + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_plans.rb b/lib/puppet-strings/markdown/puppet_plans.rb new file mode 100644 index 0000000..71ffa2e --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_plans.rb @@ -0,0 +1,37 @@ +require_relative 'puppet_plan' + +module PuppetStrings::Markdown + module PuppetPlans + + # @return [Array] list of classes + def self.in_plans + arr = YARD::Registry.all(:puppet_plan).sort_by!(&:name).map!(&:to_hash) + arr.map! { |a| PuppetStrings::Markdown::PuppetPlan.new(a) } + end + + def self.contains_private? + result = false + unless in_plans.nil? + in_plans.find { |plan| plan.private? }.nil? ? false : true + end + end + + def self.render + final = in_plans.length > 0 ? "## Plans\n\n" : "" + in_plans.each do |plan| + final << plan.render unless plan.private? + end + final + end + + def self.toc_info + final = ["Plans"] + + in_classes.each do |plan| + final.push(plan.toc_info) + end + + final + end + end +end diff --git a/lib/puppet-strings/yard.rb b/lib/puppet-strings/yard.rb index 256b69b..48cf1c6 100644 --- a/lib/puppet-strings/yard.rb +++ b/lib/puppet-strings/yard.rb @@ -49,7 +49,8 @@ class YARD::CLI::Yardoc :puppet_type, :puppet_provider, :puppet_function, - :puppet_task + :puppet_task, + :puppet_plan ) end end @@ -82,6 +83,11 @@ class YARD::CLI::Stats output 'Puppet Tasks', *type_statistics_all(:puppet_task) end + def stats_for_puppet_plans + return unless PuppetStrings.puppet_5? + output 'Puppet Plans', *type_statistics_all(:puppet_plan) + end + def output(name, data, undoc = nil) # Monkey patch output to accommodate our larger header widths @total += data if data.is_a?(Integer) && undoc diff --git a/lib/puppet-strings/yard/code_objects.rb b/lib/puppet-strings/yard/code_objects.rb index 70f511a..0d3ecd4 100644 --- a/lib/puppet-strings/yard/code_objects.rb +++ b/lib/puppet-strings/yard/code_objects.rb @@ -6,4 +6,5 @@ module PuppetStrings::Yard::CodeObjects require 'puppet-strings/yard/code_objects/provider' require 'puppet-strings/yard/code_objects/function' require 'puppet-strings/yard/code_objects/task' + require 'puppet-strings/yard/code_objects/plan' end diff --git a/lib/puppet-strings/yard/code_objects/plan.rb b/lib/puppet-strings/yard/code_objects/plan.rb new file mode 100644 index 0000000..13ef8ce --- /dev/null +++ b/lib/puppet-strings/yard/code_objects/plan.rb @@ -0,0 +1,56 @@ +require 'puppet-strings/yard/code_objects/group' + +class PuppetStrings::Yard::CodeObjects::Plans < PuppetStrings::Yard::CodeObjects::Group + # Gets the singleton instance of the group. + # @return Returns the singleton instance of the group. + def self.instance + super(:puppet_plans) + end + + # Gets the display name of the group. + # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces. + # @return [String] Returns the display name of the group. + def name(prefix = false) + 'Puppet Plans' + end +end + +class PuppetStrings::Yard::CodeObjects::Plan < PuppetStrings::Yard::CodeObjects::Base + attr_reader :statement + attr_reader :parameters + + # Initializes a Puppet plan code object. + # @param [PuppetStrings::Parsers::PlanStatement] statement The plan statement that was parsed. + # @return [void] + def initialize(statement) + @statement = statement + @parameters = statement.parameters.map { |p| [p.name, p.value] } + super(PuppetStrings::Yard::CodeObjects::Plans.instance, statement.name) + end + + # Gets the type of the code object. + # @return Returns the type of the code object. + def type + :puppet_plan + end + + # Gets the source of the code object. + # @return Returns the source of the code object. + def source + @statement.source + end + + # Converts the code object to a hash representation. + # @return [Hash] Returns a hash representation of the code object. + def to_hash + hash = {} + hash[:name] = name + hash[:file] = file + hash[:line] = line + hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring) + defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten] + hash[:defaults] = defaults unless defaults.empty? + hash[:source] = source unless source && source.empty? + hash + end +end diff --git a/lib/puppet-strings/yard/handlers.rb b/lib/puppet-strings/yard/handlers.rb index 7471a28..081e2a2 100644 --- a/lib/puppet-strings/yard/handlers.rb +++ b/lib/puppet-strings/yard/handlers.rb @@ -18,5 +18,6 @@ module PuppetStrings::Yard::Handlers require 'puppet-strings/yard/handlers/puppet/class_handler' require 'puppet-strings/yard/handlers/puppet/defined_type_handler' require 'puppet-strings/yard/handlers/puppet/function_handler' + require 'puppet-strings/yard/handlers/puppet/plan_handler' end end diff --git a/lib/puppet-strings/yard/handlers/puppet/plan_handler.rb b/lib/puppet-strings/yard/handlers/puppet/plan_handler.rb new file mode 100644 index 0000000..54d241e --- /dev/null +++ b/lib/puppet-strings/yard/handlers/puppet/plan_handler.rb @@ -0,0 +1,27 @@ +require 'puppet-strings/yard/handlers/helpers' +require 'puppet-strings/yard/handlers/puppet/base' +require 'puppet-strings/yard/parsers' +require 'puppet-strings/yard/code_objects' + +# Implements the handler for Puppet classes. +class PuppetStrings::Yard::Handlers::Puppet::PlanHandler < PuppetStrings::Yard::Handlers::Puppet::Base + handles PuppetStrings::Yard::Parsers::Puppet::PlanStatement + + process do + # Register the object + object = PuppetStrings::Yard::CodeObjects::Plan.new(statement) + register object + + # Log a warning if missing documentation + log.warn "Missing documentation for Puppet plan '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty? + + # Set the parameter types + set_parameter_types(object) + + # Mark the class as public if it doesn't already have an api tag + object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api + + # Warn if a summary longer than 140 characters was provided + PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary + end +end diff --git a/lib/puppet-strings/yard/parsers/puppet/parser.rb b/lib/puppet-strings/yard/parsers/puppet/parser.rb index a74675b..6c91826 100644 --- a/lib/puppet-strings/yard/parsers/puppet/parser.rb +++ b/lib/puppet-strings/yard/parsers/puppet/parser.rb @@ -20,6 +20,11 @@ class PuppetStrings::Yard::Parsers::Puppet::Parser < YARD::Parser::Base # @return [void] def parse begin + Puppet[:tasks] = true if Puppet.settings.include?(:tasks) + if Puppet::Util::Package.versioncmp(Puppet.version, "5.0.0") < 0 && @file.to_s.match(/^plans\//) + log.warn "Skipping #{@file}: Puppet Plans require Puppet 5 or greater." + return + end @statements ||= (@visitor.visit(::Puppet::Pops::Parser::Parser.new.parse_string(source)) || []).compact rescue ::Puppet::ParseError => ex log.error "Failed to parse #{@file}: #{ex.message}" @@ -64,6 +69,12 @@ class PuppetStrings::Yard::Parsers::Puppet::Parser < YARD::Parser::Base statement end + def transform_PlanDefinition(o) + statement = PuppetStrings::Yard::Parsers::Puppet::PlanStatement.new(o, @file) + statement.extract_docstring(@lines) + statement + end + def transform_Object(o) # Ignore anything else (will be compacted out of the resulting array) end diff --git a/lib/puppet-strings/yard/parsers/puppet/statement.rb b/lib/puppet-strings/yard/parsers/puppet/statement.rb index 89ae1fa..eea04a7 100644 --- a/lib/puppet-strings/yard/parsers/puppet/statement.rb +++ b/lib/puppet-strings/yard/parsers/puppet/statement.rb @@ -151,4 +151,18 @@ module PuppetStrings::Yard::Parsers::Puppet end end end + + # Implements the Puppet plan statement. + class PlanStatement < ParameterizedStatement + attr_reader :name + + # Initializes the Puppet plan statement. + # @param [Puppet::Pops::Model::PlanDefinition] object The model object for the plan statement. + # @param [String] file The file containing the statement. + def initialize(object, file) + super(object, file) + @name = object.name + end + end + end diff --git a/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_plan.erb b/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_plan.erb new file mode 100644 index 0000000..095188f --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_plan.erb @@ -0,0 +1,9 @@ +<% even = false %> +<% @items.each do |item| %> +
  • +
    + <%= linkify item, h(item.name(true)) %> +
    +
  • + <% even = !even %> +<% end %> diff --git a/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb b/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb index e178613..5a3425f 100644 --- a/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb +++ b/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb @@ -71,3 +71,12 @@ def generate_puppet_task_list @list_type = 'puppet_task' generate_list_contents end + +# Generates the searchable Puppet Plan list. +# @return [void] +def generate_puppet_plan_list + @items = Registry.all(:puppet_plan).sort_by {|t| t.name.to_s } + @list_title = 'Puppet Plan List' + @list_type = 'puppet_plan' + generate_list_contents +end diff --git a/lib/puppet-strings/yard/templates/default/layout/html/setup.rb b/lib/puppet-strings/yard/templates/default/layout/html/setup.rb index 7b237a8..8a5aaa1 100644 --- a/lib/puppet-strings/yard/templates/default/layout/html/setup.rb +++ b/lib/puppet-strings/yard/templates/default/layout/html/setup.rb @@ -4,7 +4,7 @@ def init case object when '_index.html' @page_title = options.title - sections :layout, [:index, [:listing, [:classes, :defined_types, :types, :providers, :functions, :tasks, :files, :objects]]] + sections :layout, [:index, [:listing, [:classes, :defined_types, :types, :providers, :functions, :tasks, :plans, :files, :objects]]] else super end @@ -50,6 +50,10 @@ def layout @nav_url = url_for_list('puppet_task') @page_title = "Puppet Task: #{object.name}" @path = object.path + when PuppetStrings::Yard::CodeObjects::Plan + @nav_url = url_for_list('puppet_plan') + @page_title = "Puppet Plan: #{object.name}" + @path = object.path else @path = object.path end @@ -97,6 +101,11 @@ def create_menu_lists title: 'Puppet Tasks', search_totle: 'Puppet Tasks' }, + { + type: 'puppet_plan', + title: 'Puppet Plans', + search_totle: 'Puppet Plans' + }, { type: 'class', title: 'Ruby Classes', @@ -186,6 +195,14 @@ def tasks erb(:objects) end +# Renders the plans section. +# @return [String] Returns the rendered section. +def plans + @title = 'Puppet Plan Listing A-Z' + @objects_by_letter = objects_by_letter(:puppet_plan) + erb(:objects) +end + # Renders the objects section. # @return [String] Returns the rendered section. def objects diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/box_info.erb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/box_info.erb new file mode 100644 index 0000000..49a6460 --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/box_info.erb @@ -0,0 +1,10 @@ +
    +
    +
    Defined in:
    +
    + <%= object.file %><% if object.files.size > 1 %>,
    + <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    + <% end %> + + + diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/header.erb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/header.erb new file mode 100644 index 0000000..9085f70 --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/header.erb @@ -0,0 +1 @@ +

    Puppet Plan: <%= object.name %>

    diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/overview.erb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/overview.erb new file mode 100644 index 0000000..a5b527a --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/overview.erb @@ -0,0 +1,6 @@ +

    Overview

    +
    +
    + <%= htmlify(object.docstring) %> +
    +
    diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/setup.rb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/setup.rb new file mode 100644 index 0000000..0db700d --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/setup.rb @@ -0,0 +1,11 @@ +# Initializes the template. +# @return [void] +def init + sections :header, :box_info, :summary, :overview, T('tags'), :source +end + +# Renders the box_info section. +# @return [String] Returns the rendered section. +def box_info + erb(:box_info) +end diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/source.erb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/source.erb new file mode 100644 index 0000000..0fd3c5e --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/source.erb @@ -0,0 +1,12 @@ +
    + + + + + +
    +
    <%= "\n\n\n" %><%= h format_lines(object) %>
    +
    +
    # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
    +
    +
    diff --git a/lib/puppet-strings/yard/templates/default/puppet_plan/html/summary.erb b/lib/puppet-strings/yard/templates/default/puppet_plan/html/summary.erb new file mode 100644 index 0000000..75e9867 --- /dev/null +++ b/lib/puppet-strings/yard/templates/default/puppet_plan/html/summary.erb @@ -0,0 +1,4 @@ +<% if object.docstring.has_tag?(:summary) %> +

    Summary

    + <%= object.docstring.tag(:summary).text %> +<% end %> diff --git a/lib/puppet-strings/yard/templates/default/tags/setup.rb b/lib/puppet-strings/yard/templates/default/tags/setup.rb index 99a3777..4e3f281 100644 --- a/lib/puppet-strings/yard/templates/default/tags/setup.rb +++ b/lib/puppet-strings/yard/templates/default/tags/setup.rb @@ -6,7 +6,8 @@ def param object.type == :puppet_class || object.type == :puppet_defined_type || object.type == :puppet_function || - object.type == :puppet_task + object.type == :puppet_task || + object.type == :puppet_plan end # Renders the overload section. diff --git a/spec/fixtures/unit/json/output.json b/spec/fixtures/unit/json/output.json index 73815d8..e874489 100644 --- a/spec/fixtures/unit/json/output.json +++ b/spec/fixtures/unit/json/output.json @@ -645,5 +645,8 @@ "supports_noop": false, "input_method": "stdin" } + ], + "puppet_plans": [ + ] } diff --git a/spec/fixtures/unit/json/output_with_plan.json b/spec/fixtures/unit/json/output_with_plan.json new file mode 100644 index 0000000..dbff7f1 --- /dev/null +++ b/spec/fixtures/unit/json/output_with_plan.json @@ -0,0 +1,689 @@ +{ + "puppet_classes": [ + { + "name": "klass", + "file": "(stdin)", + "line": 5, + "inherits": "foo::bar", + "docstring": { + "text": "A simple class.", + "tags": [ + { + "tag_name": "param", + "text": "First param.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "Second param.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "Third param.", + "types": [ + "String" + ], + "name": "param3" + } + ] + }, + "defaults": { + "param3": "hi" + }, + "source": "class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {\n}" + } + ], + "defined_types": [ + { + "name": "dt", + "file": "(stdin)", + "line": 12, + "docstring": { + "text": "A simple defined type.", + "tags": [ + { + "tag_name": "param", + "text": "First param.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "Second param.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "Third param.", + "types": [ + "String" + ], + "name": "param3" + } + ] + }, + "defaults": { + "param3": "hi" + }, + "source": "define dt(Integer $param1, $param2, String $param3 = hi) {\n}" + } + ], + "resource_types": [ + { + "name": "apt_key", + "file": "(stdin)", + "line": 92, + "docstring": { + "text": "This type provides Puppet with the capabilities to manage GPG keys needed\nby apt to perform package validation. Apt has it's own GPG keyring that can\nbe manipulated through the `apt-key` command.\n**Autorequires**:\nIf Puppet is given the location of a key file which looks like an absolute\npath this type will autorequire that file.", + "tags": [ + { + "tag_name": "summary", + "text": "Example resource type using the new API." + }, + { + "tag_name": "raise", + "text": "SomeError" + }, + { + "tag_name": "example", + "text": "apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':\n source => 'http://apt.puppetlabs.com/pubkey.gpg'\n}", + "name": "here's an example" + } + ] + }, + "properties": [ + { + "name": "ensure", + "description": "Whether this apt key should be present or absent on the target system.", + "data_type": "Enum[present, absent]" + }, + { + "name": "created", + "description": "Date the key was created, in ISO format.", + "data_type": "String" + } + ], + "parameters": [ + { + "name": "id", + "description": "The ID of the key you want to manage.", + "data_type": "Variant[Pattern[/A(0x)?[0-9a-fA-F]{8}Z/], Pattern[/A(0x)?[0-9a-fA-F]{16}Z/], Pattern[/A(0x)?[0-9a-fA-F]{40}Z/]]", + "isnamevar": true + } + ] + }, + { + "name": "database", + "file": "(stdin)", + "line": 54, + "docstring": { + "text": "An example database server resource type." + }, + "properties": [ + { + "name": "ensure", + "description": "What state the database should be in.", + "values": [ + "present", + "absent", + "up", + "down" + ], + "aliases": { + "up": "present", + "down": "absent" + }, + "default": "up" + }, + { + "name": "file", + "description": "The database file to use." + }, + { + "name": "log_level", + "description": "The log level to use.", + "values": [ + "debug", + "warn", + "error" + ], + "default": "warn" + } + ], + "parameters": [ + { + "name": "address", + "description": "The database server name.", + "isnamevar": true + }, + { + "name": "encryption_key", + "description": "The encryption key to use." + }, + { + "name": "encrypt", + "description": "Whether or not to encrypt the database.", + "values": [ + "true", + "false", + "yes", + "no" + ], + "default": "false" + } + ], + "features": [ + { + "name": "encryption", + "description": "The provider supports encryption." + } + ] + } + ], + "providers": [ + { + "name": "linux", + "type_name": "database", + "file": "(stdin)", + "line": 43, + "docstring": { + "text": "An example provider on Linux." + }, + "confines": { + "kernel": "Linux", + "osfamily": "RedHat" + }, + "features": [ + "implements_some_feature", + "some_other_feature" + ], + "defaults": [ + [ + [ + "kernel", + "Linux" + ] + ], + [ + [ + "osfamily", + "RedHat" + ], + [ + "operatingsystemmajrelease", + "7" + ] + ] + ], + "commands": { + "foo": "/usr/bin/foo" + } + } + ], + "puppet_functions": [ + { + "name": "func", + "file": "(stdin)", + "line": 6, + "type": "puppet", + "signatures": [ + { + "signature": "func(Integer $param1, Any $param2, String $param3 = hi)", + "docstring": { + "text": "A simple function.", + "tags": [ + { + "tag_name": "param", + "text": "First param.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "Second param.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "Third param.", + "types": [ + "String" + ], + "name": "param3" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + } + } + ], + "docstring": { + "text": "A simple function.", + "tags": [ + { + "tag_name": "param", + "text": "First param.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "Second param.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "Third param.", + "types": [ + "String" + ], + "name": "param3" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + }, + "defaults": { + "param3": "hi" + }, + "source": "function func(Integer $param1, $param2, String $param3 = hi) {\n}" + }, + { + "name": "func3x", + "file": "(stdin)", + "line": 1, + "type": "ruby3x", + "signatures": [ + { + "signature": "func3x(String $first, Any $second)", + "docstring": { + "text": "An example 3.x function.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "String" + ], + "name": "first" + }, + { + "tag_name": "param", + "text": "The second parameter.", + "types": [ + "Any" + ], + "name": "second" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + } + } + ], + "docstring": { + "text": "An example 3.x function.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "String" + ], + "name": "first" + }, + { + "tag_name": "param", + "text": "The second parameter.", + "types": [ + "Any" + ], + "name": "second" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + }, + "source": "Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC\nAn example 3.x function.\n@param [String] first The first parameter.\n@param second The second parameter.\n@return [Undef] Returns nothing.\nDOC\n) do |*args|\nend" + }, + { + "name": "func4x", + "file": "(stdin)", + "line": 11, + "type": "ruby4x", + "signatures": [ + { + "signature": "func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)", + "docstring": { + "text": "The first overload.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "The second parameter.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "The third parameter.", + "types": [ + "Optional[Array[String]]" + ], + "name": "param3" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + } + }, + { + "signature": "func4x(Boolean $param, Callable &$block)", + "docstring": { + "text": "", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Boolean" + ], + "name": "param" + }, + { + "tag_name": "param", + "text": "The block parameter.", + "types": [ + "Callable" + ], + "name": "&block" + }, + { + "tag_name": "return", + "text": "Returns a string.", + "types": [ + "String" + ] + } + ] + } + } + ], + "docstring": { + "text": "An example 4.x function.", + "tags": [ + { + "tag_name": "overload", + "signature": "func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)", + "docstring": { + "text": "The first overload.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "The second parameter.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "The third parameter.", + "types": [ + "Optional[Array[String]]" + ], + "name": "param3" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + }, + "name": "func4x" + }, + { + "tag_name": "overload", + "signature": "func4x(Boolean $param, Callable &$block)", + "docstring": { + "text": "", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Boolean" + ], + "name": "param" + }, + { + "tag_name": "param", + "text": "The block parameter.", + "types": [ + "Callable" + ], + "name": "&block" + }, + { + "tag_name": "return", + "text": "Returns a string.", + "types": [ + "String" + ] + } + ] + }, + "name": "func4x" + } + ] + }, + "source": "Puppet::Functions.create_function(:func4x) do\n # The first overload.\n # @param param1 The first parameter.\n # @param param2 The second parameter.\n # @param param3 The third parameter.\n # @return Returns nothing.\n dispatch :foo do\n param 'Integer', :param1\n param 'Any', :param2\n optional_param 'Array[String]', :param3\n return_type 'Undef'\n end\n\n # @param param The first parameter.\n # @param block The block parameter.\n # @return Returns a string.\n dispatch :other do\n param 'Boolean', :param\n block_param\n return_type 'String'\n end\nend" + }, + { + "name": "func4x_1", + "file": "(stdin)", + "line": 35, + "type": "ruby4x", + "signatures": [ + { + "signature": "func4x_1(Integer $param1)", + "docstring": { + "text": "An example 4.x function with only one signature.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + } + } + ], + "docstring": { + "text": "An example 4.x function with only one signature.", + "tags": [ + { + "tag_name": "param", + "text": "The first parameter.", + "types": [ + "Integer" + ], + "name": "param1" + }, + { + "tag_name": "return", + "text": "Returns nothing.", + "types": [ + "Undef" + ] + } + ] + }, + "source": "Puppet::Functions.create_function(:func4x_1) do\n # @param param1 The first parameter.\n # @return [Undef] Returns nothing.\n dispatch :foobarbaz do\n param 'Integer', :param1\n end\nend" + } + ], + "puppet_tasks": [ + { + "name": "(stdin)", + "file": "(stdin)", + "line": 0, + "docstring": { + "text": "Allows you to backup your database to local file.", + "tags": [ + { + "name": "database", + "tag_name": "param", + "text": "Database to connect to", + "types": [ + "Optional[String[1]]" + ] + }, + { + "name": "user", + "tag_name": "param", + "text": "The user", + "types": [ + "Optional[String[1]]" + ] + }, + { + "name": "password", + "tag_name": "param", + "text": "The password", + "types": [ + "Optional[String[1]]" + ] + }, + { + "name": "sql", + "tag_name": "param", + "text": "Path to file you want backup to", + "types": [ + "String[1]" + ] + } + ] + }, + "source": "{\n \"description\": \"Allows you to backup your database to local file.\",\n \"input_method\": \"stdin\",\n \"parameters\": {\n \"database\": {\n \"description\": \"Database to connect to\",\n \"type\": \"Optional[String[1]]\"\n },\n \"user\": {\n \"description\": \"The user\",\n \"type\": \"Optional[String[1]]\"\n },\n \"password\": {\n \"description\": \"The password\",\n \"type\": \"Optional[String[1]]\"\n },\n \"sql\": {\n \"description\": \"Path to file you want backup to\",\n \"type\": \"String[1]\"\n }\n }\n}\n", + "supports_noop": false, + "input_method": "stdin" + } + ], + "puppet_plans": [ + { + "name": "plann", + "file": "(stdin)", + "line": 5, + "docstring": { + "text": "A simple plan.", + "tags": [ + { + "tag_name": "param", + "text": "First param.", + "types": [ + "String" + ], + "name": "param1" + }, + { + "tag_name": "param", + "text": "Second param.", + "types": [ + "Any" + ], + "name": "param2" + }, + { + "tag_name": "param", + "text": "Third param.", + "types": [ + "Integer" + ], + "name": "param3" + } + ] + }, + "defaults": { + "param3": "1" + }, + "source": "plan plann(String $param1, $param2, Integer $param3 = 1) {\n}" + } + ] +} diff --git a/spec/fixtures/unit/markdown/output_with_plan.md b/spec/fixtures/unit/markdown/output_with_plan.md new file mode 100644 index 0000000..4b08b94 --- /dev/null +++ b/spec/fixtures/unit/markdown/output_with_plan.md @@ -0,0 +1,451 @@ +# Reference + +## Classes +### Public Classes +* [`klass`](#klass): A simple class. +### Private Classes +* `noparams`: Overview for class noparams +## Defined types +* [`klass::dt`](#klassdt): A simple defined type. +## Resource types +* [`apt_key`](#apt_key): Example resource type using the new API. +* [`database`](#database): An example database server type. +## Functions +* [`func`](#func): A simple Puppet function. +* [`func3x`](#func3x): Documentation for an example 3.x function. +* [`func4x`](#func4x): An example 4.x function. +* [`func4x_1`](#func4x_1): An example 4.x function with only one signature. +## Tasks +* [`(stdin)`](#(stdin)): Allows you to backup your database to local file. +## Classes + +### klass + +An overview for a simple class. + +* **Since** 1.0.0 + +* **See also** +www.puppet.com + + +#### Examples +##### This is an example +```puppet +class { 'klass': + param1 => 1, + param3 => 'foo', +} +``` + +##### This is another example +```puppet +class { 'klass': + param1 => 1, + param3 => 'foo', +} +``` + + +#### Parameters + +The following parameters are available in the `klass` class. + +##### `param1` + +Data type: `Integer` + +First param. + +Default value: 1 + +##### `param2` + +Data type: `Any` + +Second param. + +Options: + +* **:opt1** `String`: something about opt1 +* **:opt2** `Hash`: a hash of stuff + +Default value: `undef` + +##### `param3` + +Data type: `String` + +Third param. + +Default value: 'hi' + + +## Defined types + +### klass::dt + +An overview for a simple defined type. + +* **Since** 1.1.0 + +* **See also** +www.puppet.com + + +#### Examples +##### Here's an example of this type: +```puppet +klass::dt { 'foo': + param1 => 33, + param4 => false, +} +``` + + +#### Parameters + +The following parameters are available in the `klass::dt` defined type. + +##### `param1` + +Data type: `Integer` + +First param. + +Default value: 44 + +##### `param2` + +Data type: `Any` + +Second param. + +Options: + +* **:opt1** `String`: something about opt1 +* **:opt2** `Hash`: a hash of stuff + +##### `param3` + +Data type: `String` + +Third param. + +Default value: 'hi' + +##### `param4` + +Data type: `Boolean` + +Fourth param. + +Default value: `true` + + +## Resource types + +### apt_key + +This type provides Puppet with the capabilities to manage GPG keys needed +by apt to perform package validation. Apt has it's own GPG keyring that can +be manipulated through the `apt-key` command. +**Autorequires**: +If Puppet is given the location of a key file which looks like an absolute +path this type will autorequire that file. + +#### Examples +##### here's an example +```puppet +apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': + source => 'http://apt.puppetlabs.com/pubkey.gpg' +} +``` + +#### Properties + +The following properties are available in the `apt_key` type. + +##### `ensure` + +Data type: `Enum[present, absent]` + +Whether this apt key should be present or absent on the target system. + +##### `created` + +Data type: `String` + +Date the key was created, in ISO format. + +#### Parameters + +The following parameters are available in the `apt_key` type. + +##### `id` + +namevar + +Data type: `Variant[Pattern[/A(0x)?[0-9a-fA-F]{8}Z/], Pattern[/A(0x)?[0-9a-fA-F]{16}Z/], Pattern[/A(0x)?[0-9a-fA-F]{40}Z/]]` +_*this data type contains a regex that may not be accurately reflected in generated documentation_ + +The ID of the key you want to manage. + + +### database + +An example database server type. + +#### Examples +##### here's an example +```puppet +database { 'foo': + address => 'qux.baz.bar', +} +``` + +#### Properties + +The following properties are available in the `database` type. + +##### `ensure` + +Valid values: present, absent, up, down + +Aliases: "up"=>"present", "down"=>"absent" + +What state the database should be in. + +Default value: up + +##### `file` + +The database file to use. + +##### `log_level` + +Valid values: debug, warn, error + +The log level to use. + +Default value: warn + +#### Parameters + +The following parameters are available in the `database` type. + +##### `address` + +namevar + +The database server name. + +##### `encryption_key` + +The encryption key to use. + +##### `encrypt` + +Valid values: `true`, `false`, yes, no + +Whether or not to encrypt the database. + +Default value: `false` + + +## Functions + +### func +Type: Puppet Language + +A simple Puppet function. + +#### `func(Integer $param1, Any $param2, String $param3 = hi)` + +A simple Puppet function. + +Returns: `Undef` Returns nothing. + +Raises: +* `SomeError` this is some error + +##### `param1` + +Data type: `Integer` + +First param. + +##### `param2` + +Data type: `Any` + +Second param. + +##### `param3` + +Data type: `String` + +Third param. + +Options: + +* **:param3opt** `Array`: Something about this option + +### func3x +Type: Ruby 3.x API + +Documentation for an example 3.x function. + +#### `func3x(String $param1, Integer $param2)` + +Documentation for an example 3.x function. + +Returns: `Undef` + +##### `param1` + +Data type: `String` + +The first parameter. + +##### `param2` + +Data type: `Integer` + +The second parameter. + +### func4x +Type: Ruby 4.x API + +An example 4.x function. + +#### `func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)` + +An overview for the first overload. + +Returns: `Undef` Returns nothing. + +##### `param1` + +Data type: `Integer` + +The first parameter. + +##### `param2` + +Data type: `Any` + +The second parameter. + +Options: + +* **:option** `String`: an option +* **:option2** `String`: another option + +##### `param3` + +Data type: `Optional[Array[String]]` + +The third parameter. + +#### `func4x(Boolean $param, Callable &$block)` + +An overview for the second overload. + +Returns: `String` Returns a string. + +##### `param` + +Data type: `Boolean` + +The first parameter. + +##### `&block` + +Data type: `Callable` + +The block parameter. + +### func4x_1 +Type: Ruby 4.x API + +An example 4.x function with only one signature. + +#### `func4x_1(Integer $param1)` + +An example 4.x function with only one signature. + +Returns: `Undef` Returns nothing. + +##### `param1` + +Data type: `Integer` + +The first parameter. + +## Tasks + +### (stdin) + +Allows you to backup your database to local file. + +**Supports noop?** false + +#### Parameters + +##### `database` + +Data type: `Optional[String[1]]` + +Database to connect to + +##### `user` + +Data type: `Optional[String[1]]` + +The user + +##### `password` + +Data type: `Optional[String[1]]` + +The password + +##### `sql` + +Data type: `String[1]` + +Path to file you want backup to + +## Plans + +### plann + +A simple plan. + + +#### Parameters + +The following parameters are available in the `plann` plan. + +##### `param1` + +Data type: `String` + +First param. + +##### `param2` + +Data type: `Any` + +Second param. + +##### `param3` + +Data type: `Integer` + +Third param. + +Default value: 1 + + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 32b6351..5378af8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -27,10 +27,13 @@ require 'puppet-strings/yard' PuppetStrings::Yard.setup! # Enable testing of Puppet functions if running against 4.1+ -TEST_PUPPET_FUNCTIONS = Gem::Dependency.new('', '>= 4.1.0').match?('', Puppet::PUPPETVERSION) +TEST_PUPPET_FUNCTIONS = Puppet::Util::Package.versioncmp(Puppet.version, "4.1.0") >= 0 # Enable testing of Puppet language functions declared with return type if running against 4.8+ -TEST_FUNCTION_RETURN_TYPE = Gem::Dependency.new('', '>= 4.8.0').match?('', Puppet::PUPPETVERSION) +TEST_FUNCTION_RETURN_TYPE = Puppet::Util::Package.versioncmp(Puppet.version, "4.8.0") >= 0 + +# Enable testing of Plans if Puppet version is greater than 5.0.0 +TEST_PUPPET_PLANS = Puppet::Util::Package.versioncmp(Puppet.version, "5.0.0") >= 0 RSpec.configure do |config| config.mock_with :mocha diff --git a/spec/unit/puppet-strings/json_spec.rb b/spec/unit/puppet-strings/json_spec.rb index a6d9a7e..d9fe243 100644 --- a/spec/unit/puppet-strings/json_spec.rb +++ b/spec/unit/puppet-strings/json_spec.rb @@ -19,6 +19,15 @@ class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { # @param param3 Third param. define dt(Integer $param1, $param2, String $param3 = hi) { } +SOURCE + + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) if TEST_PUPPET_PLANS +# A simple plan. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +plan plann(String $param1, $param2, Integer $param3 = 1) { +} SOURCE # Only include Puppet functions for 4.1+ @@ -191,7 +200,13 @@ path this type will autorequire that file. SOURCE end - let(:filename) { TEST_PUPPET_FUNCTIONS ? 'output.json' : 'output_without_puppet_function.json' } + let(:filename) do + if TEST_PUPPET_PLANS + 'output_with_plan.json' + else + TEST_PUPPET_FUNCTIONS ? 'output.json' : 'output_without_puppet_function.json' + end + end let(:baseline_path) { File.join(File.dirname(__FILE__), "../../fixtures/unit/json/#{filename}") } let(:baseline) { File.read(baseline_path) } diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index a8bda64..c03b202 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -64,28 +64,12 @@ define klass::dt ( ) { } SOURCE - YARD::Parser::SourceParser.parse_string(<<-SOURCE, :json) -{ - "description": "Allows you to backup your database to local file.", - "input_method": "stdin", - "parameters": { - "database": { - "description": "Database to connect to", - "type": "Optional[String[1]]" - }, - "user": { - "description": "The user", - "type": "Optional[String[1]]" - }, - "password": { - "description": "The password", - "type": "Optional[String[1]]" - }, - "sql": { - "description": "Path to file you want backup to", - "type": "String[1]" - } - } + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) if TEST_PUPPET_PLANS +# A simple plan. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +plan plann(String $param1, $param2, Integer $param3 = 1) { } SOURCE @@ -276,7 +260,13 @@ path this type will autorequire that file. SOURCE end - let(:filename) { 'output.md' } + let(:filename) do + if TEST_PUPPET_PLANS + 'output_with_plan.md' + else + 'output.md' + end + end let(:baseline_path) { File.join(File.dirname(__FILE__), "../../fixtures/unit/markdown/#{filename}") } let(:baseline) { File.read(baseline_path) }