diff options
27 files changed, 337 insertions, 55 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index cdd063a6b05..346c1d77024 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -6ecbf56693083f1a872a53ad6accfc7d0d806718 +d950585cb9763c6014ae2c9b7c4f4923d90c9f81 diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index bf4ba6520ea..9dafbf994eb 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -13.19.1 +13.21.0 diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index 897f6ce393e..5fbd83a39a9 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -1,6 +1,5 @@ <script> -/* eslint-disable @gitlab/vue-require-i18n-strings */ -import { GlTooltipDirective, GlIcon, GlLink } from '@gitlab/ui'; +import { GlTooltipDirective, GlIcon, GlLink, GlSprintf } from '@gitlab/ui'; import { isEmpty } from 'lodash'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { __, s__, sprintf } from '~/locale'; @@ -32,6 +31,7 @@ export default { ExternalUrlComponent, GlIcon, GlLink, + GlSprintf, MonitoringButtonComponent, PinComponent, DeleteComponent, @@ -647,14 +647,17 @@ export default { </span> <span v-if="!isFolder && deploymentHasUser" class="text-break-word"> - by - <user-avatar-link - :link-href="deploymentUser.web_url" - :img-src="deploymentUser.avatar_url" - :img-alt="userImageAltDescription" - :tooltip-text="deploymentUser.username" - class="js-deploy-user-container float-none" - /> + <gl-sprintf :message="s__('Environments|by %{avatar}')"> + <template #avatar> + <user-avatar-link + :link-href="deploymentUser.web_url" + :img-src="deploymentUser.avatar_url" + :img-alt="userImageAltDescription" + :tooltip-text="deploymentUser.username" + class="js-deploy-user-container float-none" + /> + </template> + </gl-sprintf> </span> <div v-if="showNoDeployments" class="commit-title table-mobile-content"> @@ -743,13 +746,16 @@ export default { </div> <div class="gl-display-flex"> <span v-if="upcomingDeployment.user" class="text-break-word"> - by - <user-avatar-link - :link-href="upcomingDeployment.user.web_url" - :img-src="upcomingDeployment.user.avatar_url" - :img-alt="upcomingDeploymentUserImageAltDescription" - :tooltip-text="upcomingDeployment.user.username" - /> + <gl-sprintf :message="s__('Environments|by %{avatar}')"> + <template #avatar> + <user-avatar-link + :link-href="upcomingDeployment.user.web_url" + :img-src="upcomingDeployment.user.avatar_url" + :img-alt="upcomingDeploymentUserImageAltDescription" + :tooltip-text="upcomingDeployment.user.username" + /> + </template> + </gl-sprintf> </span> </div> </div> diff --git a/app/assets/javascripts/pages/groups/new/index.js b/app/assets/javascripts/pages/groups/new/index.js index 7557edb1b49..7b0418e1ad5 100644 --- a/app/assets/javascripts/pages/groups/new/index.js +++ b/app/assets/javascripts/pages/groups/new/index.js @@ -5,6 +5,7 @@ import Group from '~/group'; import { parseBoolean } from '~/lib/utils/common_utils'; import NewGroupCreationApp from './components/app.vue'; import GroupPathValidator from './group_path_validator'; +import initToggleInviteMembers from './toggle_invite_members'; new GroupPathValidator(); // eslint-disable-line no-new @@ -31,3 +32,5 @@ function initNewGroupCreation(el) { const el = document.querySelector('.js-new-group-creation'); initNewGroupCreation(el); + +initToggleInviteMembers(); diff --git a/app/assets/javascripts/pages/groups/new/toggle_invite_members.js b/app/assets/javascripts/pages/groups/new/toggle_invite_members.js new file mode 100644 index 00000000000..ffb4964cf7d --- /dev/null +++ b/app/assets/javascripts/pages/groups/new/toggle_invite_members.js @@ -0,0 +1,14 @@ +import { parseBoolean } from '~/lib/utils/common_utils'; + +export default function initToggleInviteMembers() { + const inviteMembersSection = document.querySelector('.js-invite-members-section'); + const setupForCompanyRadios = document.querySelectorAll('input[name="group[setup_for_company]"]'); + + if (inviteMembersSection && setupForCompanyRadios.length) { + setupForCompanyRadios.forEach((el) => { + el.addEventListener('change', (event) => { + inviteMembersSection.classList.toggle('hidden', !parseBoolean(event.target.value)); + }); + }); + } +} diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 2796760fbe1..8a3c72ae4f8 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -64,6 +64,7 @@ class GroupsController < Groups::ApplicationController def new @group = Group.new(params.permit(:parent_id)) + @group.build_namespace_settings end def create @@ -269,7 +270,9 @@ class GroupsController < Groups::ApplicationController :default_branch_name, :allow_mfa_for_subgroups, :resource_access_token_creation_allowed, - :prevent_sharing_groups_outside_hierarchy + :prevent_sharing_groups_outside_hierarchy, + :setup_for_company, + :jobs_to_be_done ] end @@ -342,7 +345,15 @@ class GroupsController < Groups::ApplicationController render action: 'new' end - def successful_creation_hooks; end + def successful_creation_hooks + update_user_role_and_setup_for_company + end + + def update_user_role_and_setup_for_company + user_params = params.fetch(:user, {}).permit(:role) + user_params[:setup_for_company] = @group.setup_for_company if !@group.setup_for_company.nil? && current_user.setup_for_company.nil? + Users::UpdateService.new(current_user, user_params.merge(user: current_user)).execute if user_params.present? + end def groups if @group.supports_events? diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 0fdb8b07260..0d9f57e199b 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -219,6 +219,18 @@ module GroupsHelper def group_url_error_message s_('GroupSettings|Please choose a group URL with no special characters or spaces.') end + + # Maps `jobs_to_be_done` values to option texts + def localized_jobs_to_be_done_choices + { + basics: _('I want to learn the basics of Git'), + move_repository: _('I want to move my repository to GitLab from somewhere else'), + code_storage: _('I want to store my code'), + exploring: _('I want to explore GitLab to see if it’s worth switching to'), + ci: _('I want to use GitLab CI with my existing repository'), + other: _('A different reason') + }.with_indifferent_access.freeze + end end GroupsHelper.prepend_mod_with('GroupsHelper') diff --git a/app/models/group.rb b/app/models/group.rb index ce19857dad6..4ded7174619 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -81,7 +81,7 @@ class Group < Namespace # debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads has_many :debian_distributions, class_name: 'Packages::Debian::GroupDistribution', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent - delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, to: :namespace_settings + delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings accepts_nested_attributes_for :variables, allow_destroy: true diff --git a/app/models/namespace_setting.rb b/app/models/namespace_setting.rb index 4a39bfebda0..08228b56f25 100644 --- a/app/models/namespace_setting.rb +++ b/app/models/namespace_setting.rb @@ -16,9 +16,12 @@ class NamespaceSetting < ApplicationRecord before_validation :normalize_default_branch_name + enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true + NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal, :lock_delayed_project_removal, :resource_access_token_creation_allowed, - :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap].freeze + :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, + :setup_for_company, :jobs_to_be_done].freeze self.primary_key = :namespace_id diff --git a/app/views/groups/_new_group_fields.html.haml b/app/views/groups/_new_group_fields.html.haml index 49c8c2700ce..8ee7c91a938 100644 --- a/app/views/groups/_new_group_fields.html.haml +++ b/app/views/groups/_new_group_fields.html.haml @@ -13,7 +13,10 @@ - if Gitlab.config.mattermost.enabled .row = render 'create_chat_team', f: f -.row + += render 'personalize', f: f + +.row.js-invite-members-section .col-sm-4 = render_if_exists 'shared/groups/invite_members' diff --git a/app/views/groups/_personalize.html.haml b/app/views/groups/_personalize.html.haml new file mode 100644 index 00000000000..5ecb0017cd8 --- /dev/null +++ b/app/views/groups/_personalize.html.haml @@ -0,0 +1,27 @@ +.row + .form-group.col-sm-12.gl-mb-0 + %label.label-bold + = _('Now, personalize your GitLab experience') + %p + = _("We'll use this to help surface the right features and information to you.") + +.row + .form-group.col-sm-4 + = label :user, :role, _('Role') + = select :user, :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { selected: @current_user.role }, class: 'form-control' + +.row + .form-group.col-sm-4 + = f.label :setup_for_company, _('Who will be using this group?') + .gl-display-flex.gl-flex-direction-column.gl-lg-flex-direction-row + .gl-flex-grow-1.gl-display-flex.gl-align-items-center + = f.radio_button :setup_for_company, true, checked: true + = f.label :setup_for_company, _('My company or team'), class: 'gl-font-weight-normal gl-mb-0 gl-ml-2', value: 'true' + .gl-flex-grow-1.gl-display-flex.gl-align-items-center + = f.radio_button :setup_for_company, false + = f.label :setup_for_company, _('Just me'), class: 'gl-font-weight-normal gl-mb-0 gl-ml-2', value: 'false' + +.row + .form-group.col-sm-4 + = f.label :jobs_to_be_done, _("What will you use this group for?") + = f.select :jobs_to_be_done, ::NamespaceSetting.jobs_to_be_dones.keys.map { |job_to_be_done| [localized_jobs_to_be_done_choices[job_to_be_done], job_to_be_done] }, { include_blank: true }, class: 'form-control' diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml index 683e70248b6..ee84da96ec2 100644 --- a/app/views/groups/settings/_permissions.html.haml +++ b/app/views/groups/settings/_permissions.html.haml @@ -4,8 +4,9 @@ %fieldset %h5= _('Permissions') - .form-group - = render 'shared/allow_request_access', form: f + - unless ::Feature.enabled?(:saas_user_caps) + .form-group + = render 'shared/allow_request_access', form: f - if @group.root? .form-group.gl-mb-3 @@ -43,5 +44,6 @@ = render_if_exists 'groups/settings/prevent_forking', f: f, group: @group = render 'groups/settings/two_factor_auth', f: f, group: @group = render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group + = render_if_exists 'groups/settings/membership', f: f = render_if_exists 'groups/member_lock_setting', f: f, group: @group = f.submit _('Save changes'), class: 'btn gl-button btn-confirm gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' } diff --git a/config/feature_flags/development/ci_idempotent_pipeline_process_worker.yml b/config/feature_flags/development/ci_idempotent_pipeline_process_worker.yml index db6aa3e88ff..60104bd3109 100644 --- a/config/feature_flags/development/ci_idempotent_pipeline_process_worker.yml +++ b/config/feature_flags/development/ci_idempotent_pipeline_process_worker.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332963 milestone: '14.0' type: development group: group::pipeline authoring -default_enabled: false +default_enabled: true diff --git a/db/migrate/20210819162047_add_columns_to_namespace_settings.rb b/db/migrate/20210819162047_add_columns_to_namespace_settings.rb new file mode 100644 index 00000000000..f617990582a --- /dev/null +++ b/db/migrate/20210819162047_add_columns_to_namespace_settings.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class AddColumnsToNamespaceSettings < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + def up + with_lock_retries do + add_column :namespace_settings, :setup_for_company, :boolean + add_column :namespace_settings, :jobs_to_be_done, :smallint + end + end + + def down + with_lock_retries do + remove_column :namespace_settings, :setup_for_company + remove_column :namespace_settings, :jobs_to_be_done + end + end +end diff --git a/db/schema_migrations/20210819162047 b/db/schema_migrations/20210819162047 new file mode 100644 index 00000000000..c50e07543da --- /dev/null +++ b/db/schema_migrations/20210819162047 @@ -0,0 +1 @@ +5a02c5a24bb4c7cb63da2e5cc53ff89461f328d0092bb4bb6589223dc4bdae8c
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a35f99f2ab9..608694a2814 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -15344,6 +15344,8 @@ CREATE TABLE namespace_settings ( lock_delayed_project_removal boolean DEFAULT false NOT NULL, prevent_sharing_groups_outside_hierarchy boolean DEFAULT false NOT NULL, new_user_signups_cap integer, + setup_for_company boolean, + jobs_to_be_done smallint, CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)) ); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 4c4ed0ed958..3b09810f59f 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -4472,7 +4472,6 @@ Input type: `VulnerabilityCreateInput` | <a id="mutationvulnerabilitycreateproject"></a>`project` | [`ProjectID!`](#projectid) | ID of the project to attach the vulnerability to. | | <a id="mutationvulnerabilitycreateresolvedat"></a>`resolvedAt` | [`Time`](#time) | Timestamp of when the vulnerability state changed to resolved (defaults to creation time if status is `resolved`). | | <a id="mutationvulnerabilitycreatescannername"></a>`scannerName` | [`String!`](#string) | Name of the security scanner used to discover the vulnerability. | -| <a id="mutationvulnerabilitycreatescannertype"></a>`scannerType` | [`SecurityScannerType!`](#securityscannertype) | Type of the security scanner used to discover the vulnerability. | | <a id="mutationvulnerabilitycreateseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (defaults to `unknown`). | | <a id="mutationvulnerabilitycreatesolution"></a>`solution` | [`String`](#string) | How to fix this vulnerability. | | <a id="mutationvulnerabilitycreatestate"></a>`state` | [`VulnerabilityState`](#vulnerabilitystate) | State of the vulnerability (defaults to `detected`). | diff --git a/doc/user/group/index.md b/doc/user/group/index.md index d4b3b5fbff1..47a3dae088d 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -82,6 +82,10 @@ To create a group: - Underscores - Dashes and dots (it cannot start with dashes or end in a dot) 1. Choose the [visibility level](../../public_access/public_access.md). +1. Personalize your GitLab experience by answering the following questions: + - What is your role? + - Who will be using this group? + - What will you use this group for? 1. Invite GitLab members or other users to join the group. <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> diff --git a/lib/api/lint.rb b/lib/api/lint.rb index 945cdf3edb2..fa871b4bc57 100644 --- a/lib/api/lint.rb +++ b/lib/api/lint.rb @@ -13,18 +13,13 @@ module API post '/lint' do unauthorized! if (Gitlab::CurrentSettings.signup_disabled? || Gitlab::CurrentSettings.signup_limited?) && current_user.nil? - result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute + result = Gitlab::Ci::Lint.new(project: nil, current_user: current_user) + .validate(params[:content], dry_run: false) status 200 - - response = if result.errors.empty? - { status: 'valid', errors: [], warnings: result.warnings } - else - { status: 'invalid', errors: result.errors, warnings: result.warnings } - end - - response.tap do |response| - response[:merged_yaml] = result.merged_yaml if params[:include_merged_yaml] + Entities::Ci::Lint::Result.represent(result, current_user: current_user).serializable_hash.tap do |presented_result| + presented_result[:status] = presented_result[:valid] ? 'valid' : 'invalid' + presented_result.delete(:merged_yaml) unless params[:include_merged_yaml] end end end diff --git a/lib/gitlab/checks/base_single_checker.rb b/lib/gitlab/checks/base_single_checker.rb index f93902055c9..06519833d7c 100644 --- a/lib/gitlab/checks/base_single_checker.rb +++ b/lib/gitlab/checks/base_single_checker.rb @@ -30,5 +30,3 @@ module Gitlab end end end - -Gitlab::Checks::BaseSingleChecker.prepend_mod_with('Gitlab::Checks::BaseSingleChecker') diff --git a/lib/gitlab/checks/changes_access.rb b/lib/gitlab/checks/changes_access.rb index abc5fca9eee..3ce2e50c548 100644 --- a/lib/gitlab/checks/changes_access.rb +++ b/lib/gitlab/checks/changes_access.rb @@ -76,23 +76,33 @@ module Gitlab result end + def single_change_accesses + @single_changes_accesses ||= + changes.map do |change| + commits = + if change[:newrev].blank? || Gitlab::Git.blank_ref?(change[:newrev]) + [] + else + Gitlab::Lazy.new { commits_for(change[:newrev]) } + end + + Checks::SingleChangeAccess.new( + change, + user_access: user_access, + project: project, + protocol: protocol, + logger: logger, + commits: commits + ) + end + end + protected def single_access_checks! # Iterate over all changes to find if user allowed all of them to be applied - changes.each do |change| - commits = Gitlab::Lazy.new { commits_for(change[:newrev]) } - - # If user does not have access to make at least one change, cancel all - # push by allowing the exception to bubble up - Checks::SingleChangeAccess.new( - change, - user_access: user_access, - project: project, - protocol: protocol, - logger: logger, - commits: commits - ).validate! + single_change_accesses.each do |single_change_access| + single_change_access.validate! end end @@ -102,3 +112,5 @@ module Gitlab end end end + +Gitlab::Checks::ChangesAccess.prepend_mod_with('Gitlab::Checks::ChangesAccess') diff --git a/lib/gitlab/ci/lint.rb b/lib/gitlab/ci/lint.rb index cd2c135dd7e..8c1067b9bc6 100644 --- a/lib/gitlab/ci/lint.rb +++ b/lib/gitlab/ci/lint.rb @@ -21,7 +21,7 @@ module Gitlab def initialize(project:, current_user:, sha: nil) @project = project @current_user = current_user - @sha = sha || project.repository.commit&.sha + @sha = sha || project&.repository&.commit&.sha end def validate(content, dry_run: false) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0a7fb8add7e..3437935d2fe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -12911,6 +12911,9 @@ msgstr "" msgid "Environments|Your feedback helps GitLab make environments better for you and other users. Participate and enter a sweepstake to win a USD 30 gift card." msgstr "" +msgid "Environments|by %{avatar}" +msgstr "" + msgid "Environments|protected" msgstr "" @@ -20808,6 +20811,9 @@ msgstr "" msgid "Members of a group may only view projects they have permission to access" msgstr "" +msgid "Membership" +msgstr "" + msgid "Members|%{time} by %{user}" msgstr "" @@ -23071,6 +23077,9 @@ msgstr "" msgid "Novice" msgstr "" +msgid "Now, personalize your GitLab experience" +msgstr "" + msgid "Nuget metadatum must have at least license_url, project_url or icon_url set" msgstr "" @@ -37346,6 +37355,9 @@ msgstr "" msgid "We'll continuously validate your pipeline configuration. The validation results will appear here." msgstr "" +msgid "We'll use this to help surface the right features and information to you." +msgstr "" + msgid "We've found no vulnerabilities" msgstr "" @@ -37601,6 +37613,9 @@ msgstr "" msgid "What is your job title? (optional)" msgstr "" +msgid "What will you use this group for?" +msgstr "" + msgid "What's new" msgstr "" @@ -37660,6 +37675,9 @@ msgstr "" msgid "Who will be using this GitLab trial?" msgstr "" +msgid "Who will be using this group?" +msgstr "" + msgid "Why are you signing up? (Optional)" msgstr "" diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 91b11cd46c5..a7625e65603 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -370,6 +370,57 @@ RSpec.describe GroupsController, factory_default: :keep do end end end + + context 'when creating a group with the `role` attribute present' do + it 'changes the users role' do + sign_in(user) + + expect do + post :create, params: { group: { name: 'new_group', path: 'new_group' }, user: { role: 'devops_engineer' } } + end.to change { user.reload.role }.to('devops_engineer') + end + end + + context 'when creating a group with the `setup_for_company` attribute present' do + before do + sign_in(user) + end + + subject do + post :create, params: { group: { name: 'new_group', path: 'new_group', setup_for_company: 'false' } } + end + + it 'sets the groups `setup_for_company` value' do + subject + expect(Group.last.setup_for_company).to be(false) + end + + context 'when the user already has a value for `setup_for_company`' do + before do + user.update_attribute(:setup_for_company, true) + end + + it 'does not change the users `setup_for_company` value' do + expect(Users::UpdateService).not_to receive(:new) + expect { subject }.not_to change { user.reload.setup_for_company }.from(true) + end + end + + context 'when the user has no value for `setup_for_company`' do + it 'changes the users `setup_for_company` value' do + expect(Users::UpdateService).to receive(:new).and_call_original + expect { subject }.to change { user.reload.setup_for_company }.to(false) + end + end + end + + context 'when creating a group with the `jobs_to_be_done` attribute present' do + it 'sets the groups `jobs_to_be_done` value' do + sign_in(user) + post :create, params: { group: { name: 'new_group', path: 'new_group', jobs_to_be_done: 'other' } } + expect(Group.last.jobs_to_be_done).to eq('other') + end + end end describe 'GET #index' do diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 661b1816548..f2509a4b37f 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -486,4 +486,10 @@ RSpec.describe GroupsHelper do expect(helper.can_admin_group_member?(group)).to be(false) end end + + describe '#localized_jobs_to_be_done_choices' do + it 'has a translation for all `jobs_to_be_done` values' do + expect(localized_jobs_to_be_done_choices.keys).to match_array(NamespaceSetting.jobs_to_be_dones.keys) + end + end end diff --git a/spec/lib/gitlab/checks/changes_access_spec.rb b/spec/lib/gitlab/checks/changes_access_spec.rb index b6914a0a8f1..633c4baa931 100644 --- a/spec/lib/gitlab/checks/changes_access_spec.rb +++ b/spec/lib/gitlab/checks/changes_access_spec.rb @@ -174,6 +174,101 @@ RSpec.describe Gitlab::Checks::ChangesAccess do end end + describe '#single_change_accesses' do + let(:commits_for) { {} } + let(:expected_accesses) { [] } + + shared_examples '#single_change_access' do + before do + commits_for.each do |id, commits| + expect(subject) + .to receive(:commits_for) + .with(id) + .and_return(commits) + end + end + + it 'returns an array of SingleChangeAccess' do + # Commits are wrapped in a Gitlab::Lazy and thus need to be resolved + # first such that we can directly compare types. + actual_accesses = subject.single_change_accesses + .each { |access| access.instance_variable_set(:@commits, access.commits.to_a) } + + expect(actual_accesses).to match_array(expected_accesses) + end + end + + context 'with no changes' do + let(:changes) { [] } + + it_behaves_like '#single_change_access' + end + + context 'with a single change and no new commits' do + let(:commits_for) { { 'new' => [] } } + let(:changes) do + [ + { oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' } + ] + end + + let(:expected_accesses) do + [ + have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: []) + ] + end + + it_behaves_like '#single_change_access' + end + + context 'with a single change and new commits' do + let(:commits_for) { { 'new' => [create_commit('new', [])] } } + let(:changes) do + [ + { oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' } + ] + end + + let(:expected_accesses) do + [ + have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: [create_commit('new', [])]) + ] + end + + it_behaves_like '#single_change_access' + end + + context 'with multiple changes' do + let(:commits_for) do + { + 'a' => [create_commit('a', [])], + 'c' => [create_commit('c', [])], + 'd' => [] + } + end + + let(:changes) do + [ + { newrev: 'a', ref: 'refs/heads/a' }, + { oldrev: 'b', ref: 'refs/heads/b' }, + { oldrev: 'a', newrev: 'c', ref: 'refs/heads/c' }, + { newrev: 'd', ref: 'refs/heads/d' } + ] + end + + let(:expected_accesses) do + [ + have_attributes(newrev: 'a', ref: 'refs/heads/a', commits: [create_commit('a', [])]), + have_attributes(oldrev: 'b', ref: 'refs/heads/b', commits: []), + have_attributes(oldrev: 'a', newrev: 'c', ref: 'refs/heads/c', commits: [create_commit('c', [])]), + have_attributes(newrev: 'd', ref: 'refs/heads/d', commits: []) + ] + end + + it_behaves_like '#single_change_access' + end + end + def create_commit(id, parent_ids) Gitlab::Git::Commit.new(project.repository, { id: id, diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb index 7fe516d3daa..d7f22b9d619 100644 --- a/spec/requests/api/lint_spec.rb +++ b/spec/requests/api/lint_spec.rb @@ -113,7 +113,6 @@ RSpec.describe API::Lint do expect(response).to have_gitlab_http_status(:ok) expect(json_response['status']).to eq('valid') expect(json_response['warnings']).not_to be_empty - expect(json_response['status']).to eq('valid') expect(json_response['errors']).to eq([]) end end |