Repository: kovetskiy/mark (go)

Issue:
Syncing New Pages Can Error with "409 Conflict"
Possibly a race condition when creating new pages. There seems to be two distinct operations, as indicated by the page's history:

1. Create New Blank Page
2. Sync Page Contents

We are seeing the following error when creating new pages:

```
FATAL Confluence API returned unexpected status: 409 Conflict, output: ""
```

It is believed the above two phases happening in quick succession might be the cause. A resync will allow the second operation to succeed.

Pull request:
bugfix: Add delay between create and update calls
This helps mitigate a 409 conflict response from Confluence when
creating a new page and then updating it right away. This may not be the
cleanest solution, but it seems to do the trick.

Resolves #139

Patch:
diff --git a/main.go b/main.go
index 2194ef5..9e92167 100644
--- a/main.go
+++ b/main.go
@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"time"
 
 	"github.com/docopt/docopt-go"
 	"github.com/kovetskiy/lorg"
@@ -306,6 +307,10 @@ func processFile(
 					meta.Title,
 				)
 			}
+			// (issues/139): A delay between the create and update call
+			// helps mitigate a 409 conflict that can occur when attempting
+			// to update a page just after it was created.
+			time.Sleep(1 * time.Second)
 		}
 
 		target = page
diff --git a/pkg/confluence/api.go b/pkg/confluence/api.go
index 2930851..40455ed 100644
--- a/pkg/confluence/api.go
+++ b/pkg/confluence/api.go
@@ -552,6 +552,16 @@ func (api *API) UpdatePage(
 		},
 		"metadata": map[string]interface{}{
 			"labels": labels,
+			// The Confluence API randomly sets page width for some reason:
+			// https://community.developer.atlassian.com/t/confluence-rest-api-create-content-at-random-width/57001
+
+			// This is a workaround to compensate for that bug. It forces the page to be created
+			// with the default appearance, which is "fixed" (not full-width).
+			"properties": map[string]interface{}{
+				"content-appearance-published": map[string]interface{}{
+					"value": "default",
+				},
+			},
 		},
 	}
 
diff --git a/pkg/mark/stdlib/stdlib.go b/pkg/mark/stdlib/stdlib.go
index 463d638..f1bc132 100644
--- a/pkg/mark/stdlib/stdlib.go
+++ b/pkg/mark/stdlib/stdlib.go
@@ -106,10 +106,6 @@ func templates(api *confluence.API) (*template.Template, error) {
 
 		// This template is used for rendering code in ```
 		`ac:code`: text(
-			`{{ if .Collapse }}<ac:structured-macro ac:name="expand">{{printf "\n"}}`,
-			`{{ if .Title }}<ac:parameter ac:name="title">{{ .Title }}</ac:parameter>{{printf "\n"}}{{ end }}`,
-			`<ac:rich-text-body>{{printf "\n"}}{{ end }}`,
-
 			`<ac:structured-macro ac:name="{{ if eq .Language "mermaid" }}cloudscript-confluence-mermaid{{ else }}code{{ end }}">{{printf "\n"}}`,
 			/**/ `{{ if eq .Language "mermaid" }}<ac:parameter ac:name="showSource">true</ac:parameter>{{printf "\n"}}{{ else }}`,
 			/**/ `<ac:parameter ac:name="language">{{ .Language }}</ac:parameter>{{printf "\n"}}{{ end }}`,
@@ -117,9 +113,6 @@ func templates(api *confluence.API) (*template.Template, error) {
 			/**/ `{{ if .Title }}<ac:parameter ac:name="title">{{ .Title }}</ac:parameter>{{printf "\n"}}{{ end }}`,
 			/**/ `<ac:plain-text-body><![CDATA[{{ .Text | cdata }}]]></ac:plain-text-body>{{printf "\n"}}`,
 			`</ac:structured-macro>{{printf "\n"}}`,
-
-			`{{ if .Collapse }}</ac:rich-text-body>{{printf "\n"}}`,
-			`</ac:structured-macro>{{printf "\n"}}{{ end }}`,
 		),
 
 		`ac:status`: text(


Test patch:
diff --git a/pkg/mark/testdata/codes.html b/pkg/mark/testdata/codes.html
index 4a1f879..ef0f80c 100644
--- a/pkg/mark/testdata/codes.html
+++ b/pkg/mark/testdata/codes.html
@@ -34,26 +34,17 @@ text 2</p>
 <ac:parameter ac:name="title">A b c</ac:parameter>
 <ac:plain-text-body><![CDATA[no-collapse-title]]></ac:plain-text-body>
 </ac:structured-macro>
-<ac:structured-macro ac:name="expand">
-<ac:parameter ac:name="title">A b c</ac:parameter>
-<ac:rich-text-body>
 <ac:structured-macro ac:name="code">
 <ac:parameter ac:name="language">bash</ac:parameter>
 <ac:parameter ac:name="collapse">true</ac:parameter>
 <ac:parameter ac:name="title">A b c</ac:parameter>
 <ac:plain-text-body><![CDATA[collapse-and-title]]></ac:plain-text-body>
 </ac:structured-macro>
-</ac:rich-text-body>
-</ac:structured-macro>
-<ac:structured-macro ac:name="expand">
-<ac:rich-text-body>
 <ac:structured-macro ac:name="code">
 <ac:parameter ac:name="language">c</ac:parameter>
 <ac:parameter ac:name="collapse">true</ac:parameter>
 <ac:plain-text-body><![CDATA[collapse-no-title]]></ac:plain-text-body>
 </ac:structured-macro>
-</ac:rich-text-body>
-</ac:structured-macro>
 <ac:structured-macro ac:name="cloudscript-confluence-mermaid">
 <ac:parameter ac:name="showSource">true</ac:parameter>
 <ac:parameter ac:name="collapse">false</ac:parameter>
@@ -63,9 +54,6 @@ text 2</p>
     B-->D;
     C-->D;]]></ac:plain-text-body>
 </ac:structured-macro>
-<ac:structured-macro ac:name="expand">
-<ac:parameter ac:name="title">my mermaid graph</ac:parameter>
-<ac:rich-text-body>
 <ac:structured-macro ac:name="cloudscript-confluence-mermaid">
 <ac:parameter ac:name="showSource">true</ac:parameter>
 <ac:parameter ac:name="collapse">true</ac:parameter>
@@ -76,8 +64,6 @@ text 2</p>
     B-->D;
     C-->D;]]></ac:plain-text-body>
 </ac:structured-macro>
-</ac:rich-text-body>
-</ac:structured-macro>
 <ac:structured-macro ac:name="cloudscript-confluence-mermaid">
 <ac:parameter ac:name="showSource">true</ac:parameter>
 <ac:parameter ac:name="collapse">false</ac:parameter>