Skip to content

Commit

Permalink
feat: new endpoint to get app details (#2004)
Browse files Browse the repository at this point in the history
Ref: SRX-RH7CD5

---------

Co-authored-by: Miguel Crespo <[email protected]>
Co-authored-by: Miguel Crespo <[email protected]>
  • Loading branch information
3 people authored Oct 7, 2024
1 parent 9443ab5 commit 45a0cb1
Show file tree
Hide file tree
Showing 8 changed files with 765 additions and 9 deletions.
39 changes: 39 additions & 0 deletions pkg/api/v1/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,51 @@ service VersionService {
service OverviewService {
rpc GetOverview (GetOverviewRequest) returns (GetOverviewResponse) {}
rpc StreamOverview (GetOverviewRequest) returns (stream GetOverviewResponse) {}

rpc GetAppDetails (GetAppDetailsRequest) returns (GetAppDetailsResponse) {}
}

service EnvironmentService {
rpc GetEnvironmentConfig(GetEnvironmentConfigRequest) returns (GetEnvironmentConfigResponse) {}
}

message GetAppDetailsRequest {
string app_name = 1;
}

message GetAppDetailsResponse {
Application application = 1; //General Application information
map<string, Deployment> deployments = 2; // Env -> Release
map<string, Locks> app_locks = 3; //EnvName -> []AppLocks
map<string, Locks> team_locks= 4; //EnvName -> []TeamLocks
}

//Wrapper over array of locks
message Locks {
repeated Lock locks = 2;
}

message Deployment {
message DeploymentMetaData {
string deploy_author = 1;
// we use a string here, because the UI cannot handle int64 as a type.
// the string contains the unix timestamps in seconds (utc)
string deploy_time = 2;

string ci_link = 3;
}
// version=0 means "nothing is deployed"
uint64 version = 2;
// "version" describes the currently deployed version. "queuedVersion" describes a version that was to be deployed, but a lock stopped the deployment:
// "queuedVersion" has nothing to do with queue.go
// queued_version=0 means "nothing is queued"
uint64 queued_version = 4;
// google.protobuf.Timestamp deploy_date = 5; // This is never used
bool undeploy_version = 6;
DeploymentMetaData deployment_meta_data = 7;
}


message GetOverviewRequest {
// Retrieve the overview at a certain state of the repository. If it's empty, the latest commit will be used.
string git_revision = 1;
Expand Down
311 changes: 311 additions & 0 deletions pkg/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,55 @@ func (h *DBHandler) DBSelectLatestDeployment(ctx context.Context, tx *sql.Tx, ap
return processDeployment(rows)
}

func (h *DBHandler) DBSelectAllLatestDeploymentsForApplication(ctx context.Context, tx *sql.Tx, appName string) (map[string]Deployment, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAllLatestDeployments")
defer span.Finish()

selectQuery := h.AdaptQuery(
`
SELECT
deployments.eslVersion,
deployments.created,
deployments.appname,
deployments.releaseVersion,
deployments.envName,
deployments.metadata
FROM (
SELECT
MAX(eslVersion) AS latest,
appname,
envname
FROM
deployments
GROUP BY
envName, appname
) AS latest
JOIN
deployments AS deployments
ON
latest.latest=deployments.eslVersion
AND latest.appname=deployments.appname
AND latest.envName=deployments.envName
WHERE deployments.appname = (?) AND deployments.releaseVersion IS NOT NULL ;`)

span.SetTag("query", selectQuery)
rows, err := tx.QueryContext(
ctx,
selectQuery,
appName,
)
if err != nil {
return nil, fmt.Errorf("could not select deployment from DB. Error: %w\n", err)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
logger.FromContext(ctx).Sugar().Warnf("deployments: row closing error: %v", err)
}
}(rows)
return processAllLatestDeploymentsForApp(rows)
}

func (h *DBHandler) DBSelectAllLatestDeployments(ctx context.Context, tx *sql.Tx, envName string) (map[string]*int64, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAllLatestDeployments")
defer span.Finish()
Expand Down Expand Up @@ -1740,6 +1789,48 @@ func processAllLatestDeployments(rows *sql.Rows) (map[string]*int64, error) {
return result, nil
}

func processAllLatestDeploymentsForApp(rows *sql.Rows) (map[string]Deployment, error) {
result := make(map[string]Deployment)
for rows.Next() {
var curr = Deployment{
EslVersion: 0,
Created: time.Time{},
Env: "",
App: "",
Version: nil,
Metadata: DeploymentMetadata{
DeployedByName: "",
DeployedByEmail: "",
CiLink: "",
},
TransformerID: 0,
}
var releaseVersion sql.NullInt64
var jsonMetadata string
err := rows.Scan(&curr.EslVersion, &curr.Created, &curr.App, &releaseVersion, &curr.Env, &jsonMetadata)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, fmt.Errorf("Error scanning deployments row from DB. Error: %w\n", err)
}

if releaseVersion.Valid {
curr.Version = &releaseVersion.Int64
}
result[curr.Env] = curr
}
err := rows.Close()
if err != nil {
return nil, fmt.Errorf("deployments: row closing error: %v\n", err)
}
err = rows.Err()
if err != nil {
return nil, fmt.Errorf("deployments: row has error: %v\n", err)
}
return result, nil
}

func (h *DBHandler) DBSelectSpecificDeployment(ctx context.Context, tx *sql.Tx, appSelector string, envSelector string, releaseVersion uint64) (*Deployment, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectSpecificDeployment")
defer span.Finish()
Expand Down Expand Up @@ -3472,7 +3563,116 @@ func (h *DBHandler) DBSelectAppLock(ctx context.Context, tx *sql.Tx, environment
return nil, err
}
return nil, nil // no rows, but also no error
}

func (h *DBHandler) DBSelectAllActiveAppLocksForApp(ctx context.Context, tx *sql.Tx, appName string) ([]ApplicationLock, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAllActiveAppLocksForApp")
defer span.Finish()

if h == nil {
return nil, nil
}
if tx == nil {
return nil, fmt.Errorf("DBSelectAllActiveAppLocksForApp: no transaction provided")
}

var appLocks []ApplicationLock
var rows *sql.Rows
defer func(rows *sql.Rows) {
if rows == nil {
return
}
err := rows.Close()
if err != nil {
logger.FromContext(ctx).Sugar().Warnf("row closing error: %v", err)
}
}(rows)
//Get the latest change to each lock
var err error
selectQuery := h.AdaptQuery(
`
SELECT
app_locks.eslversion,
app_locks.appname,
app_locks.envName,
app_locks.lockid,
app_locks.deleted,
app_locks.created,
app_locks.metadata
FROM (
SELECT
MAX(eslVersion) AS latest,
appname,
envName,
lockid
FROM
"app_locks"
GROUP BY
envName, appName, lockid
) AS latest
JOIN
app_locks AS app_locks
ON
latest.latest=app_locks.eslVersion
AND latest.appname=app_locks.appname
AND latest.envName=app_locks.envName
AND latest.lockid=app_locks.lockid
WHERE deleted = false
AND app_locks.appName = (?);
`)
rows, err = tx.QueryContext(ctx, selectQuery, appName)
if err != nil {
return nil, fmt.Errorf("could not query application locks table from DB. Error: %w\n", err)
}

if err != nil {
return nil, fmt.Errorf("could not query releases table from DB. Error: %w\n", err)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
logger.FromContext(ctx).Sugar().Warnf("releases: row could not be closed: %v", err)
}
}(rows)

for rows.Next() {
var row = ApplicationLock{
EslVersion: 0,
Created: time.Time{},
LockID: "",
Env: "",
App: "",
Deleted: false,
Metadata: LockMetadata{
CreatedAt: time.Time{},
CreatedByEmail: "",
CreatedByName: "",
Message: "",
CiLink: "",
},
}
var metadataJson string
err := rows.Scan(&row.EslVersion, &row.App, &row.Env, &row.LockID, &row.Deleted, &row.Created, &metadataJson)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, fmt.Errorf("Error scanning releases row from DB. Error: %w\n", err)
}

err = json.Unmarshal(([]byte)(metadataJson), &row.Metadata)
if err != nil {
return nil, fmt.Errorf("Error during json unmarshal. Error: %w. Data: %s\n", err, row.Metadata)
}

appLocks = append(appLocks, row)
}

err = closeRows(rows)
if err != nil {
return nil, err
}
return appLocks, nil
}

