From 227dcb987e578ecb4e880ca1ff97d72bebbc69bf Mon Sep 17 00:00:00 2001 From: Maxim Kalina Date: Sat, 16 May 2026 20:55:19 +0200 Subject: [PATCH] feat: add missing PUT /projects/:id attributes to updateProject ProjectApi.updateProject() was missing 35 attributes supported by the GitLab REST API for PUT /projects/:id, so those settings could not be changed through GitLab4J-API. - Add 20 new fields (+ getters/setters/builders) to the Project model that had no representation yet (e.g. merge_trains_enabled, package_registry_access_level, mr_default_title_template, ...). - Wire all 35 attributes into ProjectApi.updateProject(); the remaining 15 already had model getters but were never sent. - Extend the project.json test fixture with the 20 new attributes so TestGitLabApiBeans.testProject round-trips them. Deprecated/superseded attributes (emails_disabled, restrict_user_defined_variables) and the multipart-only `avatar` attribute are intentionally not included. Refs #1324 --- .../java/org/gitlab4j/api/ProjectApi.java | 40 +++ .../java/org/gitlab4j/api/models/Project.java | 282 ++++++++++++++++++ .../org/gitlab4j/models/project.json | 22 +- 3 files changed, 343 insertions(+), 1 deletion(-) diff --git a/gitlab4j-api/src/main/java/org/gitlab4j/api/ProjectApi.java b/gitlab4j-api/src/main/java/org/gitlab4j/api/ProjectApi.java index ad69a31e5..ca067d11a 100644 --- a/gitlab4j-api/src/main/java/org/gitlab4j/api/ProjectApi.java +++ b/gitlab4j-api/src/main/java/org/gitlab4j/api/ProjectApi.java @@ -1532,6 +1532,46 @@ public Project updateProject(Project project) throws GitLabApiException { formData.withParam("container_expiration_policy_attributes", attributes, false); } + // Additional PUT /projects/:id attributes (see gitlab4j/gitlab4j-api#1324) + formData.withParam("allow_merge_on_skipped_pipeline", project.getAllowMergeOnSkippedPipeline()) + .withParam( + "allow_pipeline_trigger_approve_deployment", project.getAllowPipelineTriggerApproveDeployment()) + .withParam("auto_devops_deploy_strategy", project.getAutoDevopsDeployStrategy()) + .withParam("auto_devops_enabled", project.getAutoDevopsEnabled()) + .withParam("auto_duo_code_review_enabled", project.getAutoDuoCodeReviewEnabled()) + .withParam("ci_default_git_depth", project.getCiDefaultGitDepth()) + .withParam("ci_display_pipeline_variables", project.getCiDisplayPipelineVariables()) + .withParam("ci_forward_deployment_rollback_allowed", project.getCiForwardDeploymentRollbackAllowed()) + .withParam( + "ci_allow_fork_pipelines_to_run_in_parent_project", + project.getCiAllowForkPipelinesToRunInParentProject()) + .withParam("ci_id_token_sub_claim_components", project.getCiIdTokenSubClaimComponents()) + .withParam("ci_separated_caches", project.getCiSeparatedCaches()) + .withParam("ci_restrict_pipeline_cancellation_role", project.getCiRestrictPipelineCancellationRole()) + .withParam("ci_push_repository_for_job_token_allowed", project.getCiPushRepositoryForJobTokenAllowed()) + .withParam("duo_remote_flows_enabled", project.getDuoRemoteFlowsEnabled()) + .withParam("duo_sast_fp_detection_enabled", project.getDuoSastFpDetectionEnabled()) + .withParam("duo_sast_vr_workflow_enabled", project.getDuoSastVrWorkflowEnabled()) + .withParam("enforce_auth_checks_on_uploads", project.getEnforceAuthChecksOnUploads()) + .withParam("import_url", project.getImportUrl()) + .withParam("keep_latest_artifact", project.getKeepLatestArtifact()) + .withParam("max_artifacts_size", project.getMaxArtifactsSize()) + .withParam("merge_pipelines_enabled", project.getMergePipelinesEnabled()) + .withParam("mr_default_title_template", project.getMrDefaultTitleTemplate()) + .withParam("merge_trains_enabled", project.getMergeTrainsEnabled()) + .withParam("merge_trains_skip_train_allowed", project.getMergeTrainsSkipTrainAllowed()) + .withParam("max_pipelines_per_merge_train", project.getMaxPipelinesPerMergeTrain()) + .withParam("mirror_overwrites_diverged_branches", project.getMirrorOverwritesDivergedBranches()) + .withParam("mirror_user_id", project.getMirrorUserId()) + .withParam("mr_default_target_self", project.getMrDefaultTargetSelf()) + .withParam("only_mirror_protected_branches", project.getOnlyMirrorProtectedBranches()) + .withParam("package_registry_access_level", project.getPackageRegistryAccessLevel()) + .withParam("prevent_merge_without_jira_issue", project.getPreventMergeWithoutJiraIssue()) + .withParam("protect_merge_request_pipelines", project.getProtectMergeRequestPipelines()) + .withParam("service_desk_enabled", project.getServiceDeskEnabled()) + .withParam("spp_repository_pipeline_access", project.getSppRepositoryPipelineAccess()) + .withParam("web_based_commit_signing_enabled", project.getWebBasedCommitSigningEnabled()); + Visibility visibility = (project.getVisibility() != null ? project.getVisibility() : project.getPublic() == Boolean.TRUE ? Visibility.PUBLIC : null); diff --git a/gitlab4j-models/src/main/java/org/gitlab4j/api/models/Project.java b/gitlab4j-models/src/main/java/org/gitlab4j/api/models/Project.java index c261c238a..170621d44 100644 --- a/gitlab4j-models/src/main/java/org/gitlab4j/api/models/Project.java +++ b/gitlab4j-models/src/main/java/org/gitlab4j/api/models/Project.java @@ -186,6 +186,28 @@ public String toString() { private ProjectFeatureVisibilityAccessLevel snippetsAccessLevel; private ProjectFeatureVisibilityAccessLevel wikiAccessLevel; + // Additional PUT /projects/:id attributes (see gitlab4j/gitlab4j-api#1324) + private Boolean autoDuoCodeReviewEnabled; + private Boolean ciDisplayPipelineVariables; + private Boolean duoRemoteFlowsEnabled; + private Boolean duoSastFpDetectionEnabled; + private Boolean duoSastVrWorkflowEnabled; + private Integer maxArtifactsSize; + private Boolean mergePipelinesEnabled; + private String mrDefaultTitleTemplate; + private Boolean mergeTrainsEnabled; + private Boolean mergeTrainsSkipTrainAllowed; + private Integer maxPipelinesPerMergeTrain; + private Boolean mirrorOverwritesDivergedBranches; + private Long mirrorUserId; + private Boolean mrDefaultTargetSelf; + private Boolean onlyMirrorProtectedBranches; + private ProjectFeatureVisibilityAccessLevel packageRegistryAccessLevel; + private Boolean preventMergeWithoutJiraIssue; + private Boolean protectMergeRequestPipelines; + private Boolean sppRepositoryPipelineAccess; + private Boolean webBasedCommitSigningEnabled; + @JsonProperty("_links") private Map links; @@ -1718,6 +1740,266 @@ public Project withWikiAccessLevel(ProjectFeatureVisibilityAccessLevel wikiAcces return this; } + public Boolean getAutoDuoCodeReviewEnabled() { + return autoDuoCodeReviewEnabled; + } + + public void setAutoDuoCodeReviewEnabled(Boolean autoDuoCodeReviewEnabled) { + this.autoDuoCodeReviewEnabled = autoDuoCodeReviewEnabled; + } + + public Project withAutoDuoCodeReviewEnabled(Boolean autoDuoCodeReviewEnabled) { + this.autoDuoCodeReviewEnabled = autoDuoCodeReviewEnabled; + return this; + } + + public Boolean getCiDisplayPipelineVariables() { + return ciDisplayPipelineVariables; + } + + public void setCiDisplayPipelineVariables(Boolean ciDisplayPipelineVariables) { + this.ciDisplayPipelineVariables = ciDisplayPipelineVariables; + } + + public Project withCiDisplayPipelineVariables(Boolean ciDisplayPipelineVariables) { + this.ciDisplayPipelineVariables = ciDisplayPipelineVariables; + return this; + } + + public Boolean getDuoRemoteFlowsEnabled() { + return duoRemoteFlowsEnabled; + } + + public void setDuoRemoteFlowsEnabled(Boolean duoRemoteFlowsEnabled) { + this.duoRemoteFlowsEnabled = duoRemoteFlowsEnabled; + } + + public Project withDuoRemoteFlowsEnabled(Boolean duoRemoteFlowsEnabled) { + this.duoRemoteFlowsEnabled = duoRemoteFlowsEnabled; + return this; + } + + public Boolean getDuoSastFpDetectionEnabled() { + return duoSastFpDetectionEnabled; + } + + public void setDuoSastFpDetectionEnabled(Boolean duoSastFpDetectionEnabled) { + this.duoSastFpDetectionEnabled = duoSastFpDetectionEnabled; + } + + public Project withDuoSastFpDetectionEnabled(Boolean duoSastFpDetectionEnabled) { + this.duoSastFpDetectionEnabled = duoSastFpDetectionEnabled; + return this; + } + + public Boolean getDuoSastVrWorkflowEnabled() { + return duoSastVrWorkflowEnabled; + } + + public void setDuoSastVrWorkflowEnabled(Boolean duoSastVrWorkflowEnabled) { + this.duoSastVrWorkflowEnabled = duoSastVrWorkflowEnabled; + } + + public Project withDuoSastVrWorkflowEnabled(Boolean duoSastVrWorkflowEnabled) { + this.duoSastVrWorkflowEnabled = duoSastVrWorkflowEnabled; + return this; + } + + public Integer getMaxArtifactsSize() { + return maxArtifactsSize; + } + + public void setMaxArtifactsSize(Integer maxArtifactsSize) { + this.maxArtifactsSize = maxArtifactsSize; + } + + public Project withMaxArtifactsSize(Integer maxArtifactsSize) { + this.maxArtifactsSize = maxArtifactsSize; + return this; + } + + public Boolean getMergePipelinesEnabled() { + return mergePipelinesEnabled; + } + + public void setMergePipelinesEnabled(Boolean mergePipelinesEnabled) { + this.mergePipelinesEnabled = mergePipelinesEnabled; + } + + public Project withMergePipelinesEnabled(Boolean mergePipelinesEnabled) { + this.mergePipelinesEnabled = mergePipelinesEnabled; + return this; + } + + public String getMrDefaultTitleTemplate() { + return mrDefaultTitleTemplate; + } + + public void setMrDefaultTitleTemplate(String mrDefaultTitleTemplate) { + this.mrDefaultTitleTemplate = mrDefaultTitleTemplate; + } + + public Project withMrDefaultTitleTemplate(String mrDefaultTitleTemplate) { + this.mrDefaultTitleTemplate = mrDefaultTitleTemplate; + return this; + } + + public Boolean getMergeTrainsEnabled() { + return mergeTrainsEnabled; + } + + public void setMergeTrainsEnabled(Boolean mergeTrainsEnabled) { + this.mergeTrainsEnabled = mergeTrainsEnabled; + } + + public Project withMergeTrainsEnabled(Boolean mergeTrainsEnabled) { + this.mergeTrainsEnabled = mergeTrainsEnabled; + return this; + } + + public Boolean getMergeTrainsSkipTrainAllowed() { + return mergeTrainsSkipTrainAllowed; + } + + public void setMergeTrainsSkipTrainAllowed(Boolean mergeTrainsSkipTrainAllowed) { + this.mergeTrainsSkipTrainAllowed = mergeTrainsSkipTrainAllowed; + } + + public Project withMergeTrainsSkipTrainAllowed(Boolean mergeTrainsSkipTrainAllowed) { + this.mergeTrainsSkipTrainAllowed = mergeTrainsSkipTrainAllowed; + return this; + } + + public Integer getMaxPipelinesPerMergeTrain() { + return maxPipelinesPerMergeTrain; + } + + public void setMaxPipelinesPerMergeTrain(Integer maxPipelinesPerMergeTrain) { + this.maxPipelinesPerMergeTrain = maxPipelinesPerMergeTrain; + } + + public Project withMaxPipelinesPerMergeTrain(Integer maxPipelinesPerMergeTrain) { + this.maxPipelinesPerMergeTrain = maxPipelinesPerMergeTrain; + return this; + } + + public Boolean getMirrorOverwritesDivergedBranches() { + return mirrorOverwritesDivergedBranches; + } + + public void setMirrorOverwritesDivergedBranches(Boolean mirrorOverwritesDivergedBranches) { + this.mirrorOverwritesDivergedBranches = mirrorOverwritesDivergedBranches; + } + + public Project withMirrorOverwritesDivergedBranches(Boolean mirrorOverwritesDivergedBranches) { + this.mirrorOverwritesDivergedBranches = mirrorOverwritesDivergedBranches; + return this; + } + + public Long getMirrorUserId() { + return mirrorUserId; + } + + public void setMirrorUserId(Long mirrorUserId) { + this.mirrorUserId = mirrorUserId; + } + + public Project withMirrorUserId(Long mirrorUserId) { + this.mirrorUserId = mirrorUserId; + return this; + } + + public Boolean getMrDefaultTargetSelf() { + return mrDefaultTargetSelf; + } + + public void setMrDefaultTargetSelf(Boolean mrDefaultTargetSelf) { + this.mrDefaultTargetSelf = mrDefaultTargetSelf; + } + + public Project withMrDefaultTargetSelf(Boolean mrDefaultTargetSelf) { + this.mrDefaultTargetSelf = mrDefaultTargetSelf; + return this; + } + + public Boolean getOnlyMirrorProtectedBranches() { + return onlyMirrorProtectedBranches; + } + + public void setOnlyMirrorProtectedBranches(Boolean onlyMirrorProtectedBranches) { + this.onlyMirrorProtectedBranches = onlyMirrorProtectedBranches; + } + + public Project withOnlyMirrorProtectedBranches(Boolean onlyMirrorProtectedBranches) { + this.onlyMirrorProtectedBranches = onlyMirrorProtectedBranches; + return this; + } + + public ProjectFeatureVisibilityAccessLevel getPackageRegistryAccessLevel() { + return packageRegistryAccessLevel; + } + + public void setPackageRegistryAccessLevel(ProjectFeatureVisibilityAccessLevel packageRegistryAccessLevel) { + this.packageRegistryAccessLevel = packageRegistryAccessLevel; + } + + public Project withPackageRegistryAccessLevel(ProjectFeatureVisibilityAccessLevel packageRegistryAccessLevel) { + this.packageRegistryAccessLevel = packageRegistryAccessLevel; + return this; + } + + public Boolean getPreventMergeWithoutJiraIssue() { + return preventMergeWithoutJiraIssue; + } + + public void setPreventMergeWithoutJiraIssue(Boolean preventMergeWithoutJiraIssue) { + this.preventMergeWithoutJiraIssue = preventMergeWithoutJiraIssue; + } + + public Project withPreventMergeWithoutJiraIssue(Boolean preventMergeWithoutJiraIssue) { + this.preventMergeWithoutJiraIssue = preventMergeWithoutJiraIssue; + return this; + } + + public Boolean getProtectMergeRequestPipelines() { + return protectMergeRequestPipelines; + } + + public void setProtectMergeRequestPipelines(Boolean protectMergeRequestPipelines) { + this.protectMergeRequestPipelines = protectMergeRequestPipelines; + } + + public Project withProtectMergeRequestPipelines(Boolean protectMergeRequestPipelines) { + this.protectMergeRequestPipelines = protectMergeRequestPipelines; + return this; + } + + public Boolean getSppRepositoryPipelineAccess() { + return sppRepositoryPipelineAccess; + } + + public void setSppRepositoryPipelineAccess(Boolean sppRepositoryPipelineAccess) { + this.sppRepositoryPipelineAccess = sppRepositoryPipelineAccess; + } + + public Project withSppRepositoryPipelineAccess(Boolean sppRepositoryPipelineAccess) { + this.sppRepositoryPipelineAccess = sppRepositoryPipelineAccess; + return this; + } + + public Boolean getWebBasedCommitSigningEnabled() { + return webBasedCommitSigningEnabled; + } + + public void setWebBasedCommitSigningEnabled(Boolean webBasedCommitSigningEnabled) { + this.webBasedCommitSigningEnabled = webBasedCommitSigningEnabled; + } + + public Project withWebBasedCommitSigningEnabled(Boolean webBasedCommitSigningEnabled) { + this.webBasedCommitSigningEnabled = webBasedCommitSigningEnabled; + return this; + } + @JsonIgnore public String getLinkByName(String name) { if (links == null || links.isEmpty()) { diff --git a/gitlab4j-models/src/test/resources/org/gitlab4j/models/project.json b/gitlab4j-models/src/test/resources/org/gitlab4j/models/project.json index 8e2dc2683..f07dc52b3 100644 --- a/gitlab4j-models/src/test/resources/org/gitlab4j/models/project.json +++ b/gitlab4j-models/src/test/resources/org/gitlab4j/models/project.json @@ -195,5 +195,25 @@ "security_and_compliance_access_level" : "private", "snippets_access_level" : "enabled", "wiki_access_level" : "enabled", - "ci_delete_pipelines_in_seconds": 604800 + "ci_delete_pipelines_in_seconds": 604800, + "auto_duo_code_review_enabled" : true, + "ci_display_pipeline_variables" : true, + "duo_remote_flows_enabled" : true, + "duo_sast_fp_detection_enabled" : true, + "duo_sast_vr_workflow_enabled" : true, + "max_artifacts_size" : 1024, + "merge_pipelines_enabled" : true, + "mr_default_title_template" : "Draft: %{source_branch}", + "merge_trains_enabled" : true, + "merge_trains_skip_train_allowed" : true, + "max_pipelines_per_merge_train" : 5, + "mirror_overwrites_diverged_branches" : true, + "mirror_user_id" : 42, + "mr_default_target_self" : false, + "only_mirror_protected_branches" : true, + "package_registry_access_level" : "enabled", + "prevent_merge_without_jira_issue" : false, + "protect_merge_request_pipelines" : true, + "spp_repository_pipeline_access" : true, + "web_based_commit_signing_enabled" : true }