{"id":25176689,"url":"https://github.com/conduitio/ecdysis","last_synced_at":"2025-04-04T01:41:34.801Z","repository":{"id":261069828,"uuid":"882776472","full_name":"ConduitIO/ecdysis","owner":"ConduitIO","description":"A Go idiomatic wrapper around spf13/cobra","archived":false,"fork":false,"pushed_at":"2025-03-27T08:15:00.000Z","size":128,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-03-27T09:28:18.637Z","etag":null,"topics":["cli","go","golang"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ConduitIO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-03T18:22:11.000Z","updated_at":"2025-03-27T08:14:58.000Z","dependencies_parsed_at":"2025-03-27T09:25:46.289Z","dependency_job_id":"32f96610-4085-473c-997f-042ac0396788","html_url":"https://github.com/ConduitIO/ecdysis","commit_stats":null,"previous_names":["conduitio/ecdysis"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConduitIO%2Fecdysis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConduitIO%2Fecdysis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConduitIO%2Fecdysis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConduitIO%2Fecdysis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ConduitIO","download_url":"https://codeload.github.com/ConduitIO/ecdysis/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247107830,"owners_count":20884797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","go","golang"],"created_at":"2025-02-09T13:17:54.026Z","updated_at":"2025-04-04T01:41:34.765Z","avatar_url":"https://github.com/ConduitIO.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ecdysis\n\n[![License](https://img.shields.io/badge/license-Apache%202-blue)](https://github.com/ConduitIO/ecdysis/blob/main/LICENSE.md)\n[![Test](https://github.com/ConduitIO/ecdysis/actions/workflows/test.yml/badge.svg)](https://github.com/ConduitIO/bwlimit/actions/workflows/test.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/conduitio/ecdysis)](https://goreportcard.com/report/github.com/conduitio/ecdysis)\n[![Go Reference](https://pkg.go.dev/badge/github.com/conduitio/ecdysis.svg)](https://pkg.go.dev/github.com/conduitio/ecdysis)\n\nEcdysis is a library for building CLI tools in Go. It is using\n[spf13/cobra](https://github.com/spf13/cobra) under the hood and provides a novel\napproach to building commands by declaring types with methods that define the\ncommand's behavior.\n\n## Quick Start\n\nInstall it using:\n\n```sh\ngo get github.com/conduitio/ecdysis\n```\n\nTo create a new command, define a struct that implements `ecdysis.Command` and\nany other `ecdysis.CommandWith*` interfaces you need. The recommended pattern is\nto list the interfaces that the command implements in a `var` block.\n\n```go\ntype VersionCommand struct{}\n\nvar (\n\t_ ecdysis.CommandWithExecute = (*VersionCommand)(nil)\n\t_ ecdysis.CommandWithDocs    = (*VersionCommand)(nil)\n)\n\nfunc (*VersionCommand) Usage() string { return \"version\" }\nfunc (*VersionCommand) Docs() ecdysis.Docs {\n\treturn ecdysis.Docs{\n\t\tShort: \"Print the version number of example-cli\",\n\t}\n}\nfunc (*VersionCommand) Execute(context.Context) error {\n\tfmt.Println(\"example-cli v0.1.0\")\n\treturn nil\n}\n```\n\nIn the `main` function, call `ecdysis.New` and build a Cobra command that can\nbe executed like any other Cobra command.\n\n```go\nfunc main() {\n\te := ecdysis.New()\n\tcmd := e.MustBuildCobraCommand(\u0026VersionCommand{})\n\tif err := cmd.Execute(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n## Decorators\n\nDecorators enable you to add functionality to commands and configure the resulting\nCobra command as you need. Ecdysis comes with a set of default decorators that\nyou can use to add flags, arguments, confirmation prompts, deprecation notices,\nand other features to your commands. Check out the\n[Go Reference](https://pkg.go.dev/github.com/conduitio/ecdysis) for a full list\nof decorators.\n\nYou can implement your own decorators and use them to extend the functionality\nof your commands.\n\nFor example, this is how you would add support for commands that log using Zerolog:\n\n```go\ntype CommandWithZerolog interface {\n\tCommand\n\tZerolog(zerolog.Logger)\n}\n\ntype CommandWithZerologDecorator struct{\n\tLogger zerolog.Logger\n}\n\nfunc (d CommandWithZerologDecorator) Decorate(_ *Ecdysis, _ *cobra.Command, c Command) error {\n\tv, ok := c.(CommandWithZerolog)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tv.Logger(d.Logger)\n\treturn nil\n}\n```\n\nYou need to supply the decorator to ecdysis when creating it.\n\n```go\nfunc main() {\n\te := ecdysis.New(\n\t\tecdysis.WithDecorators(\n\t\t\t\u0026CommandWithZerologDecorator{Logger: zerolog.New(os.Stdout)},\n\t\t),\n\t)\n\t// build and execute command ...\n}\n```\n\n### CommandWithConfig\n\nEcdysis provides an automatic way to parse a configuration file, environment variables, and flags using the [`viper`](https://github.com/spf13/viper) library. To use it, you need to implement the `CommandWithConfig` interface.\n\nThe order of precedence for configuration values is:\n\n1. Default values (slices and maps are not currently supported)\n2. Configuration file\n3. Environment variables\n4. Flags\n\n\n\u003e [!IMPORTANT]  \n\u003e For flags, it's important to set default values to ensure that the configuration will be correctly parsed. \n\u003e Otherwise, they will be empty, and it will be considered as if the user set that intentionally.\n\u003e example: `flags.SetDefault(\"config.path\", c.cfg.ConduitCfgPath)`\n\n```go\nvar (\n    _ ecdysis.CommandWithFlags   = (*RootCommand)(nil)\n    _ ecdysis.CommandWithExecute = (*RootCommand)(nil)\n    _ ecdysis.CommandWithConfig  = (*RootCommand)(nil)\n)\n\ntype ConduitConfig struct {\n    ConduitCfgPath string `long:\"config.path\" usage:\"global conduit configuration file\" default:\"./conduit.yaml\"`\n    \n    Connectors struct {\n        Path string `long:\"connectors.path\" usage:\"path to standalone connectors' directory\"`\n    }\n    \n    // ...\n}\n\ntype RootFlags struct {\n    ConduitConfig // you can embed any configuration, and it'll use the proper tags\n}\n\ntype RootCommand struct {\n    flags RootFlags\n    cfg   ConduitConfig\n}\n\nfunc (c *RootCommand) Config() ecdysis.Config {\n    return ecdysis.Config{\n        EnvPrefix:     \"CONDUIT\",\n        Parsed:        \u0026c.Cfg,\n        Path:          c.flags.ConduitCfgPath,\n        DefaultValues: conduit.DefaultConfigWithBasePath(path),\n    }\n}\n\nfunc (c *RootCommand) Execute(_ context.Context) error {\n    // c.cfg is now populated with the right parsed configuration\n    return nil\n}\n\nfunc (c *RootCommand) Flags() []ecdysis.Flag {\n    flags := ecdysis.BuildFlags(\u0026c.flags)\n    \n    // set a default value for each flag\n    flags.SetDefault(\"config.path\", c.cfg.ConduitCfgPath) \n    // ...\n\t\n    return flags\n}\n```\n\n### Fetching `cobra.Command` from `CommandWithExecute`\n\nIf you need to access the `cobra.Command` instance from a `CommandWithExecute` implementation, you can utilize\nthe `ecdysis.CobraCmdFromContext` function to fetch it from the context:\n\n```go\nfunc (c *RootCommand) Execute(ctx context.Context) error {\n    if cmd := ecdysis.CobraCmdFromContext(ctx); cmd != nil {\n        return cmd.Help()\n    }\n    return nil\n}\n```\n\n## Flags\n\nEcdysis provides a way to define flags using field tags. Flags will be\nautomatically parsed and populated.\n\n```go\ntype MyCommand struct {\n\tflags struct {\n\t\tVerbose bool   `long:\"verbose\" short:\"v\", usage:\"enable verbose output\" persistent:\"true\"`\n\t\tConfig  string `long:\"config\" usage:\"config file (default is $HOME/.example-cli.yaml)\" persistent:\"true\"`\n\t}\n}\n\n\nfunc (c *MyCommand) Flags() []ecdysis.Flag {\n\treturn ecdysis.BuildFlags(\u0026c.flags)\n}\n```\n\nA full list of supported tags:\n\n- `long`: The long flag name\n- `short`: The short flag name\n- `required`: Whether the flag is required\n- `persistent`: Whether the flag is persistent (i.e. available to subcommands)\n- `usage`: The flag usage\n- `hidden`: Whether the flag is hidden (i.e. not shown in help)\n\nFor a more example on how to use persistent flags in subcommands, see the\n[example](./example).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconduitio%2Fecdysis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconduitio%2Fecdysis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconduitio%2Fecdysis/lists"}