in internal/provider/resource_gitlab_project_protected_environment.go [440:631]
func (r *gitlabProjectProtectedEnvironmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data *gitlabProjectProtectedEnvironmentResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
rules := make([]*gitlabProjectProtectedEnvironmentApprovalRuleModel, len(data.ApprovalRules.Elements()))
data.ApprovalRules.ElementsAs(ctx, &rules, true)
if resp.Diagnostics.HasError() {
return
}
// local copies of plan arguments
projectID := data.Project.ValueString()
environmentName := data.Environment.ValueString()
// Retrieve the protected environment (to know which deploy/approval rules to remove)
protectedEnvironment, _, err := r.client.ProtectedEnvironments.GetProtectedEnvironment(projectID, environmentName, gitlab.WithContext(ctx))
if err != nil {
if api.Is404(err) {
resp.Diagnostics.AddError(
"GitLab Feature not available",
fmt.Sprintf("The protected environment feature is not available on this project. Make sure it's part of an enterprise plan. Error: %s", err.Error()),
)
return
}
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to update protected environment details: %s", err.Error()))
return
}
// configure GitLab API call
options := &gitlab.UpdateProtectedEnvironmentsOptions{
Name: gitlab.Ptr(environmentName),
}
// deploy access levels
deployAccessLevels := make([]*gitlabProjectProtectedEnvironmentDeployAccessLevelModel, 0, len(data.DeployAccessLevels.Elements()))
resp.Diagnostics.Append(data.DeployAccessLevels.ElementsAs(ctx, &deployAccessLevels, false)...)
if resp.Diagnostics.HasError() {
return
}
deployAccessLevelsOption := make([]*gitlab.UpdateEnvironmentAccessOptions, 0)
for _, v := range deployAccessLevels {
deployAccessLevelOptions := &gitlab.UpdateEnvironmentAccessOptions{}
// the ID will be null when adding a new deploy rule via update
if !v.ID.IsNull() && v.ID.ValueInt64() != 0 {
deployAccessLevelOptions.ID = gitlab.Ptr(int(v.ID.ValueInt64()))
}
if !v.AccessLevel.IsNull() && v.AccessLevel.ValueString() != "" {
deployAccessLevelOptions.AccessLevel = gitlab.Ptr(api.AccessLevelNameToValue[v.AccessLevel.ValueString()])
}
if !v.UserId.IsNull() && v.UserId.ValueInt64() != 0 {
deployAccessLevelOptions.UserID = gitlab.Ptr(int(v.UserId.ValueInt64()))
}
if !v.GroupId.IsNull() && v.GroupId.ValueInt64() != 0 {
deployAccessLevelOptions.GroupID = gitlab.Ptr(int(v.GroupId.ValueInt64()))
}
if !v.GroupInheritanceType.IsNull() && v.GroupInheritanceType.ValueInt64() != 0 {
deployAccessLevelOptions.GroupInheritanceType = gitlab.Ptr(int(v.GroupInheritanceType.ValueInt64()))
}
deployAccessLevelsOption = append(deployAccessLevelsOption, deployAccessLevelOptions)
}
// Remove deploy access levels that aren't present in the config
for _, v := range protectedEnvironment.DeployAccessLevels {
isPresent := false
for _, j := range deployAccessLevels {
if v.ID == int(j.ID.ValueInt64()) {
isPresent = true
break
}
}
// If the existing deploy isn't present, add it to the values to remove it
if !isPresent {
deployAccessLevelOptions := &gitlab.UpdateEnvironmentAccessOptions{
ID: gitlab.Ptr(v.ID),
Destroy: gitlab.Ptr(true),
}
// Seems weird, but the API does validate that these values are present even
// when destroyin
if v.AccessLevel != 0 {
deployAccessLevelOptions.AccessLevel = &v.AccessLevel
}
if v.UserID != 0 {
deployAccessLevelOptions.UserID = &v.UserID
}
if v.GroupID != 0 {
deployAccessLevelOptions.GroupID = &v.GroupID
}
deployAccessLevelsOption = append(deployAccessLevelsOption, deployAccessLevelOptions)
}
}
options.DeployAccessLevels = &deployAccessLevelsOption
// approval rules
approvalRulesOptionSlice := make([]*gitlab.UpdateEnvironmentApprovalRuleOptions, 0)
for _, v := range rules {
approvalRuleOptions := &gitlab.UpdateEnvironmentApprovalRuleOptions{}
// the ID will be null when adding a new approval rule via update
if !v.ID.IsNull() && v.ID.ValueInt64() != 0 {
approvalRuleOptions.ID = gitlab.Ptr(int(v.ID.ValueInt64()))
}
if !v.AccessLevel.IsNull() && v.AccessLevel.ValueString() != "" {
approvalRuleOptions.AccessLevel = gitlab.Ptr(api.AccessLevelNameToValue[v.AccessLevel.ValueString()])
}
if !v.UserId.IsNull() && v.UserId.ValueInt64() != 0 {
approvalRuleOptions.UserID = gitlab.Ptr(int(v.UserId.ValueInt64()))
}
if !v.GroupId.IsNull() && v.GroupId.ValueInt64() != 0 {
approvalRuleOptions.GroupID = gitlab.Ptr(int(v.GroupId.ValueInt64()))
}
if !v.GroupInheritanceType.IsNull() && v.GroupInheritanceType.ValueInt64() != 0 {
approvalRuleOptions.GroupInheritanceType = gitlab.Ptr(int(v.GroupInheritanceType.ValueInt64()))
}
if !v.RequiredApprovals.IsNull() && v.RequiredApprovals.ValueInt64() != 0 {
approvalRuleOptions.RequiredApprovalCount = gitlab.Ptr(int(v.RequiredApprovals.ValueInt64()))
}
approvalRulesOptionSlice = append(approvalRulesOptionSlice, approvalRuleOptions)
}
// Remove approval levels that aren't present in the config
for _, v := range protectedEnvironment.ApprovalRules {
isPresent := false
for _, j := range rules {
if v.ID == int(j.ID.ValueInt64()) {
isPresent = true
break
}
}
// If the existing deploy isn't present, add it to the values to remove it
if !isPresent {
approvalRuleOptions := &gitlab.UpdateEnvironmentApprovalRuleOptions{
ID: gitlab.Ptr(v.ID),
Destroy: gitlab.Ptr(true),
}
// Seems weird, but the API does validate that these values are present even
// when destroying
if v.AccessLevel != 0 {
approvalRuleOptions.AccessLevel = &v.AccessLevel
}
if v.UserID != 0 {
approvalRuleOptions.UserID = &v.UserID
}
if v.GroupID != 0 {
approvalRuleOptions.GroupID = &v.GroupID
}
approvalRulesOptionSlice = append(approvalRulesOptionSlice, approvalRuleOptions)
}
}
options.ApprovalRules = &approvalRulesOptionSlice
tflog.Debug(ctx, "Updating protected environment with options", map[string]any{
"project": projectID,
"options": options,
"environment_name": environmentName,
})
protectedEnvironment, _, err = r.client.ProtectedEnvironments.UpdateProtectedEnvironments(projectID, environmentName, options, gitlab.WithContext(ctx))
if err != nil {
if api.Is404(err) {
resp.Diagnostics.AddError(
"GitLab Feature not available",
fmt.Sprintf("The protected environment feature is not available on this project. Make sure it's part of an enterprise plan. Error: %s", err.Error()),
)
return
}
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to update protected environment details: %s", err.Error()))
return
}
tflog.Debug(ctx, "Updating protected environment completed with options", map[string]any{
"project": projectID,
"environment_name": environmentName,
"result": protectedEnvironment,
})
// Add data to state
r.protectedEnvironmentToStateModel(ctx, resp.Diagnostics, projectID, protectedEnvironment, data)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}