adding markdown conversion to PDF + fixing some issue in CI process

This commit is contained in:
Julien Neuhart
2018-04-10 16:56:30 +02:00
parent 563733f496
commit e29ab4760a
21 changed files with 114 additions and 19 deletions

View File

@@ -55,9 +55,10 @@ ENTRYPOINT [".ci/docker-entrypoint.sh"]
COPY .ci/gotenberg /usr/bin/gotenberg COPY .ci/gotenberg /usr/bin/gotenberg
RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg
WORKDIR /gotenberg
COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml
WORKDIR /gotenberg
EXPOSE 3000 EXPOSE 3000
CMD ["gotenberg"] CMD ["gotenberg"]
{{- end }} {{- end }}

View File

@@ -11,17 +11,22 @@ if [[ "$VERSION" == "snapshot" ]]; then
go test -race -cover $d; go test -race -cover $d;
done done
else else
echo "" > ./.ci/coverage.txt; echo "" > .ci/coverage.txt;
for d in $(go list ./... | grep -v vendor); do for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic $d; go test -race -coverprofile=profile.out -covermode=atomic $d;
if [ -f profile.out ]; then if [ -f profile.out ]; then
cat profile.out >> ./.ci/coverage.txt; cat profile.out >> .ci/coverage.txt;
rm profile.out; rm profile.out;
fi fi
done done
fi fi
# Builds the Linux binary. # Builds the Linux binary.
if [ -f .ci/gotenberg ]; then
rm .ci/gotenberg
fi
env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.version=${VERSION}" && mv gotenberg .ci/; env GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.version=${VERSION}" && mv gotenberg .ci/;
# Bye! # Bye!

View File

@@ -12,6 +12,10 @@ logs:
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -38,8 +38,9 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - &&\
COPY .ci/gotenberg /usr/bin/gotenberg COPY .ci/gotenberg /usr/bin/gotenberg
RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg
WORKDIR /gotenberg
COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml
WORKDIR /gotenberg
EXPOSE 3000 EXPOSE 3000
CMD ["gotenberg"] CMD ["gotenberg"]

View File

@@ -6,6 +6,9 @@ logs:
... ...
} }
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 0
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 0 timeout: 0
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "DEBUG" format: "DEBUG"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "text" level: "text"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -0,0 +1,17 @@
port: 3000
logs:
level: "DEBUG"
format: "text"
commands:
markdown:
timeout: 30
template: "markdown-pdf {{ FilePath }} -o {{ .ResultFilePath }}"
html:
timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"
office:
timeout: 30
template: "unoconv --format pdf --output \"{{ .ResultFilePath }}\" \"{{ .FilePath }}\""
merge:
timeout: 30
template: "pdftk {{ range $filePath := .FilesPaths }} {{ $filePath }} {{ end }} cat output {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

View File

@@ -3,6 +3,9 @@ logs:
level: "DEBUG" level: "DEBUG"
format: "text" format: "text"
commands: commands:
markdown:
timeout: 30
template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}"
html: html:
timeout: 30 timeout: 30
template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}"

1
_tests/file.md Normal file
View File

@@ -0,0 +1 @@
# Hi, I've been converted from a markdown file!

View File

