Skip to content

Commit

Permalink
CLOUDP-292660: add a new 'foascli sunset list' command to foascli to …
Browse files Browse the repository at this point in the history
…list all endpoints with theirs sunset date (#339)
  • Loading branch information
andreaangiolillo authored Jan 8, 2025
1 parent 2323449 commit bd33e5e
Show file tree
Hide file tree
Showing 17 changed files with 558 additions and 17 deletions.
3 changes: 0 additions & 3 deletions tools/cli/internal/cli/breakingchanges/breakingchanges.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "breaking-changes",
Short: "Manage API Breaking changes related commands.",
Annotations: map[string]string{
"toc": "true",
},
}

cmd.AddCommand(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "exemptions",
Short: "Manage exemptions.",
Annotations: map[string]string{
"toc": "true",
},
}

cmd.AddCommand(ParseBuilder())
Expand Down
3 changes: 0 additions & 3 deletions tools/cli/internal/cli/changelog/changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "changelog",
Short: "Manage the API Changelog for the OpenAPI spec.",
Annotations: map[string]string{
"toc": "true",
},
}

cmd.AddCommand(
Expand Down
3 changes: 0 additions & 3 deletions tools/cli/internal/cli/changelog/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "convert",
Short: "Convert API Changelog entries into another format.",
Annotations: map[string]string{
"toc": "true",
},
}

cmd.AddCommand(SlackBuilder())
Expand Down
2 changes: 1 addition & 1 deletion tools/cli/internal/cli/changelog/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (o *Opts) newOutputFilePath(fileName string) string {
return fileName
}

// Builder builds the merge command with the following signature:
// CreateBuilder builds the merge command with the following signature:
// changelog create -b path_folder -r path_folder --dry-run
func CreateBuilder() *cobra.Command {
opts := &Opts{
Expand Down
3 changes: 0 additions & 3 deletions tools/cli/internal/cli/changelog/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "metadata",
Short: "Manage the API Changelog Metadata.",
Annotations: map[string]string{
"toc": "true",
},
}

cmd.AddCommand(CreateBuilder())
Expand Down
2 changes: 2 additions & 0 deletions tools/cli/internal/cli/flag/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ const (
MessageID = "msg-id"
ChannelID = "channel-id"
ChannelIDShort = "c"
From = "from"
To = "to"
)
2 changes: 2 additions & 0 deletions tools/cli/internal/cli/root/openapi/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/mongodb/openapi/tools/cli/internal/cli/changelog"
"github.com/mongodb/openapi/tools/cli/internal/cli/merge"
"github.com/mongodb/openapi/tools/cli/internal/cli/split"
"github.com/mongodb/openapi/tools/cli/internal/cli/sunset"
"github.com/mongodb/openapi/tools/cli/internal/cli/versions"
"github.com/mongodb/openapi/tools/cli/internal/version"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -59,6 +60,7 @@ func Builder() *cobra.Command {
versions.Builder(),
changelog.Builder(),
breakingchanges.Builder(),
sunset.Builder(),
)
return rootCmd
}
Expand Down
2 changes: 1 addition & 1 deletion tools/cli/internal/cli/split/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (o *Opts) Run() error {
}

