Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

markup/asciidocext: Enable converter templates #12318

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/data/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,8 @@ config:
preserveTOC: false
safeMode: unsafe
sectionNumbers: false
templateDirectories: []
templateEngine: handlebars
trace: false
verbose: false
workingFolderCurrent: false
Expand Down Expand Up @@ -2797,8 +2799,8 @@ tpl:
{{ $m.Set "Hugo" "Rocks!" }}
{{ $m.Values | debug.Dump | safeHTML }}
- |-
map[string]interface {}{
"Hugo": "Rocks!",
{
"Hugo": "Rocks!"
}
TestDeprecationErr:
Aliases: null
Expand Down
8 changes: 8 additions & 0 deletions markup/asciidocext/asciidocext_config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ var (
FailureLevel: "fatal",
WorkingFolderCurrent: false,
PreserveTOC: false,
TemplateDirectories: []string{},
TemplateEngine: "handlebars",
}

// CliDefault holds Asciidoctor CLI defaults (see https://asciidoctor.org/docs/user-manual/)
Expand Down Expand Up @@ -58,6 +60,10 @@ var (
"manpage": true,
}

AllowedTemplateEngine = map[string]bool{
"handlebars": true,
}

DisallowedAttributes = map[string]bool{
"outdir": true,
}
Expand All @@ -76,4 +82,6 @@ type Config struct {
FailureLevel string
WorkingFolderCurrent bool
PreserveTOC bool
TemplateDirectories []string
TemplateEngine string
}
135 changes: 135 additions & 0 deletions markup/asciidocext/asciidocext_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package asciidocext_test

import (
"strings"
"testing"

"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/markup/asciidocext"
)

func TestAsciiDocConverterTemplates(t *testing.T) {
if !asciidocext.Supports() {
t.Skip("asciidoctor not installed")
}
missingGems := listMissingConverterTemplateGems()
if len(missingGems) > 0 {
t.Skip("these ruby gems, required to use AsciiDoc converter templates, are not installed:", strings.Join(missingGems, ", "))
}

files := `
-- hugo.toml --
disableKinds = ['page','section','rss','section','sitemap','taxonomy','term']
[markup.asciidocext]
templateDirectories = ['a','b']
templateEngine = 'handlebars'
[security.exec]
allow = ['asciidoctor']
-- content/_index.adoc --
---
title: home
---
https://gohugo.io[This is a link,title="Hugo rocks!"]

image:a.jpg[alt=A kitten,title=This is my kitten!]
-- layouts/index.html --
{{ .Content }}
-- a/inline_anchor.html.handlebars --
inline_anchor_html_handlebars
-- b/inline_image.html.handlebars --
inline_image_html_handlebars
`

b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
NeedsOsFS: true,
}).Build()

b.AssertFileContent("public/index.html",
`<p>inline_anchor_html_handlebars</p>`,
`<p>inline_image_html_handlebars</p>`,
)
}

func TestAsciiDocConverterTemplatesWithDisallowedFile(t *testing.T) {
if !asciidocext.Supports() {
t.Skip("asciidoctor not installed")
}
missingGems := listMissingConverterTemplateGems()
if len(missingGems) > 0 {
t.Skip("these ruby gems, required to use AsciiDoc converter templates, are not installed:", strings.Join(missingGems, ", "))
}

files := `
-- hugo.toml --
disableKinds = ['page','section','rss','section','sitemap','taxonomy','term']
[markup.asciidocext]
templateDirectories = ['a','b']
templateEngine = 'handlebars'
[security.exec]
allow = ['asciidoctor']
-- content/_index.adoc --
---
title: home
---
https://gohugo.io[This is a link,title="Hugo rocks!"]

image:a.jpg[alt=A kitten,title=This is my kitten!]
-- layouts/index.html --
{{ .Content }}
-- a/inline_anchor.html.handlebars --
inline_anchor_html_handlebars
-- b/inline_image.html.handlebars --
inline_image_html_handlebars
-- b/helpers.js --
I have the potential to execute arbitrary code; skip this directory!
`

b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
NeedsOsFS: true,
}).Build()

