Skip to content

Commit f7b73ec

Browse files
committed
feat: CLI exclusions, write confirmations, and job alias removal
- Parse x-exclude-from-cli OpenAPI extension; skip excluded ops in auto-generated command tree (superuser and legacy endpoints stay accessible via API but are hidden from CLI) - Add --yes / -y persistent flag to bypass write confirmation prompt - Prompt for confirmation on POST/PUT/DELETE/PATCH unless --yes or --dry-run (CI-friendly: use --yes in scripts) - Add Excluded bool field to Operation struct - Remove job-runs running/failed/completed alias subcommands; use job-runs list --status RUNNING|FAILED|COMPLETED instead - Add CODEOWNERS assigning @wherobots/wbc-crew to all files
1 parent 697f8ec commit f7b73ec

6 files changed

Lines changed: 51 additions & 81 deletions

File tree

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @wherobots/wbc-crew

internal/commands/builder.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"bufio"
45
"bytes"
56
"encoding/json"
67
"fmt"
@@ -23,6 +24,8 @@ var persistentFlagNames = map[string]struct{}{
2324
"q": {},
2425
"dry-run": {},
2526
"tree": {},
27+
"yes": {},
28+
"y": {},
2629
}
2730

2831
type parameterBinding struct {
@@ -75,6 +78,7 @@ func BuildRootCommand(cfg config.Config, runtimeSpec *spec.RuntimeSpec) *cobra.C
7578
root.PersistentFlags().StringArrayVarP(&flags.Query, "query", "q", nil, "query pair (key=value), repeatable")
7679
root.PersistentFlags().BoolVar(&flags.DryRun, "dry-run", false, "print curl equivalent without executing request")
7780
root.PersistentFlags().BoolVar(&flags.Tree, "tree", false, "print available command tree")
81+
root.PersistentFlags().BoolVarP(&flags.Yes, "yes", "y", false, "skip confirmation prompt (for CI/scripts)")
7882

7983
root.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
8084
return hints.Wrap(findOperationContext(operationByCommand, cmd), err)
@@ -95,6 +99,9 @@ func BuildRootCommand(cfg config.Config, runtimeSpec *spec.RuntimeSpec) *cobra.C
9599
root.AddCommand(apiCmd)
96100

97101
for _, op := range runtimeSpec.Operations {
102+
if op.Excluded {
103+
continue
104+
}
98105
parent := ensureResourceHierarchy(apiCmd, resourceCommands, PathToResourceSegments(op.Path))
99106
verb := uniqueVerbName(parent, ChooseVerb(op))
100107
op.Verb = verb
@@ -142,6 +149,12 @@ func buildOperationCommand(
142149
return printTree(cmd)
143150
}
144151

152+
if !flags.DryRun && isWriteMethod(op.Method) && !flags.Yes {
153+
if err := confirmAction(cmd, op); err != nil {
154+
return err
155+
}
156+
}
157+
145158
parsedQuery, err := ParseQueryPairs(flags.Query)
146159
if err != nil {
147160
return hints.Wrap(op, err)
@@ -684,3 +697,22 @@ func buildOperationShort(op *spec.Operation) string {
684697
}
685698
return fmt.Sprintf("%s operation", strings.ToUpper(op.Method))
686699
}
700+
701+
func isWriteMethod(method string) bool {
702+
switch strings.ToUpper(method) {
703+
case "POST", "PUT", "DELETE", "PATCH":
704+
return true
705+
}
706+
return false
707+
}
708+
709+
func confirmAction(cmd *cobra.Command, op *spec.Operation) error {
710+
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s %s\nProceed? [y/N]: ", strings.ToUpper(op.Method), op.Path)
711+
scanner := bufio.NewScanner(cmd.InOrStdin())
712+
scanner.Scan()
713+
answer := strings.TrimSpace(scanner.Text())
714+
if strings.ToLower(answer) != "y" {
715+
return fmt.Errorf("aborted")
716+
}
717+
return nil
718+
}

internal/commands/flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type GlobalFlags struct {
1010
Query []string
1111
DryRun bool
1212
Tree bool
13+
Yes bool
1314
}
1415

1516
type QueryPair struct {

internal/commands/jobs.go

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ func addJobsCustomCommands(root *cobra.Command, cfg config.Config, runtimeSpec *
7474
jobsCmd.AddCommand(runner.newCreateCommand())
7575
jobsCmd.AddCommand(runner.newLogsCommand())
7676
jobsCmd.AddCommand(runner.newListCommand())
77-
jobsCmd.AddCommand(runner.newRunningAliasCommand())
78-
jobsCmd.AddCommand(runner.newFailedAliasCommand())
79-
jobsCmd.AddCommand(runner.newCompletedAliasCommand())
8077
if runner.getRunMetrics != nil {
8178
jobsCmd.AddCommand(runner.newMetricsCommand())
8279
}
@@ -730,84 +727,6 @@ func writeRunListTable(out io.Writer, body []byte) error {
730727
return tw.Flush()
731728
}
732729

733-
func (r *jobsRunner) newRunningAliasCommand() *cobra.Command {
734-
var (
735-
name string
736-
after string
737-
limit int
738-
region string
739-
output string
740-
)
741-
742-
cmd := &cobra.Command{
743-
Use: "running",
744-
Short: "Alias for job-runs list --status RUNNING",
745-
SilenceUsage: true,
746-
SilenceErrors: true,
747-
RunE: func(cmd *cobra.Command, _ []string) error {
748-
return r.executeList(cmd, []string{"RUNNING"}, name, after, limit, region, output)
749-
},
750-
}
751-
cmd.Flags().StringVar(&name, "name", "", "filter by name pattern")
752-
cmd.Flags().StringVar(&after, "after", "", "filter runs created after ISO timestamp")
753-
cmd.Flags().IntVarP(&limit, "limit", "l", defaultListLimit, "max results")
754-
cmd.Flags().StringVar(&region, "region", "", "filter by region")
755-
cmd.Flags().StringVar(&output, "output", outputText, "output format: text|json")
756-
return cmd
757-
}
758-
759-
func (r *jobsRunner) newFailedAliasCommand() *cobra.Command {
760-
var (
761-
name string
762-
after string
763-
limit int
764-
region string
765-
output string
766-
)
767-
768-
cmd := &cobra.Command{
769-
Use: "failed",
770-
Short: "Alias for job-runs list --status FAILED",
771-
SilenceUsage: true,
772-
SilenceErrors: true,
773-
RunE: func(cmd *cobra.Command, _ []string) error {
774-
return r.executeList(cmd, []string{"FAILED"}, name, after, limit, region, output)
775-
},
776-
}
777-
cmd.Flags().StringVar(&name, "name", "", "filter by name pattern")
778-
cmd.Flags().StringVar(&after, "after", "", "filter runs created after ISO timestamp")
779-
cmd.Flags().IntVarP(&limit, "limit", "l", defaultListLimit, "max results")
780-
cmd.Flags().StringVar(&region, "region", "", "filter by region")
781-
cmd.Flags().StringVar(&output, "output", outputText, "output format: text|json")
782-
return cmd
783-
}
784-
785-
func (r *jobsRunner) newCompletedAliasCommand() *cobra.Command {
786-
var (
787-
name string
788-
after string
789-
limit int
790-
region string
791-
output string
792-
)
793-
794-
cmd := &cobra.Command{
795-
Use: "completed",
796-
Short: "Alias for job-runs list --status COMPLETED",
797-
SilenceUsage: true,
798-
SilenceErrors: true,
799-
RunE: func(cmd *cobra.Command, _ []string) error {
800-
return r.executeList(cmd, []string{"COMPLETED"}, name, after, limit, region, output)
801-
},
802-
}
803-
cmd.Flags().StringVar(&name, "name", "", "filter by name pattern")
804-
cmd.Flags().StringVar(&after, "after", "", "filter runs created after ISO timestamp")
805-
cmd.Flags().IntVarP(&limit, "limit", "l", defaultListLimit, "max results")
806-
cmd.Flags().StringVar(&region, "region", "", "filter by region")
807-
cmd.Flags().StringVar(&output, "output", outputText, "output format: text|json")
808-
return cmd
809-
}
810-
811730
func (r *jobsRunner) newMetricsCommand() *cobra.Command {
812731
var output string
813732

internal/spec/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Operation struct {
1919
PathParamOrder []string
2020
QueryParams []Parameter
2121
RequestBody *RequestBodyInfo
22+
Excluded bool
2223
}
2324

2425
type Parameter struct {

internal/spec/parser.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func Parse(rawSpec []byte, openAPIURL string) (*RuntimeSpec, error) {
6767
PathParamOrder: pathParamOrder,
6868
QueryParams: queryParams,
6969
RequestBody: extractRequestBodyInfo(op),
70+
Excluded: isOperationExcluded(op),
7071
})
7172
}
7273
}
@@ -113,6 +114,21 @@ func deriveBaseURL(doc *highv3.Document, openAPIURL string) string {
113114
return strings.TrimRight(parsedSpecURL.String(), "/")
114115
}
115116

117+
func isOperationExcluded(op *highv3.Operation) bool {
118+
if op == nil || op.Extensions == nil {
119+
return false
120+
}
121+
for pair := orderedmap.First(op.Extensions); pair != nil; pair = pair.Next() {
122+
if pair.Key() == "x-exclude-from-cli" {
123+
node := pair.Value()
124+
if node != nil && strings.ToLower(strings.TrimSpace(node.Value)) == "true" {
125+
return true
126+
}
127+
}
128+
}
129+
return false
130+
}
131+
116132
func extractPathParamOrder(pathTemplate string) []string {
117133
matches := pathParamPattern.FindAllStringSubmatch(pathTemplate, -1)
118134
seen := make(map[string]struct{}, len(matches))

0 commit comments

Comments
 (0)