Skip to content

Commit

Permalink
feat: Get commit deployment status for all applications (#1899)
Browse files Browse the repository at this point in the history
The `GetCommitDeploymentInfo` endpoint now accepts only a commit hash,
and returns a map of all applications and their deployment status for
all environments, as shown:
```
{
  "app1": {
    "dev": DEPLOYED,
    "staging": DEPLOYED,
  },
  "app2": {
    "dev": DEPLOYED,
    "staging": PENDING,
  },
}
```
Ref: SRX-H0ZDQS
  • Loading branch information
ahmed-nour-fdc authored Aug 23, 2024
1 parent f9fa0cd commit 667f721
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 35 deletions.
7 changes: 5 additions & 2 deletions pkg/api/v1/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,12 @@ service CommitDeploymentService {

message GetCommitDeploymentInfoRequest {
string commit_id = 1;
string application = 2;
}

message GetCommitDeploymentInfoResponse {
message AppCommitDeploymentStatus {
map<string, CommitDeploymentStatus> deployment_status = 1;
}

message GetCommitDeploymentInfoResponse {
map<string,AppCommitDeploymentStatus> deployment_status = 1;
}
107 changes: 74 additions & 33 deletions services/cd-service/pkg/service/commit_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
api "github.com/freiheit-com/kuberpult/pkg/api/v1"
"github.com/freiheit-com/kuberpult/pkg/db"
"github.com/freiheit-com/kuberpult/pkg/event"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)

type CommitStatus map[string]api.CommitDeploymentStatus
Expand All @@ -35,45 +36,46 @@ type CommitDeploymentServer struct {
}

func (s *CommitDeploymentServer) GetCommitDeploymentInfo(ctx context.Context, in *api.GetCommitDeploymentInfoRequest) (*api.GetCommitDeploymentInfoResponse, error) {
status, err := getCommitDeploymentInfoForApp(ctx, s.DBHandler, in.CommitId, in.Application)
if err != nil {
return nil, fmt.Errorf("Could not get commit deployment info: %v", err)
}
return &api.GetCommitDeploymentInfoResponse{
DeploymentStatus: status,
}, nil
}

func getCommitDeploymentInfoForApp(ctx context.Context, h *db.DBHandler, commit, app string) (CommitStatus, error) {
commitDeploymentStatus := make(map[string]*api.AppCommitDeploymentStatus, 0)
var jsonCommitEventsMetadata []byte
var jsonAllDeploymentsMetadata []byte
var jsonAllEnvironmentsMetadata []byte

err := h.WithTransaction(ctx, true, func(ctx context.Context, transaction *sql.Tx) error {
applicationReleases := make(map[string][]byte, 0)
allApplicationReleasesQuery := `
SELECT
deployments.appname,
deployments.json
FROM (
SELECT
MAX(eslVersion) AS latest,
appname
FROM
"public"."all_deployments"
GROUP BY
appname) AS latest
JOIN
"public".all_deployments AS deployments
ON
latest.latest=deployments.eslVersion
AND latest.appname=deployments.appname;
`
span, _ := tracer.StartSpanFromContext(ctx, "GetCommitDeploymentInfo")
defer span.Finish()
span.SetTag("commit_id", in.CommitId)

err := s.DBHandler.WithTransaction(ctx, true, func(ctx context.Context, transaction *sql.Tx) error {
// Get the latest new-release event for the commit
query := h.AdaptQuery("SELECT json FROM commit_events WHERE commithash = ? AND eventtype = ? ORDER BY timestamp DESC LIMIT 1;")
row := transaction.QueryRow(query, commit, "new-release")
query := s.DBHandler.AdaptQuery("SELECT json FROM commit_events WHERE commithash = ? AND eventtype = ? ORDER BY timestamp DESC LIMIT 1;")
row := transaction.QueryRow(query, in.CommitId, "new-release")
err := row.Scan(&jsonCommitEventsMetadata)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("commit \"%s\" could not be found", commit)
}
return err
}

// Get all deployments for the commit
query = h.AdaptQuery("SELECT json FROM all_deployments WHERE appname = ? ORDER BY eslversion DESC LIMIT 1;")
row = transaction.QueryRow(query, app)
err = row.Scan(&jsonAllDeploymentsMetadata)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("application \"%s\" does not exist or has no deployments yet.", app)
return fmt.Errorf("commit \"%s\" could not be found", in.CommitId)
}
return err
}

// Get all environments
query = h.AdaptQuery("SELECT json FROM all_environments ORDER BY version DESC LIMIT 1;")
query = s.DBHandler.AdaptQuery("SELECT json FROM all_environments ORDER BY version DESC LIMIT 1;")
row = transaction.QueryRow(query)
err = row.Scan(&jsonAllEnvironmentsMetadata)
if err != nil {
Expand All @@ -82,11 +84,29 @@ func getCommitDeploymentInfoForApp(ctx context.Context, h *db.DBHandler, commit,
}
return err
}

// Get latest releases for all apps
rows, err := transaction.QueryContext(ctx, allApplicationReleasesQuery)
if err != nil {
return err
}
defer rows.Close()

for rows.Next() {
var appName string
var appRelease []byte
err = rows.Scan(&appName, &appRelease)
if err != nil {
return err
}
applicationReleases[appName] = appRelease
}
return nil
})
if err != nil {
return nil, err
}

releaseNumber, err := getCommitReleaseNumber(jsonCommitEventsMetadata)
if err != nil {
return nil, fmt.Errorf("Could not get commit release number from commit_events metadata: %v", err)
Expand All @@ -95,13 +115,34 @@ func getCommitDeploymentInfoForApp(ctx context.Context, h *db.DBHandler, commit,
if err != nil {
return nil, fmt.Errorf("Could not get all environments from all_environments metadata: %v", err)
}
environmentReleases, err := getEnvironmentReleases(jsonAllDeploymentsMetadata)

for app, releases := range applicationReleases {
commitDeploymentStatusForApp, err := getCommitDeploymentInfoForApp(ctx, s.DBHandler, releaseNumber, app, allEnvironments, releases)
if err != nil {
return nil, fmt.Errorf("Could not get commit deployment info for app %s: %v", app, err)
}
commitDeploymentStatus[app] = commitDeploymentStatusForApp
}

return &api.GetCommitDeploymentInfoResponse{
DeploymentStatus: commitDeploymentStatus,
}, nil
}

func getCommitDeploymentInfoForApp(ctx context.Context, h *db.DBHandler, commitReleaseNumber uint64, app string, environments []string, appDeployments []byte) (*api.AppCommitDeploymentStatus, error) {

span, _ := tracer.StartSpanFromContext(ctx, "getCommitDeploymentInfoForApp")
defer span.Finish()
span.SetTag("app", app)

environmentReleases, err := getEnvironmentReleases(appDeployments)
if err != nil {
return nil, fmt.Errorf("Could not get environment releases from all_deployments metadata: %v", err)
}

commitStatus := getCommitStatus(releaseNumber, environmentReleases, allEnvironments)
return commitStatus, nil
commitStatus := getCommitStatus(commitReleaseNumber, environmentReleases, environments)
return &api.AppCommitDeploymentStatus{
DeploymentStatus: commitStatus,
}, nil
}

func getCommitStatus(commitReleaseNumber uint64, environmentReleases map[string]uint64, allEnvironments []string) CommitStatus {
Expand All @@ -116,7 +157,7 @@ func getCommitStatus(commitReleaseNumber uint64, environmentReleases map[string]
}

for _, env := range allEnvironments {
// by defauly, a commit is pending in all environments
// by default, a commit is pending in all environments
commitStatus[env] = api.CommitDeploymentStatus_PENDING
}

Expand Down

0 comments on commit 667f721

Please sign in to comment.