func (o *Opts) filter(oas *openapi3.T, version string) (result *openapi3.T, err error) {
log.Printf("Filtering OpenAPI document by version %s", version)
log.Printf("Filtering OpenAPI document by version %q", version)
apiVersion, err := apiversion.New(apiversion.WithVersion(version))
if err != nil {
return nil, err
Expand Down
176 changes: 176 additions & 0 deletions tools/cli/internal/cli/sunset/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright 2025 MongoDB Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sunset

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

"github.com/mongodb/openapi/tools/cli/internal/openapi"

"github.com/mongodb/openapi/tools/cli/internal/cli/flag"
"github.com/mongodb/openapi/tools/cli/internal/cli/usage"
"github.com/mongodb/openapi/tools/cli/internal/openapi/sunset"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

type ListOpts struct {
fs afero.Fs
basePath string
outputPath string
format string
from string
to string
toDate *time.Time
fromDate *time.Time
}

func (o *ListOpts) Run() error {
loader := openapi.NewOpenAPI3()
specInfo, err := loader.CreateOpenAPISpecFromPath(o.basePath)
if err != nil {
return err
}

sunsets, err := o.newSunsetInRange(sunset.NewListFromSpec(specInfo))
if err != nil {
return err
}

bytes, err := o.newSunsetListBytes(sunsets)
if err != nil {
return err
}
if o.outputPath != "" {
return afero.WriteFile(o.fs, o.outputPath, bytes, 0o600)
}

fmt.Println(string(bytes))
return nil
}

func (o *ListOpts) newSunsetInRange(sunsets []*sunset.Sunset) ([]*sunset.Sunset, error) {
var out []*sunset.Sunset
if o.from == "" && o.to == "" {
return sunsets, nil
}

for _, s := range sunsets {
sunsetDate, err := time.Parse("2006-01-02", s.SunsetDate)
if err != nil {
return nil, err
}

if isDateInRange(&sunsetDate, o.fromDate, o.toDate) {
out = append(out, s)
}
}

return out, nil
}

func isDateInRange(date, from, to *time.Time) bool {
if date == nil {
return false
}

if from != nil && date.Before(*from) {
return false
}

if to != nil && date.After(*to) {
return false
}

return true
}

func (o *ListOpts) newSunsetListBytes(versions []*sunset.Sunset) ([]byte, error) {
data, err := json.MarshalIndent(versions, "", " ")
if err != nil {
return nil, err
}

if format := strings.ToLower(o.format); format == "json" {
return data, nil
}

var jsonData any
if mErr := json.Unmarshal(data, &jsonData); mErr != nil {
return nil, mErr
}

yamlData, err := yaml.Marshal(jsonData)
if err != nil {
return nil, err
}

return yamlData, nil
}

func (o *ListOpts) validate() error {
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
}

return nil
}

// ListBuilder builds the merge command with the following signature:
// sunset ls -s spec.json -f 2024-01-01 -t 2024-09-22
func ListBuilder() *cobra.Command {
opts := &ListOpts{
fs: afero.NewOsFs(),
}

cmd := &cobra.Command{
Use: "list -s spec.json -o json",
Short: "List API endpoints with a Sunset date for a given OpenAPI spec.",
Aliases: []string{"ls"},
Args: cobra.NoArgs,
PreRunE: func(_ *cobra.Command, _ []string) error {
return opts.validate()
},
RunE: func(_ *cobra.Command, _ []string) error {
return opts.Run()
},
}

cmd.Flags().StringVarP(&opts.basePath, flag.Spec, flag.SpecShort, "", usage.Spec)
cmd.Flags().StringVarP(&opts.outputPath, flag.Output, flag.OutputShort, "", usage.Output)
cmd.Flags().StringVar(&opts.from, flag.From, "", usage.From)
cmd.Flags().StringVar(&opts.to, flag.To, "", usage.To)
cmd.Flags().StringVarP(&opts.format, flag.Format, flag.FormatShort, "json", usage.Format)

_ = cmd.MarkFlagRequired(flag.Spec)

return cmd
}
37 changes: 37 additions & 0 deletions tools/cli/internal/cli/sunset/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2025 MongoDB Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sunset

import (
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestList_Run(t *testing.T) {
fs := afero.NewMemMapFs()
opts := &ListOpts{
basePath: "../../../test/data/base_spec.json",
outputPath: "foas.json",
fs: fs,
}

require.NoError(t, opts.Run())
b, err := afero.ReadFile(fs, opts.outputPath)
require.NoError(t, err)
assert.NotEmpty(t, b)
}
30 changes: 30 additions & 0 deletions tools/cli/internal/cli/sunset/sunset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2025 MongoDB Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sunset

import (
"github.com/spf13/cobra"
)

func Builder() *cobra.Command {
cmd := &cobra.Command{
Use: "sunset",
Short: "Manage the Sunset API for the OpenAPI spec.",
}

cmd.AddCommand(ListBuilder())

return cmd
}
30 changes: 30 additions & 0 deletions tools/cli/internal/cli/sunset/sunset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2025 MongoDB Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sunset

import (
"testing"

"github.com/mongodb/openapi/tools/cli/internal/test"
)

func TestBuilder(t *testing.T) {
test.CmdValidator(
t,
Builder(),
1,
[]string{},
)
}
2 changes: 2 additions & 0 deletions tools/cli/internal/cli/usage/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ const (
Path = "Path to the changelog file."
MessageID = "Message ID of the slack message. This ID is used to add the message as slack thread."
SlackChannelID = "Slack Channel ID."
From = "Date in the format YYYY-MM-DD that indicates the start of a date range"
To = "Date in the format YYYY-MM-DD that indicates the end of a date range"
)
Loading

0 comments on commit bd33e5e

Please sign in to comment.