From 78b7b3ed994c98f61db0d4605f5a23eaa58c1ec3 Mon Sep 17 00:00:00 2001 From: Khanh Tran <32532742+khanhtc1202@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:25:17 +0700 Subject: [PATCH] Implement list breaking changes note endpoint for web_api (#5199) Signed-off-by: khanhtc1202 --- go.mod | 1 + go.sum | 2 + pkg/app/server/grpcapi/web_api.go | 78 ++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 10eed4a87b..9e89f672cb 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( go.uber.org/atomic v1.7.0 go.uber.org/zap v1.10.1-0.20190709142728-9a9fa7d4b5f0 golang.org/x/crypto v0.25.0 + golang.org/x/mod v0.17.0 golang.org/x/net v0.27.0 golang.org/x/oauth2 v0.21.0 golang.org/x/sync v0.7.0 diff --git a/go.sum b/go.sum index b855f83816..41664e880e 100644 --- a/go.sum +++ b/go.sum @@ -788,6 +788,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/pkg/app/server/grpcapi/web_api.go b/pkg/app/server/grpcapi/web_api.go index 059136b8b9..e5a8bccace 100644 --- a/pkg/app/server/grpcapi/web_api.go +++ b/pkg/app/server/grpcapi/web_api.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "regexp" "sort" "strconv" "strings" @@ -26,6 +27,7 @@ import ( "github.com/google/go-github/v29/github" "github.com/google/uuid" "go.uber.org/zap" + "golang.org/x/mod/semver" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -44,6 +46,10 @@ import ( "github.com/pipe-cd/pipecd/pkg/rpc/rpcauth" ) +var ( + breakingChangesRegex = regexp.MustCompile(`(?s)### Breaking Changes(.*?)(### |$)`) +) + type encrypter interface { Encrypt(text string) (string, error) } @@ -1860,5 +1866,75 @@ func (a *WebAPI) ListReleasedVersions(ctx context.Context, req *webservice.ListR } func (a *WebAPI) ListDeprecatedNotes(ctx context.Context, req *webservice.ListDeprecatedNotesRequest) (*webservice.ListDeprecatedNotesResponse, error) { - return &webservice.ListDeprecatedNotesResponse{}, nil + claims, err := rpcauth.ExtractClaims(ctx) + if err != nil { + a.logger.Error("failed to authenticate the current user", zap.Error(err)) + return nil, err + } + + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: claims.Role.ProjectId, + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + + pipeds, err := a.pipedStore.List(ctx, opts) + if err != nil { + return nil, gRPCStoreError(err, "list pipeds") + } + + // No Pipeds for given project. + if len(pipeds) == 0 { + return &webservice.ListDeprecatedNotesResponse{}, nil + } + + versions := make([]string, 0, len(pipeds)) + for _, piped := range pipeds { + if !semver.IsValid(piped.Version) { + continue + } + versions = append(versions, piped.Version) + } + + semver.Sort(versions) + oldestVersion := versions[0] + + // Github fecth release notes. + releases, _, err := a.githubCli.Repositories.ListReleases(ctx, "pipe-cd", "pipecd", nil) + if err != nil { + return nil, status.Error(codes.Internal, "Failed to list released versions") + } + + notes := "" + for _, release := range releases { + // Ignore pre-release tagged or draft release. + if *release.Prerelease || *release.Draft { + continue + } + + // Ignore the release that is older than the oldest version of the piped. + if semver.Compare(*release.TagName, oldestVersion) < 0 { + continue + } + + matches := breakingChangesRegex.FindStringSubmatch(*release.Body) + if len(matches) < 2 { + continue + } + + notes += fmt.Sprintf("## %s\n%s\n", *release.TagName, matches[1]) + } + + return &webservice.ListDeprecatedNotesResponse{ + Notes: notes, + }, nil }