Skip to content

Commit

Permalink
Implement list spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuel Rüger committed Sep 30, 2024
1 parent 406f661 commit 5f2e458
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 92 deletions.
114 changes: 106 additions & 8 deletions cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package cmd

import (
"encoding/json"
"fmt"
"os"

"github.com/kovetskiy/lorg"
"github.com/kovetskiy/mark/auth"
"github.com/kovetskiy/mark/confluence"
"github.com/reconquest/pkg/log"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
)

var listFlags = []cli.Flag{
altsrc.NewStringFlag(&cli.StringFlag{
Name: "output-format",
Aliases: []string{"o"},
Value: "table",
Usage: "Defines output format (json or table)",
EnvVars: []string{"MARK_SPACE"},
})}

var ListCmd = &cli.Command{
Name: "list",
Usage: "lists pages, spaces and labels",
Flags: []cli.Flag{},
Subcommands: []*cli.Command{
{
Name: "pages",
Expand All @@ -23,15 +37,13 @@ var ListCmd = &cli.Command{
EnvVars: []string{"MARK_SPACE"},
}),
},
Action: ListSpaces,
Action: ListPages,
},
{
Name: "spaces",
Usage: "lists spaces.",
Action: func(cCtx *cli.Context) error {
fmt.Println("removed task template: ", cCtx.Args().First())
return nil
},
Name: "spaces",
Usage: "lists spaces.",
Flags: append(flags, listFlags...),
Action: ListSpaces,
},
{
Name: "labels",
Expand All @@ -44,6 +56,92 @@ var ListCmd = &cli.Command{
},
}

func ListPages(cCtx *cli.Context) error {

if cCtx.Bool("debug") {
log.SetLevel(lorg.LevelDebug)
}

if cCtx.Bool("trace") {
log.SetLevel(lorg.LevelTrace)
}

if cCtx.String("color") == "never" {
log.GetLogger().SetFormat(
lorg.NewFormat(
`${time:2006-01-02 15:04:05.000} ${level:%s:left:true} ${prefix}%s`,
),
)
log.GetLogger().SetOutput(os.Stderr)
}

return nil
}

func ListSpaces(cCtx *cli.Context) error {

if cCtx.Bool("debug") {
log.SetLevel(lorg.LevelDebug)
}

if cCtx.Bool("trace") {
log.SetLevel(lorg.LevelTrace)
}

if cCtx.String("color") == "never" {
log.GetLogger().SetFormat(
lorg.NewFormat(
`${time:2006-01-02 15:04:05.000} ${level:%s:left:true} ${prefix}%s`,
),
)
log.GetLogger().SetOutput(os.Stderr)
}

creds, err := auth.GetCredentials(cCtx.String("username"), cCtx.String("password"), "", cCtx.String("base-url"), false)
if err != nil {
return err
}

api := confluence.NewAPI(creds.BaseURL, creds.Username, creds.Password)

spaces, err := api.ListSpaces()

if err != nil {
log.Fatal(err)
os.Exit(0)
}

if cCtx.String("output-format") == "json" {
s, _ := json.MarshalIndent(spaces.Spaces, "", "\t")
fmt.Print(string(s))
} else {
fmt.Printf("ID\t\tKey\t\tName\n")
for _, space := range spaces.Spaces {
fmt.Printf("%s\t\t%s\t\t%d\n", space.Key, space.Name, space.ID)
}
}

return nil
}

func ListLabels(cCtx *cli.Context) error {

if cCtx.Bool("debug") {
log.SetLevel(lorg.LevelDebug)
}

if cCtx.Bool("trace") {
log.SetLevel(lorg.LevelTrace)
}

if cCtx.String("color") == "never" {
log.GetLogger().SetFormat(
lorg.NewFormat(
`${time:2006-01-02 15:04:05.000} ${level:%s:left:true} ${prefix}%s`,
),
)
log.GetLogger().SetOutput(os.Stderr)
}

return nil
}
23 changes: 21 additions & 2 deletions cmd/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,20 @@ import (
var PublishCmd = &cli.Command{
Name: "publish",
Usage: "renders markdown and publishes content to confluence.",
Flags: []cli.Flag{
Flags: append(flags, []cli.Flag{
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "compile-only",
Value: false,
Usage: "show resulting HTML and don't update Confluence page content.",
EnvVars: []string{"MARK_COMPILE_ONLY"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "target-url",
Aliases: []string{"l"},
Value: "",
Usage: "edit specified Confluence page. If -l is not specified, file should contain metadata (see above).",
EnvVars: []string{"MARK_TARGET_URL"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "files",
Aliases: []string{"f"},
Expand Down Expand Up @@ -116,7 +129,13 @@ var PublishCmd = &cli.Command{
TakesFile: true,
EnvVars: []string{"MARK_INCLUDE_PATH"},
}),
},
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "ci",
Value: false,
Usage: "run on CI mode. It won't fail if files are not found.",
EnvVars: []string{"MARK_CI"},
}),
}...),
Action: Publish,
}

Expand Down
137 changes: 59 additions & 78 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,86 +14,67 @@ const (
description = `Mark is a tool to update Atlassian Confluence pages from markdown. Documentation is available here: https://github.com/kovetskiy/mark`
)

