Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ If successful, the go compiler does not output anything. You should now have an

**Makefile**

If you are using a sytem that has `make` installed, then you can also simpl run `make` in the cli root folder.
If you are using a system that has `make` installed, then you can also simply run `make` in the cli root folder.
The default action for the `Makefile` is to run `go build`, as above.

## Running the CLI
Expand Down
218 changes: 170 additions & 48 deletions pkg/cmd/project/variables/view/view.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package view

import (
"encoding/json"
"fmt"
"strconv"
"strings"

"github.com/MakeNowJust/heredoc/v2"
"github.com/OctopusDeploy/cli/pkg/apiclient"
variableShared "github.com/OctopusDeploy/cli/pkg/cmd/project/variables/shared"
Expand All @@ -14,9 +18,6 @@ import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/resources"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
"github.com/spf13/cobra"
"io"
"strconv"
"strings"
)

const (
Expand All @@ -34,9 +35,35 @@ type ViewFlags struct {
type ViewOptions struct {
Client *client.Client
Host string
out io.Writer
name string
*ViewFlags
cmd *cobra.Command
}

type VarScopedItem struct {
Id string `json:"id"`
Name string `json:"name"`
}

type VarProcessScopedItem struct {
VarScopedItem
ProcessType string `json:"processtype"`
}

type VariableViewData struct {
Id string `json:"id"`
Value string `json:"value"`
Description string `json:"description"`
EnvironmentScope []*VarScopedItem `json:"environmentscope"`
RoleScope []*VarScopedItem `json:"rolescope"`
MachineScope []*VarScopedItem `json:"machinescope"`
ProcessScope []*VarProcessScopedItem `json:"processscope"`
StepScope []*VarScopedItem `json:"stepscope"`
ChannelScope []*VarScopedItem `json:"channelscope"`
Prompted bool `json:"prompted,omitempty"`
PromptLabel string `json:"promptlabel,omitempty"`
PromptLabelDescription string `json:"promptlabeldescription,omitempty"`
PromptRequired string `json:"promptrequired,omitempty"`
}

func NewViewFlags() *ViewFlags {
Expand Down Expand Up @@ -71,9 +98,9 @@ func NewCmdView(f factory.Factory) *cobra.Command {
opts := &ViewOptions{
client,
f.GetCurrentHost(),
cmd.OutOrStdout(),
args[0],
viewFlags,
cmd,
}

return viewRun(opts)
Expand Down Expand Up @@ -113,55 +140,150 @@ func viewRun(opts *ViewOptions) error {
return fmt.Errorf("cannot find variable '%s'", opts.name)
}

fmt.Fprintln(opts.out, output.Bold(filteredVars[0].Name))
outputFormat, err := opts.cmd.Flags().GetString(constants.FlagOutputFormat)

for _, v := range filteredVars {
data := []*output.DataRow{}
if err != nil { // should never happen, but fallback if it does
outputFormat = constants.OutputFormatTable
}

data = append(data, output.NewDataRow("Id", output.Dim(v.GetID())))
if v.IsSensitive {
data = append(data, output.NewDataRow("Value", output.Bold("*** (sensitive)")))
} else {
data = append(data, output.NewDataRow("Value", output.Bold(v.Value)))
}
out := opts.cmd.OutOrStdout()

if v.Description == "" {
v.Description = constants.NoDescription
}
data = append(data, output.NewDataRow("Description", output.Dim(v.Description)))
switch strings.ToLower(outputFormat) {
case constants.OutputFormatBasic, constants.OutputFormatTable:
fmt.Fprintln(out, output.Bold(filteredVars[0].Name))
for _, v := range filteredVars {
data := []*output.DataRow{}
if outputFormat == constants.OutputFormatTable {
data = append(data, output.NewDataRow(output.Bold("KEY"), output.Bold("VALUE")))
}
data = append(data, output.NewDataRow("Id", output.Dim(v.GetID())))
if v.IsSensitive {
data = append(data, output.NewDataRow("Value", output.Bold("*** (sensitive)")))
} else {
data = append(data, output.NewDataRow("Value", output.Bold(v.Value)))
}

scopeValues, err := variableShared.ToScopeValues(v, allVars.ScopeValues)
if err != nil {
return err
}
data = addScope(scopeValues.Environments, "Environment scope", data, nil)
data = addScope(scopeValues.Roles, "Role scope", data, nil)
data = addScope(scopeValues.Channels, "Channel scope", data, nil)
data = addScope(scopeValues.Machines, "Machine scope", data, nil)
data = addScope(scopeValues.TenantTags, "Tenant tag scope", data, func(item *resources.ReferenceDataItem) string {
return item.ID
})
data = addScope(scopeValues.Actions, "Step scope", data, nil)
data = addScope(
util.SliceTransform(scopeValues.Processes, func(item *resources.ProcessReferenceDataItem) *resources.ReferenceDataItem {
return &resources.ReferenceDataItem{
ID: item.ID,
Name: item.Name,
}
}),
"Process scope",
data,
nil)

if v.Prompt != nil {
data = append(data, output.NewDataRow("Prompted", "true"))
data = append(data, output.NewDataRow("Prompt Label", v.Prompt.Label))
data = append(data, output.NewDataRow("Prompt Description", output.Dim(v.Prompt.Description)))
data = append(data, output.NewDataRow("Prompt Required", strconv.FormatBool(v.Prompt.IsRequired)))
if v.Description == "" {
v.Description = constants.NoDescription
}
data = append(data, output.NewDataRow("Description", output.Dim(v.Description)))

scopeValues, err := variableShared.ToScopeValues(v, allVars.ScopeValues)
if err != nil {
return err
}

data = addScope(scopeValues.Environments, "Environment scope", data, nil)
data = addScope(scopeValues.Roles, "Role scope", data, nil)
data = addScope(scopeValues.Channels, "Channel scope", data, nil)
data = addScope(scopeValues.Machines, "Machine scope", data, nil)
data = addScope(scopeValues.TenantTags, "Tenant tag scope", data, func(item *resources.ReferenceDataItem) string {
return item.ID
})
data = addScope(scopeValues.Actions, "Step scope", data, nil)
data = addScope(
util.SliceTransform(scopeValues.Processes, func(item *resources.ProcessReferenceDataItem) *resources.ReferenceDataItem {
return &resources.ReferenceDataItem{
ID: item.ID,
Name: item.Name,
}
}),
"Process scope",
data,
nil)

if v.Prompt != nil {
data = append(data, output.NewDataRow("Prompted", "true"))
data = append(data, output.NewDataRow("Prompt Label", v.Prompt.Label))
data = append(data, output.NewDataRow("Prompt Description", output.Dim(v.Prompt.Description)))
data = append(data, output.NewDataRow("Prompt Required", strconv.FormatBool(v.Prompt.IsRequired)))
}

fmt.Fprintln(out)
output.PrintRows(data, out)
}
case constants.OutputFormatJson:

viewItems := make([]VariableViewData, 0, len(filteredVars))
for _, v := range filteredVars {

scopeValues, err := variableShared.ToScopeValues(v, allVars.ScopeValues)
if err != nil {
return err
}

fmt.Fprintln(opts.out)
output.PrintRows(data, opts.out)
vd := VariableViewData{}
vd.Id = v.ID
if v.IsSensitive {
vd.Value = "*** (sensitive)"
} else {
vd.Value = v.Value
}
vd.Description = v.Description

if util.Any(scopeValues.Environments) {
vd.EnvironmentScope = util.SliceTransform(scopeValues.Environments, func(e *resources.ReferenceDataItem) *VarScopedItem {
return &VarScopedItem{
Id: e.ID,
Name: e.Name,
}
})
}
if util.Any(scopeValues.Roles) {
vd.RoleScope = util.SliceTransform(scopeValues.Roles, func(e *resources.ReferenceDataItem) *VarScopedItem {
return &VarScopedItem{
Id: e.ID,
Name: e.Name,
}
})
}
if util.Any(scopeValues.Machines) {
vd.MachineScope = util.SliceTransform(scopeValues.Machines, func(e *resources.ReferenceDataItem) *VarScopedItem {
return &VarScopedItem{
Id: e.ID,
Name: e.Name,
}
})
}
if util.Any(scopeValues.Processes) {
vd.ProcessScope = util.SliceTransform(scopeValues.Processes, func(e *resources.ProcessReferenceDataItem) *VarProcessScopedItem {
return &VarProcessScopedItem{
VarScopedItem: VarScopedItem{
Id: e.ID,
Name: e.Name,
},
ProcessType: e.ProcessType,
}
})
}
if util.Any(scopeValues.Actions) {
vd.StepScope = util.SliceTransform(scopeValues.Actions, func(e *resources.ReferenceDataItem) *VarScopedItem {
return &VarScopedItem{
Id: e.ID,
Name: e.Name,
}
})
}
if util.Any(scopeValues.Channels) {
vd.ChannelScope = util.SliceTransform(scopeValues.Channels, func(e *resources.ReferenceDataItem) *VarScopedItem {
return &VarScopedItem{
Id: e.ID,
Name: e.Name,
}
})
}
if v.Prompt != nil {
vd.Prompted = true
vd.PromptLabel = v.Prompt.Label
vd.PromptLabelDescription = v.Prompt.Description
vd.PromptRequired = strconv.FormatBool(v.Prompt.IsRequired)
} else {
vd.Prompted = false
}
viewItems = append(viewItems, vd)
}
data, _ := json.MarshalIndent(viewItems, "", " ")
opts.cmd.Println(string(data))
}

return nil
Expand Down
67 changes: 54 additions & 13 deletions pkg/cmd/project/view/view.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package view

import (
"encoding/json"
"fmt"
"strings"

"github.com/OctopusDeploy/cli/pkg/apiclient"
"io"

"github.com/MakeNowJust/heredoc/v2"
"github.com/OctopusDeploy/cli/pkg/constants"
Expand Down Expand Up @@ -34,9 +36,9 @@ func NewViewFlags() *ViewFlags {
type ViewOptions struct {
Client *client.Client
Host string
out io.Writer
idOrName string
flags *ViewFlags
cmd *cobra.Command
}

func NewCmdView(f factory.Factory) *cobra.Command {
Expand All @@ -60,9 +62,9 @@ func NewCmdView(f factory.Factory) *cobra.Command {
opts := &ViewOptions{
client,
f.GetCurrentHost(),
cmd.OutOrStdout(),
args[0],
viewFlags,
cmd,
}

return viewRun(opts)
Expand All @@ -81,23 +83,62 @@ func viewRun(opts *ViewOptions) error {
return err
}

fmt.Fprintf(opts.out, "%s %s\n", output.Bold(project.Name), output.Dimf("(%s)", project.Slug))
outputFormat, err := opts.cmd.Flags().GetString(constants.FlagOutputFormat)

if err != nil { // should never happen, but fallback if it does
outputFormat = constants.OutputFormatTable
}
out := opts.cmd.OutOrStdout()

cacBranch := "Not version controlled"
projectVcsBranch := "N/A"
if project.IsVersionControlled {
cacBranch = project.PersistenceSettings.(projects.GitPersistenceSettings).DefaultBranch()
projectVcsBranch = project.PersistenceSettings.(projects.GitPersistenceSettings).DefaultBranch()
}
fmt.Fprintf(opts.out, "Version control branch: %s\n", output.Cyan(cacBranch))
if project.Description == "" {
fmt.Fprintln(opts.out, output.Dim(constants.NoDescription))
} else {
fmt.Fprintln(opts.out, output.Dim(project.Description))

projectDescription := project.Description
if projectDescription == "" {
projectDescription = constants.NoDescription
}

url := opts.Host + project.Links["Web"]

// footer
fmt.Fprintf(opts.out, "View this project in Octopus Deploy: %s\n", output.Blue(url))
type ViewData struct {
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
IsVersionControlled bool `json:"isversioncontrolled"`
Branch string `json:"branch"`
Url string `json:"url"`
}

switch strings.ToLower(outputFormat) {
case constants.OutputFormatBasic:
fmt.Fprintf(out, "Name: %s %s\n", output.Bold(project.Name), output.Dimf("(%s)", project.Slug))
fmt.Fprintf(out, "Description: %s\n", output.Dim(projectDescription))
fmt.Fprintf(out, "Is version controlled: %s\n", output.Cyanf("%t", project.IsVersionControlled))
fmt.Fprintf(out, "Branch: %s\n", output.Cyan(projectVcsBranch))
fmt.Fprintf(out, "View this project in Octopus Deploy: %s\n", output.Blue(url))
case constants.OutputFormatTable:
t := output.NewTable(out)
t.AddRow(output.Bold("KEY"), output.Bold("VALUE"))
t.AddRow("Name", project.Name)
t.AddRow("Slug", project.Slug)
t.AddRow("Description", project.Description)
t.AddRow("IsVersionControlled", fmt.Sprintf("%t", project.IsVersionControlled))
t.AddRow("Branch", projectVcsBranch)
t.AddRow("Url", fmt.Sprintf("%s", output.Blue(url)))
t.Print()
case constants.OutputFormatJson:
viewData := &ViewData{}
viewData.Name = project.Name
viewData.Slug = project.Slug
viewData.Description = project.Description
viewData.IsVersionControlled = project.IsVersionControlled
viewData.Branch = projectVcsBranch
viewData.Url = url
data, _ := json.MarshalIndent(viewData, "", " ")
opts.cmd.Println(string(data))
}

if opts.flags.Web.Value {
browser.OpenURL(url)
Expand Down