diff options
author | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2019-07-09 20:09:45 +0000 |
---|---|---|
committer | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2019-07-09 20:09:45 +0000 |
commit | 109956a65b873a245b26915eb5f48f40942e4453 (patch) | |
tree | c254489b88313594a7e4b5867cafbf57d3609716 | |
parent | 6e106f66ad9d692b88e90506c0b35c4281f2b600 (diff) | |
parent | 2615265ef82e07ea36df67f6d1a11ad4a731ad63 (diff) | |
download | gitlab-ce-109956a65b873a245b26915eb5f48f40942e4453.tar.gz |
Merge branch 'project_api' into 'master'
Improve Project API
Closes #49938, #40892, and #35992
See merge request gitlab-org/gitlab-ce!28327
-rw-r--r-- | app/models/concerns/project_api_compatibility.rb | 20 | ||||
-rw-r--r-- | app/models/concerns/project_features_compatibility.rb | 54 | ||||
-rw-r--r-- | app/models/project.rb | 1 | ||||
-rw-r--r-- | app/models/project_feature.rb | 18 | ||||
-rw-r--r-- | changelogs/unreleased/project_api.yml | 5 | ||||
-rw-r--r-- | doc/api/projects.md | 66 | ||||
-rw-r--r-- | lib/api/entities.rb | 20 | ||||
-rw-r--r-- | lib/api/helpers/projects_helpers.rb | 45 | ||||
-rw-r--r-- | spec/models/concerns/project_api_compatibility_spec.rb | 38 | ||||
-rw-r--r-- | spec/models/concerns/project_features_compatibility_spec.rb | 18 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 54 |
11 files changed, 304 insertions, 35 deletions
diff --git a/app/models/concerns/project_api_compatibility.rb b/app/models/concerns/project_api_compatibility.rb new file mode 100644 index 00000000000..cb00efb06df --- /dev/null +++ b/app/models/concerns/project_api_compatibility.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# Add methods used by the projects API +module ProjectAPICompatibility + extend ActiveSupport::Concern + + def build_git_strategy=(value) + write_attribute(:build_allow_git_fetch, value == 'fetch') + end + + def auto_devops_enabled=(value) + self.build_auto_devops if self.auto_devops&.enabled.nil? + self.auto_devops.update! enabled: value + end + + def auto_devops_deploy_strategy=(value) + self.build_auto_devops if self.auto_devops&.enabled.nil? + self.auto_devops.update! deploy_strategy: value + end +end diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb index f268a842db4..551a2e56ecf 100644 --- a/app/models/concerns/project_features_compatibility.rb +++ b/app/models/concerns/project_features_compatibility.rb @@ -9,32 +9,70 @@ require 'gitlab/utils' module ProjectFeaturesCompatibility extend ActiveSupport::Concern + # TODO: remove in API v5, replaced by *_access_level def wiki_enabled=(value) - write_feature_attribute(:wiki_access_level, value) + write_feature_attribute_boolean(:wiki_access_level, value) end + # TODO: remove in API v5, replaced by *_access_level def builds_enabled=(value) - write_feature_attribute(:builds_access_level, value) + write_feature_attribute_boolean(:builds_access_level, value) end + # TODO: remove in API v5, replaced by *_access_level def merge_requests_enabled=(value) - write_feature_attribute(:merge_requests_access_level, value) + write_feature_attribute_boolean(:merge_requests_access_level, value) end + # TODO: remove in API v5, replaced by *_access_level def issues_enabled=(value) - write_feature_attribute(:issues_access_level, value) + write_feature_attribute_boolean(:issues_access_level, value) end + # TODO: remove in API v5, replaced by *_access_level def snippets_enabled=(value) - write_feature_attribute(:snippets_access_level, value) + write_feature_attribute_boolean(:snippets_access_level, value) + end + + def repository_access_level=(value) + write_feature_attribute_string(:repository_access_level, value) + end + + def wiki_access_level=(value) + write_feature_attribute_string(:wiki_access_level, value) + end + + def builds_access_level=(value) + write_feature_attribute_string(:builds_access_level, value) + end + + def merge_requests_access_level=(value) + write_feature_attribute_string(:merge_requests_access_level, value) + end + + def issues_access_level=(value) + write_feature_attribute_string(:issues_access_level, value) + end + + def snippets_access_level=(value) + write_feature_attribute_string(:snippets_access_level, value) end private - def write_feature_attribute(field, value) + def write_feature_attribute_boolean(field, value) + access_level = Gitlab::Utils.to_boolean(value) ? ProjectFeature::ENABLED : ProjectFeature::DISABLED + write_feature_attribute_raw(field, access_level) + end + + def write_feature_attribute_string(field, value) + access_level = ProjectFeature.access_level_from_str(value) + write_feature_attribute_raw(field, access_level) + end + + def write_feature_attribute_raw(field, value) build_project_feature unless project_feature - access_level = Gitlab::Utils.to_boolean(value) ? ProjectFeature::ENABLED : ProjectFeature::DISABLED - project_feature.__send__(:write_attribute, field, access_level) # rubocop:disable GitlabSecurity/PublicSend + project_feature.__send__(:write_attribute, field, value) # rubocop:disable GitlabSecurity/PublicSend end end diff --git a/app/models/project.rb b/app/models/project.rb index 075f7882d72..bfc35b77b8f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -15,6 +15,7 @@ class Project < ApplicationRecord include CaseSensitivity include TokenAuthenticatable include ValidAttribute + include ProjectAPICompatibility include ProjectFeaturesCompatibility include SelectForProjectAuthorization include Presentable diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 0542581c6e0..7ff06655de0 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -24,6 +24,12 @@ class ProjectFeature < ApplicationRecord FEATURES = %i(issues merge_requests wiki snippets builds repository pages).freeze PRIVATE_FEATURES_MIN_ACCESS_LEVEL = { merge_requests: Gitlab::Access::REPORTER }.freeze + STRING_OPTIONS = HashWithIndifferentAccess.new({ + 'disabled' => DISABLED, + 'private' => PRIVATE, + 'enabled' => ENABLED, + 'public' => PUBLIC + }).freeze class << self def access_level_attribute(feature) @@ -45,6 +51,14 @@ class ProjectFeature < ApplicationRecord PRIVATE_FEATURES_MIN_ACCESS_LEVEL.fetch(feature, Gitlab::Access::GUEST) end + def access_level_from_str(level) + STRING_OPTIONS.fetch(level) + end + + def str_from_access_level(level) + STRING_OPTIONS.key(level) + end + private def ensure_feature!(feature) @@ -83,6 +97,10 @@ class ProjectFeature < ApplicationRecord public_send(ProjectFeature.access_level_attribute(feature)) # rubocop:disable GitlabSecurity/PublicSend end + def string_access_level(feature) + ProjectFeature.str_from_access_level(access_level(feature)) + end + def builds_enabled? builds_access_level > DISABLED end diff --git a/changelogs/unreleased/project_api.yml b/changelogs/unreleased/project_api.yml new file mode 100644 index 00000000000..a04f9bb5608 --- /dev/null +++ b/changelogs/unreleased/project_api.yml @@ -0,0 +1,5 @@ +--- +title: Improve Project API +merge_request: 28327 +author: Mathieu Parent +type: added diff --git a/doc/api/projects.md b/doc/api/projects.md index 6468d73e0af..c199babc1be 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -708,11 +708,17 @@ POST /projects | `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) | | `default_branch` | string | no | `master` by default | | `description` | string | no | Short project description | -| `issues_enabled` | boolean | no | Enable issues for this project | -| `merge_requests_enabled` | boolean | no | Enable merge requests for this project | -| `jobs_enabled` | boolean | no | Enable jobs for this project | -| `wiki_enabled` | boolean | no | Enable wiki for this project | -| `snippets_enabled` | boolean | no | Enable snippets for this project | +| `issues_enabled` | boolean | no | (deprecated) Enable issues for this project. Use `issues_access_level` instead | +| `merge_requests_enabled` | boolean | no | (deprecated) Enable merge requests for this project. Use `merge_requests_access_level` instead | +| `jobs_enabled` | boolean | no | (deprecated) Enable jobs for this project. Use `builds_access_level` instead | +| `wiki_enabled` | boolean | no | (deprecated) Enable wiki for this project. Use `wiki_access_level` instead | +| `snippets_enabled` | boolean | no | (deprecated) Enable snippets for this project. Use `snippets_access_level` instead | +| `issues_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `repository_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `merge_requests_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` | | `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push | | `container_registry_enabled` | boolean | no | Enable container registry for this project | | `shared_runners_enabled` | boolean | no | Enable shared runners for this project | @@ -727,7 +733,13 @@ POST /projects | `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project | | `avatar` | mixed | no | Image file for avatar of the project | | `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line | +| `build_git_strategy` | string | no | The Git strategy. Defaults to `fetch` | +| `build_timeout` | integer | no | The maximum amount of time in minutes that a job is able run (in seconds) | +| `auto_cancel_pending_pipelines` | string | no | Auto-cancel pending pipelines (Note: this is not a boolean, but enabled/disabled | +| `build_coverage_regex` | string | no | Test coverage parsing | | `ci_config_path` | string | no | The path to CI config file | +| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project | +| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) | | `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins | | `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default | | `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project | @@ -753,11 +765,17 @@ POST /projects/user/:user_id | `path` | string | no | Custom repository name for new project. By default generated based on name | | `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) | | `description` | string | no | Short project description | -| `issues_enabled` | boolean | no | Enable issues for this project | -| `merge_requests_enabled` | boolean | no | Enable merge requests for this project | -| `jobs_enabled` | boolean | no | Enable jobs for this project | -| `wiki_enabled` | boolean | no | Enable wiki for this project | -| `snippets_enabled` | boolean | no | Enable snippets for this project | +| `issues_enabled` | boolean | no | (deprecated) Enable issues for this project. Use `issues_access_level` instead | +| `merge_requests_enabled` | boolean | no | (deprecated) Enable merge requests for this project. Use `merge_requests_access_level` instead | +| `jobs_enabled` | boolean | no | (deprecated) Enable jobs for this project. Use `builds_access_level` instead | +| `wiki_enabled` | boolean | no | (deprecated) Enable wiki for this project. Use `wiki_access_level` instead | +| `snippets_enabled` | boolean | no | (deprecated) Enable snippets for this project. Use `snippets_access_level` instead | +| `issues_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `repository_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `merge_requests_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` | | `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push | | `container_registry_enabled` | boolean | no | Enable container registry for this project | | `shared_runners_enabled` | boolean | no | Enable shared runners for this project | @@ -772,7 +790,13 @@ POST /projects/user/:user_id | `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project | | `avatar` | mixed | no | Image file for avatar of the project | | `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line | +| `build_git_strategy` | string | no | The Git strategy. Defaults to `fetch` | +| `build_timeout` | integer | no | The maximum amount of time in minutes that a job is able run (in seconds) | +| `auto_cancel_pending_pipelines` | string | no | Auto-cancel pending pipelines (Note: this is not a boolean, but enabled/disabled | +| `build_coverage_regex` | string | no | Test coverage parsing | | `ci_config_path` | string | no | The path to CI config file | +| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project | +| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) | | `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins | | `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default | | `external_authorization_classification_label` | string | no | **(CORE ONLY)** The classification label for the project | @@ -798,11 +822,17 @@ PUT /projects/:id | `path` | string | no | Custom repository name for the project. By default generated based on name | | `default_branch` | string | no | `master` by default | | `description` | string | no | Short project description | -| `issues_enabled` | boolean | no | Enable issues for this project | -| `merge_requests_enabled` | boolean | no | Enable merge requests for this project | -| `jobs_enabled` | boolean | no | Enable jobs for this project | -| `wiki_enabled` | boolean | no | Enable wiki for this project | -| `snippets_enabled` | boolean | no | Enable snippets for this project | +| `issues_enabled` | boolean | no | (deprecated) Enable issues for this project. Use `issues_access_level` instead | +| `merge_requests_enabled` | boolean | no | (deprecated) Enable merge requests for this project. Use `merge_requests_access_level` instead | +| `jobs_enabled` | boolean | no | (deprecated) Enable jobs for this project. Use `builds_access_level` instead | +| `wiki_enabled` | boolean | no | (deprecated) Enable wiki for this project. Use `wiki_access_level` instead | +| `snippets_enabled` | boolean | no | (deprecated) Enable snippets for this project. Use `snippets_access_level` instead | +| `issues_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `repository_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `merge_requests_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` | +| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` | | `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push | | `container_registry_enabled` | boolean | no | Enable container registry for this project | | `shared_runners_enabled` | boolean | no | Enable shared runners for this project | @@ -816,8 +846,14 @@ PUT /projects/:id | `request_access_enabled` | boolean | no | Allow users to request member access | | `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project | | `avatar` | mixed | no | Image file for avatar of the project | +| `build_git_strategy` | string | no | The Git strategy. Defaults to `fetch` | +| `build_timeout` | integer | no | The maximum amount of time in minutes that a job is able run (in seconds) | +| `auto_cancel_pending_pipelines` | string | no | Auto-cancel pending pipelines (Note: this is not a boolean, but enabled/disabled | +| `build_coverage_regex` | string | no | Test coverage parsing | | `ci_config_path` | string | no | The path to CI config file | | `ci_default_git_depth` | integer | no | Default number of revisions for [shallow cloning](../user/project/pipelines/settings.md#git-shallow-clone) | +| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project | +| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) | | `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins | | `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge request by default | | `external_authorization_classification_label` | string | no | **(CORE ONLY)** The classification label for the project | diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b9aa387ba61..5eae87fea02 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -201,6 +201,7 @@ module API # MR describing the solution: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20555 projects_relation.preload(:project_feature, :route) .preload(:import_state, :tags) + .preload(:auto_devops) .preload(namespace: [:route, :owner]) end # rubocop: enable CodeReuse/ActiveRecord @@ -247,12 +248,20 @@ module API expose :container_registry_enabled # Expose old field names with the new permissions methods to keep API compatible + # TODO: remove in API v5, replaced by *_access_level expose(:issues_enabled) { |project, options| project.feature_available?(:issues, options[:current_user]) } expose(:merge_requests_enabled) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) } expose(:wiki_enabled) { |project, options| project.feature_available?(:wiki, options[:current_user]) } expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) } expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) } + expose(:issues_access_level) { |project, options| project.project_feature.string_access_level(:issues) } + expose(:repository_access_level) { |project, options| project.project_feature.string_access_level(:repository) } + expose(:merge_requests_access_level) { |project, options| project.project_feature.string_access_level(:merge_requests) } + expose(:wiki_access_level) { |project, options| project.project_feature.string_access_level(:wiki) } + expose(:builds_access_level) { |project, options| project.project_feature.string_access_level(:builds) } + expose(:snippets_access_level) { |project, options| project.project_feature.string_access_level(:snippets) } + expose :shared_runners_enabled expose :lfs_enabled?, as: :lfs_enabled expose :creator_id @@ -267,6 +276,12 @@ module API expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :ci_default_git_depth expose :public_builds, as: :public_jobs + expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options| + project.build_allow_git_fetch ? 'fetch' : 'clone' + end + expose :build_timeout + expose :auto_cancel_pending_pipelines + expose :build_coverage_regex expose :ci_config_path, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) } expose :shared_with_groups do |project, options| SharedGroup.represent(project.project_group_links, options) @@ -280,6 +295,10 @@ module API options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project) } expose :external_authorization_classification_label + expose :auto_devops_enabled?, as: :auto_devops_enabled + expose :auto_devops_deploy_strategy do |project, options| + project.auto_devops.nil? ? 'continuous' : project.auto_devops.deploy_strategy + end # rubocop: disable CodeReuse/ActiveRecord def self.preload_relation(projects_relation, options = {}) @@ -289,6 +308,7 @@ module API # MR describing the solution: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20555 super(projects_relation).preload(:group) .preload(:ci_cd_settings) + .preload(:auto_devops) .preload(project_group_links: { group: :route }, fork_network: :root_project, fork_network_member: :forked_from_project, diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index f242f1fea0e..0e21a7a66fd 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -8,12 +8,26 @@ module API params :optional_project_params_ce do optional :description, type: String, desc: 'The description of the project' + optional :build_git_strategy, type: String, values: %w(fetch clone), desc: 'The Git strategy. Defaults to `fetch`' + optional :build_timeout, type: Integer, desc: 'Build timeout' + optional :auto_cancel_pending_pipelines, type: String, values: %w(disabled enabled), desc: 'Auto-cancel pending pipelines' + optional :build_coverage_regex, type: String, desc: 'Test coverage parsing' optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`' + + # TODO: remove in API v5, replaced by *_access_level optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled' optional :merge_requests_enabled, type: Boolean, desc: 'Flag indication if merge requests are enabled' optional :wiki_enabled, type: Boolean, desc: 'Flag indication if the wiki is enabled' optional :jobs_enabled, type: Boolean, desc: 'Flag indication if jobs are enabled' optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled' + + optional :issues_access_level, type: String, values: %w(disabled private enabled), desc: 'Issues access level. One of `disabled`, `private` or `enabled`' + optional :repository_access_level, type: String, values: %w(disabled private enabled), desc: 'Repository access level. One of `disabled`, `private` or `enabled`' + optional :merge_requests_access_level, type: String, values: %w(disabled private enabled), desc: 'Merge requests access level. One of `disabled`, `private` or `enabled`' + optional :wiki_access_level, type: String, values: %w(disabled private enabled), desc: 'Wiki access level. One of `disabled`, `private` or `enabled`' + optional :builds_access_level, type: String, values: %w(disabled private enabled), desc: 'Builds access level. One of `disabled`, `private` or `enabled`' + optional :snippets_access_level, type: String, values: %w(disabled private enabled), desc: 'Snippets access level. One of `disabled`, `private` or `enabled`' + optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project' optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push' optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project' @@ -30,6 +44,8 @@ module API optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md" optional :external_authorization_classification_label, type: String, desc: 'The classification label for the project' optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning' + optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled' + optional :auto_devops_deploy_strategy, type: String, values: %w(continuous manual timed_incremental), desc: 'Auto Deploy strategy' end params :optional_project_params_ee do @@ -48,15 +64,20 @@ module API def self.update_params_at_least_one_of [ - :jobs_enabled, - :resolve_outdated_diff_discussions, + :auto_devops_enabled, + :auto_devops_deploy_strategy, + :auto_cancel_pending_pipelines, + :build_coverage_regex, + :build_git_strategy, + :build_timeout, + :builds_access_level, :ci_config_path, :container_registry_enabled, :default_branch, :description, - :issues_enabled, + :issues_access_level, :lfs_enabled, - :merge_requests_enabled, + :merge_requests_access_level, :merge_method, :name, :only_allow_merge_if_all_discussions_are_resolved, @@ -64,14 +85,24 @@ module API :path, :printing_merge_request_link_enabled, :public_builds, + :repository_access_level, :request_access_enabled, + :resolve_outdated_diff_discussions, :shared_runners_enabled, - :snippets_enabled, + :snippets_access_level, :tag_list, :visibility, - :wiki_enabled, + :wiki_access_level, :avatar, - :external_authorization_classification_label + :external_authorization_classification_label, + + # TODO: remove in API v5, replaced by *_access_level + :issues_enabled, + :jobs_enabled, + :merge_requests_enabled, + :wiki_enabled, + :jobs_enabled, + :snippets_enabled ] end end diff --git a/spec/models/concerns/project_api_compatibility_spec.rb b/spec/models/concerns/project_api_compatibility_spec.rb new file mode 100644 index 00000000000..8cecd4fe7bc --- /dev/null +++ b/spec/models/concerns/project_api_compatibility_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ProjectAPICompatibility do + let(:project) { create(:project) } + + # git_strategy + it "converts build_git_strategy=fetch to build_allow_git_fetch=true" do + project.update!(build_git_strategy: 'fetch') + expect(project.build_allow_git_fetch).to eq(true) + end + + it "converts build_git_strategy=clone to build_allow_git_fetch=false" do + project.update!(build_git_strategy: 'clone') + expect(project.build_allow_git_fetch).to eq(false) + end + + # auto_devops_enabled + it "converts auto_devops_enabled=false to auto_devops_enabled?=false" do + expect(project.auto_devops_enabled?).to eq(true) + project.update!(auto_devops_enabled: false) + expect(project.auto_devops_enabled?).to eq(false) + end + + it "converts auto_devops_enabled=true to auto_devops_enabled?=true" do + expect(project.auto_devops_enabled?).to eq(true) + project.update!(auto_devops_enabled: true) + expect(project.auto_devops_enabled?).to eq(true) + end + + # auto_devops_deploy_strategy + it "converts auto_devops_deploy_strategy=timed_incremental to auto_devops.deploy_strategy=timed_incremental" do + expect(project.auto_devops).to be_nil + project.update!(auto_devops_deploy_strategy: 'timed_incremental') + expect(project.auto_devops.deploy_strategy).to eq('timed_incremental') + end +end diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 5aa43b58217..1fe176ab5af 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -4,7 +4,8 @@ require 'spec_helper' describe ProjectFeaturesCompatibility do let(:project) { create(:project) } - let(:features) { %w(issues wiki builds merge_requests snippets) } + let(:features_except_repository) { %w(issues wiki builds merge_requests snippets) } + let(:features) { features_except_repository + ['repository'] } # We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table # All those fields got moved to a new table called project_feature and are now integers instead of booleans @@ -12,30 +13,37 @@ describe ProjectFeaturesCompatibility do # So we can keep it compatible it "converts fields from 'true' to ProjectFeature::ENABLED" do - features.each do |feature| + features_except_repository.each do |feature| project.update_attribute("#{feature}_enabled".to_sym, "true") expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::ENABLED) end end it "converts fields from 'false' to ProjectFeature::DISABLED" do - features.each do |feature| + features_except_repository.each do |feature| project.update_attribute("#{feature}_enabled".to_sym, "false") expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::DISABLED) end end it "converts fields from true to ProjectFeature::ENABLED" do - features.each do |feature| + features_except_repository.each do |feature| project.update_attribute("#{feature}_enabled".to_sym, true) expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::ENABLED) end end it "converts fields from false to ProjectFeature::DISABLED" do - features.each do |feature| + features_except_repository.each do |feature| project.update_attribute("#{feature}_enabled".to_sym, false) expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::DISABLED) end end + + it "accepts private as ProjectFeature::PRIVATE" do + features.each do |feature| + project.update!("#{feature}_access_level".to_sym => 'private') + expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::PRIVATE) + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index c67412a44c1..a2aae257352 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1102,6 +1102,12 @@ describe API::Projects do expect(json_response['wiki_enabled']).to be_present expect(json_response['jobs_enabled']).to be_present expect(json_response['snippets_enabled']).to be_present + expect(json_response['snippets_access_level']).to be_present + expect(json_response['repository_access_level']).to be_present + expect(json_response['issues_access_level']).to be_present + expect(json_response['merge_requests_access_level']).to be_present + expect(json_response['wiki_access_level']).to be_present + expect(json_response['builds_access_level']).to be_present expect(json_response['resolve_outdated_diff_discussions']).to eq(project.resolve_outdated_diff_discussions) expect(json_response['container_registry_enabled']).to be_present expect(json_response['created_at']).to be_present @@ -1913,6 +1919,34 @@ describe API::Projects do end end + it 'updates builds_access_level' do + project_param = { builds_access_level: 'private' } + + put api("/projects/#{project3.id}", user), params: project_param + + expect(response).to have_gitlab_http_status(200) + + expect(json_response['builds_access_level']).to eq('private') + end + + it 'updates build_git_strategy' do + project_param = { build_git_strategy: 'clone' } + + put api("/projects/#{project3.id}", user), params: project_param + + expect(response).to have_gitlab_http_status(200) + + expect(json_response['build_git_strategy']).to eq('clone') + end + + it 'rejects to update build_git_strategy when build_git_strategy is invalid' do + project_param = { build_git_strategy: 'invalid' } + + put api("/projects/#{project3.id}", user), params: project_param + + expect(response).to have_gitlab_http_status(400) + end + it 'updates merge_method' do project_param = { merge_method: 'ff' } @@ -1946,6 +1980,26 @@ describe API::Projects do '-/system/project/avatar/'\ "#{project3.id}/banana_sample.gif") end + + it 'updates auto_devops_deploy_strategy' do + project_param = { auto_devops_deploy_strategy: 'timed_incremental' } + + put api("/projects/#{project3.id}", user), params: project_param + + expect(response).to have_gitlab_http_status(200) + + expect(json_response['auto_devops_deploy_strategy']).to eq('timed_incremental') + end + + it 'updates auto_devops_enabled' do + project_param = { auto_devops_enabled: false } + + put api("/projects/#{project3.id}", user), params: project_param + + expect(response).to have_gitlab_http_status(200) + + expect(json_response['auto_devops_enabled']).to eq(false) + end end context 'when authenticated as project maintainer' do |