diff --git a/README.md b/README.md
index e6b8a4b..0a3a641 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ and add the binary in your local `PATH`
```shell
curl -LO https://github.com/justmiles/go-markdown2confluence/releases/download/v3.1.2/go-markdown2confluence_3.1.2_linux_x86_64.tar.gz
-
+
sudo tar -xzvf go-markdown2confluence_3.1.2_linux_x86_64.tar.gz -C /usr/local/bin/ markdown2confluence
```
@@ -20,12 +20,12 @@ and add the binary in your local `PATH`
```shell
curl -LO https://github.com/justmiles/go-markdown2confluence/releases/download/v3.1.2/go-markdown2confluence_3.1.2_darwin_x86_64.tar.gz
-
+
sudo tar -xzvf go-markdown2confluence_3.1.2_darwin_x86_64.tar.gz -C /usr/local/bin/ markdown2confluence
```
- Windows
-
+
Download [the latest release](https://github.com/justmiles/go-markdown2confluence/releases/download/v3.1.2/go-markdown2confluence_3.1.2_windows_x86_64.tar.gz) and add to your system `PATH`
## Use with Docker
@@ -54,20 +54,22 @@ For best practice we recommend you [authenticate using an API token](https://id.
Push markdown files to Confluence Cloud
Usage:
-markdown2confluence [flags] (files or directories)
+ markdown2confluence [flags]
Flags:
--d, --debug Enable debug logging
--e, --endpoint string Confluence endpoint. (Alternatively set CONFLUENCE_ENDPOINT environment variable) (default "https://mydomain.atlassian.net/wiki")
--h, --help help for markdown2confluence
--m, --modified-since int Only upload files that have modifed in the past n minutes
- --parent string Optional parent page to nest content under
--p, --password string Confluence password. (Alternatively set CONFLUENCE_PASSWORD environment variable)
--s, --space string Space in which page should be created
--t, --title string Set the page title on upload (defaults to filename without extension)
--u, --username string Confluence username. (Alternatively set CONFLUENCE_USERNAME environment variable)
--w, --hardwraps Render newlines as
- --version version for markdown2confluence
+ -d, --debug Enable debug logging
+ -e, --endpoint string Confluence endpoint. (Alternatively set CONFLUENCE_ENDPOINT environment variable) (default "https://mydomain.atlassian.net/wiki")
+ -x, --exclude strings list of exclude file patterns (regex) that will be applied on markdown file paths
+ -w, --hardwraps Render newlines as
+ -h, --help help for markdown2confluence
+ -m, --modified-since int Only upload files that have modifed in the past n minutes
+ --parent string Optional parent page to next content under
+ -p, --password string Confluence password. (Alternatively set CONFLUENCE_PASSWORD environment variable)
+ -s, --space string Space in which page should be created
+ -t, --title string Set the page title on upload (defaults to filename without extension)
+ --use-document-title Will use the Markdown document title (# Title) if available
+ -u, --username string Confluence username. (Alternatively set CONFLUENCE_USERNAME environment variable)
+ --version version for markdown2confluence
```
## Examples
@@ -75,25 +77,56 @@ Flags:
Upload a local directory of markdown files called `markdown-files` to Confluence.
```shell
-markdown2confluence --space 'MyTeamSpace' markdown-files
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ markdown-files
```
Upload the same directory, but only those modified in the last 30 minutes. This is particurlarly useful for cron jobs/recurring one-way syncs.
```shell
-markdown2confluence --space 'MyTeamSpace' --modified-since 30 markdown-files
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ --modified-since 30 \
+ markdown-files
```
Upload a single file
```shell
-markdown2confluence --space 'MyTeamSpace' markdown-files/test.md
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ markdown-files/test.md
```
Upload a directory of markdown files in space `MyTeamSpace` under the parent page `API Docs`
```shell
-markdown2confluence --space 'MyTeamSpace' --parent 'API Docs' markdown-files
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ --parent 'API Docs' \
+ markdown-files
+```
+
+Upload a directory of markdown files in space `MyTeamSpace` under a _nested_ parent page `Docs/API` and _exclude_ mardown files/directories that match `.*generated.*` or `.*temp.md`
+
+```shell
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ --parent 'API/Docs' \
+ --exclude '.*generated.*' \
+ --exclude '.*temp.md' \
+ markdown-files
+```
+
+Upload a directory of markdown files in space `MyTeamSpace` under the parent page `API Docs` and use the markdown _document-title_ instead of the filname as document title (if available) in Confluence.
+
+```shell
+markdown2confluence \
+ --space 'MyTeamSpace' \
+ --parent 'API Docs' \
+ --use-document-title \
+ markdown-files
```
## Enhancements
diff --git a/cmd/root.go b/cmd/root.go
index a104aa1..5961eea 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -22,10 +22,11 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&m.Endpoint, "endpoint", "e", lib.DefaultEndpoint, "Confluence endpoint. (Alternatively set CONFLUENCE_ENDPOINT environment variable)")
rootCmd.PersistentFlags().StringVar(&m.Parent, "parent", "", "Optional parent page to next content under")
rootCmd.PersistentFlags().BoolVarP(&m.Debug, "debug", "d", false, "Enable debug logging")
+ rootCmd.PersistentFlags().BoolVarP(&m.UseDocumentTitle, "use-document-title", "", false, "Will use the Markdown document title (# Title) if available")
rootCmd.PersistentFlags().BoolVarP(&m.WithHardWraps, "hardwraps", "w", false, "Render newlines as
")
rootCmd.PersistentFlags().IntVarP(&m.Since, "modified-since", "m", 0, "Only upload files that have modifed in the past n minutes")
rootCmd.PersistentFlags().StringVarP(&m.Title, "title", "t", "", "Set the page title on upload (defaults to filename without extension)")
-
+ rootCmd.PersistentFlags().StringSliceVarP(&m.ExcludeFilePatterns, "exclude", "x", []string{}, "list of exclude file patterns (regex) for that will be applied on markdown file paths")
m.SourceEnvironmentVariables()
}
diff --git a/lib/markdown.go b/lib/markdown.go
index 1ef366a..5a3f049 100644
--- a/lib/markdown.go
+++ b/lib/markdown.go
@@ -3,8 +3,11 @@ package lib
import (
"bytes"
"fmt"
+ "io/ioutil"
+ "log"
"os"
"path/filepath"
+ "regexp"
"strings"
"sync"
"time"
@@ -28,19 +31,21 @@ const (
// Markdown2Confluence stores the settings for each run
type Markdown2Confluence struct {
- Space string
- Title string
- File string
- Ancestor string
- Debug bool
- WithHardWraps bool
- Since int
- Username string
- Password string
- Endpoint string
- Parent string
- SourceMarkdown []string
- client *confluence.Client
+ Space string
+ Title string
+ File string
+ Ancestor string
+ Debug bool
+ UseDocumentTitle bool
+ WithHardWraps bool
+ Since int
+ Username string
+ Password string
+ Endpoint string
+ Parent string
+ SourceMarkdown []string
+ ExcludeFilePatterns []string
+ client *confluence.Client
}
// CreateClient returns a new markdown clietn
@@ -100,6 +105,18 @@ func (m Markdown2Confluence) Validate() error {
return nil
}
+func (m *Markdown2Confluence) IsExcluded(p string) bool {
+ for _, pattern := range m.ExcludeFilePatterns {
+ r := regexp.MustCompile(pattern)
+ if r.MatchString(p) {
+ fmt.Printf("excluding markdown file '%s': exclude pattern '%s'\n", p, pattern)
+ return true
+ }
+ }
+
+ return false
+}
+
// Run the sync
func (m *Markdown2Confluence) Run() []error {
var markdownFiles []MarkdownFile
@@ -133,7 +150,7 @@ func (m *Markdown2Confluence) Run() []error {
return err
}
- if strings.HasSuffix(path, ".md") {
+ if strings.HasSuffix(path, ".md") && !m.IsExcluded(path) {
// Only include this file if it was modified m.Since minutes ago
if m.Since != 0 {
@@ -156,6 +173,13 @@ func (m *Markdown2Confluence) Run() []error {
tempParents = deleteFromSlice(strings.Split(filepath.Dir(strings.TrimPrefix(filepath.ToSlash(path), filepath.ToSlash(f))), "/"), ".")
}
+ if m.UseDocumentTitle == true {
+ doc_title := getDocumentTitle(path)
+ if doc_title != "" {
+ tempTitle = doc_title
+ }
+ }
+
md = MarkdownFile{
Path: path,
Parents: tempParents,
@@ -163,7 +187,8 @@ func (m *Markdown2Confluence) Run() []error {
}
if m.Parent != "" {
- md.Parents = append([]string{m.Parent}, md.Parents...)
+ parents := strings.Split(m.Parent, "/")
+ md.Parents = append(parents, md.Parents...)
md.Parents = deleteEmpty(md.Parents)
}
@@ -183,11 +208,17 @@ func (m *Markdown2Confluence) Run() []error {
}
if md.Title == "" {
- md.Title = strings.TrimSuffix(filepath.Base(f), ".md")
+ if m.UseDocumentTitle == true {
+ md.Title = getDocumentTitle(f)
+ }
+ if md.Title == "" {
+ md.Title = strings.TrimSuffix(filepath.Base(f), ".md")
+ }
}
if m.Parent != "" {
- md.Parents = append([]string{m.Parent}, md.Parents...)
+ parents := strings.Split(m.Parent, "/")
+ md.Parents = append(parents, md.Parents...)
md.Parents = deleteEmpty(md.Parents)
}
@@ -299,3 +330,24 @@ func deleteFromSlice(s []string, del string) []string {
}
return s
}
+
+func getDocumentTitle(p string) string {
+ // Read file to check for the content
+ file_content, err := ioutil.ReadFile(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ // Convert []byte to string and print to screen
+ text := string(file_content)
+
+ // check if there is a
+ e := `^#\s+(.+)`
+ r := regexp.MustCompile(e)
+ result := r.FindStringSubmatch(text)
+ if len(result) > 1 {
+ // assign the Title to the matching group
+ return result[1]
+ }
+
+ return ""
+}