diff --git a/app/models/project.rb b/app/models/project.rb index 7012cb7b25bcc84be66ce3ee9e7e2ba4631b4bf7..9b26be0f7d6d73a49230f995e9055f952ab430f2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -3221,6 +3221,10 @@ def path_availability errors.add(:path, s_('Project|already in use')) end + def repository_object_format + project_repository&.object_format + end + def instance_runner_running_jobs_count # excluding currently started job ::Ci::RunningBuild.instance_type.where(project_id: self.id) diff --git a/doc/api/projects.md b/doc/api/projects.md index d3e63f8607b475cba66e8b812137bada12846384..b33b5dec3cd7b2e3209cbf40736e7c04c0250a6e 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1567,6 +1567,7 @@ curl --request POST --header "PRIVATE-TOKEN: " \ | `public_builds` | boolean | No | _(Deprecated)_ If `true`, jobs can be viewed by non-project members. Use `public_jobs` instead. | | `public_jobs` | boolean | No | If `true`, jobs can be viewed by non-project members. | | `releases_access_level` | string | No | One of `disabled`, `private`, or `enabled`. | +| `repository_object_format` | string | No | Repository object format. Defaults to `sha1`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419887) in GitLab 16.9. | | `remove_source_branch_after_merge` | boolean | No | Enable `Delete source branch` option by default for all new merge requests. | | `repository_access_level` | string | No | One of `disabled`, `private`, or `enabled`. | | `repository_storage` | string | No | Which storage shard the repository is on. _(administrator only)_ | @@ -1661,6 +1662,7 @@ POST /projects/user/:user_id | `public_builds` | boolean | No | _(Deprecated)_ If `true`, jobs can be viewed by non-project members. Use `public_jobs` instead. | | `public_jobs` | boolean | No | If `true`, jobs can be viewed by non-project members. | | `releases_access_level` | string | No | One of `disabled`, `private`, or `enabled`. | +| `repository_object_format` | string | No | Repository object format. Defaults to `sha1`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419887) in GitLab 16.9. | | `remove_source_branch_after_merge` | boolean | No | Enable `Delete source branch` option by default for all new merge requests. | | `repository_access_level` | string | No | One of `disabled`, `private`, or `enabled`. | | `repository_storage` | string | No | Which storage shard the repository is on. _(administrators only)_ | @@ -1891,6 +1893,7 @@ Example responses: "name_with_namespace": "Diaspora / Diaspora Project Site", "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", + "repository_object_format": "sha1", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, @@ -1993,6 +1996,7 @@ Example response: "name_with_namespace": "Diaspora / Diaspora Project Site", "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", + "repository_object_format": "sha1", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, @@ -2101,6 +2105,7 @@ Example response: "name_with_namespace": "Diaspora / Diaspora Project Site", "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", + "repository_object_format": "sha1", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, @@ -2289,6 +2294,7 @@ Example response: "name_with_namespace": "Diaspora / Diaspora Project Site", "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", + "repository_object_format": "sha1", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, @@ -2422,6 +2428,7 @@ Example response: "name_with_namespace": "Diaspora / Diaspora Project Site", "path": "diaspora-project-site", "path_with_namespace": "diaspora/diaspora-project-site", + "repository_object_format": "sha1", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb index 071d71e3a191d65c297f15b21985eebe9962a6d2..fbde9164a4f5ea04685cc8935dce74ac830dfb6c 100644 --- a/lib/api/entities/project.rb +++ b/lib/api/entities/project.rb @@ -51,6 +51,7 @@ class Project < BasicProjectDetails expose :container_expiration_policy, using: Entities::ContainerExpirationPolicy, if: -> (project, _) { project.container_expiration_policy } + expose :repository_object_format, documentation: { type: 'string', example: 'sha1' } # Expose old field names with the new permissions methods to keep API compatible # TODO: remove in API v5, replaced by *_access_level @@ -179,6 +180,7 @@ def self.preload_relation(projects_relation, options = {}) .preload(:project_setting) .preload(:container_expiration_policy) .preload(:auto_devops) + .preload(:project_repository) .preload(:service_desk_setting) .preload(project_group_links: { group: :route }, fork_network: :root_project, diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 214bef31e9ce97399fd1a813a4b9aa212a029e53..63d7961afe1eca2d742690d603012df831289e4e 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -82,6 +82,7 @@ module ProjectsHelpers optional :squash_option, type: String, values: %w[never always default_on default_off], desc: 'Squash default for project. One of `never`, `always`, `default_on`, or `default_off`.' optional :mr_default_target_self, type: Boolean, desc: 'Merge requests of this forked project targets itself by default' optional :warn_about_potentially_unwanted_characters, type: Boolean, desc: 'Warn about potentially unwanted characters' + optional :repository_object_format, type: String, values: %w[sha1 sha256], desc: 'The object format of the project repository' end params :optional_project_params_ee do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d7037df66782be8ba8fd23d6f2ec27042e629436..20ea99ca18a66a29fb7b78384866142f4aa3d53b 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -9029,6 +9029,28 @@ def create_hook end end + describe '#repository_object_format' do + subject { project.repository_object_format } + + let_it_be(:project) { create(:project) } + + context 'when project without a repository' do + it { is_expected.to be_nil } + end + + context 'when project with sha1 repository' do + let_it_be(:project_repository) { create(:project_repository, project: project, object_format: 'sha1') } + + it { is_expected.to eq 'sha1' } + end + + context 'when project with sha256 repository' do + let_it_be(:project_repository) { create(:project_repository, project: project, object_format: 'sha256') } + + it { is_expected.to eq 'sha256' } + end + end + describe '#supports_lock_on_merge?' do it_behaves_like 'checks self (project) and root ancestor feature flag' do let(:feature_flag) { :enforce_locked_labels_on_merge } diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index 6d9f932daf649d460d0aeb7752c814adfdcfc47e..ada2a917c316945f857f7f4871a44e94dcf4e6a1 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -78,6 +78,7 @@ itself: # project - topics - web_url - description_html + - repository_object_format build_auto_devops: # auto_devops unexposed_attributes: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index ab2770b28e791ad9644eb7e64fd6600fd180be6b..8514692580a3e96a975d8e40587e10c358198590 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1644,6 +1644,55 @@ def request expect(response).to have_gitlab_http_status(:created) end + context 'with repository_object_format' do + context 'when sha1' do + it 'creates a project with SHA1 repository' do + project = attributes_for(:project) + + post api(path, user), params: project.merge(repository_object_format: 'sha1') + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['repository_object_format']).to eq 'sha1' + end + end + + context 'when sha256' do + it 'creates a project with SHA256 repository' do + project = attributes_for(:project) + + post api(path, user), params: project.merge(repository_object_format: 'sha256') + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['repository_object_format']).to eq 'sha256' + end + + context 'when "support_sha256_repositories" FF is disabled' do + before do + stub_feature_flags(support_sha256_repositories: false) + end + + it 'creates a project with SHA1 repository' do + project = attributes_for(:project) + + post api(path, user), params: project.merge(repository_object_format: 'sha256') + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['repository_object_format']).to eq 'sha1' + end + end + end + + context 'when unknown format' do + it 'rejects a project creation' do + project = attributes_for(:project) + + post api(path, user), params: project.merge(repository_object_format: 'unknown') + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + end + context 'when a visibility level is restricted' do let(:project_param) { attributes_for(:project, visibility: 'public') }