@@ -33,6 +33,9 @@ type (
// CommandsConfig gathers all commands' configurations as defined // CommandsConfig gathers all commands' configurations as defined
// by the user in the gotenberg.yml file. // by the user in the gotenberg.yml file.
CommandsConfig struct { CommandsConfig struct {
// Markdown is the command's configuration for converting
// an markdown file to PDF.
Markdown *CommandConfig
// HTML is the command's configuration for converting // HTML is the command's configuration for converting
// an HTML file to PDF. // an HTML file to PDF.
HTML *CommandConfig HTML *CommandConfig
@@ -79,13 +82,20 @@ func NewAppConfig(configurationFilePath string) (*AppConfig, error) {
c.Logs.Formatter = formatter c.Logs.Formatter = formatter
c.CommandsConfig = &CommandsConfig{} c.CommandsConfig = &CommandsConfig{}
c.CommandsConfig.Markdown = &CommandConfig{}
c.CommandsConfig.HTML = &CommandConfig{} c.CommandsConfig.HTML = &CommandConfig{}
c.CommandsConfig.Office = &CommandConfig{} c.CommandsConfig.Office = &CommandConfig{}
c.CommandsConfig.Merge = &CommandConfig{} c.CommandsConfig.Merge = &CommandConfig{}
c.CommandsConfig.Markdown.Timeout = fileConfig.Commands.Markdown.Timeout
c.CommandsConfig.HTML.Timeout = fileConfig.Commands.HTML.Timeout c.CommandsConfig.HTML.Timeout = fileConfig.Commands.HTML.Timeout
c.CommandsConfig.Office.Timeout = fileConfig.Commands.Office.Timeout c.CommandsConfig.Office.Timeout = fileConfig.Commands.Office.Timeout
c.CommandsConfig.Merge.Timeout = fileConfig.Commands.Merge.Timeout c.CommandsConfig.Merge.Timeout = fileConfig.Commands.Merge.Timeout
tmplMarkdown, err := getCommandTemplate(fileConfig.Commands.Markdown.Template, "Markdown")
if err != nil {
return nil, err
}
tmplHTML, err := getCommandTemplate(fileConfig.Commands.HTML.Template, "HTML") tmplHTML, err := getCommandTemplate(fileConfig.Commands.HTML.Template, "HTML")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -101,6 +111,7 @@ func NewAppConfig(configurationFilePath string) (*AppConfig, error) {
return nil, err return nil, err
} }
c.CommandsConfig.Markdown.Template = tmplMarkdown
c.CommandsConfig.HTML.Template = tmplHTML c.CommandsConfig.HTML.Template = tmplHTML
c.CommandsConfig.Office.Template = tmplOffice c.CommandsConfig.Office.Template = tmplOffice
c.CommandsConfig.Merge.Template = tmplMerge c.CommandsConfig.Merge.Template = tmplMerge
@@ -116,6 +127,10 @@ type fileConfig struct {
Format string `yaml:"format"` Format string `yaml:"format"`
} `yaml:"logs"` } `yaml:"logs"`
Commands struct { Commands struct {
Markdown struct {
Timeout int `yaml:"timeout"`
Template string `yaml:"template"`
} `yaml:"markdown"`
HTML struct { HTML struct {
Timeout int Timeout int
Template string Template string

View File

@@ -29,25 +29,31 @@ func TestNewAppConfig(t *testing.T) {
t.Error("AppConfig should not have been instantiated!") t.Error("AppConfig should not have been instantiated!")
} }
// case 5: uses a configuration file with a wrong HTML command template. // case 5: uses a configuration file with a wrong markdown command template.
path, _ = filepath.Abs("../../_tests/configurations/wrong-markdown-command-template-gotenberg.yml")
if _, err := NewAppConfig(path); err == nil {
t.Error("AppConfig should not have been instantiated!")
}
// case 6: uses a configuration file with a wrong HTML command template.
path, _ = filepath.Abs("../../_tests/configurations/wrong-html-command-template-gotenberg.yml") path, _ = filepath.Abs("../../_tests/configurations/wrong-html-command-template-gotenberg.yml")
if _, err := NewAppConfig(path); err == nil { if _, err := NewAppConfig(path); err == nil {
t.Error("AppConfig should not have been instantiated!") t.Error("AppConfig should not have been instantiated!")
} }
// case 6: uses a configuration file with a wrong Office command template. // case 7: uses a configuration file with a wrong Office command template.
path, _ = filepath.Abs("../../_tests/configurations/wrong-office-command-template-gotenberg.yml") path, _ = filepath.Abs("../../_tests/configurations/wrong-office-command-template-gotenberg.yml")
if _, err := NewAppConfig(path); err == nil { if _, err := NewAppConfig(path); err == nil {
t.Error("AppConfig should not have been instantiated!") t.Error("AppConfig should not have been instantiated!")
} }
// case 7: uses a configuration file with a wrong merge command template. // case 8: uses a configuration file with a wrong merge command template.
path, _ = filepath.Abs("../../_tests/configurations/wrong-merge-command-template-gotenberg.yml") path, _ = filepath.Abs("../../_tests/configurations/wrong-merge-command-template-gotenberg.yml")
if _, err := NewAppConfig(path); err == nil { if _, err := NewAppConfig(path); err == nil {
t.Error("AppConfig should not have been instantiated!") t.Error("AppConfig should not have been instantiated!")
} }
// case 8: uses a correct configuration file. // case 9: uses a correct configuration file.
path, _ = filepath.Abs("../../_tests/configurations/gotenberg.yml") path, _ = filepath.Abs("../../_tests/configurations/gotenberg.yml")
if _, err := NewAppConfig(path); err != nil { if _, err := NewAppConfig(path); err != nil {
t.Error("AppConfig should have been instantiated!") t.Error("AppConfig should have been instantiated!")

View File

@@ -25,6 +25,8 @@ type Type uint32
const ( const (
// PDFType represents a... PDF file. // PDFType represents a... PDF file.
PDFType Type = iota PDFType Type = iota
// MarkdownType represents a... markdown file.
MarkdownType
// HTMLType represents an... HTML file. // HTMLType represents an... HTML file.
HTMLType HTMLType
// OfficeType represents an... Office document. // OfficeType represents an... Office document.
@@ -34,6 +36,7 @@ const (
// filesTypes associates a file extension with its file kind counterpart. // filesTypes associates a file extension with its file kind counterpart.
var filesTypes = map[string]Type{ var filesTypes = map[string]Type{
".pdf": PDFType, ".pdf": PDFType,
".md": MarkdownType,
".htm": HTMLType, ".htm": HTMLType,
".html": HTMLType, ".html": HTMLType,
".doc": OfficeType, ".doc": OfficeType,

View File

@@ -3,6 +3,7 @@ package process
import ( import (
"bytes" "bytes"
"fmt"
"os/exec" "os/exec"
"text/template" "text/template"
"time" "time"
@@ -45,6 +46,10 @@ func Unconv(workingDir string, file *gfile.File) (string, error) {
) )
switch file.Type { switch file.Type {
case gfile.MarkdownType:
cmdTemplate = commandsConfig.Markdown.Template
cmdTimeout = commandsConfig.Markdown.Timeout
break
case gfile.HTMLType: case gfile.HTMLType:
cmdTemplate = commandsConfig.HTML.Template cmdTemplate = commandsConfig.HTML.Template
cmdTimeout = commandsConfig.HTML.Timeout cmdTimeout = commandsConfig.HTML.Timeout
@@ -99,12 +104,13 @@ func Merge(workingDir string, filesPaths []string) (string, error) {
return cmdData.ResultFilePath, nil return cmdData.ResultFilePath, nil
} }
type commandTimeoutError struct{} type commandTimeoutError struct {
command string
const commandTimeoutErrorMessage = "The command has reached timeout" timeout int
}
func (e *commandTimeoutError) Error() string { func (e *commandTimeoutError) Error() string {
return commandTimeoutErrorMessage return fmt.Sprintf("The command '%s' has reached the %d second(s) timeout", e.command, e.timeout)
} }
// run runs the given command. If timeout is reached or // run runs the given command. If timeout is reached or
@@ -126,7 +132,10 @@ func run(command string, timeout int) error {
if err := cmd.Process.Kill(); err != nil { if err := cmd.Process.Kill(); err != nil {
return err return err
} }
return &commandTimeoutError{} return &commandTimeoutError{
command: command,
timeout: timeout,
}
case err := <-done: case err := <-done:
if err != nil { if err != nil {
return err return err

View File

@@ -120,8 +120,14 @@ func TestImpossibleConversionError(t *testing.T) {
} }
func TestCommandTimeoutError(t *testing.T) { func TestCommandTimeoutError(t *testing.T) {
err := &commandTimeoutError{} err := &commandTimeoutError{
if err.Error() != commandTimeoutErrorMessage { command: "echo hello",
t.Errorf("Error returned a wrong message: got %s want %s", err.Error(), commandTimeoutErrorMessage) timeout: 30,
}
expected := fmt.Sprintf("The command '%s' has reached the %d second(s) timeout", err.command, err.timeout)
if err.Error() != expected {
t.Errorf("Error returned a wrong message: got %s want %s", err.Error(), expected)
} }
} }

View File

@@ -15,8 +15,8 @@ tasks:
- use: ci - use: ci
short: Runs CI process inside a container short: Runs CI process inside a container
run: run:
- docker build -t gotenberg:ci -f Dockerfile.ci . - docker build -t thecodingmachine/gotenberg:ci -f Dockerfile.ci .
- docker run --rm -e "VERSION={{ .Orbit.Version }}" -v "$(pwd)/.ci:/go/src/github.com/thecodingmachine/gotenberg/.ci" gotenberg:ci - docker run --rm -e "VERSION={{ .Orbit.Version }}" -v "$(pwd)/.ci:/go/src/github.com/thecodingmachine/gotenberg/.ci" thecodingmachine/gotenberg:ci
- use: build - use: build
short: Builds the main Docker image short: Builds the main Docker image
@@ -26,4 +26,4 @@ tasks:
- use: up - use: up
short: Starts the {{ .Orbit.Version }} version of the Gotenberg image short: Starts the {{ .Orbit.Version }} version of the Gotenberg image
run: run:
- docker run --rm -p 3000:3000/tcp gotenberg:{{ .Orbit.Version }} - docker run --rm -p 3000:3000/tcp thecodingmachine/gotenberg:{{ .Orbit.Version }}