Commit c38e4ccd authored by Jacques's avatar Jacques

Add canCurrentUserPushToBranch permission

Added canCurrentUserPushToBranch to graphQL

Changelog: added
parent b93d0f11
...@@ -53,6 +53,10 @@ export default { ...@@ -53,6 +53,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
canPushToBranch: {
type: Boolean,
required: true,
},
emptyRepo: { emptyRepo: {
type: Boolean, type: Boolean,
required: true, required: true,
...@@ -126,6 +130,7 @@ export default { ...@@ -126,6 +130,7 @@ export default {
:target-branch="targetBranch || ref" :target-branch="targetBranch || ref"
:original-branch="originalBranch || ref" :original-branch="originalBranch || ref"
:can-push-code="canPushCode" :can-push-code="canPushCode"
:can-push-to-branch="canPushToBranch"
:empty-repo="emptyRepo" :empty-repo="emptyRepo"
/> />
</div> </div>
......
...@@ -106,6 +106,7 @@ export default { ...@@ -106,6 +106,7 @@ export default {
ideForkAndEditPath: '', ideForkAndEditPath: '',
storedExternally: false, storedExternally: false,
canModifyBlob: false, canModifyBlob: false,
canCurrentUserPushToBranch: false,
rawPath: '', rawPath: '',
externalStorageUrl: '', externalStorageUrl: '',
replacePath: '', replacePath: '',
...@@ -266,6 +267,7 @@ export default { ...@@ -266,6 +267,7 @@ export default {
:replace-path="blobInfo.replacePath" :replace-path="blobInfo.replacePath"
:delete-path="blobInfo.webPath" :delete-path="blobInfo.webPath"
:can-push-code="project.userPermissions.pushCode" :can-push-code="project.userPermissions.pushCode"
:can-push-to-branch="blobInfo.canCurrentUserPushToBranch"
:empty-repo="project.repository.empty" :empty-repo="project.repository.empty"
:project-path="projectPath" :project-path="projectPath"
:is-locked="isLocked" :is-locked="isLocked"
......
...@@ -71,6 +71,10 @@ export default { ...@@ -71,6 +71,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
canPushToBranch: {
type: Boolean,
required: true,
},
emptyRepo: { emptyRepo: {
type: Boolean, type: Boolean,
required: true, required: true,
...@@ -176,9 +180,12 @@ export default { ...@@ -176,9 +180,12 @@ export default {
</template> </template>
<template v-else> <template v-else>
<input type="hidden" name="original_branch" :value="originalBranch" /> <input type="hidden" name="original_branch" :value="originalBranch" />
<!-- Once "push to branch" permission is made available, will need to add to conditional <input
Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/335462 --> v-if="createNewMr || !canPushToBranch"
<input v-if="createNewMr" type="hidden" name="create_merge_request" value="1" /> type="hidden"
name="create_merge_request"
value="1"
/>
<gl-form-group <gl-form-group
:label="$options.i18n.COMMIT_LABEL" :label="$options.i18n.COMMIT_LABEL"
label-for="commit_message" label-for="commit_message"
......
...@@ -28,6 +28,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) { ...@@ -28,6 +28,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) {
forkAndEditPath forkAndEditPath
ideForkAndEditPath ideForkAndEditPath
canModifyBlob canModifyBlob
canCurrentUserPushToBranch
storedExternally storedExternally
rawPath rawPath
replacePath replacePath
......
...@@ -91,6 +91,9 @@ module Types ...@@ -91,6 +91,9 @@ module Types
calls_gitaly: true, calls_gitaly: true,
description: 'Whether the current user can modify the blob.' description: 'Whether the current user can modify the blob.'
field :can_current_user_push_to_branch, GraphQL::Types::Boolean, null: true, method: :can_current_user_push_to_branch?,
description: 'Whether the current user can push to the branch.'
def raw_text_blob def raw_text_blob
object.data unless object.binary? object.data unless object.binary?
end end
......
...@@ -78,6 +78,12 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated ...@@ -78,6 +78,12 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
super(blob, project, blob.commit_id) super(blob, project, blob.commit_id)
end end
def can_current_user_push_to_branch?
return false unless current_user && project.repository.branch_exists?(blob.commit_id)
user_access(project).can_push_to_branch?(blob.commit_id)
end
def ide_edit_path def ide_edit_path
super(project, blob.commit_id, blob.path) super(project, blob.commit_id, blob.path)
end end
......
...@@ -14072,6 +14072,7 @@ Returns [`Tree`](#tree). ...@@ -14072,6 +14072,7 @@ Returns [`Tree`](#tree).
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="repositoryblobcancurrentuserpushtobranch"></a>`canCurrentUserPushToBranch` | [`Boolean`](#boolean) | Whether the current user can push to the branch. |
| <a id="repositoryblobcanmodifyblob"></a>`canModifyBlob` | [`Boolean`](#boolean) | Whether the current user can modify the blob. | | <a id="repositoryblobcanmodifyblob"></a>`canModifyBlob` | [`Boolean`](#boolean) | Whether the current user can modify the blob. |
| <a id="repositoryblobeditblobpath"></a>`editBlobPath` | [`String`](#string) | Web path to edit the blob in the old-style editor. | | <a id="repositoryblobeditblobpath"></a>`editBlobPath` | [`String`](#string) | Web path to edit the blob in the old-style editor. |
| <a id="repositoryblobexternalstorageurl"></a>`externalStorageUrl` | [`String`](#string) | Web path to download the raw blob via external storage, if enabled. | | <a id="repositoryblobexternalstorageurl"></a>`externalStorageUrl` | [`String`](#string) | Web path to download the raw blob via external storage, if enabled. |
...@@ -6,6 +6,7 @@ const DEFAULT_PROPS = { ...@@ -6,6 +6,7 @@ const DEFAULT_PROPS = {
name: 'some name', name: 'some name',
path: 'some/path', path: 'some/path',
canPushCode: true, canPushCode: true,
canPushToBranch: true,
replacePath: 'some/replace/path', replacePath: 'some/replace/path',
deletePath: 'some/delete/path', deletePath: 'some/delete/path',
emptyRepo: false, emptyRepo: false,
......
...@@ -9,6 +9,7 @@ const DEFAULT_PROPS = { ...@@ -9,6 +9,7 @@ const DEFAULT_PROPS = {
name: 'some name', name: 'some name',
path: 'some/path', path: 'some/path',
canPushCode: true, canPushCode: true,
canPushToBranch: true,
replacePath: 'some/replace/path', replacePath: 'some/replace/path',
deletePath: 'some/delete/path', deletePath: 'some/delete/path',
emptyRepo: false, emptyRepo: false,
......
...@@ -13,6 +13,7 @@ const initialProps = { ...@@ -13,6 +13,7 @@ const initialProps = {
targetBranch: 'some-target-branch', targetBranch: 'some-target-branch',
originalBranch: 'main', originalBranch: 'main',
canPushCode: true, canPushCode: true,
canPushToBranch: true,
emptyRepo: false, emptyRepo: false,
}; };
...@@ -103,22 +104,25 @@ describe('DeleteBlobModal', () => { ...@@ -103,22 +104,25 @@ describe('DeleteBlobModal', () => {
); );
it.each` it.each`
input | value | emptyRepo | canPushCode | exist input | value | emptyRepo | canPushCode | canPushToBranch | exist
${'authenticity_token'} | ${'mock-csrf-token'} | ${false} | ${true} | ${true} ${'authenticity_token'} | ${'mock-csrf-token'} | ${false} | ${true} | ${true} | ${true}
${'authenticity_token'} | ${'mock-csrf-token'} | ${true} | ${false} | ${true} ${'authenticity_token'} | ${'mock-csrf-token'} | ${true} | ${false} | ${true} | ${true}
${'_method'} | ${'delete'} | ${false} | ${true} | ${true} ${'_method'} | ${'delete'} | ${false} | ${true} | ${true} | ${true}
${'_method'} | ${'delete'} | ${true} | ${false} | ${true} ${'_method'} | ${'delete'} | ${true} | ${false} | ${true} | ${true}
${'original_branch'} | ${initialProps.originalBranch} | ${false} | ${true} | ${true} ${'original_branch'} | ${initialProps.originalBranch} | ${false} | ${true} | ${true} | ${true}
${'original_branch'} | ${undefined} | ${true} | ${true} | ${false} ${'original_branch'} | ${undefined} | ${true} | ${true} | ${true} | ${false}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true} ${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${true} | ${true} ${'create_merge_request'} | ${'1'} | ${false} | ${true} | ${true} | ${true}
${'create_merge_request'} | ${undefined} | ${true} | ${false} | ${false} ${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${false} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true} | ${true}
${'create_merge_request'} | ${undefined} | ${true} | ${false} | ${true} | ${false}
`( `(
'passes $input as a hidden input with the correct value', 'passes $input as a hidden input with the correct value',
({ input, value, emptyRepo, canPushCode, exist }) => { ({ input, value, emptyRepo, canPushCode, canPushToBranch, exist }) => {
createComponent({ createComponent({
emptyRepo, emptyRepo,
canPushCode, canPushCode,
canPushToBranch,
}); });
const inputMethod = findForm().find(`input[name="${input}"]`); const inputMethod = findForm().find(`input[name="${input}"]`);
......
...@@ -11,6 +11,7 @@ export const simpleViewerMock = { ...@@ -11,6 +11,7 @@ export const simpleViewerMock = {
forkAndEditPath: 'some_file.js/fork/edit', forkAndEditPath: 'some_file.js/fork/edit',
ideForkAndEditPath: 'some_file.js/fork/ide', ideForkAndEditPath: 'some_file.js/fork/ide',
canModifyBlob: true, canModifyBlob: true,
canCurrentUserPushToBranch: true,
storedExternally: false, storedExternally: false,
rawPath: 'some_file.js', rawPath: 'some_file.js',
replacePath: 'some_file.js/replace', replacePath: 'some_file.js/replace',
......
...@@ -28,6 +28,7 @@ RSpec.describe Types::Repository::BlobType do ...@@ -28,6 +28,7 @@ RSpec.describe Types::Repository::BlobType do
:rich_viewer, :rich_viewer,
:plain_data, :plain_data,
:can_modify_blob, :can_modify_blob,
:can_current_user_push_to_branch,
:ide_edit_path, :ide_edit_path,
:external_storage_url, :external_storage_url,
:fork_and_edit_path, :fork_and_edit_path,
......
...@@ -31,6 +31,28 @@ RSpec.describe BlobPresenter do ...@@ -31,6 +31,28 @@ RSpec.describe BlobPresenter do
it { expect(presenter.replace_path).to eq("/#{project.full_path}/-/create/#{blob.commit_id}/#{blob.path}") } it { expect(presenter.replace_path).to eq("/#{project.full_path}/-/create/#{blob.commit_id}/#{blob.path}") }
end end
describe '#can_current_user_push_to_branch' do
let(:branch_exists) { true }
before do
allow(project.repository).to receive(:branch_exists?).with(blob.commit_id).and_return(branch_exists)
end
it { expect(presenter.can_current_user_push_to_branch?).to eq(true) }
context 'current_user is nil' do
let(:user) { nil }
it { expect(presenter.can_current_user_push_to_branch?).to eq(false) }
end
context 'branch does not exist' do
let(:branch_exists) { false }
it { expect(presenter.can_current_user_push_to_branch?).to eq(false) }
end
end
describe '#pipeline_editor_path' do describe '#pipeline_editor_path' do
context 'when blob is .gitlab-ci.yml' do context 'when blob is .gitlab-ci.yml' do
before do before do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment