-
Notifications
You must be signed in to change notification settings - Fork 16
feat: add to and from flags to FOASCLI sunset diff command #1243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
92ce1d4
aa36715
e085695
2e4011f
185b3e5
b63147e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ import ( | |
| "fmt" | ||
| "sort" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/mongodb/openapi/tools/cli/internal/cli/flag" | ||
| "github.com/mongodb/openapi/tools/cli/internal/cli/usage" | ||
|
|
@@ -35,6 +36,10 @@ type DiffOpts struct { | |
| specPath string | ||
| outputPath string | ||
| format string | ||
| from string | ||
| to string | ||
| toDate *time.Time | ||
| fromDate *time.Time | ||
| } | ||
|
|
||
| type Diff struct { | ||
|
|
@@ -68,7 +73,10 @@ func (o *DiffOpts) Run() error { | |
| specSunsets := sunset.NewListFromSpec(specInfo) | ||
|
|
||
| // Find differences | ||
| var diffs = findDiffs(baseSunsets, specSunsets, o.basePath, o.specPath) | ||
| diffs, err := o.findDiffs(baseSunsets, specSunsets) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Write to output | ||
| bytes, err := o.newSunsetDiffBytes(diffs) | ||
|
|
@@ -84,7 +92,7 @@ func (o *DiffOpts) Run() error { | |
| return nil | ||
| } | ||
|
|
||
| func findDiffs(baseSunsets, specSunsets []*sunset.Sunset, baseSpecPath, specPath string) []*Diff { | ||
| func (o *DiffOpts) findDiffs(baseSunsets, specSunsets []*sunset.Sunset) ([]*Diff, error) { | ||
| // Create maps for easy lookup | ||
| baseMap := make(map[string]*sunset.Sunset) | ||
| for _, s := range baseSunsets { | ||
|
|
@@ -106,15 +114,14 @@ func findDiffs(baseSunsets, specSunsets []*sunset.Sunset, baseSpecPath, specPath | |
| if specSunset, exists := specMap[key]; exists { | ||
| // Endpoint exists in both specs | ||
| if baseSunset.SunsetDate != specSunset.SunsetDate { | ||
| // Different sunset dates | ||
| diffs = append(diffs, &Diff{ | ||
| Operation: baseSunset.Operation, | ||
| Path: baseSunset.Path, | ||
| Version: baseSunset.Version, | ||
| BaseSunsetDate: baseSunset.SunsetDate, | ||
| SpecSunsetDate: specSunset.SunsetDate, | ||
| BaseSpec: baseSpecPath, | ||
| Spec: specPath, | ||
| BaseSpec: o.basePath, | ||
| Spec: o.specPath, | ||
| Team: baseSunset.Team, | ||
| }) | ||
| } | ||
|
|
@@ -126,8 +133,8 @@ func findDiffs(baseSunsets, specSunsets []*sunset.Sunset, baseSpecPath, specPath | |
| Version: baseSunset.Version, | ||
| BaseSunsetDate: baseSunset.SunsetDate, | ||
| SpecSunsetDate: "", | ||
| BaseSpec: baseSpecPath, | ||
| Spec: specPath, | ||
| BaseSpec: o.basePath, | ||
| Spec: o.specPath, | ||
| Team: baseSunset.Team, | ||
| }) | ||
| } | ||
|
|
@@ -142,8 +149,8 @@ func findDiffs(baseSunsets, specSunsets []*sunset.Sunset, baseSpecPath, specPath | |
| Version: specSunset.Version, | ||
| BaseSunsetDate: "", | ||
| SpecSunsetDate: specSunset.SunsetDate, | ||
| BaseSpec: baseSpecPath, | ||
| Spec: specPath, | ||
| BaseSpec: o.basePath, | ||
| Spec: o.specPath, | ||
| Team: specSunset.Team, | ||
| }) | ||
| } | ||
|
|
@@ -156,7 +163,50 @@ func findDiffs(baseSunsets, specSunsets []*sunset.Sunset, baseSpecPath, specPath | |
| return iKey < jKey | ||
| }) | ||
|
|
||
| return diffs | ||
| // Filter diffs by date range if specified | ||
| filteredDiffs, err := o.diffsInRange(diffs) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return filteredDiffs, nil | ||
| } | ||
|
|
||
| func (o *DiffOpts) diffsInRange(diffs []*Diff) ([]*Diff, error) { | ||
| var out []*Diff | ||
|
|
||
| if o.from == "" && o.to == "" { | ||
| return diffs, nil | ||
| } | ||
|
|
||
| for _, d := range diffs { | ||
| baseSunsetDate, err := parseSunsetDate(d.BaseSunsetDate) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| specSunsetDate, err := parseSunsetDate(d.SpecSunsetDate) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if isDateInRange(baseSunsetDate, o.fromDate, o.toDate) || isDateInRange(specSunsetDate, o.fromDate, o.toDate) { | ||
| out = append(out, d) | ||
| } | ||
| } | ||
|
|
||
| return out, nil | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we support open intervals here (either of the date is not provided)? If this code returns a nil slice, would something break?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good Qs!
Hmm, we do however I don't think it's currently working as expected. When only one of the flags is provided, for example only
It wouldn't, it would either be an empty slice or one populated with values.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made a small adjustment to make it work as I described above, and added tests to cover those cases. Let me know what you think! Ty |
||
| } | ||
|
|
||
| func parseSunsetDate(dateStr string) (*time.Time, error) { | ||
| if dateStr == "" { | ||
| return nil, nil | ||
| } | ||
| parsedDate, err := time.Parse("2006-01-02", dateStr) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return &parsedDate, err | ||
| } | ||
|
|
||
| func makeKey(path, operation, version string) string { | ||
|
|
@@ -186,6 +236,30 @@ func (o *DiffOpts) newSunsetDiffBytes(diffs []*Diff) ([]byte, error) { | |
| return yamlData, nil | ||
| } | ||
|
|
||
| func (o *DiffOpts) validate() error { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quick one:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, I'll add a check 👍 |
||
| if o.from != "" { | ||
| value, err := time.Parse("2006-01-02", o.from) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| o.fromDate = &value | ||
| } | ||
|
|
||
| if o.to != "" { | ||
| value, err := time.Parse("2006-01-02", o.to) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| o.toDate = &value | ||
| } | ||
|
|
||
| if o.from != "" && o.to != "" && o.fromDate.After(*o.toDate) { | ||
| return fmt.Errorf("%s date cannot be after %s date", flag.From, flag.To) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // DiffBuilder builds the diff command with the following signature: | ||
| // sunset diff --base base-spec.json --spec spec.json. | ||
| func DiffBuilder() *cobra.Command { | ||
|
|
@@ -197,6 +271,9 @@ func DiffBuilder() *cobra.Command { | |
| Use: "diff --base spec1.json --spec spec2.json", | ||
| Short: "List API endpoints with different sunset dates between two OpenAPI specs.", | ||
| Args: cobra.NoArgs, | ||
| PreRunE: func(_ *cobra.Command, _ []string) error { | ||
| return opts.validate() | ||
| }, | ||
| RunE: func(_ *cobra.Command, _ []string) error { | ||
| return opts.Run() | ||
| }, | ||
|
|
@@ -206,6 +283,8 @@ func DiffBuilder() *cobra.Command { | |
| cmd.Flags().StringVarP(&opts.specPath, flag.Spec, flag.SpecShort, "", usage.Spec) | ||
| cmd.Flags().StringVarP(&opts.outputPath, flag.Output, flag.OutputShort, "", usage.Output) | ||
| cmd.Flags().StringVarP(&opts.format, flag.Format, flag.FormatShort, "json", usage.Format) | ||
| cmd.Flags().StringVar(&opts.from, flag.From, "", usage.From) | ||
| cmd.Flags().StringVar(&opts.to, flag.To, "", usage.To) | ||
|
|
||
| _ = cmd.MarkFlagRequired(flag.Base) | ||
| _ = cmd.MarkFlagRequired(flag.Spec) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diffsInRangereturnserrorbut I don't think any branch ever sets it — thetime.Parsefailures just fall back totime.Time{}. Woud it be cleaner to drop the return type and the matchingif err != nilplumbing infindDiffs/Run(), or actually propagate a wrapped error when the date string is malformed?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, this is probably left from some changes I made.
I think we would want to distinguish between the date beling Nil/empty, and invalid. In the case of invalid we should probably return an error instead of silently fail. I'll make some changes 👍