Skip to content

Commit

Permalink
Add support for updating project protected environment
Browse files Browse the repository at this point in the history
A new API for updating existing project protected environments was added to GitLab.  This change adds support for the update API.

https://docs.gitlab.com/ee/api/protected_environments.html#update-a-protected-environment
  • Loading branch information
beekeep committed Aug 22, 2023
1 parent f4bde6c commit 2496a42
Show file tree
Hide file tree
Showing 2 changed files with 324 additions and 0 deletions.
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

0 comments on commit 2496a42

Please sign in to comment.