b.AssertFileContent("public/index.html",
`<p>inline_anchor_html_handlebars</p>`,
`<img src="a.jpg" alt="A kitten" title="This is my kitten!"/>`,
)
}

// converterTemplateGems is a map of the ruby gems required to test AsciiDoc
// converter templates. The key is the gem name, while the value is the
// executable name.
var converterTemplateGems = map[string]string{
"tilt": "tilt",
"tilt-handlebars": "handlebars",
}

// listMissingConverterTemplateGems returns a slice of missing (not installed)
// ruby gems that are required to test AsciiDoc converter templates.
func listMissingConverterTemplateGems() []string {
var gems []string
for name, exec := range converterTemplateGems {
if !hexec.InPath(exec) {
gems = append(gems, name)
}
}
return gems
}
64 changes: 41 additions & 23 deletions markup/asciidocext/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestAsciidoctorDefaultArgs(t *testing.T) {
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(converter.DocumentContext{})
expected := []string{"--no-header-footer"}
expected := []string{"--template-engine", "handlebars", "--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected)
}

Expand All @@ -70,6 +70,8 @@ func TestAsciidoctorNonDefaultArgs(t *testing.T) {
mconf.AsciidocExt.Verbose = true
mconf.AsciidocExt.Trace = false
mconf.AsciidocExt.FailureLevel = "warn"
mconf.AsciidocExt.TemplateDirectories = []string{"foo"}
mconf.AsciidocExt.TemplateEngine = "handlebars"

conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)

Expand All @@ -88,7 +90,10 @@ func TestAsciidoctorNonDefaultArgs(t *testing.T) {
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(converter.DocumentContext{})
expected := []string{"-b", "manpage", "--section-numbers", "--verbose", "--failure-level", "warn", "--safe-mode", "safe"}
expected := []string{
"-b", "manpage", "--failure-level", "warn", "--safe-mode", "safe",
"--template-engine", "handlebars", "--section-numbers", "--verbose",
}
c.Assert(args, qt.DeepEquals, expected)
}

Expand All @@ -100,6 +105,7 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) {
mconf.AsciidocExt.Attributes = map[string]string{"outdir": "disallowed-attribute"}
mconf.AsciidocExt.SafeMode = "disallowed-safemode"
mconf.AsciidocExt.FailureLevel = "disallowed-failurelevel"
mconf.AsciidocExt.TemplateEngine = "disallowed-templateengine"

conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)

Expand Down Expand Up @@ -142,7 +148,7 @@ func TestAsciidoctorArbitraryExtension(t *testing.T) {
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(converter.DocumentContext{})
expected := []string{"-r", "arbitrary-extension", "--no-header-footer"}
expected := []string{"--template-engine", "handlebars", "-r", "arbitrary-extension", "--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected)
}

Expand Down Expand Up @@ -176,7 +182,7 @@ func TestAsciidoctorDisallowedExtension(t *testing.T) {
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(converter.DocumentContext{})
expected := []string{"--no-header-footer"}
expected := []string{"--template-engine", "handlebars", "--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected)
}
}
Expand All @@ -188,6 +194,8 @@ func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
[markup.asciidocext]
workingFolderCurrent = true
trace = false
templateDirectories = ['foo']
templateEngine = 'handlebars'
`)

conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg)
Expand All @@ -208,12 +216,14 @@ trace = false
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(ctx)
c.Assert(len(args), qt.Equals, 5)
c.Assert(args[0], qt.Equals, "--base-dir")
c.Assert(filepath.ToSlash(args[1]), qt.Matches, "/tmp/hugo_asciidoc_ddd/docs/chapter2")
c.Assert(args[2], qt.Equals, "-a")
c.Assert(args[3], qt.Matches, `outdir=.*chapter2`)
c.Assert(args[4], qt.Equals, "--no-header-footer")
c.Assert(len(args), qt.Equals, 7)
c.Assert(args[0], qt.Equals, "--template-engine")
c.Assert(args[1], qt.Equals, "handlebars")
c.Assert(args[2], qt.Equals, "--base-dir")
c.Assert(filepath.ToSlash(args[3]), qt.Matches, "/tmp/hugo_asciidoc_ddd/docs/chapter2")
c.Assert(args[4], qt.Equals, "-a")
c.Assert(args[5], qt.Matches, `outdir=.*chapter2`)
c.Assert(args[6], qt.Equals, "--no-header-footer")
}

func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) {
Expand All @@ -226,6 +236,8 @@ workingFolderCurrent = true
trace = false
noHeaderOrFooter = true
extensions = ["asciidoctor-html5s", "asciidoctor-diagram"]
templateDirectories = ['foo']
templateEngine = 'handlebars'
`)
conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg)

