Skip to content

Commit

Permalink
Merge branch 'main' into feat/change-pivot-date-october
Browse files Browse the repository at this point in the history
  • Loading branch information
RaduPetreTarean authored Sep 2, 2024
2 parents fadc3a9 + cde530e commit 1c669b5
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 3 deletions.
17 changes: 15 additions & 2 deletions internal/cmd/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import (
)

var defaultPivotDate = vervet.MustParseVersion("2024-10-01")
var defaultVersioningUrl = "https://api.snyk.io/rest/openapi"

var pivotDateCLIFlagName = "pivot-version"
var versioningUrlCLIFlagName = "versioning-url"

var buildFlags = []cli.Flag{
&cli.StringFlag{
Expand All @@ -34,6 +37,12 @@ var buildFlags = []cli.Flag{
" Flag for testing only, recommend to use the default date(%s)", defaultPivotDate.String()),
Value: defaultPivotDate.String(),
},
&cli.StringFlag{
Name: versioningUrlCLIFlagName,
Aliases: []string{"U"},
Usage: fmt.Sprintf("URL to fetch versioning information. Default is %q", defaultVersioningUrl),
Value: defaultVersioningUrl,
},
}

// BuildCommand is the `vervet build` subcommand.
Expand Down Expand Up @@ -73,7 +82,9 @@ func SimpleBuild(ctx *cli.Context) error {
return fmt.Errorf("failed to parse pivot date %q: %w", pivotDate, err)
}

err = simplebuild.Build(ctx.Context, project, pivotDate, false)
versioningURL := ctx.String(versioningUrlCLIFlagName)

err = simplebuild.Build(ctx.Context, project, pivotDate, versioningURL, false)
return err
}

Expand All @@ -89,6 +100,8 @@ func CombinedBuild(ctx *cli.Context) error {
return fmt.Errorf("failed to parse pivot date %q: %w", pivotDate, err)
}

versioningURL := ctx.String(versioningUrlCLIFlagName)

comp, err := compiler.New(ctx.Context, project)
if err != nil {
return err
Expand All @@ -98,7 +111,7 @@ func CombinedBuild(ctx *cli.Context) error {
return err
}

return simplebuild.Build(ctx.Context, project, pivotDate, true)
return simplebuild.Build(ctx.Context, project, pivotDate, versioningURL, true)
}

