Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Add support for updating project protected environment #1780

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions protected_environments.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,73 @@ func (s *ProtectedEnvironmentsService) ProtectRepositoryEnvironments(pid interfa
return pe, resp, nil
}

// UpdateProtectedEnvironmentsOptions represents the available
// UpdateProtectedEnvironments() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_environments.html#update-a-protected-environment
type UpdateProtectedEnvironmentsOptions struct {
Name *string `url:"name,omitempty" json:"name,omitempty"`
DeployAccessLevels *[]*UpdateEnvironmentAccessOptions `url:"deploy_access_levels,omitempty" json:"deploy_access_levels,omitempty"`
RequiredApprovalCount *int `url:"required_approval_count,omitempty" json:"required_approval_count,omitempty"`
ApprovalRules *[]*UpdateEnvironmentApprovalRuleOptions `url:"approval_rules,omitempty" json:"approval_rules,omitempty"`
}

// UpdateEnvironmentAccessOptions represents the options for updates to an
// access decription for a protected environment.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_environments.html#update-a-protected-environment
type UpdateEnvironmentAccessOptions struct {
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
ID *int `url:"id,omitempty" json:"id,omitempty"`
UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"`
GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"`
Destroy *bool `url:"_destroy,omitempty" json:"_destroy,omitempty"`
}

// UpdateEnvironmentApprovalRuleOptions represents the updates to the approval
// rules for a protected environment.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_environments.html#update-a-protected-environment
type UpdateEnvironmentApprovalRuleOptions struct {
ID *int `url:"id,omitempty" json:"id,omitempty"`
UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"`
GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"`
AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
AccessLevelDescription *string `url:"access_level_description,omitempty" json:"access_level_description,omitempty"`
RequiredApprovalCount *int `url:"required_approvals,omitempty" json:"required_approvals,omitempty"`
GroupInheritanceType *int `url:"group_inheritance_type,omitempty" json:"group_inheritance_type,omitempty"`
Destroy *bool `url:"_destroy,omitempty" json:"_destroy,omitempty"`
}

// UpdateProtectedEnvironments updates a single repository environment or
// several project repository environments using wildcard protected environment.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/protected_environments.html#update-a-protected-environment
func (s *ProtectedEnvironmentsService) UpdateProtectedEnvironments(pid interface{}, environment string, opt *UpdateProtectedEnvironmentsOptions, options ...RequestOptionFunc) (*ProtectedEnvironment, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/protected_environments/%s", PathEscape(project), environment)

req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
if err != nil {
return nil, nil, err
}

pe := new(ProtectedEnvironment)
resp, err := s.client.Do(req, pe)
if err != nil {
return nil, resp, err
}

return pe, resp, nil
}

// UnprotectEnvironment unprotects the given protected environment or wildcard
// protected environment.
//
Expand Down
257 changes: 257 additions & 0 deletions protected_environments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,263 @@ func TestProtectRepositoryEnvironments(t *testing.T) {
assert.Equal(t, expected, environment)
}

func TestUpdateProtectedEnvironments(t *testing.T) {
mux, client := setup(t)

// Test with DeployAccessLevels, RequiredApprovalCount, and ApprovalRules as if adding new to existing protected environment
environmentName := "dev-test"

mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_environments/%s", environmentName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
fmt.Fprintf(w, `{
"name":"%s",
"deploy_access_levels": [
{
"id": 42,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"required_approval_count": 2,
"approval_rules": [
{
"id": 1,
"user_id": null,
"group_id": 10,
"access_level": 5,
"access_level_description": "devops",
"required_approvals": 0,
"group_inheritance_type": 0
}
]
}`, environmentName)
})

expected := &ProtectedEnvironment{
Name: environmentName,
DeployAccessLevels: []*EnvironmentAccessDescription{
{
ID: 42,
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
RequiredApprovalCount: 2,
ApprovalRules: []*EnvironmentApprovalRule{
{
ID: 1,
GroupID: 10,
AccessLevel: 5,
AccessLevelDescription: "devops",
},
},
}

opt := &UpdateProtectedEnvironmentsOptions{
Name: String(environmentName),
DeployAccessLevels: &[]*UpdateEnvironmentAccessOptions{
{AccessLevel: AccessLevel(30)},
},
RequiredApprovalCount: Int(2),
ApprovalRules: &[]*UpdateEnvironmentApprovalRuleOptions{
{
GroupID: Int(10),
AccessLevel: AccessLevel(0),
AccessLevelDescription: String("devops"),
},
},
}

environment, _, err := client.ProtectedEnvironments.UpdateProtectedEnvironments(1, environmentName, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, environment)

// Test with DeployAccessLevels only, as if adding new to existing protected environment
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/2/protected_environments/%s", environmentName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
fmt.Fprintf(w, `{
"name":"%s",
"deploy_access_levels": [
{
"id": 42,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
]
}`, environmentName)
})