Expand All @@ -244,18 +256,20 @@ extensions = ["asciidoctor-html5s", "asciidoctor-diagram"]
c.Assert(ac, qt.Not(qt.IsNil))

args := ac.ParseArgs(converter.DocumentContext{})
c.Assert(len(args), qt.Equals, 11)
c.Assert(len(args), qt.Equals, 13)
c.Assert(args[0], qt.Equals, "-b")
c.Assert(args[1], qt.Equals, "html5s")
c.Assert(args[2], qt.Equals, "-r")
c.Assert(args[3], qt.Equals, "asciidoctor-html5s")
c.Assert(args[2], qt.Equals, "--template-engine")
c.Assert(args[3], qt.Equals, "handlebars")
c.Assert(args[4], qt.Equals, "-r")
c.Assert(args[5], qt.Equals, "asciidoctor-diagram")
c.Assert(args[6], qt.Equals, "--base-dir")
c.Assert(args[7], qt.Equals, ".")
c.Assert(args[8], qt.Equals, "-a")
c.Assert(args[9], qt.Contains, "outdir=")
c.Assert(args[10], qt.Equals, "--no-header-footer")
c.Assert(args[5], qt.Equals, "asciidoctor-html5s")
c.Assert(args[6], qt.Equals, "-r")
c.Assert(args[7], qt.Equals, "asciidoctor-diagram")
c.Assert(args[8], qt.Equals, "--base-dir")
c.Assert(args[9], qt.Equals, ".")
c.Assert(args[10], qt.Equals, "-a")
c.Assert(args[11], qt.Contains, "outdir=")
c.Assert(args[12], qt.Equals, "--no-header-footer")
}

func TestAsciidoctorAttributes(t *testing.T) {
Expand All @@ -264,6 +278,8 @@ func TestAsciidoctorAttributes(t *testing.T) {
[markup]
[markup.asciidocext]
trace = false
templateDirectories = ['foo']
templateEngine = 'handlebars'
[markup.asciidocext.attributes]
my-base-url = "https://gohugo.io/"
my-attribute-name = "my value"
Expand All @@ -289,12 +305,14 @@ my-attribute-name = "my value"
}

args := ac.ParseArgs(converter.DocumentContext{})
c.Assert(len(args), qt.Equals, 5)
c.Assert(args[0], qt.Equals, "-a")
c.Assert(expectedValues[args[1]], qt.Equals, true)
c.Assert(len(args), qt.Equals, 7)
c.Assert(args[0], qt.Equals, "--template-engine")
c.Assert(args[1], qt.Equals, "handlebars")
c.Assert(args[2], qt.Equals, "-a")
c.Assert(expectedValues[args[3]], qt.Equals, true)
c.Assert(args[4], qt.Equals, "--no-header-footer")
c.Assert(args[4], qt.Equals, "-a")
c.Assert(expectedValues[args[5]], qt.Equals, true)
c.Assert(args[6], qt.Equals, "--no-header-footer")
}

func getProvider(c *qt.C, mConfStr string) converter.Provider {
Expand Down
Loading
Loading