func parsePivotDate(ctx *cli.Context) (vervet.Version, error) {
Expand Down
99 changes: 98 additions & 1 deletion internal/simplebuild/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ package simplebuild

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"path/filepath"
"slices"
"sort"
"strings"
"time"

"github.com/getkin/kin-openapi/openapi3"
Expand All @@ -19,16 +24,39 @@ import (

// Build compiles the versioned resources in a project configuration based on
// simplified versioning rules, after the start date.
func Build(ctx context.Context, project *config.Project, startDate vervet.Version, appendOutputFiles bool) error {
func Build(
ctx context.Context,
project *config.Project,
startDate vervet.Version,
versioningUrl string,
appendOutputFiles bool,
) error {
if time.Now().Before(startDate.Date) {
return nil
}

latestVersion, err := fetchLatestVersion(versioningUrl)
if err != nil {
return err
}

for _, apiConfig := range project.APIs {
if apiConfig.Output == nil {
fmt.Printf("No output specified for %s, skipping\n", apiConfig.Name)
continue
}

for _, resource := range apiConfig.Resources {
paths, err := ResourceSpecFiles(resource)
if err != nil {
return err
}

if err := CheckSingleVersionResourceToBeBeforeLatestVersion(paths, latestVersion); err != nil {
return err
}
}

operations, err := LoadPaths(ctx, apiConfig)
if err != nil {
return err
Expand Down Expand Up @@ -314,3 +342,72 @@ func CheckBreakingChanges(docs DocSet) error {
}
return nil
}

func fetchLatestVersion(versioningURL string) (vervet.Version, error) {
resp, err := http.Get(versioningURL)
if err != nil {
return vervet.Version{}, fmt.Errorf("failed to fetch versioning information from %q: %w", versioningURL, err)
}

defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
fmt.Println("failed to close response body")
}
}(resp.Body)

if resp.StatusCode != http.StatusOK {
return vervet.Version{}, fmt.Errorf("failed to fetch versioning information, status code: %d", resp.StatusCode)
}

var versions []string
if err := json.NewDecoder(resp.Body).Decode(&versions); err != nil {
return vervet.Version{}, fmt.Errorf("failed to parse versioning information: %w", err)
}

var dates = make([]string, 0, len(versions))

for _, version := range versions {
parts := strings.Split(version, "~")
dates = append(dates, parts[0])
}
sort.Strings(dates)

latestVersion, err := vervet.ParseVersion(dates[len(dates)-1])
if err != nil {
return vervet.Version{}, fmt.Errorf("failed to parse latest version date %q: %w", dates[len(dates)-1], err)
}

return latestVersion, nil
}

func CheckSingleVersionResourceToBeBeforeLatestVersion(paths []string, latestVersion vervet.Version) error {
resourceVersions := make(map[string][]string)

for _, path := range paths {
resourceDir := filepath.Dir(filepath.Dir(path))
versionDir := filepath.Base(filepath.Dir(path))
resourceVersions[resourceDir] = append(resourceVersions[resourceDir], versionDir)
}

for _, versions := range resourceVersions {
if len(versions) == 1 {
versionStr := versions[0]
version, err := vervet.ParseVersion(versionStr)
if err != nil {
return fmt.Errorf("invalid version %q", versionStr)
}

if version.Date.After(latestVersion.Date) {
return fmt.Errorf(
"version %s is after the last released version of the global API %s. "+
"Please change the version date to be before %s or at the same date",
version.Date.Format("2006-01-02"),
latestVersion.Date.Format("2006-01-02"),
latestVersion.Date.Format("2006-01-02"),
)
}
}
}
return nil
}
46 changes: 46 additions & 0 deletions internal/simplebuild/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,52 @@ func TestCheckBreakingChanges(t *testing.T) {
c.Assert(err, qt.Not(qt.IsNil), qt.Commentf("expected no breaking changes"))
})
}

func TestCheckSingleVersionResource(t *testing.T) {
c := qt.New(t)

c.Run("no error when version is before or equal to the latest version", func(c *qt.C) {
paths := []string{
"internal/api/hidden/resources/apps/2023-07-31/spec.yaml",
}
latestVersion := vervet.MustParseVersion("2024-01-01")

err := simplebuild.CheckSingleVersionResourceToBeBeforeLatestVersion(paths, latestVersion)
c.Assert(err, qt.IsNil)
})

c.Run("error when version is after the latest version", func(c *qt.C) {
paths := []string{
"internal/api/hidden/resources/apps/2025-07-31/spec.yaml",
}
latestVersion := vervet.MustParseVersion("2024-01-01")

err := simplebuild.CheckSingleVersionResourceToBeBeforeLatestVersion(paths, latestVersion)
c.Assert(err, qt.ErrorMatches, "version .* is after the last released version .*")
})

c.Run("no error when multiple versions are present", func(c *qt.C) {
paths := []string{
"internal/api/hidden/resources/apps/2023-07-31/spec.yaml",
"internal/api/hidden/resources/apps/2024-01-01/spec.yaml",
}
latestVersion := vervet.MustParseVersion("2024-01-01")

err := simplebuild.CheckSingleVersionResourceToBeBeforeLatestVersion(paths, latestVersion)
c.Assert(err, qt.IsNil)
})

c.Run("handles version parsing error gracefully", func(c *qt.C) {
paths := []string{
"internal/api/hidden/resources/apps/invalid-version/spec.yaml",
}
latestVersion := vervet.MustParseVersion("2024-01-01")

err := simplebuild.CheckSingleVersionResourceToBeBeforeLatestVersion(paths, latestVersion)
c.Assert(err, qt.ErrorMatches, "invalid version .*")
})
}

func compareDocs(a, b simplebuild.VersionedDoc) int {
return a.VersionDate.Compare(b.VersionDate)
}
Expand Down

0 comments on commit 1c669b5

Please sign in to comment.