expected = &ProtectedEnvironment{
Name: environmentName,
DeployAccessLevels: []*EnvironmentAccessDescription{
{
ID: 42,
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
}

opt = &UpdateProtectedEnvironmentsOptions{
Name: String(environmentName),
DeployAccessLevels: &[]*UpdateEnvironmentAccessOptions{
{AccessLevel: AccessLevel(30)},
},
}
environment, _, err = client.ProtectedEnvironments.UpdateProtectedEnvironments(2, environmentName, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, environment)

// Test update to DeployAccessLevel
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/3/protected_environments/%s", environmentName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
fmt.Fprintf(w, `{
"name":"%s",
"deploy_access_levels": [
{
"id": 42,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"required_approval_count": 2
}`, environmentName)
})

expected = &ProtectedEnvironment{
Name: environmentName,
DeployAccessLevels: []*EnvironmentAccessDescription{
{
ID: 42,
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
RequiredApprovalCount: 2,
}

opt = &UpdateProtectedEnvironmentsOptions{
Name: String(environmentName),
DeployAccessLevels: &[]*UpdateEnvironmentAccessOptions{
{
ID: Int(42),
AccessLevel: AccessLevel(30),
},
},
}
environment, _, err = client.ProtectedEnvironments.UpdateProtectedEnvironments(3, environmentName, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, environment)

// Test update to ApprovalRules
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/4/protected_environments/%s", environmentName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
fmt.Fprintf(w, `{
"name":"%s",
"deploy_access_levels": [
{
"id": 42,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"required_approval_count": 2,
"approval_rules": [
{
"id": 1,
"user_id": null,
"group_id": 10,
"access_level": 5,
"access_level_description": "devops",
"required_approvals": 0,
"group_inheritance_type": 0
}
]
}`, environmentName)
})

expected = &ProtectedEnvironment{
Name: environmentName,
DeployAccessLevels: []*EnvironmentAccessDescription{
{
ID: 42,
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
RequiredApprovalCount: 2,
ApprovalRules: []*EnvironmentApprovalRule{
{
ID: 1,
GroupID: 10,
AccessLevel: 5,
AccessLevelDescription: "devops",
},
},
}

opt = &UpdateProtectedEnvironmentsOptions{
Name: String(environmentName),
ApprovalRules: &[]*UpdateEnvironmentApprovalRuleOptions{
{
ID: Int(1),
GroupID: Int(10),
AccessLevel: AccessLevel(0),
AccessLevelDescription: String("devops"),
},
},
}

environment, _, err = client.ProtectedEnvironments.UpdateProtectedEnvironments(4, environmentName, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, environment)

// Test destroy ApprovalRule
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/5/protected_environments/%s", environmentName), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
fmt.Fprintf(w, `{
"name":"%s",
"deploy_access_levels": [
{
"id": 42,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"required_approval_count": 0,
"approval_rules": []
}`, environmentName)
})

expected = &ProtectedEnvironment{
Name: environmentName,
DeployAccessLevels: []*EnvironmentAccessDescription{
{
ID: 42,
AccessLevel: 30,
AccessLevelDescription: "Developers + Maintainers",
},
},
RequiredApprovalCount: 0,
ApprovalRules: []*EnvironmentApprovalRule{},
}

opt = &UpdateProtectedEnvironmentsOptions{
Name: String(environmentName),
ApprovalRules: &[]*UpdateEnvironmentApprovalRuleOptions{
{
ID: Int(1),
Destroy: Bool(true),
},
},
RequiredApprovalCount: Int(0),
}

environment, _, err = client.ProtectedEnvironments.UpdateProtectedEnvironments(5, environmentName, opt)
assert.NoError(t, err, "failed to get response")
assert.Equal(t, expected, environment)
}

func TestUnprotectRepositoryEnvironments(t *testing.T) {
mux, client := setup(t)

Expand Down