Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-10-25 21:12:12 +00:00
parent 942229d2b4
commit 4d0bc99be4
30 changed files with 329 additions and 39 deletions

View file

@ -193,9 +193,7 @@ graphql-schema-dump:
# Disable warnings in browserslist which can break on backports
# https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
BROWSERSLIST_IGNORE_OLD_DATA: "true"
SETUP_DB: "false"
before_script:
- !reference [.default-before_script, before_script]
- *yarn-install
stage: test

View file

@ -476,7 +476,7 @@ end
gem 'spamcheck', '~> 0.1.0'
# Gitaly GRPC protocol definitions
gem 'gitaly', '~> 14.3.0.pre.rc2'
gem 'gitaly', '~> 14.4.0.pre.rc43'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'

View file

@ -450,7 +450,7 @@ GEM
rails (>= 3.2.0)
git (1.7.0)
rchardet (~> 1.8)
gitaly (14.3.0.pre.rc2)
gitaly (14.4.0.pre.rc43)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab (4.16.1)
@ -1457,7 +1457,7 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly (~> 14.3.0.pre.rc2)
gitaly (~> 14.4.0.pre.rc43)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 2.3.1)

View file

@ -20,7 +20,7 @@ export default {
<gl-sprintf
:message="
s__(
'GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects. Groups can also be nested by creating subgroups.',
'GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.',
)
"
>

View file

@ -63,6 +63,7 @@ export default {
v-if="showPipelineStatus"
:commit-sha="commitSha"
:class="$options.pipelineStatusClasses"
v-on="$listeners"
/>
<validation-segment :class="validationStyling" :ci-config="ciConfigData" />
</div>

View file

@ -1,17 +1,52 @@
<script>
import { __ } from '~/locale';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '../../constants';
export default {
i18n: {
linkedPipelinesFetchError: __('Unable to fetch upstream and downstream pipelines.'),
},
components: {
PipelineMiniGraph,
LinkedPipelinesMiniList: () =>
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
},
inject: ['projectFullPath'],
props: {
pipeline: {
type: Object,
required: true,
},
},
apollo: {
linkedPipelines: {
query: getLinkedPipelinesQuery,
variables() {
return {
fullPath: this.projectFullPath,
iid: this.pipeline.iid,
};
},
skip() {
return !this.pipeline.iid;
},
update({ project }) {
return project?.pipeline;
},
error() {
this.$emit('showError', {
type: PIPELINE_FAILURE,
reasons: [this.$options.i18n.linkedPipelinesFetchError],
});
},
},
},
computed: {
downstreamPipelines() {
return this.linkedPipelines?.downstream?.nodes || [];
},
pipelinePath() {
return this.pipeline.detailedStatus?.detailsPath || '';
},
@ -38,12 +73,29 @@ export default {
};
});
},
showDownstreamPipelines() {
return this.downstreamPipelines.length > 0;
},
upstreamPipeline() {
return this.linkedPipelines?.upstream;
},
},
};
</script>
<template>
<div v-if="pipelineStages.length > 0" class="stage-cell gl-mr-5">
<linked-pipelines-mini-list
v-if="upstreamPipeline"
:triggered-by="[upstreamPipeline]"
data-testid="pipeline-editor-mini-graph-upstream"
/>
<pipeline-mini-graph class="gl-display-inline" :stages="pipelineStages" />
<linked-pipelines-mini-list
v-if="showDownstreamPipelines"
:triggered="downstreamPipelines"
:pipeline-path="pipelinePath"
data-testid="pipeline-editor-mini-graph-downstream"
/>
</div>
</template>

View file

