Skip to content
Merged
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
6 changes: 5 additions & 1 deletion cmd/devstream/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/pkg/util/log"
)

var applyCMD = &cobra.Command{
Use: "apply",
Short: "Create or update DevOps tools according to DevStream configuration file",
Long: `Create or update DevOps tools according to DevStream configuration file.
Long: `Create or update DevOps tools according to DevStream configuration file.
DevStream will generate and execute a new plan based on the config file and the state file by default.`,
Run: applyCMDFunc,
}
Expand All @@ -25,8 +26,11 @@ func applyCMDFunc(cmd *cobra.Command, args []string) {
}
log.Success("Apply finished.")
}

func init() {
applyCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
applyCMD.Flags().StringVarP(&pluginDir, "plugin-dir", "d", pluginengine.DefaultPluginDir, "plugins directory")
applyCMD.Flags().BoolVarP(&continueDirectly, "yes", "y", false, "apply directly without confirmation")

completion.FlagConfigFileCompletion(applyCMD)
}
61 changes: 61 additions & 0 deletions cmd/devstream/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"io"
"os"
"path/filepath"

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
)

func completionCMD(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "completion",
Short: "Generate the autocompletion script for dtm for the specified shell",
Long: "See each sub-command's help for details on how to use the generated script.",
DisableFlagsInUseLine: true,
Args: cobra.ExactValidArgs(1),
}

binaryName := filepath.Base(os.Args[0])
bash := &cobra.Command{
Use: "bash",
Short: "generate autocompletion script for bash",
Example: completion.BashExample(binaryName),
RunE: func(cmd *cobra.Command, args []string) error {
return completion.CompletionBash(out, cmd)
},
}

zsh := &cobra.Command{
Use: "zsh",
Short: "generate autocompletion script for zsh",
Example: completion.ZshExample(binaryName),
RunE: func(cmd *cobra.Command, args []string) error {
return completion.CompletionZsh(out, cmd)
},
}

fish := &cobra.Command{
Use: "fish",
Short: "generate autocompletion script for fish",
Example: completion.FishExample(binaryName),
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Root().GenFishCompletion(out, true)
},
}

powershell := &cobra.Command{
Use: "powershell",
Short: "generate autocompletion script for powershell",
Example: completion.PowershellExample(binaryName),
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Root().GenPowerShellCompletionWithDesc(out)
},
}
cmd.AddCommand(bash, zsh, fish, powershell)

return cmd
}
5 changes: 4 additions & 1 deletion cmd/devstream/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/pkg/util/log"
)
Expand All @@ -14,7 +15,7 @@ var isForceDelete bool
var deleteCMD = &cobra.Command{
Use: "delete",
Short: "Delete DevOps tools according to DevStream configuration file",
Long: `Delete DevOps tools according to DevStream configuration file.
Long: `Delete DevOps tools according to DevStream configuration file.
DevStream will delete everything defined in the config file, regardless of the state.`,
Run: deleteCMDFunc,
}
Expand All @@ -34,4 +35,6 @@ func init() {
deleteCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
deleteCMD.Flags().StringVarP(&pluginDir, "plugin-dir", "d", pluginengine.DefaultPluginDir, "plugins directory")
deleteCMD.Flags().BoolVarP(&continueDirectly, "yes", "y", false, "delete directly without confirmation")

completion.FlagConfigFileCompletion(applyCMD)
}
3 changes: 3 additions & 0 deletions cmd/devstream/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/pkg/util/log"
)
Expand All @@ -28,4 +29,6 @@ func destroyCMDFunc(cmd *cobra.Command, args []string) {
func init() {
destroyCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
destroyCMD.Flags().BoolVarP(&continueDirectly, "yes", "y", false, "destroy directly without confirmation")

completion.FlagConfigFileCompletion(destroyCMD)
}
3 changes: 3 additions & 0 deletions cmd/devstream/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/configloader"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/internal/pkg/pluginmanager"
Expand Down Expand Up @@ -35,4 +36,6 @@ func initCMDFunc(cmd *cobra.Command, args []string) {
func init() {
initCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
initCMD.Flags().StringVarP(&pluginDir, "plugin-dir", "d", pluginengine.DefaultPluginDir, "plugins directory")

completion.FlagConfigFileCompletion(initCMD)
}
16 changes: 9 additions & 7 deletions cmd/devstream/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"os"
"strings"

"github.com/sirupsen/logrus"
Expand All @@ -17,13 +18,13 @@ var (
Short: `DevStream is an open-source DevOps toolchain manager`,
Long: `DevStream is an open-source DevOps toolchain manager

###### #####
# # ###### # # # # ##### ##### ###### ## # #
# # # # # # # # # # # # ## ##
# # ##### # # ##### # # # ##### # # # ## #
# # # # # # # ##### # ###### # #
# # # # # # # # # # # # # # #
###### ###### ## ##### # # # ###### # # # #
###### #####
# # ###### # # # # ##### ##### ###### ## # #
# # # # # # # # # # # # ## ##
# # ##### # # ##### # # # ##### # # # ## #
# # # # # # # ##### # ###### # #
# # # # # # # # # # # # # # #
###### ###### ## ##### # # # ###### # # # #
`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initLog()
Expand All @@ -34,6 +35,7 @@ var (
func init() {
cobra.OnInitialize(initConfig)
rootCMD.PersistentFlags().BoolVarP(&isDebug, "debug", "", false, "debug level log")
rootCMD.AddCommand(completionCMD(os.Stdout))
rootCMD.AddCommand(versionCMD)
rootCMD.AddCommand(initCMD)
rootCMD.AddCommand(applyCMD)
Expand Down
3 changes: 3 additions & 0 deletions cmd/devstream/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/internal/pkg/show/config"
"github.com/devstream-io/devstream/internal/pkg/show/status"
Expand Down Expand Up @@ -58,10 +59,12 @@ func init() {
showCMD.AddCommand(showStatusCMD)

showConfigCMD.Flags().StringVarP(&plugin, "plugin", "p", "", "specify name with the plugin")
completion.FlagPluginsCompletion(showConfigCMD, "plugin")

showStatusCMD.Flags().StringVarP(&plugin, "plugin", "p", "", "specify name with the plugin")
showStatusCMD.Flags().StringVarP(&instanceID, "id", "i", "", "specify id with the plugin instance")
showStatusCMD.Flags().BoolVarP(&statusAllFlag, "all", "a", false, "show all instances of all plugins status")
showStatusCMD.Flags().StringVarP(&pluginDir, "plugin-dir", "d", pluginengine.DefaultPluginDir, "plugins directory")
showStatusCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
completion.FlagPluginsCompletion(showStatusCMD, "plugin")
}
3 changes: 3 additions & 0 deletions cmd/devstream/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"github.com/spf13/cobra"

"github.com/devstream-io/devstream/internal/pkg/completion"
"github.com/devstream-io/devstream/internal/pkg/pluginengine"
"github.com/devstream-io/devstream/pkg/util/log"
)
Expand All @@ -26,4 +27,6 @@ func verifyCMDFunc(cmd *cobra.Command, args []string) {
func init() {
verifyCMD.Flags().StringVarP(&configFile, "config-file", "f", "config.yaml", "config file")
verifyCMD.Flags().StringVarP(&pluginDir, "plugin-dir", "d", pluginengine.DefaultPluginDir, "plugins directory")

completion.FlagConfigFileCompletion(verifyCMD)
}
100 changes: 100 additions & 0 deletions internal/pkg/completion/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package completion

import (
"fmt"
"io"
"os"
"path/filepath"

"github.com/spf13/cobra"

"github.com/devstream-io/devstream/cmd/devstream/list"
"github.com/devstream-io/devstream/pkg/util/log"
)

func FlagPluginsCompletion(cmd *cobra.Command, flag string) {
if err := cmd.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return list.PluginsNameSlice(), cobra.ShellCompDirectiveDefault
}); err != nil {
log.Warn(err)
}
}

func FlagConfigFileCompletion(cmd *cobra.Command) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said before, it's not mandatory to achieve and you also didn't think it is necessary to achieve, but since you have achieved it, I refer to the official documentation and found that this implementation is not applicable to Fish and PowerShell

Fish doesn't support BashCompFilenameExt

Powershell doesn't support BashCompFilenameExt

A more generic implementation is as follows.

https://github.com/spf13/cobra/blob/d8184d32696bee36f682bcb3ace5642af54cd7ad/shell_completions.md#specify-valid-filename-extensions-for-flags-that-take-a-filename

Of course, if you still don't think it's necessary to implement this feature, you can just remove the relevant code. Thanks again.

validConfigFilenames := []string{"yaml"}

if err := cmd.Flags().SetAnnotation("config-file", cobra.BashCompFilenameExt, validConfigFilenames); err != nil {
log.Warn(err)
}
}

func CompletionBash(out io.Writer, cmd *cobra.Command) error {
err := cmd.Root().GenBashCompletion(out)

// The default binary name downloaded from the Releases page is dtm-{os}-amd64
// solve the problem that autocompletion fails when the name of the binary is not dtm
if binary := filepath.Base(os.Args[0]); binary != "dtm" {
renamedBinary := `
# the user renamed the dtm binary
if [[ $(type -t compopt) = "builtin" ]]; then
complete -o default -F __start_dtm %[1]s
else
complete -o default -o nospace -F __start_dtm %[1]s
fi
`
fmt.Fprintf(out, renamedBinary, binary)
}

return err
}

func CompletionZsh(out io.Writer, cmd *cobra.Command) error {
err := cmd.Root().GenZshCompletionNoDesc(out)

// The default binary name downloaded from the Releases page is dtm-{os}-amd64
// solve the problem that autocompletion fails when the name of the binary is not dtm
if binary := filepath.Base(os.Args[0]); binary != "dtm" {
renamedBinary := `
# the user renamed the dtm binary
compdef _dtm %[1]s
`
fmt.Fprintf(out, renamedBinary, binary)
}

fmt.Fprintf(out, "compdef _dtm dtm")

return err
}

func BashExample(binary string) string {
return fmt.Sprintf(`Load is completions in the current shell session:
# source <(%s completion bash)

Load completions for every new session:
(in Linux)# %s completion bash > /etc/bash_completion.d/dtm
(in MacOS)# %s completion bash > $(brew --prefix)/etc/bash_completion.d/dtm`, binary, binary, binary)
}

func ZshExample(binary string) string {
return fmt.Sprintf(`Load is completions in the current shell session:
# source <(%s completion zsh)

Load completions for every new session:
# %s completion zsh > "${fpath[1]}/_dtm"`, binary, binary)
}

func FishExample(binary string) string {
return fmt.Sprintf(`Load is completions in the current shell session:
# %s completion fish | source

Load completions for every new session:
# %s completion fish > ~/.config/fish/completions/dtm.fish`, binary, binary)
}

func PowershellExample(binary string) string {
return fmt.Sprintf(`Load is completions in the current shell session:
C:\> %s completion powershell | Out-String | Invoke-Expression

Load completions for every new session:
add the output of the above command to powershell profile.`, binary)
}