diff --git a/.blueprints/Dockerfile.blueprint b/.blueprints/Dockerfile.blueprint index c46a27d2..1dd6e3ea 100644 --- a/.blueprints/Dockerfile.blueprint +++ b/.blueprints/Dockerfile.blueprint @@ -55,9 +55,10 @@ ENTRYPOINT [".ci/docker-entrypoint.sh"] COPY .ci/gotenberg /usr/bin/gotenberg RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg -WORKDIR /gotenberg COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml +WORKDIR /gotenberg + EXPOSE 3000 CMD ["gotenberg"] {{- end }} \ No newline at end of file diff --git a/.ci/docker-entrypoint.sh b/.ci/docker-entrypoint.sh index 404e24d0..30efdfa2 100755 --- a/.ci/docker-entrypoint.sh +++ b/.ci/docker-entrypoint.sh @@ -11,17 +11,22 @@ if [[ "$VERSION" == "snapshot" ]]; then go test -race -cover $d; done else - echo "" > ./.ci/coverage.txt; + echo "" > .ci/coverage.txt; for d in $(go list ./... | grep -v vendor); do go test -race -coverprofile=profile.out -covermode=atomic $d; if [ -f profile.out ]; then - cat profile.out >> ./.ci/coverage.txt; + cat profile.out >> .ci/coverage.txt; rm profile.out; fi done fi + # 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/; # Bye! diff --git a/.ci/gotenberg.yml b/.ci/gotenberg.yml index 3e48d72d..43ccb2e9 100644 --- a/.ci/gotenberg.yml +++ b/.ci/gotenberg.yml @@ -12,6 +12,10 @@ logs: commands: + markdown: + timeout: 30 + template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}" + html: timeout: 30 template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" diff --git a/Dockerfile b/Dockerfile index 8d0fa13e..4ffdf955 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,8 +38,9 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - &&\ COPY .ci/gotenberg /usr/bin/gotenberg RUN ln -s /usr/bin/gotenberg /usr/local/bin/gotenberg -WORKDIR /gotenberg COPY .ci/gotenberg.yml /gotenberg/gotenberg.yml +WORKDIR /gotenberg + EXPOSE 3000 CMD ["gotenberg"] \ No newline at end of file diff --git a/_tests/configurations/broken-gotenberg.yml b/_tests/configurations/broken-gotenberg.yml index 01a20b71..d593a215 100644 --- a/_tests/configurations/broken-gotenberg.yml +++ b/_tests/configurations/broken-gotenberg.yml @@ -6,6 +6,9 @@ logs: ... } commands: + markdown: + timeout: 30 + template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}" html: timeout: 30 template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" diff --git a/_tests/configurations/gotenberg.yml b/_tests/configurations/gotenberg.yml index 87459cf2..d0fe6da2 100644 --- a/_tests/configurations/gotenberg.yml +++ b/_tests/configurations/gotenberg.yml @@ -3,6 +3,9 @@ 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 }}" diff --git a/_tests/configurations/merge-timeout-gotenberg.yml b/_tests/configurations/merge-timeout-gotenberg.yml index cc1323fe..41fd7f9f 100644 --- a/_tests/configurations/merge-timeout-gotenberg.yml +++ b/_tests/configurations/merge-timeout-gotenberg.yml @@ -3,6 +3,9 @@ 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 }}" diff --git a/_tests/configurations/timeout-gotenberg.yml b/_tests/configurations/timeout-gotenberg.yml index 99e24e5b..ffd402e5 100644 --- a/_tests/configurations/timeout-gotenberg.yml +++ b/_tests/configurations/timeout-gotenberg.yml @@ -3,6 +3,9 @@ logs: level: "DEBUG" format: "text" commands: + markdown: + timeout: 0 + template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}" html: timeout: 0 template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" diff --git a/_tests/configurations/wrong-html-command-template-gotenberg.yml b/_tests/configurations/wrong-html-command-template-gotenberg.yml index 1ea42ca2..4c8ea014 100644 --- a/_tests/configurations/wrong-html-command-template-gotenberg.yml +++ b/_tests/configurations/wrong-html-command-template-gotenberg.yml @@ -3,6 +3,9 @@ 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 }}" diff --git a/_tests/configurations/wrong-logging-format-gotenberg.yml b/_tests/configurations/wrong-logging-format-gotenberg.yml index b627462f..118135e2 100644 --- a/_tests/configurations/wrong-logging-format-gotenberg.yml +++ b/_tests/configurations/wrong-logging-format-gotenberg.yml @@ -3,6 +3,9 @@ logs: level: "DEBUG" format: "DEBUG" commands: + markdown: + timeout: 30 + template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}" html: timeout: 30 template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" diff --git a/_tests/configurations/wrong-logging-level-gotenberg.yml b/_tests/configurations/wrong-logging-level-gotenberg.yml index cab7bb49..acd3a0a3 100644 --- a/_tests/configurations/wrong-logging-level-gotenberg.yml +++ b/_tests/configurations/wrong-logging-level-gotenberg.yml @@ -3,6 +3,9 @@ logs: level: "text" format: "text" commands: + markdown: + timeout: 30 + template: "markdown-pdf {{ .FilePath }} -o {{ .ResultFilePath }}" html: timeout: 30 template: "xvfb-run -e /dev/stdout wkhtmltopdf {{ .FilePath }} {{ .ResultFilePath }}" diff --git a/_tests/configurations/wrong-markdown-command-template-gotenberg.yml b/_tests/configurations/wrong-markdown-command-template-gotenberg.yml new file mode 100644 index 00000000..d9cd3647 --- /dev/null +++ b/_tests/configurations/wrong-markdown-command-template-gotenberg.yml @@ -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 }}" diff --git a/_tests/configurations/wrong-merge-command-template-gotenberg.yml b/_tests/configurations/wrong-merge-command-template-gotenberg.yml index c0cad22a..64813c4e 100644 --- a/_tests/configurations/wrong-merge-command-template-gotenberg.yml +++ b/_tests/configurations/wrong-merge-command-template-gotenberg.yml @@ -3,6 +3,9 @@ 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 }}" diff --git a/_tests/configurations/wrong-office-command-template-gotenberg.yml b/_tests/configurations/wrong-office-command-template-gotenberg.yml index a2aa6cc2..3738d05d 100644 --- a/_tests/configurations/wrong-office-command-template-gotenberg.yml +++ b/_tests/configurations/wrong-office-command-template-gotenberg.yml @@ -3,6 +3,9 @@ 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 }}" diff --git a/_tests/file.md b/_tests/file.md new file mode 100644 index 00000000..64c0c35d --- /dev/null +++ b/_tests/file.md @@ -0,0 +1 @@ +# Hi, I've been converted from a markdown file! \ No newline at end of file diff --git a/app/config/config.go b/app/config/config.go index 0288fe21..4a6f2387 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -33,6 +33,9 @@ type ( // CommandsConfig gathers all commands' configurations as defined // by the user in the gotenberg.yml file. 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 // an HTML file to PDF. HTML *CommandConfig @@ -79,13 +82,20 @@ func NewAppConfig(configurationFilePath string) (*AppConfig, error) { c.Logs.Formatter = formatter c.CommandsConfig = &CommandsConfig{} + c.CommandsConfig.Markdown = &CommandConfig{} c.CommandsConfig.HTML = &CommandConfig{} c.CommandsConfig.Office = &CommandConfig{} c.CommandsConfig.Merge = &CommandConfig{} + c.CommandsConfig.Markdown.Timeout = fileConfig.Commands.Markdown.Timeout c.CommandsConfig.HTML.Timeout = fileConfig.Commands.HTML.Timeout c.CommandsConfig.Office.Timeout = fileConfig.Commands.Office.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") if err != nil { return nil, err @@ -101,6 +111,7 @@ func NewAppConfig(configurationFilePath string) (*AppConfig, error) { return nil, err } + c.CommandsConfig.Markdown.Template = tmplMarkdown c.CommandsConfig.HTML.Template = tmplHTML c.CommandsConfig.Office.Template = tmplOffice c.CommandsConfig.Merge.Template = tmplMerge @@ -116,6 +127,10 @@ type fileConfig struct { Format string `yaml:"format"` } `yaml:"logs"` Commands struct { + Markdown struct { + Timeout int `yaml:"timeout"` + Template string `yaml:"template"` + } `yaml:"markdown"` HTML struct { Timeout int Template string diff --git a/app/config/config_test.go b/app/config/config_test.go index d6d48eef..4d44e73c 100644 --- a/app/config/config_test.go +++ b/app/config/config_test.go @@ -29,25 +29,31 @@ func TestNewAppConfig(t *testing.T) { 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") if _, err := NewAppConfig(path); err == nil { 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") if _, err := NewAppConfig(path); err == nil { 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") if _, err := NewAppConfig(path); err == nil { 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") if _, err := NewAppConfig(path); err != nil { t.Error("AppConfig should have been instantiated!") diff --git a/app/converter/file/file.go b/app/converter/file/file.go index 054fc73d..23f55812 100644 --- a/app/converter/file/file.go +++ b/app/converter/file/file.go @@ -25,6 +25,8 @@ type Type uint32 const ( // PDFType represents a... PDF file. PDFType Type = iota + // MarkdownType represents a... markdown file. + MarkdownType // HTMLType represents an... HTML file. HTMLType // OfficeType represents an... Office document. @@ -34,6 +36,7 @@ const ( // filesTypes associates a file extension with its file kind counterpart. var filesTypes = map[string]Type{ ".pdf": PDFType, + ".md": MarkdownType, ".htm": HTMLType, ".html": HTMLType, ".doc": OfficeType, diff --git a/app/converter/process/process.go b/app/converter/process/process.go index c015194a..9d596f14 100644 --- a/app/converter/process/process.go +++ b/app/converter/process/process.go @@ -3,6 +3,7 @@ package process import ( "bytes" + "fmt" "os/exec" "text/template" "time" @@ -45,6 +46,10 @@ func Unconv(workingDir string, file *gfile.File) (string, error) { ) switch file.Type { + case gfile.MarkdownType: + cmdTemplate = commandsConfig.Markdown.Template + cmdTimeout = commandsConfig.Markdown.Timeout + break case gfile.HTMLType: cmdTemplate = commandsConfig.HTML.Template cmdTimeout = commandsConfig.HTML.Timeout @@ -99,12 +104,13 @@ func Merge(workingDir string, filesPaths []string) (string, error) { return cmdData.ResultFilePath, nil } -type commandTimeoutError struct{} - -const commandTimeoutErrorMessage = "The command has reached timeout" +type commandTimeoutError struct { + command string + timeout int +} 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 @@ -126,7 +132,10 @@ func run(command string, timeout int) error { if err := cmd.Process.Kill(); err != nil { return err } - return &commandTimeoutError{} + return &commandTimeoutError{ + command: command, + timeout: timeout, + } case err := <-done: if err != nil { return err diff --git a/app/converter/process/process_test.go b/app/converter/process/process_test.go index 5d383cdd..d261bc62 100644 --- a/app/converter/process/process_test.go +++ b/app/converter/process/process_test.go @@ -120,8 +120,14 @@ func TestImpossibleConversionError(t *testing.T) { } func TestCommandTimeoutError(t *testing.T) { - err := &commandTimeoutError{} - if err.Error() != commandTimeoutErrorMessage { - t.Errorf("Error returned a wrong message: got %s want %s", err.Error(), commandTimeoutErrorMessage) + err := &commandTimeoutError{ + command: "echo hello", + 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) } } diff --git a/orbit.yml b/orbit.yml index 974f0d8b..c325eb60 100644 --- a/orbit.yml +++ b/orbit.yml @@ -15,8 +15,8 @@ tasks: - use: ci short: Runs CI process inside a container run: - - docker build -t 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 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" thecodingmachine/gotenberg:ci - use: build short: Builds the main Docker image @@ -26,4 +26,4 @@ tasks: - use: up short: Starts the {{ .Orbit.Version }} version of the Gotenberg image run: - - docker run --rm -p 3000:3000/tcp gotenberg:{{ .Orbit.Version }} \ No newline at end of file + - docker run --rm -p 3000:3000/tcp thecodingmachine/gotenberg:{{ .Orbit.Version }} \ No newline at end of file