@ -62,11 +62,12 @@ export default {
};
},
update(data) {
const { id, commitPath = '', detailedStatus = {}, stages, status } =
const { id, iid, commitPath = '', detailedStatus = {}, stages, status } =
data.project?.pipeline || {};
return {
id,
iid,
commitPath,
detailedStatus,
stages,
@ -174,6 +175,7 @@ export default {
<pipeline-editor-mini-graph
v-if="glFeatures.pipelineEditorMiniGraph"
:pipeline="pipeline"
v-on="$listeners"
/>
<gl-button
class="gl-mt-2 gl-md-mt-0"

View file

@ -8,6 +8,7 @@ import {
DEFAULT_FAILURE,
DEFAULT_SUCCESS,
LOAD_FAILURE_UNKNOWN,
PIPELINE_FAILURE,
} from '../../constants';
import CodeSnippetAlert from '../code_snippet_alert/code_snippet_alert.vue';
import {
@ -24,6 +25,7 @@ export default {
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
[DEFAULT_FAILURE]: __('Something went wrong on our end.'),
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
[PIPELINE_FAILURE]: s__('Pipelines|There was a problem with loading the pipeline data.'),
},
successTexts: {
[COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
@ -74,6 +76,11 @@ export default {
text: this.$options.errorTexts[COMMIT_FAILURE],
variant: 'danger',
};
case PIPELINE_FAILURE:
return {
text: this.$options.errorTexts[PIPELINE_FAILURE],
variant: 'danger',
};
default:
return {
text: this.$options.errorTexts[DEFAULT_FAILURE],

View file

@ -16,6 +16,7 @@ export const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
export const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
export const DEFAULT_SUCCESS = 'DEFAULT_SUCCESS';
export const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
export const PIPELINE_FAILURE = 'PIPELINE_FAILURE';
export const CREATE_TAB = 'CREATE_TAB';
export const LINT_TAB = 'LINT_TAB';

View file

@ -93,6 +93,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
ciExamplesHelpPagePath,
ciHelpPagePath,
configurationPaths,
dataMethod: 'graphql',
defaultBranch,
emptyStateIllustrationPath,
helpPaths,

View file

@ -111,6 +111,7 @@ export default {
:ci-config-data="ciConfigData"
:commit-sha="commitSha"
:is-new-ci-config-file="isNewCiConfigFile"
v-on="$listeners"
/>
<pipeline-editor-tabs
:ci-config-data="ciConfigData"

View file

@ -76,13 +76,21 @@ export default {
},
onTokenReset(token) {
this.currentRegistrationToken = token;
this.$refs.runnerRegistrationDropdown.hide(true);
},
},
};
</script>
<template>
<gl-dropdown menu-class="gl-w-auto!" :text="dropdownText" variant="confirm" v-bind="$attrs">
<gl-dropdown
ref="runnerRegistrationDropdown"
menu-class="gl-w-auto!"
:text="dropdownText"
variant="confirm"
v-bind="$attrs"
>
<gl-dropdown-item @click.capture.native.stop="onShowInstructionsClick">
{{ $options.i18n.showInstallationInstructions }}
<runner-instructions-modal

View file

@ -302,6 +302,14 @@ module Integrations
private
def branch_name(noteable)
if Feature.enabled?(:jira_use_first_ref_by_oid, project, default_enabled: :yaml)
noteable.first_ref_by_oid(project.repository)
else
noteable.ref_names(project.repository).first
end
end
def server_info
strong_memoize(:server_info) do
client_url.present? ? jira_request { client.ServerInfo.all.attrs } : nil
@ -495,7 +503,7 @@ module Integrations
{
id: noteable.short_id,
description: noteable.safe_message,
branch: noteable.ref_names(project.repository).first
branch: branch_name(noteable)
}
elsif noteable.is_a?(MergeRequest)
{

View file

@ -5,8 +5,6 @@ module MergeRequests
MAX_RETARGET_MERGE_REQUESTS = 4
def execute(merge_request)
return unless Feature.enabled?(:retarget_merge_requests, merge_request.target_project, default_enabled: :yaml)
# we can only retarget MRs that are targeting the same project
return unless merge_request.for_same_project? && merge_request.merged?

View file

@ -1,8 +1,8 @@
---
name: retarget_merge_requests
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53710
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/320895
milestone: '13.9'
name: jira_use_first_ref_by_oid
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72739
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343585
milestone: '14.5'
type: development
group: group::memory
default_enabled: true
group: group::integrations
default_enabled: false

View file

@ -321,15 +321,16 @@ We execute both analyzers because they use different sources of vulnerability da
The analyzer for these languages supports multiple lockfiles.
### Future support for additional languages
### Support for additional languages
Plans are underway for supporting the following languages, dependency managers, and dependency files. For details, see the issue link for each.
For workarounds, see the [Troubleshooting section](#troubleshooting)
Support for additional languages, dependency managers, and dependency files are tracked in the following issues:
| Package Managers | Languages | Supported files | Scan tools | Issue |
| ------------------- | --------- | --------------- | ---------- | ----- |
| [Poetry](https://python-poetry.org/) | Python | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) |
For workarounds, see the [Troubleshooting section](#troubleshooting).
## Contribute your scanner
The [Security Scanner Integration](../../../development/integrations/secure.md) documentation explains how to integrate other security scanners into GitLab.

View file

@ -172,11 +172,6 @@ is set for deletion, the merge request widget displays the
> - [Disabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/320902) in GitLab 13.9.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/320895) GitLab 13.10.
FLAG:
On self-managed GitLab, by default this feature is available. To hide the feature,
ask an administrator to
[disable the `retarget_merge_requests` flag](../../../administration/feature_flags.md).
In specific circumstances, GitLab can retarget the destination branch of
open merge request, if the destination branch merges while the merge request is
open. Merge requests are often chained in this manner, with one merge request

View file

@ -315,10 +315,18 @@ module Gitlab
#
def ref_names(repo)
refs(repo).map do |ref|
ref.sub(%r{^refs/(heads|remotes|tags)/}, "")
strip_ref_prefix(ref)
end
end
def first_ref_by_oid(repo)
ref = repo.refs_by_oid(oid: id, limit: 1)&.first
return unless ref
strip_ref_prefix(ref)
end
def message
encode! @message
end
@ -466,6 +474,10 @@ module Gitlab
commit_id.match?(/\s/)
)
end
def strip_ref_prefix(ref)
ref.sub(%r{^refs/(heads|remotes|tags)/}, "")
end
end
end
end

View file

@ -519,6 +519,17 @@ module Gitlab
@refs_hash
end
# Returns matching refs for OID
#
# Limit of 0 means there is no limit.
def refs_by_oid(oid:, limit: 0)
wrapped_gitaly_errors do
gitaly_ref_client.find_refs_by_oid(oid: oid, limit: limit)
end
rescue CommandError, TypeError, NoRepository
nil
end
# Returns url for submodule
#
# Ex.

View file

@ -210,6 +210,13 @@ module Gitlab
GitalyClient.call(@storage, :ref_service, :pack_refs, request, timeout: GitalyClient.long_timeout)
end
def find_refs_by_oid(oid:, limit:)
request = Gitaly::FindRefsByOIDRequest.new(repository: @gitaly_repo, sort_field: :refname, oid: oid, limit: limit)
response = GitalyClient.call(@storage, :ref_service, :find_refs_by_oid, request, timeout: GitalyClient.medium_timeout)
response&.refs&.to_a
end
private
def consume_refs_response(response)

View file

@ -16625,7 +16625,7 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group members permissions and access to each project in the group."
msgstr ""
msgid "GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects. Groups can also be nested by creating subgroups."
msgid "GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
msgstr ""
msgid "GroupsNew|Assemble related projects together and grant members access to several projects at once."
@ -25285,6 +25285,9 @@ msgstr ""
msgid "Pipelines|There are currently no pipelines."
msgstr ""
msgid "Pipelines|There was a problem with loading the pipeline data."
msgstr ""
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr ""
@ -36367,6 +36370,9 @@ msgstr ""
msgid "Unable to fetch branches list, please close the form and try again"
msgstr ""
msgid "Unable to fetch upstream and downstream pipelines."
msgstr ""
msgid "Unable to fetch vulnerable projects"
msgstr ""

View file

@ -323,6 +323,8 @@ RSpec.describe "Admin Runners" do
end
it 'changes registration token' do
click_on 'Register an instance runner'
click_on 'Click to reveal'
expect(page_token).not_to eq token
end

View file

@ -1,22 +1,54 @@
import { shallowMount } from '@vue/test-utils';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import { mockProjectPipeline } from '../../mock_data';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '~/pipeline_editor/constants';
import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
const localVue = createLocalVue();
localVue.use(VueApollo);
describe('Pipeline Status', () => {
let wrapper;
let mockApollo;
let mockLinkedPipelinesQuery;
const createComponent = ({ hasStages = true } = {}) => {
const createComponent = ({ hasStages = true, options } = {}) => {
wrapper = shallowMount(PipelineEditorMiniGraph, {
provide: {
dataMethod: 'graphql',
projectFullPath: mockProjectFullPath,
},
propsData: {
pipeline: mockProjectPipeline({ hasStages }).pipeline,
},
...options,
});
};
const createComponentWithApollo = (hasStages = true) => {
const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]];
mockApollo = createMockApollo(handlers);
createComponent({
hasStages,
options: {
localVue,
apolloProvider: mockApollo,
},
});
};
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
beforeEach(() => {
mockLinkedPipelinesQuery = jest.fn();
});
afterEach(() => {
mockLinkedPipelinesQuery.mockReset();
wrapper.destroy();
});
@ -39,4 +71,38 @@ describe('Pipeline Status', () => {
expect(findPipelineMiniGraph().exists()).toBe(false);
});
});
describe('when querying upstream and downstream pipelines', () => {
describe('when query succeeds', () => {
beforeEach(() => {
mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines());
createComponentWithApollo();
});
it('should call the query with the correct variables', () => {
expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1);
expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({
fullPath: mockProjectFullPath,
iid: mockProjectPipeline().pipeline.iid,
});
});
});
describe('when query fails', () => {
beforeEach(() => {
mockLinkedPipelinesQuery.mockRejectedValue(new Error());
createComponentWithApollo();
});
it('should emit an error event when query fails', async () => {
expect(wrapper.emitted('showError')).toHaveLength(1);
expect(wrapper.emitted('showError')[0]).toEqual([
{
type: PIPELINE_FAILURE,
reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError],
},
]);
});
});
});
});

View file

@ -11,6 +11,7 @@ import {
DEFAULT_FAILURE,
DEFAULT_SUCCESS,
LOAD_FAILURE_UNKNOWN,
PIPELINE_FAILURE,
} from '~/pipeline_editor/constants';
beforeEach(() => {
@ -65,6 +66,7 @@ describe('Pipeline Editor messages', () => {
failureType | message | expectedFailureType
${COMMIT_FAILURE} | ${'failed commit'} | ${COMMIT_FAILURE}
${LOAD_FAILURE_UNKNOWN} | ${'loading failure'} | ${LOAD_FAILURE_UNKNOWN}
${PIPELINE_FAILURE} | ${'pipeline failure'} | ${PIPELINE_FAILURE}
${'random'} | ${'error without a specified type'} | ${DEFAULT_FAILURE}
`('shows a message for $message', ({ failureType, expectedFailureType }) => {
createComponent({ failureType, showFailure: true });

View file

@ -290,6 +290,62 @@ export const mockProjectPipeline = ({ hasStages = true } = {}) => {
};
};
export const mockLinkedPipelines = ({ hasDownstream = true, hasUpstream = true } = {}) => {
let upstream = null;
let downstream = {
nodes: [],
__typename: 'PipelineConnection',
};
if (hasDownstream) {
downstream = {
nodes: [
{
id: 'gid://gitlab/Ci::Pipeline/612',
path: '/root/job-log-sections/-/pipelines/612',
project: { name: 'job-log-sections', __typename: 'Project' },
detailedStatus: {
group: 'success',
icon: 'status_success',
label: 'passed',
__typename: 'DetailedStatus',
},
__typename: 'Pipeline',
},
],
__typename: 'PipelineConnection',
};
}
if (hasUpstream) {
upstream = {
id: 'gid://gitlab/Ci::Pipeline/610',
path: '/root/trigger-downstream/-/pipelines/610',
project: { name: 'trigger-downstream', __typename: 'Project' },
detailedStatus: {
group: 'success',
icon: 'status_success',
label: 'passed',
__typename: 'DetailedStatus',
},
__typename: 'Pipeline',
};
}
return {
data: {
project: {
pipeline: {
path: '/root/ci-project/-/pipelines/790',
downstream,
upstream,
},
__typename: 'Project',
},
},
};
};
export const mockLintResponse = {
valid: true,
mergedYaml: mockCiYml,

View file

@ -715,6 +715,14 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
it { is_expected.not_to include("feature") }
end
describe '#first_ref_by_oid' do
let(:commit) { described_class.find(repository, 'master') }
subject { commit.first_ref_by_oid(repository) }
it { is_expected.to eq("master") }
end
describe '.get_message' do
let(:commit_ids) { %w[6d394385cf567f80a8fd85055db1ab4c5295806f cfe32cf61b73a0d5e9f13e774abde7ff789b1660] }

View file

@ -1900,6 +1900,32 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end
end
describe '#refs_by_oid' do
it 'returns a list of refs from a OID' do
refs = repository.refs_by_oid(oid: repository.commit.id)
expect(refs).to be_an(Array)
expect(refs).to include(Gitlab::Git::BRANCH_REF_PREFIX + repository.root_ref)
end
it 'returns a single ref from a OID' do
refs = repository.refs_by_oid(oid: repository.commit.id, limit: 1)
expect(refs).to be_an(Array)
expect(refs).to eq([Gitlab::Git::BRANCH_REF_PREFIX + repository.root_ref])
end
it 'returns empty for unknown ID' do
expect(repository.refs_by_oid(oid: Gitlab::Git::BLANK_SHA, limit: 0)).to eq([])
end
it 'returns nil for an empty repo' do
project = create(:project)
expect(project.repository.refs_by_oid(oid: SeedRepo::Commit::ID, limit: 0)).to be_nil
end
end
describe '#set_full_path' do
before do
repository_rugged.config["gitlab.fullpath"] = repository_path

View file

@ -282,4 +282,19 @@ RSpec.describe Gitlab::GitalyClient::RefService do
client.pack_refs
end
end
describe '#find_refs_by_oid' do
let(:oid) { project.repository.commit.id }
it 'sends a find_refs_by_oid message' do
expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_refs_by_oid)
.with(gitaly_request_with_params(sort_field: 'refname', oid: oid, limit: 1), kind_of(Hash))
.and_call_original
refs = client.find_refs_by_oid(oid: oid, limit: 1)
expect(refs.to_a).to eq([Gitlab::Git::BRANCH_REF_PREFIX + project.repository.root_ref])
end
end
end

View file

@ -876,10 +876,24 @@ RSpec.describe Integrations::Jira do
subject
expect(WebMock).to have_requested(:post, comment_url).with(
body: /mentioned this issue in/
body: /mentioned this issue.*on branch \[master/
).once
end
context 'with jira_use_first_ref_by_oid feature flag disabled' do
before do
stub_feature_flags(jira_use_first_ref_by_oid: false)
end
it 'creates a comment on Jira' do
subject
expect(WebMock).to have_requested(:post, comment_url).with(
body: /mentioned this issue.*on branch \[master/
).once
end
end
it 'tracks usage' do
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)

View file

@ -45,14 +45,6 @@ RSpec.describe MergeRequests::RetargetChainService do
.from(merge_request.source_branch)
.to(merge_request.target_branch)
end
context 'when FF retarget_merge_requests is disabled' do
before do
stub_feature_flags(retarget_merge_requests: false)
end
include_examples 'does not retarget merge request'
end
end
context 'in the same project' do