in internal/provider/sdk/resource_gitlab_project.go [1232:1726]
func resourceGitlabProjectUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
client := meta.(*gitlab.Client)
// Always send the name field, to satisfy the requirement of having one
// of the project attributes listed below in the update call
// https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/api/helpers/projects_helpers.rb#L120-188
options := &gitlab.EditProjectOptions{
Name: gitlab.Ptr(d.Get("name").(string)),
}
transferOptions := &gitlab.TransferProjectOptions{}
if d.HasChange("name") {
options.Name = gitlab.Ptr(d.Get("name").(string))
}
if d.HasChange("path") && (d.Get("path").(string) != "") {
options.Path = gitlab.Ptr(d.Get("path").(string))
}
if d.HasChange("namespace_id") {
transferOptions.Namespace = gitlab.Ptr(d.Get("namespace_id").(int))
}
if d.HasChange("description") {
options.Description = gitlab.Ptr(d.Get("description").(string))
}
if d.HasChange("default_branch") {
options.DefaultBranch = gitlab.Ptr(d.Get("default_branch").(string))
}
if d.HasChange("visibility_level") {
options.Visibility = stringToVisibilityLevel(d.Get("visibility_level").(string))
}
if d.HasChange("merge_method") {
options.MergeMethod = stringToMergeMethod(d.Get("merge_method").(string))
}
if d.HasChange("only_allow_merge_if_pipeline_succeeds") {
options.OnlyAllowMergeIfPipelineSucceeds = gitlab.Ptr(d.Get("only_allow_merge_if_pipeline_succeeds").(bool))
}
if d.HasChange("only_allow_merge_if_all_discussions_are_resolved") {
options.OnlyAllowMergeIfAllDiscussionsAreResolved = gitlab.Ptr(d.Get("only_allow_merge_if_all_discussions_are_resolved").(bool))
}
if d.HasChange("allow_merge_on_skipped_pipeline") {
options.AllowMergeOnSkippedPipeline = gitlab.Ptr(d.Get("allow_merge_on_skipped_pipeline").(bool))
}
if d.HasChange("allow_pipeline_trigger_approve_deployment") {
options.AllowPipelineTriggerApproveDeployment = gitlab.Ptr(d.Get("allow_pipeline_trigger_approve_deployment").(bool))
}
if d.HasChange("restrict_user_defined_variables") {
options.RestrictUserDefinedVariables = gitlab.Ptr(d.Get("restrict_user_defined_variables").(bool)) //nolint:staticcheck
}
if d.HasChange("request_access_enabled") {
options.RequestAccessEnabled = gitlab.Ptr(d.Get("request_access_enabled").(bool))
}
if d.HasChange("issues_enabled") {
// TODO: Remove issuesEnabled on the next breaking update, since it will need to be replaced with a
// issue access level integer.
// nolint:staticcheck // SA1019
options.IssuesEnabled = gitlab.Ptr(d.Get("issues_enabled").(bool))
}
if d.HasChange("merge_requests_enabled") {
// TODO: Remove mergeRequestsEnabled on the next breaking update, since it will need to be replaced with a
// merge request access level integer.
// nolint:staticcheck // SA1019
options.MergeRequestsEnabled = gitlab.Ptr(d.Get("merge_requests_enabled").(bool))
}
if d.HasChange("pipelines_enabled") {
// nolint:staticcheck // SA1019
options.JobsEnabled = gitlab.Ptr(d.Get("pipelines_enabled").(bool))
}
if d.HasChange("approvals_before_merge") {
options.ApprovalsBeforeMerge = gitlab.Ptr(d.Get("approvals_before_merge").(int)) //nolint:staticcheck
}
if d.HasChange("wiki_enabled") {
// nolint:staticcheck // SA1019
options.WikiEnabled = gitlab.Ptr(d.Get("wiki_enabled").(bool)) //nolint:staticcheck
}
if d.HasChange("snippets_enabled") {
// nolint:staticcheck // SA1019
options.SnippetsEnabled = gitlab.Ptr(d.Get("snippets_enabled").(bool))
}
if d.HasChange("shared_runners_enabled") {
options.SharedRunnersEnabled = gitlab.Ptr(d.Get("shared_runners_enabled").(bool))
}
if d.HasChange("group_runners_enabled") {
options.GroupRunnersEnabled = gitlab.Ptr(d.Get("group_runners_enabled").(bool))
}
if d.HasChange("tags") {
// nolint:staticcheck // SA1019
options.TagList = stringSetToStringSlice(d.Get("tags").(*schema.Set))
}
if d.HasChange("container_registry_enabled") {
// nolint:staticcheck // SA1019
options.ContainerRegistryEnabled = gitlab.Ptr(d.Get("container_registry_enabled").(bool))
}
if d.HasChange("lfs_enabled") {
options.LFSEnabled = gitlab.Ptr(d.Get("lfs_enabled").(bool))
}
if d.HasChange("squash_option") {
options.SquashOption = stringToSquashOptionValue(d.Get("squash_option").(string))
}
if d.HasChange("remove_source_branch_after_merge") {
options.RemoveSourceBranchAfterMerge = gitlab.Ptr(d.Get("remove_source_branch_after_merge").(bool))
}
if d.HasChange("printing_merge_request_link_enabled") {
options.PrintingMergeRequestLinkEnabled = gitlab.Ptr(d.Get("printing_merge_request_link_enabled").(bool))
}
if d.HasChange("packages_enabled") {
options.PackagesEnabled = gitlab.Ptr(d.Get("packages_enabled").(bool))
}
if d.HasChange("pages_access_level") {
options.PagesAccessLevel = stringToAccessControlValue(d.Get("pages_access_level").(string))
}
if d.HasChanges("mirror", "import_url", "import_url_username", "import_url_password") {
options.Mirror = gitlab.Ptr(d.Get("mirror").(bool))
importURL, err := constructImportUrl(d.Get("import_url").(string), d.Get("import_url_username").(string), d.Get("import_url_password").(string))
if err != nil {
return diag.Errorf("Unable to construct import URL for API: %s", err)
}
options.ImportURL = gitlab.Ptr(importURL)
}
if d.HasChange("mirror_trigger_builds") {
options.MirrorTriggerBuilds = gitlab.Ptr(d.Get("mirror_trigger_builds").(bool))
if options.ImportURL == nil {
importURL, err := constructImportUrl(d.Get("import_url").(string), d.Get("import_url_username").(string), d.Get("import_url_password").(string))
if err != nil {
return diag.Errorf("Unable to construct import URL for API: %s", err)
}
options.ImportURL = gitlab.Ptr(importURL)
}
}
if d.HasChange("only_mirror_protected_branches") {
options.OnlyMirrorProtectedBranches = gitlab.Ptr(d.Get("only_mirror_protected_branches").(bool))
if options.ImportURL == nil {
importURL, err := constructImportUrl(d.Get("import_url").(string), d.Get("import_url_username").(string), d.Get("import_url_password").(string))
if err != nil {
return diag.Errorf("Unable to construct import URL for API: %s", err)
}
options.ImportURL = gitlab.Ptr(importURL)
}
}
if d.HasChange("mirror_overwrites_diverged_branches") {
options.MirrorOverwritesDivergedBranches = gitlab.Ptr(d.Get("mirror_overwrites_diverged_branches").(bool))
if options.ImportURL == nil {
importURL, err := constructImportUrl(d.Get("import_url").(string), d.Get("import_url_username").(string), d.Get("import_url_password").(string))
if err != nil {
return diag.Errorf("Unable to construct import URL for API: %s", err)
}
options.ImportURL = gitlab.Ptr(importURL)
}
}
if d.HasChange("issues_template") {
options.IssuesTemplate = gitlab.Ptr(d.Get("issues_template").(string))
}
if d.HasChange("merge_requests_template") {
options.MergeRequestsTemplate = gitlab.Ptr(d.Get("merge_requests_template").(string))
}
if d.HasChange("ci_config_path") {
options.CIConfigPath = gitlab.Ptr(d.Get("ci_config_path").(string))
}
if d.HasChange("ci_id_token_sub_claim_components") {
options.CIIdTokenSubClaimComponents = stringListToStringSlice(d.Get("ci_id_token_sub_claim_components").([]any))
}
if d.HasChange("ci_forward_deployment_enabled") {
options.CIForwardDeploymentEnabled = gitlab.Ptr(d.Get("ci_forward_deployment_enabled").(bool))
}
if d.HasChange("ci_restrict_pipeline_cancellation_role") {
stringVal := d.Get("ci_restrict_pipeline_cancellation_role").(string)
options.CIRestrictPipelineCancellationRole = gitlab.Ptr(api.AccessControlLevelValueToName(stringVal))
}
if d.HasChange("ci_pipeline_variables_minimum_override_role") {
stringVal := d.Get("ci_pipeline_variables_minimum_override_role").(string)
options.CIPipelineVariablesMinimumOverrideRole = gitlab.Ptr(stringVal)
}
if d.HasChange("merge_pipelines_enabled") {
options.MergePipelinesEnabled = gitlab.Ptr(d.Get("merge_pipelines_enabled").(bool))
}
if d.HasChange("merge_trains_enabled") {
options.MergeTrainsEnabled = gitlab.Ptr(d.Get("merge_trains_enabled").(bool))
}
if d.HasChange("resolve_outdated_diff_discussions") {
options.ResolveOutdatedDiffDiscussions = gitlab.Ptr(d.Get("resolve_outdated_diff_discussions").(bool))
}
if d.HasChange("analytics_access_level") {
options.AnalyticsAccessLevel = stringToAccessControlValue(d.Get("analytics_access_level").(string))
}
if d.HasChange("auto_cancel_pending_pipelines") {
options.AutoCancelPendingPipelines = gitlab.Ptr(d.Get("auto_cancel_pending_pipelines").(string))
}
if d.HasChange("auto_devops_deploy_strategy") {
options.AutoDevopsDeployStrategy = gitlab.Ptr(d.Get("auto_devops_deploy_strategy").(string))
}
if d.HasChange("auto_devops_enabled") {
options.AutoDevopsEnabled = gitlab.Ptr(d.Get("auto_devops_enabled").(bool))
}
if d.HasChange("autoclose_referenced_issues") {
options.AutocloseReferencedIssues = gitlab.Ptr(d.Get("autoclose_referenced_issues").(bool))
}
if d.HasChange("build_git_strategy") {
options.BuildGitStrategy = gitlab.Ptr(d.Get("build_git_strategy").(string))
}
if d.HasChange("build_timeout") {
options.BuildTimeout = gitlab.Ptr(d.Get("build_timeout").(int))
}
if d.HasChange("builds_access_level") {
options.BuildsAccessLevel = stringToAccessControlValue(d.Get("builds_access_level").(string))
}
if d.HasChange("container_expiration_policy") {
options.ContainerExpirationPolicyAttributes = expandContainerExpirationPolicyAttributes(d)
}
if d.HasChange("container_registry_access_level") {
options.ContainerRegistryAccessLevel = stringToAccessControlValue(d.Get("container_registry_access_level").(string))
}
if d.HasChange("emails_enabled") {
options.EmailsEnabled = gitlab.Ptr(d.Get("emails_enabled").(bool))
}
if d.HasChange("external_authorization_classification_label") {
options.ExternalAuthorizationClassificationLabel = gitlab.Ptr(d.Get("external_authorization_classification_label").(string))
}
if d.HasChange("forking_access_level") {
options.ForkingAccessLevel = stringToAccessControlValue(d.Get("forking_access_level").(string))
}
if d.HasChange("issues_access_level") {
options.IssuesAccessLevel = stringToAccessControlValue(d.Get("issues_access_level").(string))
}
if d.HasChange("merge_requests_access_level") {
options.MergeRequestsAccessLevel = stringToAccessControlValue(d.Get("merge_requests_access_level").(string))
}
// Ignore deprecated public_builds in favor of public_jobs.
if d.HasChange("public_jobs") {
options.PublicBuilds = gitlab.Ptr(d.Get("public_jobs").(bool)) //nolint:staticcheck
} else if d.HasChange("public_builds") {
options.PublicBuilds = gitlab.Ptr(d.Get("public_builds").(bool)) //nolint:staticcheck
}
if d.HasChange("repository_access_level") {
options.RepositoryAccessLevel = stringToAccessControlValue(d.Get("repository_access_level").(string))
}
if d.HasChange("repository_storage") {
options.RepositoryStorage = gitlab.Ptr(d.Get("repository_storage").(string))
}
if d.HasChange("requirements_access_level") {
options.RequirementsAccessLevel = stringToAccessControlValue(d.Get("requirements_access_level").(string))
}
if d.HasChange("security_and_compliance_access_level") {
options.SecurityAndComplianceAccessLevel = stringToAccessControlValue(d.Get("security_and_compliance_access_level").(string))
}
if d.HasChange("snippets_access_level") {
options.SnippetsAccessLevel = stringToAccessControlValue(d.Get("snippets_access_level").(string))
}
if d.HasChange("suggestion_commit_message") {
options.SuggestionCommitMessage = gitlab.Ptr(d.Get("suggestion_commit_message").(string))
}
if d.HasChange("topics") {
options.Topics = stringSetToStringSlice(d.Get("topics").(*schema.Set))
}
if d.HasChange("wiki_access_level") {
options.WikiAccessLevel = stringToAccessControlValue(d.Get("wiki_access_level").(string))
}
if d.HasChange("squash_commit_template") {
options.SquashCommitTemplate = gitlab.Ptr(d.Get("squash_commit_template").(string))
}
if d.HasChange("merge_commit_template") {
options.MergeCommitTemplate = gitlab.Ptr(d.Get("merge_commit_template").(string))
}
if d.HasChange("ci_default_git_depth") {
options.CIDefaultGitDepth = gitlab.Ptr(d.Get("ci_default_git_depth").(int))
}
if d.HasChange("ci_delete_pipelines_in_seconds") {
if v, ok := d.GetOk("ci_delete_pipelines_in_seconds"); !ok || v == nil {
err := updateNilCIDeletePipelinesInSecondsSetting(client, d.Id())
if err != nil {
return diag.FromErr(err)
}
options.CIDeletePipelinesInSeconds = nil
} else {
options.CIDeletePipelinesInSeconds = gitlab.Ptr(d.Get("ci_delete_pipelines_in_seconds").(int))
}
}
if d.HasChange("ci_separated_caches") {
options.CISeperateCache = gitlab.Ptr(d.Get("ci_separated_caches").(bool))
}
if d.HasChange("keep_latest_artifact") {
options.KeepLatestArtifact = gitlab.Ptr(d.Get("keep_latest_artifact").(bool))
}
if d.HasChange("mr_default_target_self") {
options.MergeRequestDefaultTargetSelf = gitlab.Ptr(d.Get("mr_default_target_self").(bool))
}
if d.HasChange("releases_access_level") {
options.ReleasesAccessLevel = stringToAccessControlValue(d.Get("releases_access_level").(string))
}
if d.HasChange("environments_access_level") {
options.EnvironmentsAccessLevel = stringToAccessControlValue(d.Get("environments_access_level").(string))
}
if d.HasChange("feature_flags_access_level") {
options.FeatureFlagsAccessLevel = stringToAccessControlValue(d.Get("feature_flags_access_level").(string))
}
if d.HasChange("infrastructure_access_level") {
options.InfrastructureAccessLevel = stringToAccessControlValue(d.Get("infrastructure_access_level").(string))
}
if d.HasChange("monitor_access_level") {
options.MonitorAccessLevel = stringToAccessControlValue(d.Get("monitor_access_level").(string))
}
if d.HasChange("model_experiments_access_level") {
options.ModelExperimentsAccessLevel = stringToAccessControlValue(d.Get("model_experiments_access_level").(string))
}
if d.HasChange("model_registry_access_level") {
options.ModelRegistryAccessLevel = stringToAccessControlValue(d.Get("model_registry_access_level").(string))
}
if d.HasChange("prevent_merge_without_jira_issue") {
options.PreventMergeWithoutJiraIssue = gitlab.Ptr(d.Get("prevent_merge_without_jira_issue").(bool))
}
avatar, err := handleAvatarOnUpdate(d)
if err != nil {
return diag.FromErr(err)
}
if avatar != nil {
options.Avatar = &gitlab.ProjectAvatar{
Filename: avatar.Filename,
Image: avatar.Image,
}
}
var project *gitlab.Project
if *options != (gitlab.EditProjectOptions{}) {
tflog.Debug(ctx, fmt.Sprintf("[DEBUG] update gitlab project %s", d.Id()))
project, _, err = client.Projects.EditProject(d.Id(), options, gitlab.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}
}
// If we don't have the project from the EditProject call, retrieve the project here so we have the full
// path for further calls.
if project == nil {
project, _, err = client.Projects.GetProject(d.Id(), nil)
if err != nil {
return diag.FromErr(err)
}
}
// If enabling Secret Push Detection, then update that value on the project via
// GraphQL
// lintignore: XR001 // TODO: replace with alternative for GetOkExists
if changed := d.HasChange("pre_receive_secret_detection_enabled"); changed {
val := d.Get("pre_receive_secret_detection_enabled").(bool)
err := updateProjectSecretDetectionValue(ctx, client, project.PathWithNamespace, val)
if err != nil {
return diag.Errorf("Error updating Secret Push Detection on Project %s: %v", d.Id(), err)
}
}
if d.HasChange("forked_from_project_id") {
oldRaw, newRaw := d.GetChange("forked_from_project_id")
oldValue, newValue := oldRaw.(int), newRaw.(int)
var createRelation, removeRelation bool
if newValue != 0 && oldValue != 0 {
// change fork relation
removeRelation = true
createRelation = true
} else if newValue != 0 {
// create fork relation
createRelation = true
} else if newValue == 0 {
removeRelation = true
}
if removeRelation {
// Remove fork relation
if _, err := client.Projects.DeleteProjectForkRelation(d.Id(), gitlab.WithContext(ctx)); err != nil {
return diag.Errorf("unable to remove fork relation from project %q: %v", d.Id(), err)
}
}
// Add fork relationship
if createRelation {
// Add fork relation
if _, _, err := client.Projects.CreateProjectForkRelation(d.Id(), newValue, gitlab.WithContext(ctx)); err != nil {
return diag.Errorf("unable to add fork relation to project %q (to project %d): %v", d.Id(), newValue, err)
}
}
}
if *transferOptions != (gitlab.TransferProjectOptions{}) {
tflog.Debug(ctx, fmt.Sprintf("[DEBUG] transferring project %s to namespace %d", d.Id(), transferOptions.Namespace))
_, _, err := client.Projects.TransferProject(d.Id(), transferOptions, gitlab.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}
}
if d.HasChange("archived") {
if d.Get("archived").(bool) {
if _, _, err := client.Projects.ArchiveProject(d.Id(), gitlab.WithContext(ctx)); err != nil {
return diag.Errorf("project %q could not be archived: %s", d.Id(), err)
}
} else {
if _, _, err := client.Projects.UnarchiveProject(d.Id(), gitlab.WithContext(ctx)); err != nil {
return diag.Errorf("project %q could not be unarchived: %s", d.Id(), err)
}
}
}
if d.HasChange("push_rules") {
err := editOrAddPushRules(ctx, client, d.Id(), d)
if err != nil {
if api.Is404(err) {
tflog.Debug(ctx, fmt.Sprintf("[DEBUG] Failed to get push rules for project %q: %v", d.Id(), err))
return diag.Errorf("Project push rules are not supported in your version of GitLab")
}
return diag.Errorf("Failed to edit push rules for project %q: %s", d.Id(), err)
}
}
return resourceGitlabProjectRead(ctx, d, meta)
}