func (h *DBHandler) DBSelectAppLockSet(ctx context.Context, tx *sql.Tx, environment, appName string, lockIDs []string) ([]ApplicationLock, error) {
Expand Down Expand Up @@ -3983,6 +4183,117 @@ func (h *DBHandler) DBWriteAllTeamLocks(ctx context.Context, transaction *sql.Tx
return nil
}

func (h *DBHandler) DBSelectAllActiveTeamLocksForTeam(ctx context.Context, tx *sql.Tx, teamName string) ([]TeamLock, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAllActiveAppLocksForApp")
defer span.Finish()

if h == nil {
return nil, nil
}
if tx == nil {
return nil, fmt.Errorf("DBSelectAllActiveAppLocksForApp: no transaction provided")
}

var appLocks []TeamLock
var rows *sql.Rows

defer func(rows *sql.Rows) {
if rows == nil {
return
}
err := rows.Close()
if err != nil {
logger.FromContext(ctx).Sugar().Warnf("row closing error: %v", err)
}
}(rows)
//Get the latest change to each lock
var err error
selectQuery := h.AdaptQuery(
`
SELECT
team_locks.eslversion,
team_locks.teamName,
team_locks.envName,
team_locks.lockid,
team_locks.deleted,
team_locks.created,
team_locks.metadata
FROM (
SELECT
MAX(eslVersion) AS latest,
teamName,
envName,
lockid
FROM
"team_locks"
GROUP BY
envName, teamName, lockid
) AS latest
JOIN
team_locks AS team_locks
ON
latest.latest=team_locks.eslVersion
AND latest.teamName=team_locks.teamName
AND latest.envName=team_locks.envName
AND latest.lockid=team_locks.lockid
WHERE deleted = false
AND team_locks.teamName = (?);
`)
rows, err = tx.QueryContext(ctx, selectQuery, teamName)
if err != nil {
return nil, fmt.Errorf("could not query application locks table from DB. Error: %w\n", err)
}

if err != nil {
return nil, fmt.Errorf("could not query releases table from DB. Error: %w\n", err)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
logger.FromContext(ctx).Sugar().Warnf("releases: row could not be closed: %v", err)
}
}(rows)

for rows.Next() {
var row = TeamLock{
EslVersion: 0,
Created: time.Time{},
LockID: "",
Env: "",
Team: "",
Deleted: false,
Metadata: LockMetadata{
CreatedAt: time.Time{},
CreatedByEmail: "",
CreatedByName: "",
Message: "",
CiLink: "",
},
}
var metadataJson string
err := rows.Scan(&row.EslVersion, &row.Team, &row.Env, &row.LockID, &row.Deleted, &row.Created, &metadataJson)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, fmt.Errorf("Error scanning releases row from DB. Error: %w\n", err)
}

err = json.Unmarshal(([]byte)(metadataJson), &row.Metadata)
if err != nil {
return nil, fmt.Errorf("Error during json unmarshal. Error: %w. Data: %s\n", err, row.Metadata)
}

appLocks = append(appLocks, row)
}

err = closeRows(rows)
if err != nil {
return nil, err
}
return appLocks, nil
}

func (h *DBHandler) DBSelectTeamLock(ctx context.Context, tx *sql.Tx, environment, teamName, lockID string) (*TeamLock, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectTeamLock")
defer span.Finish()
Expand Down
1 change: 1 addition & 0 deletions services/cd-service/pkg/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ func RunServer() {
RepositoryConfig: cfg,
Shutdown: shutdownCh,
Context: ctx,
DBHandler: dbHandler,
}
api.RegisterOverviewServiceServer(srv, overviewSrv)
api.RegisterGitServiceServer(srv, &service.GitServer{Config: cfg, OverviewService: overviewSrv, PageSize: 10})
Expand Down
Loading

0 comments on commit 45a0cb1

Please sign in to comment.