Skip to content

Commit

Permalink
Merge pull request #3 from seanson/add_confluence_server_support
Browse files Browse the repository at this point in the history
Add confluence server support
  • Loading branch information
DrFaust92 authored Oct 6, 2021
2 parents 9760d41 + f885be7 commit 7abe395
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 41 deletions.
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## To be released
## 0.2.0

FEATURES:

* **New Resource:** `confluence_content`
- **Experimental:** Support for Confluence Server
- Added additional parameters for public and api sites and schemes for Confluence Server
- Fix: Fixed index error when creating resources without a parent

## 0.1.0

FEATURES:

- **New Resource:** `confluence_content`
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.2.0
13 changes: 6 additions & 7 deletions confluence/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ type Metadata struct {

// AttachmentLinks is part of Content
type AttachmentLinks struct {
Context string `json:"context,omitempty"` // "/wiki"
Context string `json:"context,omitempty"` // ""
Download string `json:"download,omitempty"` // prefix with Context
}

func (c *Client) CreateAttachment(attachment *Attachment, data, pageId string) (*Attachment, error) {
var response AttachmentResults
path := fmt.Sprintf("/wiki/rest/api/content/%s/child/attachment", pageId)
path := fmt.Sprintf("/rest/api/content/%s/child/attachment", pageId)
if err := c.PostForm(path, attachment.Title, data, &response); err != nil {
return nil, err
}
Expand All @@ -45,7 +45,7 @@ func (c *Client) CreateAttachment(attachment *Attachment, data, pageId string) (
func (c *Client) UpdateAttachment(attachment *Attachment, data, pageId string) (*Attachment, error) {
var response AttachmentResults
attachment.Version.Number++
path := fmt.Sprintf("/wiki/rest/api/content/%s/child/attachment/%s", pageId, attachment.Id)
path := fmt.Sprintf("/rest/api/content/%s/child/attachment/%s", pageId, attachment.Id)
if err := c.PutForm(path, attachment.Title, data, &response); err != nil {
return nil, err
}
Expand All @@ -57,24 +57,23 @@ func (c *Client) UpdateAttachment(attachment *Attachment, data, pageId string) (

func (c *Client) GetAttachment(id string) (*Attachment, error) {
var response Attachment
path := fmt.Sprintf("/wiki/rest/api/content/%s?expand=version", id)
path := fmt.Sprintf("/rest/api/content/%s?expand=version", id)
if err := c.Get(path, &response); err != nil {
return nil, err
}
return &response, nil
}

func (c *Client) GetAttachmentBody(attachment *Attachment) (string, error) {
path := attachment.Links.Context + attachment.Links.Download
result, err := c.GetString(path)
result, err := c.GetString(attachment.Links.Download)
if err != nil {
return "", err
}
return result, nil
}

func (c *Client) DeleteAttachment(id, pageId string) error {
path := fmt.Sprintf("/wiki/rest/api/content/%s", id)
path := fmt.Sprintf("/rest/api/content/%s", id)
if err := c.Delete(path); err != nil {
return err
}
Expand Down
36 changes: 28 additions & 8 deletions confluence/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ import (
type Client struct {
client *http.Client
baseURL *url.URL
basePath string
publicURL *url.URL
}

// NewClientInput provides information to connect to the Confluence API
type NewClientInput struct {
site string
user string
token string
site string
siteScheme string
publicSite string
publicSiteScheme string
context string
user string
token string
}

// ErrorResponse describes why a request failed
Expand All @@ -41,16 +46,30 @@ type ErrorResponse struct {
// NewClient returns an authenticated client ready to use
func NewClient(input *NewClientInput) *Client {
publicURL := url.URL{
Scheme: "https",
Host: input.site + ".atlassian.net",
Scheme: input.publicSiteScheme,
Host: input.site,
}
if input.publicSite != "" {
publicURL.Host = input.publicSite
}

basePath := input.context

// Default to /wiki if using Confluence Cloud`
if strings.HasSuffix(input.site, ".atlassian.net") {
basePath = "/wiki"
}
baseURL := url.URL{
Scheme: input.siteScheme,
Host: input.site,
}
baseURL := publicURL
baseURL.User = url.UserPassword(input.user, input.token)
return &Client{
client: &http.Client{
Timeout: time.Second * 10,
},
baseURL: &baseURL,
basePath: basePath,
publicURL: &publicURL,
}
}
Expand Down Expand Up @@ -159,7 +178,8 @@ func (c *Client) do(method, path, contentType string, body *bytes.Buffer, result

// do uses the client to send a specified request
func (c *Client) doRaw(method, path, contentType string, body *bytes.Buffer) (*bytes.Buffer, error) {
u, err := c.baseURL.Parse(path)
fullPath := c.basePath + path
u, err := c.baseURL.Parse(fullPath)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -193,7 +213,7 @@ func (c *Client) doRaw(method, path, contentType string, body *bytes.Buffer) (*b
}
s := body.String()
return nil, fmt.Errorf("%s\n\n%s %s\n%s\n\n%s",
resp.Status, method, path, s, responseBody)
resp.Status, method, fullPath, s, responseBody)
}
result := new(bytes.Buffer)
_, err = result.ReadFrom(resp.Body)
Expand Down
8 changes: 4 additions & 4 deletions confluence/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ type Version struct {

func (c *Client) CreateContent(content *Content) (*Content, error) {
var response Content
if err := c.Post("/wiki/rest/api/content", content, &response); err != nil {
if err := c.Post("/rest/api/content", content, &response); err != nil {
return nil, err
}
return &response, nil
}

func (c *Client) GetContent(id string) (*Content, error) {
var response Content
path := fmt.Sprintf("/wiki/rest/api/content/%s?expand=space,body.storage,version,ancestors", id)
path := fmt.Sprintf("/rest/api/content/%s?expand=space,body.storage,version,ancestors", id)
if err := c.Get(path, &response); err != nil {
return nil, err
}
Expand All @@ -63,15 +63,15 @@ func (c *Client) GetContent(id string) (*Content, error) {
func (c *Client) UpdateContent(content *Content) (*Content, error) {
var response Content
content.Version.Number++
path := fmt.Sprintf("/wiki/rest/api/content/%s", content.Id)
path := fmt.Sprintf("/rest/api/content/%s", content.Id)
if err := c.Put(path, content, &response); err != nil {
return nil, err
}
return &response, nil
}

func (c *Client) DeleteContent(id string) error {
path := fmt.Sprintf("/wiki/rest/api/content/%s", id)
path := fmt.Sprintf("/rest/api/content/%s", id)
if err := c.Delete(path); err != nil {
return err
}
Expand Down
40 changes: 34 additions & 6 deletions confluence/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,43 @@ func Provider() *schema.Provider {
"site": {
Type: schema.TypeString,
Required: true,
Description: "Cloud Confluence Site Name (the name before atlassian.net)",
Description: "Confluence hostname (<name>.atlassian.net if using Cloud Confluence, otherwise hostname)",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_SITE", nil),
},
"site_scheme": {
Type: schema.TypeString,
Required: true,
Description: "Optional https or http scheme to use for API calls",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_SITE_SCHEME", "https"),
},
"public_site": {
Type: schema.TypeString,
Required: true,
Description: "Optional public Confluence Server hostname if different than API hostname",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_PUBLIC_SITE", ""),
},
"public_site_scheme": {
Type: schema.TypeString,
Required: true,
Description: "Optional https or http scheme to use for public site URLs",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_PUBLIC_SITE_SCHEME", "https"),
},
"context": {
Type: schema.TypeString,
Required: true,
Description: "Confluence path context (Will default to /wiki if using an atlassian.net hostname)",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_CONTEXT", ""),
},
"user": {
Type: schema.TypeString,
Required: true,
Description: "User's email address",
Description: "User's email address for Cloud Confluence or username for Confluence Server",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_USER", nil),
},
"token": {
Type: schema.TypeString,
Required: true,
Description: "Confluence API Token for user",
Description: "Confluence API Token for Cloud Confluence or password for Confluence Server",
DefaultFunc: schema.EnvDefaultFunc("CONFLUENCE_TOKEN", nil),
},
},
Expand All @@ -38,8 +62,12 @@ func Provider() *schema.Provider {

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
return NewClient(&NewClientInput{
site: d.Get("site").(string),
token: d.Get("token").(string),
user: d.Get("user").(string),
site: d.Get("site").(string),
siteScheme: d.Get("site_scheme").(string),
publicSite: d.Get("public_site").(string),
publicSiteScheme: d.Get("public_site_scheme").(string),
context: d.Get("context").(string),
token: d.Get("token").(string),
user: d.Get("user").(string),
}), nil
}
4 changes: 3 additions & 1 deletion confluence/resource_content.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ func updateResourceDataFromContent(d *schema.ResourceData, content *Content, cli
"title": content.Title,
"version": content.Version.Number,
"url": client.URL(content.Links.Context + content.Links.WebUI),
"parent": content.Ancestors[len(content.Ancestors)-1].Id, // the last ancestor is the parent
}
if len(content.Ancestors) > 1 {
m["parent"] = content.Ancestors[len(content.Ancestors)-1].Id
}
for k, v := range m {
err := d.Set(k, v)
Expand Down
41 changes: 29 additions & 12 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ layout: "confluence"
page_title: "Provider: Confluence"
sidebar_current: "docs-confluence-index"
description: |-
The Confluence provider is used to interact with Cloud Confluence.
The Confluence provider is used to interact with Confluence.
It can automate the publishing of content and is often used to publish
information about other resources created in terraform.
---

# Confluence Provider

The Confluence provider is used to interact with the Cloud Confluence. The
The Confluence provider is used to interact with the Confluence. The
provider needs to be configured with the proper credentials before it can be
used.

Expand All @@ -20,7 +20,7 @@ Use the navigation to the left to read about the available data sources.

```hcl
provider "confluence" {
site = "my-site"
site = "my-site.atlassian.net"
user = "my-user"
token = "my-token"
}
Expand All @@ -38,14 +38,31 @@ Static credentials must be passed to the provider block.

## Argument Reference

* `site` - (Required) The site is the name of the site and appears in your wiki
URL (https://*my-site*.atlassian.net/wiki/spaces/my-space/). This can also be
set via the `CONFLUENCE_SITE` environment variable.
- `site` - (Required) For Confluence Cloud: The site is the name of the site
and appears in your wiki URL (https://_my-site.atlassian.net_/wiki/spaces/my-space/).
For Confluence Server users this should be the hostname of your Confluence
instance that can receive `/rest/api` requests. This can also be set via the
`CONFLUENCE_SITE` environment variable.

* `user` - (Required) The user is your user's email address. This can also be
set via the `CONFLUENCE_USER` environment variable.
- `site_schema` - (Optional) Set the schema for connecting to the REST API.
Defaults to `https`. This can also be set via the `CONFLUENCE_SITE_SCHEMA`
environment variable.

* `token` - (Required) The token is a secret every user can generate. It is
similar to a password and should be treated as such. This can also be set via
the `CONFLUENCE_TOKEN` environment variable. See [Manage your
account](https://id.atlassian.com/manage/api-tokens).
- `public_site` - (Optional) For Confluence Server instances where your
Confluence site URL is different than the hostname that serves REST API
requests. Defaults to `site` if not set. This can also be set via the
`CONFLUENCE_PUBLIC_SITE` environment variable.

- `public_site_schema` - (Optional) Set the schema for generated public URLs.
Defaults to `https`. This can also be set via the `CONFLUENCE_PUBLIC_SITE_SCHEMA`
environment variable.

- `user` - (Required) For Confluence Cloud the user is your user's email
address. For Confluence Server this is the username of the user to login.
This can also be set via the `CONFLUENCE_USER` environment variable.

- `token` - (Required) For Confluence Cloud the token is a secret every user
can generate. It is similar to a password and should be treated as such. For
Confluence Server, this is the password of the user. This can also be set via
the `CONFLUENCE_TOKEN` environment variable. For Cloud token details, see
[Manage your account](https://id.atlassian.com/manage/api-tokens).

0 comments on commit 7abe395

Please sign in to comment.