var flags = []cli.Flag{
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "dry-run",
Value: false,
Usage: "resolve page and ancestry, show resulting HTML and exit.",
EnvVars: []string{"MARK_DRY_RUN"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "color",
Value: "auto",
Usage: "display logs in color. Possible values: auto, never.",
EnvVars: []string{"MARK_COLOR"},
}),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "debug",
Value: false,
Usage: "enable debug logs.",
EnvVars: []string{"MARK_DEBUG"},
}),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "trace",
Value: false,
Usage: "enable trace logs.",
EnvVars: []string{"MARK_TRACE"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Value: "",
Usage: "use specified username for updating Confluence page.",
EnvVars: []string{"MARK_USERNAME"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "password",
Aliases: []string{"p"},
Value: "",
Usage: "use specified token for updating Confluence page. Specify - as password to read password from stdin, or your Personal access token. Username is not mandatory if personal access token is provided. For more info please see: https://developer.atlassian.com/server/confluence/confluence-server-rest-api/#authentication.",
EnvVars: []string{"MARK_PASSWORD"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "base-url",
Aliases: []string{"b", "base_url"},
Value: "",
Usage: "base URL for Confluence. Alternative option for base_url config field.",
EnvVars: []string{"MARK_BASE_URL"},
}),
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Value: configFilePath(),
Usage: "use the specified configuration file.",
TakesFile: true,
EnvVars: []string{"MARK_CONFIG"},
}}

func Exec() {
app := &cli.App{
Name: "mark",
Usage: usage,
Description: description,
Version: version,
Flags: []cli.Flag{
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "compile-only",
Value: false,
Usage: "show resulting HTML and don't update Confluence page content.",
EnvVars: []string{"MARK_COMPILE_ONLY"},
}),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "dry-run",
Value: false,
Usage: "resolve page and ancestry, show resulting HTML and exit.",
EnvVars: []string{"MARK_DRY_RUN"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "color",
Value: "auto",
Usage: "display logs in color. Possible values: auto, never.",
EnvVars: []string{"MARK_COLOR"},
}),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "debug",
Value: false,
Usage: "enable debug logs.",
EnvVars: []string{"MARK_DEBUG"},
}),
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "trace",
Value: false,
Usage: "enable trace logs.",
EnvVars: []string{"MARK_TRACE"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Value: "",
Usage: "use specified username for updating Confluence page.",
EnvVars: []string{"MARK_USERNAME"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "password",
Aliases: []string{"p"},
Value: "",
Usage: "use specified token for updating Confluence page. Specify - as password to read password from stdin, or your Personal access token. Username is not mandatory if personal access token is provided. For more info please see: https://developer.atlassian.com/server/confluence/confluence-server-rest-api/#authentication.",
EnvVars: []string{"MARK_PASSWORD"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "target-url",
Aliases: []string{"l"},
Value: "",
Usage: "edit specified Confluence page. If -l is not specified, file should contain metadata (see above).",
EnvVars: []string{"MARK_TARGET_URL"},
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "base-url",
Aliases: []string{"b", "base_url"},
Value: "",
Usage: "base URL for Confluence. Alternative option for base_url config field.",
EnvVars: []string{"MARK_BASE_URL"},
}),
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Value: configFilePath(),
Usage: "use the specified configuration file.",
TakesFile: true,
EnvVars: []string{"MARK_CONFIG"},
},
altsrc.NewBoolFlag(&cli.BoolFlag{
Name: "ci",
Value: false,
Usage: "run on CI mode. It won't fail if files are not found.",
EnvVars: []string{"MARK_CI"},
}),
},
Name: "mark",
Usage: usage,
Description: description,
Version: version,
EnableBashCompletion: true,
HideHelpCommand: true,
Commands: []*cli.Command{
Expand Down
31 changes: 27 additions & 4 deletions confluence/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ type SpaceInfo struct {
} `json:"_links"`
}

type SpaceInfoList struct {
Spaces []SpaceInfo `json:"results"`
}

type PageInfo struct {
ID string `json:"id"`
Title string `json:"title"`
Expand Down Expand Up @@ -258,7 +262,7 @@ func (api *API) CreateAttachment(

if len(result.Results) == 0 {
return info, errors.New(
"Confluence REST API for creating attachments returned " +
"the Confluence REST API for creating attachments returned " +
"0 json objects, expected at least 1",
)
}
Expand Down Expand Up @@ -775,24 +779,43 @@ func (api *API) RestrictPageUpdates(
return err
}

func (api *API) ListSpaces() (*SpaceInfoList, error) {
payload := map[string]string{
"limit": "1000",
}

request, err := api.rest.Res(
"space", &SpaceInfoList{},
).Get(payload)
if err != nil {
return nil, err
}

if request.Raw.StatusCode != http.StatusOK {
return nil, newErrorStatusNotOK(request)
}

return request.Response.(*SpaceInfoList), nil
}

func newErrorStatusNotOK(request *gopencils.Resource) error {
if request.Raw.StatusCode == http.StatusUnauthorized {
return errors.New(
"Confluence API returned unexpected status: 401 (Unauthorized)",
"the Confluence API returned unexpected status: 401 (Unauthorized)",
)
}

if request.Raw.StatusCode == http.StatusNotFound {
return errors.New(
"Confluence API returned unexpected status: 404 (Not Found)",
"the Confluence API returned unexpected status: 404 (Not Found)",
)
}

output, _ := io.ReadAll(request.Raw.Body)
defer request.Raw.Body.Close()

return fmt.Errorf(
"Confluence API returned unexpected status: %v, "+
"the Confluence API returned unexpected status: %v, "+
"output: %q",
request.Raw.Status, output,
)
Expand Down

0 comments on commit 5f2e458

Please sign in to comment.