Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
942229d2b4
commit
4d0bc99be4
30 changed files with 329 additions and 39 deletions
|
@ -193,9 +193,7 @@ graphql-schema-dump:
|
||||||
# Disable warnings in browserslist which can break on backports
|
# Disable warnings in browserslist which can break on backports
|
||||||
# https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
|
# https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
|
||||||
BROWSERSLIST_IGNORE_OLD_DATA: "true"
|
BROWSERSLIST_IGNORE_OLD_DATA: "true"
|
||||||
SETUP_DB: "false"
|
|
||||||
before_script:
|
before_script:
|
||||||
- !reference [.default-before_script, before_script]
|
|
||||||
- *yarn-install
|
- *yarn-install
|
||||||
stage: test
|
stage: test
|
||||||
|
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -476,7 +476,7 @@ end
|
||||||
gem 'spamcheck', '~> 0.1.0'
|
gem 'spamcheck', '~> 0.1.0'
|
||||||
|
|
||||||
# Gitaly GRPC protocol definitions
|
# Gitaly GRPC protocol definitions
|
||||||
gem 'gitaly', '~> 14.3.0.pre.rc2'
|
gem 'gitaly', '~> 14.4.0.pre.rc43'
|
||||||
|
|
||||||
# KAS GRPC protocol definitions
|
# KAS GRPC protocol definitions
|
||||||
gem 'kas-grpc', '~> 0.0.2'
|
gem 'kas-grpc', '~> 0.0.2'
|
||||||
|
|
|
@ -450,7 +450,7 @@ GEM
|
||||||
rails (>= 3.2.0)
|
rails (>= 3.2.0)
|
||||||
git (1.7.0)
|
git (1.7.0)
|
||||||
rchardet (~> 1.8)
|
rchardet (~> 1.8)
|
||||||
gitaly (14.3.0.pre.rc2)
|
gitaly (14.4.0.pre.rc43)
|
||||||
grpc (~> 1.0)
|
grpc (~> 1.0)
|
||||||
github-markup (1.7.0)
|
github-markup (1.7.0)
|
||||||
gitlab (4.16.1)
|
gitlab (4.16.1)
|
||||||
|
@ -1457,7 +1457,7 @@ DEPENDENCIES
|
||||||
gettext (~> 3.3)
|
gettext (~> 3.3)
|
||||||
gettext_i18n_rails (~> 1.8.0)
|
gettext_i18n_rails (~> 1.8.0)
|
||||||
gettext_i18n_rails_js (~> 1.3)
|
gettext_i18n_rails_js (~> 1.3)
|
||||||
gitaly (~> 14.3.0.pre.rc2)
|
gitaly (~> 14.4.0.pre.rc43)
|
||||||
github-markup (~> 1.7.0)
|
github-markup (~> 1.7.0)
|
||||||
gitlab-chronic (~> 0.10.5)
|
gitlab-chronic (~> 0.10.5)
|
||||||
gitlab-dangerfiles (~> 2.3.1)
|
gitlab-dangerfiles (~> 2.3.1)
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default {
|
||||||
<gl-sprintf
|
<gl-sprintf
|
||||||
:message="
|
:message="
|
||||||
s__(
|
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.',
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
@ -63,6 +63,7 @@ export default {
|
||||||
v-if="showPipelineStatus"
|
v-if="showPipelineStatus"
|
||||||
:commit-sha="commitSha"
|
:commit-sha="commitSha"
|
||||||
:class="$options.pipelineStatusClasses"
|
:class="$options.pipelineStatusClasses"
|
||||||
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
<validation-segment :class="validationStyling" :ci-config="ciConfigData" />
|
<validation-segment :class="validationStyling" :ci-config="ciConfigData" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,17 +1,52 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { __ } from '~/locale';
|
||||||
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
|
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 {
|
export default {
|
||||||
|
i18n: {
|
||||||
|
linkedPipelinesFetchError: __('Unable to fetch upstream and downstream pipelines.'),
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
PipelineMiniGraph,
|
PipelineMiniGraph,
|
||||||
|
LinkedPipelinesMiniList: () =>
|
||||||
|
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
|
||||||
},
|
},
|
||||||
|
inject: ['projectFullPath'],
|
||||||
props: {
|
props: {
|
||||||
pipeline: {
|
pipeline: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
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: {
|
computed: {
|
||||||
|
downstreamPipelines() {
|
||||||
|
return this.linkedPipelines?.downstream?.nodes || [];
|
||||||
|
},
|
||||||
pipelinePath() {
|
pipelinePath() {
|
||||||
return this.pipeline.detailedStatus?.detailsPath || '';
|
return this.pipeline.detailedStatus?.detailsPath || '';
|
||||||
},
|
},
|
||||||
|
@ -38,12 +73,29 @@ export default {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
showDownstreamPipelines() {
|
||||||
|
return this.downstreamPipelines.length > 0;
|
||||||
|
},
|
||||||
|
upstreamPipeline() {
|
||||||
|
return this.linkedPipelines?.upstream;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="pipelineStages.length > 0" class="stage-cell gl-mr-5">
|
<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" />
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -62,11 +62,12 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
update(data) {
|
update(data) {
|
||||||
const { id, commitPath = '', detailedStatus = {}, stages, status } =
|
const { id, iid, commitPath = '', detailedStatus = {}, stages, status } =
|
||||||
data.project?.pipeline || {};
|
data.project?.pipeline || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
iid,
|
||||||
commitPath,
|
commitPath,
|
||||||
detailedStatus,
|
detailedStatus,
|
||||||
stages,
|
stages,
|
||||||
|
@ -174,6 +175,7 @@ export default {
|
||||||
<pipeline-editor-mini-graph
|
<pipeline-editor-mini-graph
|
||||||
v-if="glFeatures.pipelineEditorMiniGraph"
|
v-if="glFeatures.pipelineEditorMiniGraph"
|
||||||
:pipeline="pipeline"
|
:pipeline="pipeline"
|
||||||
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
<gl-button
|
<gl-button
|
||||||
class="gl-mt-2 gl-md-mt-0"
|
class="gl-mt-2 gl-md-mt-0"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
DEFAULT_FAILURE,
|
DEFAULT_FAILURE,
|
||||||
DEFAULT_SUCCESS,
|
DEFAULT_SUCCESS,
|
||||||
LOAD_FAILURE_UNKNOWN,
|
LOAD_FAILURE_UNKNOWN,
|
||||||
|
PIPELINE_FAILURE,
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import CodeSnippetAlert from '../code_snippet_alert/code_snippet_alert.vue';
|
import CodeSnippetAlert from '../code_snippet_alert/code_snippet_alert.vue';
|
||||||
import {
|
import {
|
||||||
|
@ -24,6 +25,7 @@ export default {
|
||||||
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
|
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
|
||||||
[DEFAULT_FAILURE]: __('Something went wrong on our end.'),
|
[DEFAULT_FAILURE]: __('Something went wrong on our end.'),
|
||||||
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
|
[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: {
|
successTexts: {
|
||||||
[COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
|
[COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
|
||||||
|
@ -74,6 +76,11 @@ export default {
|
||||||
text: this.$options.errorTexts[COMMIT_FAILURE],
|
text: this.$options.errorTexts[COMMIT_FAILURE],
|
||||||
variant: 'danger',
|
variant: 'danger',
|
||||||
};
|
};
|
||||||
|
case PIPELINE_FAILURE:
|
||||||
|
return {
|
||||||
|
text: this.$options.errorTexts[PIPELINE_FAILURE],
|
||||||
|
variant: 'danger',
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
text: this.$options.errorTexts[DEFAULT_FAILURE],
|
text: this.$options.errorTexts[DEFAULT_FAILURE],
|
||||||
|
|
|
@ -16,6 +16,7 @@ export const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
|
||||||
export const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
|
export const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
|
||||||
export const DEFAULT_SUCCESS = 'DEFAULT_SUCCESS';
|
export const DEFAULT_SUCCESS = 'DEFAULT_SUCCESS';
|
||||||
export const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
|
export const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
|
||||||
|
export const PIPELINE_FAILURE = 'PIPELINE_FAILURE';
|
||||||
|
|
||||||
export const CREATE_TAB = 'CREATE_TAB';
|
export const CREATE_TAB = 'CREATE_TAB';
|
||||||
export const LINT_TAB = 'LINT_TAB';
|
export const LINT_TAB = 'LINT_TAB';
|
||||||
|
|
|
@ -93,6 +93,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => {
|
||||||
ciExamplesHelpPagePath,
|
ciExamplesHelpPagePath,
|
||||||
ciHelpPagePath,
|
ciHelpPagePath,
|
||||||
configurationPaths,
|
configurationPaths,
|
||||||
|
dataMethod: 'graphql',
|
||||||
defaultBranch,
|
defaultBranch,
|
||||||
emptyStateIllustrationPath,
|
emptyStateIllustrationPath,
|
||||||
helpPaths,
|
helpPaths,
|
||||||
|
|
|
@ -111,6 +111,7 @@ export default {
|
||||||
:ci-config-data="ciConfigData"
|
:ci-config-data="ciConfigData"
|
||||||
:commit-sha="commitSha"
|
:commit-sha="commitSha"
|
||||||
:is-new-ci-config-file="isNewCiConfigFile"
|
:is-new-ci-config-file="isNewCiConfigFile"
|
||||||
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
<pipeline-editor-tabs
|
<pipeline-editor-tabs
|
||||||
:ci-config-data="ciConfigData"
|
:ci-config-data="ciConfigData"
|
||||||
|
|
|
@ -76,13 +76,21 @@ export default {
|
||||||
},
|
},
|
||||||
onTokenReset(token) {
|
onTokenReset(token) {
|
||||||
this.currentRegistrationToken = token;
|
this.currentRegistrationToken = token;
|
||||||
|
|
||||||
|
this.$refs.runnerRegistrationDropdown.hide(true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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">
|
<gl-dropdown-item @click.capture.native.stop="onShowInstructionsClick">
|
||||||
{{ $options.i18n.showInstallationInstructions }}
|
{{ $options.i18n.showInstallationInstructions }}
|
||||||
<runner-instructions-modal
|
<runner-instructions-modal
|
||||||
|
|
|
@ -302,6 +302,14 @@ module Integrations
|
||||||
|
|
||||||
private
|
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
|
def server_info
|
||||||
strong_memoize(:server_info) do
|
strong_memoize(:server_info) do
|
||||||
client_url.present? ? jira_request { client.ServerInfo.all.attrs } : nil
|
client_url.present? ? jira_request { client.ServerInfo.all.attrs } : nil
|
||||||
|
@ -495,7 +503,7 @@ module Integrations
|
||||||
{
|
{
|
||||||
id: noteable.short_id,
|
id: noteable.short_id,
|
||||||
description: noteable.safe_message,
|
description: noteable.safe_message,
|
||||||
branch: noteable.ref_names(project.repository).first
|
branch: branch_name(noteable)
|
||||||
}
|
}
|
||||||
elsif noteable.is_a?(MergeRequest)
|
elsif noteable.is_a?(MergeRequest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,8 +5,6 @@ module MergeRequests
|
||||||
MAX_RETARGET_MERGE_REQUESTS = 4
|
MAX_RETARGET_MERGE_REQUESTS = 4
|
||||||
|
|
||||||
def execute(merge_request)
|
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
|
# we can only retarget MRs that are targeting the same project
|
||||||
return unless merge_request.for_same_project? && merge_request.merged?
|
return unless merge_request.for_same_project? && merge_request.merged?
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
name: retarget_merge_requests
|
name: jira_use_first_ref_by_oid
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53710
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72739
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/320895
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343585
|
||||||
milestone: '13.9'
|
milestone: '14.5'
|
||||||
type: development
|
type: development
|
||||||
group: group::memory
|
group: group::integrations
|
||||||
default_enabled: true
|
default_enabled: false
|
|
@ -321,15 +321,16 @@ We execute both analyzers because they use different sources of vulnerability da
|
||||||
|
|
||||||
The analyzer for these languages supports multiple lockfiles.
|
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.
|
Support for additional languages, dependency managers, and dependency files are tracked in the following issues:
|
||||||
For workarounds, see the [Troubleshooting section](#troubleshooting)
|
|
||||||
|
|
||||||
| Package Managers | Languages | Supported files | Scan tools | Issue |
|
| 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) |
|
| [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
|
## Contribute your scanner
|
||||||
|
|
||||||
The [Security Scanner Integration](../../../development/integrations/secure.md) documentation explains how to integrate other security scanners into GitLab.
|
The [Security Scanner Integration](../../../development/integrations/secure.md) documentation explains how to integrate other security scanners into GitLab.
|
||||||
|
|
|
@ -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.
|
> - [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.
|
> - [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
|
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 request, if the destination branch merges while the merge request is
|
||||||
open. Merge requests are often chained in this manner, with one merge request
|
open. Merge requests are often chained in this manner, with one merge request
|
||||||
|
|
|
@ -315,10 +315,18 @@ module Gitlab
|
||||||
#
|
#
|
||||||
def ref_names(repo)
|
def ref_names(repo)
|
||||||
refs(repo).map do |ref|
|
refs(repo).map do |ref|
|
||||||
ref.sub(%r{^refs/(heads|remotes|tags)/}, "")
|
strip_ref_prefix(ref)
|
||||||
end
|
end
|
||||||
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
|
def message
|
||||||
encode! @message
|
encode! @message
|
||||||
end
|
end
|
||||||
|
@ -466,6 +474,10 @@ module Gitlab
|
||||||
commit_id.match?(/\s/)
|
commit_id.match?(/\s/)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def strip_ref_prefix(ref)
|
||||||
|
ref.sub(%r{^refs/(heads|remotes|tags)/}, "")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -519,6 +519,17 @@ module Gitlab
|
||||||
@refs_hash
|
@refs_hash
|
||||||
end
|
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
|
# Returns url for submodule
|
||||||
#
|
#
|
||||||
# Ex.
|
# Ex.
|
||||||
|
|
|
@ -210,6 +210,13 @@ module Gitlab
|
||||||
GitalyClient.call(@storage, :ref_service, :pack_refs, request, timeout: GitalyClient.long_timeout)
|
GitalyClient.call(@storage, :ref_service, :pack_refs, request, timeout: GitalyClient.long_timeout)
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def consume_refs_response(response)
|
def consume_refs_response(response)
|
||||||
|
|
|
@ -16625,7 +16625,7 @@ msgstr ""
|
||||||
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
|
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
|
||||||
msgstr ""
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "GroupsNew|Assemble related projects together and grant members access to several projects at once."
|
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."
|
msgid "Pipelines|There are currently no pipelines."
|
||||||
msgstr ""
|
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."
|
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -36367,6 +36370,9 @@ msgstr ""
|
||||||
msgid "Unable to fetch branches list, please close the form and try again"
|
msgid "Unable to fetch branches list, please close the form and try again"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Unable to fetch upstream and downstream pipelines."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Unable to fetch vulnerable projects"
|
msgid "Unable to fetch vulnerable projects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -323,6 +323,8 @@ RSpec.describe "Admin Runners" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'changes registration token' do
|
it 'changes registration token' do
|
||||||
|
click_on 'Register an instance runner'
|
||||||
|
|
||||||
click_on 'Click to reveal'
|
click_on 'Click to reveal'
|
||||||
expect(page_token).not_to eq token
|
expect(page_token).not_to eq token
|
||||||
end
|
end
|
||||||
|
|
|
@ -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 PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
|
||||||
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_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', () => {
|
describe('Pipeline Status', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
let mockApollo;
|
||||||
|
let mockLinkedPipelinesQuery;
|
||||||
|
|
||||||
const createComponent = ({ hasStages = true } = {}) => {
|
const createComponent = ({ hasStages = true, options } = {}) => {
|
||||||
wrapper = shallowMount(PipelineEditorMiniGraph, {
|
wrapper = shallowMount(PipelineEditorMiniGraph, {
|
||||||
|
provide: {
|
||||||
|
dataMethod: 'graphql',
|
||||||
|
projectFullPath: mockProjectFullPath,
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
pipeline: mockProjectPipeline({ hasStages }).pipeline,
|
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);
|
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockLinkedPipelinesQuery = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
mockLinkedPipelinesQuery.mockReset();
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,4 +71,38 @@ describe('Pipeline Status', () => {
|
||||||
expect(findPipelineMiniGraph().exists()).toBe(false);
|
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],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
DEFAULT_FAILURE,
|
DEFAULT_FAILURE,
|
||||||
DEFAULT_SUCCESS,
|
DEFAULT_SUCCESS,
|
||||||
LOAD_FAILURE_UNKNOWN,
|
LOAD_FAILURE_UNKNOWN,
|
||||||
|
PIPELINE_FAILURE,
|
||||||
} from '~/pipeline_editor/constants';
|
} from '~/pipeline_editor/constants';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -65,6 +66,7 @@ describe('Pipeline Editor messages', () => {
|
||||||
failureType | message | expectedFailureType
|
failureType | message | expectedFailureType
|
||||||
${COMMIT_FAILURE} | ${'failed commit'} | ${COMMIT_FAILURE}
|
${COMMIT_FAILURE} | ${'failed commit'} | ${COMMIT_FAILURE}
|
||||||
${LOAD_FAILURE_UNKNOWN} | ${'loading failure'} | ${LOAD_FAILURE_UNKNOWN}
|
${LOAD_FAILURE_UNKNOWN} | ${'loading failure'} | ${LOAD_FAILURE_UNKNOWN}
|
||||||
|
${PIPELINE_FAILURE} | ${'pipeline failure'} | ${PIPELINE_FAILURE}
|
||||||
${'random'} | ${'error without a specified type'} | ${DEFAULT_FAILURE}
|
${'random'} | ${'error without a specified type'} | ${DEFAULT_FAILURE}
|
||||||
`('shows a message for $message', ({ failureType, expectedFailureType }) => {
|
`('shows a message for $message', ({ failureType, expectedFailureType }) => {
|
||||||
createComponent({ failureType, showFailure: true });
|
createComponent({ failureType, showFailure: true });
|
||||||
|
|
|
@ -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 = {
|
export const mockLintResponse = {
|
||||||
valid: true,
|
valid: true,
|
||||||
mergedYaml: mockCiYml,
|
mergedYaml: mockCiYml,
|
||||||
|
|
|
@ -715,6 +715,14 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
|
||||||
it { is_expected.not_to include("feature") }
|
it { is_expected.not_to include("feature") }
|
||||||
end
|
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
|
describe '.get_message' do
|
||||||
let(:commit_ids) { %w[6d394385cf567f80a8fd85055db1ab4c5295806f cfe32cf61b73a0d5e9f13e774abde7ff789b1660] }
|
let(:commit_ids) { %w[6d394385cf567f80a8fd85055db1ab4c5295806f cfe32cf61b73a0d5e9f13e774abde7ff789b1660] }
|
||||||
|
|
||||||
|
|
|
@ -1900,6 +1900,32 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
||||||
end
|
end
|
||||||
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
|
describe '#set_full_path' do
|
||||||
before do
|
before do
|
||||||
repository_rugged.config["gitlab.fullpath"] = repository_path
|
repository_rugged.config["gitlab.fullpath"] = repository_path
|
||||||
|
|
|
@ -282,4 +282,19 @@ RSpec.describe Gitlab::GitalyClient::RefService do
|
||||||
client.pack_refs
|
client.pack_refs
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -876,10 +876,24 @@ RSpec.describe Integrations::Jira do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
expect(WebMock).to have_requested(:post, comment_url).with(
|
expect(WebMock).to have_requested(:post, comment_url).with(
|
||||||
body: /mentioned this issue in/
|
body: /mentioned this issue.*on branch \[master/
|
||||||
).once
|
).once
|
||||||
end
|
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
|
it 'tracks usage' do
|
||||||
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
|
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
|
||||||
.to receive(:track_event)
|
.to receive(:track_event)
|
||||||
|
|
|
@ -45,14 +45,6 @@ RSpec.describe MergeRequests::RetargetChainService do
|
||||||
.from(merge_request.source_branch)
|
.from(merge_request.source_branch)
|
||||||
.to(merge_request.target_branch)
|
.to(merge_request.target_branch)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context 'in the same project' do
|
context 'in the same project' do
|
||||||
|
|
Loading…
Reference in a new issue