Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
020afca749
commit
081c20deca
9 changed files with 123 additions and 117 deletions
|
@ -4,6 +4,7 @@ import {
|
||||||
DIFF_FILE_MANUAL_COLLAPSE,
|
DIFF_FILE_MANUAL_COLLAPSE,
|
||||||
DIFF_FILE_AUTOMATIC_COLLAPSE,
|
DIFF_FILE_AUTOMATIC_COLLAPSE,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
import { getDerivedMergeRequestInformation } from './merge_request';
|
||||||
import { uuids } from './uuids';
|
import { uuids } from './uuids';
|
||||||
|
|
||||||
function fileSymlinkInformation(file, fileList) {
|
function fileSymlinkInformation(file, fileList) {
|
||||||
|
@ -34,8 +35,12 @@ function collapsed(file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function identifier(file) {
|
function identifier(file) {
|
||||||
|
const { userOrGroup, project, id } = getDerivedMergeRequestInformation({
|
||||||
|
endpoint: file.load_collapsed_diff_url,
|
||||||
|
});
|
||||||
|
|
||||||
return uuids({
|
return uuids({
|
||||||
seeds: [file.file_identifier_hash, file.blob?.id],
|
seeds: [userOrGroup, project, id, file.file_identifier_hash, file.blob?.id],
|
||||||
})[0];
|
})[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +53,10 @@ export function prepareRawDiffFile({ file, allFiles, meta = false }) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// It's possible, but not confirmed, that `content_sha` isn't available sometimes
|
// It's possible, but not confirmed, that `blob.id` isn't available sometimes
|
||||||
// See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49506#note_464692057
|
// See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49506#note_464692057
|
||||||
// We don't want duplicate IDs if that's the case, so we just don't assign an ID
|
// We don't want duplicate IDs if that's the case, so we just don't assign an ID
|
||||||
if (!meta && file.blob?.id) {
|
if (!meta && file.blob?.id && file.load_collapsed_diff_url) {
|
||||||
additionalProperties.id = identifier(file);
|
additionalProperties.id = identifier(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
const endpointRE = /^(\/?(.+?)\/(.+?)\/-\/merge_requests\/(\d+)).*$/i;
|
||||||
|
|
||||||
export function getDerivedMergeRequestInformation({ endpoint } = {}) {
|
export function getDerivedMergeRequestInformation({ endpoint } = {}) {
|
||||||
const mrPath = endpoint
|
let mrPath;
|
||||||
?.split('/')
|
let userOrGroup;
|
||||||
.slice(0, -1)
|
let project;
|
||||||
.join('/');
|
let id;
|
||||||
|
const matches = endpointRE.exec(endpoint);
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
[, mrPath, userOrGroup, project, id] = matches;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mrPath,
|
mrPath,
|
||||||
|
userOrGroup,
|
||||||
|
project,
|
||||||
|
id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,76 +26,6 @@ module VisibilityLevelHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def project_visibility_level_description(level)
|
|
||||||
case level
|
|
||||||
when Gitlab::VisibilityLevel::PRIVATE
|
|
||||||
_("Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.")
|
|
||||||
when Gitlab::VisibilityLevel::INTERNAL
|
|
||||||
_("The project can be accessed by any logged in user except external users.")
|
|
||||||
when Gitlab::VisibilityLevel::PUBLIC
|
|
||||||
_("The project can be accessed without any authentication.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def group_visibility_level_description(level)
|
|
||||||
case level
|
|
||||||
when Gitlab::VisibilityLevel::PRIVATE
|
|
||||||
_("The group and its projects can only be viewed by members.")
|
|
||||||
when Gitlab::VisibilityLevel::INTERNAL
|
|
||||||
_("The group and any internal projects can be viewed by any logged in user except external users.")
|
|
||||||
when Gitlab::VisibilityLevel::PUBLIC
|
|
||||||
_("The group and any public projects can be viewed without any authentication.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Note: these messages closely mirror the form validation strings found in the project
|
|
||||||
# model and any changes or additons to these may also need to be made there.
|
|
||||||
def disallowed_project_visibility_level_description(level, project)
|
|
||||||
level_name = Gitlab::VisibilityLevel.level_name(level).downcase
|
|
||||||
reasons = []
|
|
||||||
instructions = []
|
|
||||||
|
|
||||||
unless project.visibility_level_allowed_as_fork?(level)
|
|
||||||
reasons << "the fork source project has lower visibility"
|
|
||||||
end
|
|
||||||
|
|
||||||
unless project.visibility_level_allowed_by_group?(level)
|
|
||||||
errors = visibility_level_errors_for_group(project.group, level_name)
|
|
||||||
|
|
||||||
reasons << errors[:reason]
|
|
||||||
instructions << errors[:instruction]
|
|
||||||
end
|
|
||||||
|
|
||||||
reasons = reasons.any? ? ' because ' + reasons.to_sentence : ''
|
|
||||||
"This project cannot be #{level_name}#{reasons}.#{instructions.join}".html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
# Note: these messages closely mirror the form validation strings found in the group
|
|
||||||
# model and any changes or additons to these may also need to be made there.
|
|
||||||
def disallowed_group_visibility_level_description(level, group)
|
|
||||||
level_name = Gitlab::VisibilityLevel.level_name(level).downcase
|
|
||||||
reasons = []
|
|
||||||
instructions = []
|
|
||||||
|
|
||||||
unless group.visibility_level_allowed_by_projects?(level)
|
|
||||||
reasons << "it contains projects with higher visibility"
|
|
||||||
end
|
|
||||||
|
|
||||||
unless group.visibility_level_allowed_by_sub_groups?(level)
|
|
||||||
reasons << "it contains sub-groups with higher visibility"
|
|
||||||
end
|
|
||||||
|
|
||||||
unless group.visibility_level_allowed_by_parent?(level)
|
|
||||||
errors = visibility_level_errors_for_group(group.parent, level_name)
|
|
||||||
|
|
||||||
reasons << errors[:reason]
|
|
||||||
instructions << errors[:instruction]
|
|
||||||
end
|
|
||||||
|
|
||||||
reasons = reasons.any? ? ' because ' + reasons.to_sentence : ''
|
|
||||||
"This group cannot be #{level_name}#{reasons}.#{instructions.join}".html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def visibility_icon_description(form_model)
|
def visibility_icon_description(form_model)
|
||||||
if form_model.respond_to?(:visibility_level_allowed_as_fork?)
|
if form_model.respond_to?(:visibility_level_allowed_as_fork?)
|
||||||
project_visibility_icon_description(form_model.visibility_level)
|
project_visibility_icon_description(form_model.visibility_level)
|
||||||
|
@ -104,14 +34,6 @@ module VisibilityLevelHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def group_visibility_icon_description(level)
|
|
||||||
"#{visibility_level_label(level)} - #{group_visibility_level_description(level)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def project_visibility_icon_description(level)
|
|
||||||
"#{visibility_level_label(level)} - #{project_visibility_level_description(level)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def visibility_level_label(level)
|
def visibility_level_label(level)
|
||||||
# The visibility level can be:
|
# The visibility level can be:
|
||||||
# 'VisibilityLevel|Private', 'VisibilityLevel|Internal', 'VisibilityLevel|Public'
|
# 'VisibilityLevel|Private', 'VisibilityLevel|Internal', 'VisibilityLevel|Public'
|
||||||
|
@ -203,11 +125,33 @@ module VisibilityLevelHelper
|
||||||
current_level
|
current_level
|
||||||
end
|
end
|
||||||
|
|
||||||
def visibility_level_errors_for_group(group, level_name)
|
def project_visibility_level_description(level)
|
||||||
group_name = link_to group.name, group_path(group)
|
case level
|
||||||
change_visibility = link_to 'change the visibility', edit_group_path(group)
|
when Gitlab::VisibilityLevel::PRIVATE
|
||||||
|
_("Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.")
|
||||||
|
when Gitlab::VisibilityLevel::INTERNAL
|
||||||
|
_("The project can be accessed by any logged in user except external users.")
|
||||||
|
when Gitlab::VisibilityLevel::PUBLIC
|
||||||
|
_("The project can be accessed without any authentication.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
{ reason: "the visibility of #{group_name} is #{group.visibility}",
|
def group_visibility_level_description(level)
|
||||||
instruction: " To make this group #{level_name}, you must first #{change_visibility} of the parent group." }
|
case level
|
||||||
|
when Gitlab::VisibilityLevel::PRIVATE
|
||||||
|
_("The group and its projects can only be viewed by members.")
|
||||||
|
when Gitlab::VisibilityLevel::INTERNAL
|
||||||
|
_("The group and any internal projects can be viewed by any logged in user except external users.")
|
||||||
|
when Gitlab::VisibilityLevel::PUBLIC
|
||||||
|
_("The group and any public projects can be viewed without any authentication.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def project_visibility_icon_description(level)
|
||||||
|
"#{visibility_level_label(level)} - #{project_visibility_level_description(level)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_visibility_icon_description(level)
|
||||||
|
"#{visibility_level_label(level)} - #{group_visibility_level_description(level)}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -493,6 +493,8 @@ An alternative is the open source community-maintained tool [BFG](https://rtyley
|
||||||
Keep in mind that these tools are faster because they do not provide the same
|
Keep in mind that these tools are faster because they do not provide the same
|
||||||
feature set as `git filter-branch` does, but focus on specific use cases.
|
feature set as `git filter-branch` does, but focus on specific use cases.
|
||||||
|
|
||||||
|
Refer [Reduce repository size](../../../user/project/repository/reducing_the_repo_size_using_git.md) page to know more about purging files from repository history & GitLab storage.
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
There are various options of undoing your work with any version control system, but
|
There are various options of undoing your work with any version control system, but
|
||||||
|
|
|
@ -94,6 +94,7 @@ module Gitlab
|
||||||
when :engineering_productivity
|
when :engineering_productivity
|
||||||
return false unless role[/Engineering Productivity/]
|
return false unless role[/Engineering Productivity/]
|
||||||
return true if kind == :reviewer
|
return true if kind == :reviewer
|
||||||
|
return true if capabilities(project).include?("#{kind} engineering_productivity")
|
||||||
|
|
||||||
capabilities(project).include?("#{kind} backend")
|
capabilities(project).include?("#{kind} backend")
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { prepareRawDiffFile } from '~/diffs/utils/diff_file';
|
import { prepareRawDiffFile } from '~/diffs/utils/diff_file';
|
||||||
|
|
||||||
function getDiffFiles() {
|
function getDiffFiles() {
|
||||||
|
const loadFull = 'namespace/project/-/merge_requests/12345/diff_for_path?file_identifier=abc';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
blob: {
|
blob: {
|
||||||
|
@ -8,6 +10,7 @@ function getDiffFiles() {
|
||||||
},
|
},
|
||||||
file_hash: 'ABC', // This file is just a normal file
|
file_hash: 'ABC', // This file is just a normal file
|
||||||
file_identifier_hash: 'ABC1',
|
file_identifier_hash: 'ABC1',
|
||||||
|
load_collapsed_diff_url: loadFull,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
blob: {
|
blob: {
|
||||||
|
@ -15,6 +18,7 @@ function getDiffFiles() {
|
||||||
},
|
},
|
||||||
file_hash: 'DEF', // This file replaces a symlink
|
file_hash: 'DEF', // This file replaces a symlink
|
||||||
file_identifier_hash: 'DEF1',
|
file_identifier_hash: 'DEF1',
|
||||||
|
load_collapsed_diff_url: loadFull,
|
||||||
a_mode: '0',
|
a_mode: '0',
|
||||||
b_mode: '0755',
|
b_mode: '0755',
|
||||||
},
|
},
|
||||||
|
@ -24,6 +28,7 @@ function getDiffFiles() {
|
||||||
},
|
},
|
||||||
file_hash: 'DEF', // This symlink is replaced by a file
|
file_hash: 'DEF', // This symlink is replaced by a file
|
||||||
file_identifier_hash: 'DEF2',
|
file_identifier_hash: 'DEF2',
|
||||||
|
load_collapsed_diff_url: loadFull,
|
||||||
a_mode: '120000',
|
a_mode: '120000',
|
||||||
b_mode: '0',
|
b_mode: '0',
|
||||||
},
|
},
|
||||||
|
@ -33,6 +38,7 @@ function getDiffFiles() {
|
||||||
},
|
},
|
||||||
file_hash: 'GHI', // This symlink replaces a file
|
file_hash: 'GHI', // This symlink replaces a file
|
||||||
file_identifier_hash: 'GHI1',
|
file_identifier_hash: 'GHI1',
|
||||||
|
load_collapsed_diff_url: loadFull,
|
||||||
a_mode: '0',
|
a_mode: '0',
|
||||||
b_mode: '120000',
|
b_mode: '120000',
|
||||||
},
|
},
|
||||||
|
@ -42,6 +48,7 @@ function getDiffFiles() {
|
||||||
},
|
},
|
||||||
file_hash: 'GHI', // This file is replaced by a symlink
|
file_hash: 'GHI', // This file is replaced by a symlink
|
||||||
file_identifier_hash: 'GHI2',
|
file_identifier_hash: 'GHI2',
|
||||||
|
load_collapsed_diff_url: loadFull,
|
||||||
a_mode: '0755',
|
a_mode: '0755',
|
||||||
b_mode: '0',
|
b_mode: '0',
|
||||||
},
|
},
|
||||||
|
@ -86,11 +93,11 @@ describe('diff_file utilities', () => {
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
fileIndex | id
|
fileIndex | id
|
||||||
${0} | ${'8dcd585e-a421-4dab-a04e-6f88c81b7b4c'}
|
${0} | ${'68296a4f-f1c7-445a-bd0e-6e3b02c4eec0'}
|
||||||
${1} | ${'3f178b78-392b-44a4-bd7d-5d6192208a97'}
|
${1} | ${'051c9bb8-cdba-4eb7-b8d1-508906e6d8ba'}
|
||||||
${2} | ${'3d9e1354-cddf-4a11-8234-f0413521b2e5'}
|
${2} | ${'ed3d53d5-5da0-412d-a3c6-7213f84e88d3'}
|
||||||
${3} | ${'460f005b-d29d-43c1-9a08-099a7c7f08de'}
|
${3} | ${'39d998dc-bc69-4b19-a6af-41e4369c2bd5'}
|
||||||
${4} | ${'d8c89733-6ce1-4455-ae3d-f8aad6ee99f9'}
|
${4} | ${'7072d115-ce39-423c-8346-9fcad58cd68e'}
|
||||||
`('sets the file id properly { id: $id } on normal diff files', ({ fileIndex, id }) => {
|
`('sets the file id properly { id: $id } on normal diff files', ({ fileIndex, id }) => {
|
||||||
const preppedFile = prepareRawDiffFile({
|
const preppedFile = prepareRawDiffFile({
|
||||||
file: files[fileIndex],
|
file: files[fileIndex],
|
||||||
|
@ -122,5 +129,18 @@ describe('diff_file utilities', () => {
|
||||||
|
|
||||||
expect(preppedFile).not.toHaveProp('id');
|
expect(preppedFile).not.toHaveProp('id');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not set the id property if the file is missing a `load_collapsed_diff_url` property', () => {
|
||||||
|
const fileMissingContentSha = { ...files[0] };
|
||||||
|
|
||||||
|
delete fileMissingContentSha.load_collapsed_diff_url;
|
||||||
|
|
||||||
|
const preppedFile = prepareRawDiffFile({
|
||||||
|
file: fileMissingContentSha,
|
||||||
|
allFiles: files,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(preppedFile).not.toHaveProp('id');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,16 +2,28 @@ import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request';
|
||||||
import { diffMetadata } from '../mock_data/diff_metadata';
|
import { diffMetadata } from '../mock_data/diff_metadata';
|
||||||
|
|
||||||
describe('Merge Request utilities', () => {
|
describe('Merge Request utilities', () => {
|
||||||
|
const derivedMrInfo = {
|
||||||
|
mrPath: '/gitlab-org/gitlab-test/-/merge_requests/4',
|
||||||
|
userOrGroup: 'gitlab-org',
|
||||||
|
project: 'gitlab-test',
|
||||||
|
id: '4',
|
||||||
|
};
|
||||||
|
const unparseableEndpoint = {
|
||||||
|
mrPath: undefined,
|
||||||
|
userOrGroup: undefined,
|
||||||
|
project: undefined,
|
||||||
|
id: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
describe('getDerivedMergeRequestInformation', () => {
|
describe('getDerivedMergeRequestInformation', () => {
|
||||||
const endpoint = `${diffMetadata.latest_version_path}.json?searchParam=irrelevant`;
|
const endpoint = `${diffMetadata.latest_version_path}.json?searchParam=irrelevant`;
|
||||||
const mrPath = diffMetadata.latest_version_path.replace(/\/diffs$/, '');
|
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
argument | response
|
argument | response
|
||||||
${{ endpoint }} | ${{ mrPath }}
|
${{ endpoint }} | ${derivedMrInfo}
|
||||||
${{}} | ${{ mrPath: undefined }}
|
${{}} | ${unparseableEndpoint}
|
||||||
${{ endpoint: undefined }} | ${{ mrPath: undefined }}
|
${{ endpoint: undefined }} | ${unparseableEndpoint}
|
||||||
${{ endpoint: null }} | ${{ mrPath: undefined }}
|
${{ endpoint: null }} | ${unparseableEndpoint}
|
||||||
`('generates the correct derived results based on $argument', ({ argument, response }) => {
|
`('generates the correct derived results based on $argument', ({ argument, response }) => {
|
||||||
expect(getDerivedMergeRequestInformation(argument)).toStrictEqual(response);
|
expect(getDerivedMergeRequestInformation(argument)).toStrictEqual(response);
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,29 +35,33 @@ RSpec.describe VisibilityLevelHelper do
|
||||||
|
|
||||||
describe 'visibility_level_description' do
|
describe 'visibility_level_description' do
|
||||||
context 'used with a Project' do
|
context 'used with a Project' do
|
||||||
it 'delegates projects to #project_visibility_level_description' do
|
let(:descriptions) do
|
||||||
expect(visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, project))
|
[
|
||||||
.to match /project/i
|
visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, project),
|
||||||
|
visibility_level_description(Gitlab::VisibilityLevel::INTERNAL, project),
|
||||||
|
visibility_level_description(Gitlab::VisibilityLevel::PUBLIC, project)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns different project related descriptions depending on visibility level' do
|
||||||
|
expect(descriptions.uniq.size).to eq(descriptions.size)
|
||||||
|
expect(descriptions).to all match /project/i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'used with a Group' do
|
context 'used with a Group' do
|
||||||
it 'delegates groups to #group_visibility_level_description' do
|
let(:descriptions) do
|
||||||
expect(visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, group))
|
[
|
||||||
.to match /group/i
|
visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, group),
|
||||||
|
visibility_level_description(Gitlab::VisibilityLevel::INTERNAL, group),
|
||||||
|
visibility_level_description(Gitlab::VisibilityLevel::PUBLIC, group)
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#project_visibility_level_description" do
|
it 'returns different group related descriptions depending on visibility level' do
|
||||||
it "describes private projects" do
|
expect(descriptions.uniq.size).to eq(descriptions.size)
|
||||||
expect(project_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE))
|
expect(descriptions).to all match /group/i
|
||||||
.to eq _('Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.')
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it "describes public projects" do
|
|
||||||
expect(project_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC))
|
|
||||||
.to eq _('The project can be accessed without any authentication.')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,14 @@ RSpec.describe Gitlab::Danger::Teammate do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when capabilities include maintainer engineering productivity' do
|
||||||
|
let(:capabilities) { ['maintainer engineering_productivity'] }
|
||||||
|
|
||||||
|
it '#maintainer? returns true' do
|
||||||
|
expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when capabilities include trainee_maintainer backend' do
|
context 'when capabilities include trainee_maintainer backend' do
|
||||||
let(:capabilities) { ['trainee_maintainer backend'] }
|
let(:capabilities) { ['trainee_maintainer backend'] }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue