Skip to content

Commit 32d961a

Browse files
Handled direct association of project to application
1 parent c74376f commit 32d961a

File tree

7 files changed

+98
-3
lines changed

7 files changed

+98
-3
lines changed

internal/commands/scan_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3662,3 +3662,21 @@ func Test_CreateScanWithExistingProjectAndAssign_FailedApplication_DoesNot_Exist
36623662
)
36633663
assert.ErrorContains(t, err, errorConstants.FailedToGetApplication, err.Error())
36643664
}
3665+
3666+
func Test_CreateScanWithExistingProjectAssign_to_Application_FF_DirectAssociationEnabledShouldPass(t *testing.T) {
3667+
file := createOutputFile(t, outputFileName)
3668+
defer deleteOutputFile(file)
3669+
defer logger.SetOutput(os.Stdout)
3670+
3671+
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.DirectAssociationEnabled, Status: true}
3672+
baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug", "--application-name", mock.ExistingApplication}
3673+
execCmdNilAssertion(
3674+
t,
3675+
baseArgs...,
3676+
)
3677+
stdoutString, err := util.ReadFileAsString(file.Name())
3678+
if err != nil {
3679+
t.Fatalf("Failed to read log file: %v", err)
3680+
}
3681+
assert.Equal(t, strings.Contains(stdoutString, "Successfully updated the application"), true, "Expected output: %s", "Successfully updated the application")
3682+
}

internal/services/applications.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func verifyApplicationNameExactMatch(applicationName string, resp *wrappers.Appl
6464
return application
6565
}
6666

67-
func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper, projectName string) error {
67+
func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper, projectName string, projectID string, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error {
6868
if applicationName == "" {
6969
logger.PrintfIfVerbose("No application name provided. Skipping application update")
7070
return nil
@@ -76,6 +76,15 @@ func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappe
7676
if applicationResp == nil {
7777
return errors.Errorf("%s: %s", errorConstants.ApplicationNotFound, applicationName)
7878
}
79+
80+
directAssociationEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.DirectAssociationEnabled)
81+
if directAssociationEnabled.Status {
82+
err = associateProjectToApplication(applicationResp.ID, projectID, applicationResp.ProjectIds, applicationsWrapper)
83+
if err != nil {
84+
return err
85+
}
86+
return nil
87+
}
7988
var applicationModel wrappers.ApplicationConfiguration
8089
var newApplicationRule wrappers.Rule
8190
var applicationID string
@@ -100,6 +109,19 @@ func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappe
100109

101110
func updateApplication(applicationModel *wrappers.ApplicationConfiguration, applicationWrapper wrappers.ApplicationsWrapper, applicationID string) error {
102111
errorModel, err := applicationWrapper.Update(applicationID, applicationModel)
112+
return handleApplicationUpdateResponse(errorModel, err)
113+
}
114+
115+
func associateProjectToApplication(applicationID string, projectID string, associatedProjectIds []string, applicationsWrapper wrappers.ApplicationsWrapper) error {
116+
associatedProjectIds = append(associatedProjectIds, projectID)
117+
associateProjectsModel := &wrappers.AssociateProjectModel{
118+
ProjectIds: associatedProjectIds,
119+
}
120+
errorModel, err := applicationsWrapper.CreateProjectAssociation(applicationID, associateProjectsModel)
121+
return handleApplicationUpdateResponse(errorModel, err)
122+
}
123+
124+
func handleApplicationUpdateResponse(errorModel *wrappers.ErrorModel, err error) error {
103125
if errorModel != nil {
104126
err = errors.Errorf(ErrorCodeFormat, errorConstants.FailedToUpdateApplication, errorModel.Code, errorModel.Message)
105127
}

internal/services/projects.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func FindProject(
4444
for i := 0; i < len(resp.Projects); i++ {
4545
project := resp.Projects[i]
4646
if project.Name == projectName {
47-
err = findApplicationAndUpdate(applicationName, applicationWrapper, projectName)
47+
err = findApplicationAndUpdate(applicationName, applicationWrapper, projectName, project.ID, featureFlagsWrapper)
4848
if err != nil {
4949
return "", err
5050
}

internal/wrappers/application-http.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,44 @@ func NewApplicationsHTTPWrapper(path string) ApplicationsWrapper {
2222
}
2323
}
2424

25+
func (a *ApplicationsHTTPWrapper) CreateProjectAssociation(applicationID string, projectAssociationModel *AssociateProjectModel) (*ErrorModel, error) {
26+
clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey)
27+
jsonBytes, err := json.Marshal(*projectAssociationModel)
28+
if err != nil {
29+
return nil, err
30+
}
31+
associationPath := fmt.Sprintf("%s/%s/%s", a.path, applicationID, "projects")
32+
resp, err := SendHTTPRequest(http.MethodPost, associationPath, bytes.NewBuffer(jsonBytes), true, clientTimeout)
33+
if err != nil {
34+
return nil, err
35+
}
36+
decoder := json.NewDecoder(resp.Body)
37+
defer func() {
38+
_ = resp.Body.Close()
39+
}()
40+
switch resp.StatusCode {
41+
case http.StatusBadRequest:
42+
errorModel := ErrorModel{}
43+
err = decoder.Decode(&errorModel)
44+
if err != nil {
45+
return nil, errors.Errorf("failed to parse application response for project updation: %s ", err)
46+
}
47+
return &errorModel, nil
48+
49+
case http.StatusCreated:
50+
return nil, nil
51+
52+
case http.StatusForbidden:
53+
return nil, errors.New(errorConstants.NoPermissionToUpdateApplication)
54+
55+
case http.StatusUnauthorized:
56+
return nil, errors.New(errorConstants.StatusUnauthorized)
57+
default:
58+
return nil, errors.Errorf("response status code %d", resp.StatusCode)
59+
}
60+
61+
}
62+
2563
func (a *ApplicationsHTTPWrapper) Update(applicationID string, applicationBody *ApplicationConfiguration) (*ErrorModel, error) {
2664
clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey)
2765
jsonBytes, err := json.Marshal(applicationBody)

internal/wrappers/application.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ type ApplicationConfiguration struct {
3030
Tags map[string]string `json:"tags"`
3131
}
3232

33+
type AssociateProjectModel struct {
34+
ProjectIds []string `json:"projectIds"`
35+
}
36+
3337
type Rule struct {
3438
ID string `json:"id"`
3539
Type string `json:"type"`
@@ -39,4 +43,5 @@ type Rule struct {
3943
type ApplicationsWrapper interface {
4044
Get(params map[string]string) (*ApplicationsResponseModel, error)
4145
Update(applicationID string, applicationBody *ApplicationConfiguration) (*ErrorModel, error)
46+
CreateProjectAssociation(applicationID string, requestModel *AssociateProjectModel) (*ErrorModel, error)
4247
}

internal/wrappers/feature-flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const SCSEngineCLIEnabled = "NEW_2MS_SCORECARD_RESULTS_CLI_ENABLED"
1616
const RiskManagementEnabled = "RISK_MANAGEMENT_IDES_PROJECT_RESULTS_SCORES_API_ENABLED"
1717
const OssRealtimeEnabled = "OSS_REALTIME_ENABLED"
1818
const ScsLicensingV2Enabled = "SSCS_NEW_LICENSING_ENABLED"
19+
const DirectAssociationEnabled = "DIRECT_APP_ASSOCIATION_ENABLED"
1920
const maxRetries = 3
2021

2122
var DefaultFFLoad bool = false

internal/wrappers/mock/application-mock.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,18 @@ func (a ApplicationsMockWrapper) Get(params map[string]string) (*wrappers.Applic
5454
}
5555

5656
func (a ApplicationsMockWrapper) Update(applicationID string, applicationBody *wrappers.ApplicationConfiguration) (*wrappers.ErrorModel, error) {
57-
fmt.Println("called Update project")
57+
fmt.Println("called Update application")
58+
if applicationID == FakeForbidden403 {
59+
return nil, errors.Errorf(errorConstants.NoPermissionToUpdateApplication)
60+
}
61+
if applicationID == FakeUnauthorized401 {
62+
return nil, errors.Errorf(errorConstants.StatusUnauthorized)
63+
}
64+
return nil, nil
65+
}
66+
67+
func (a ApplicationsMockWrapper) CreateProjectAssociation(applicationID string, requestModel *wrappers.AssociateProjectModel) (*wrappers.ErrorModel, error) {
68+
fmt.Println("called Create project association to application")
5869
if applicationID == FakeForbidden403 {
5970
return nil, errors.Errorf(errorConstants.NoPermissionToUpdateApplication)
6071
}

0 commit comments

Comments
 (0)