Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3fdeaff80e
commit
f167d24074
|
@ -6,6 +6,7 @@ import { GlModal, GlSprintf, GlLink } from '@gitlab/ui';
|
|||
import { escape } from 'lodash';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
||||
import rollbackEnvironment from '../graphql/mutations/rollback_environment.mutation.graphql';
|
||||
import eventHub from '../event_hub';
|
||||
|
@ -84,7 +85,9 @@ export default {
|
|||
return this.environment.commitUrl;
|
||||
},
|
||||
modalActionText() {
|
||||
return this.isLastDeployment ? s__('Environments|Re-deploy') : s__('Environments|Rollback');
|
||||
return this.isLastDeployment
|
||||
? s__('Environments|Re-deploy environment')
|
||||
: s__('Environments|Rollback environment');
|
||||
},
|
||||
primaryProps() {
|
||||
let attributes = [{ variant: 'danger' }];
|
||||
|
@ -101,6 +104,15 @@ export default {
|
|||
isLastDeployment() {
|
||||
return this.environment?.isLastDeployment || this.environment?.lastDeployment?.isLast;
|
||||
},
|
||||
modalBodyText() {
|
||||
return this.isLastDeployment
|
||||
? s__(
|
||||
'Environments|This action will %{docsStart}retry the latest deployment%{docsEnd} with the commit %{commitId}, for this environment. Are you sure you want to continue?',
|
||||
)
|
||||
: s__(
|
||||
'Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?',
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChange(event) {
|
||||
|
@ -125,6 +137,7 @@ export default {
|
|||
text: __('Cancel'),
|
||||
attributes: [{ variant: 'danger' }],
|
||||
},
|
||||
docsPath: helpPagePath('ci/environments/index.md', { anchor: 'retry-or-roll-back-a-deployment' }),
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
@ -137,33 +150,14 @@ export default {
|
|||
@ok="onOk"
|
||||
@change="handleChange"
|
||||
>
|
||||
<gl-sprintf
|
||||
v-if="environment.isLastDeployment"
|
||||
:message="
|
||||
s__(
|
||||
'Environments|This action will relaunch the job for commit %{linkStart}%{commitId}%{linkEnd}, putting the environment in a previous version. Are you sure you want to continue?',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #link>
|
||||
<gl-sprintf :message="modalBodyText">
|
||||
<template #commitId>
|
||||
<gl-link :href="commitUrl" target="_blank" class="commit-sha mr-0">{{
|
||||
commitShortSha
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
<gl-sprintf
|
||||
v-else
|
||||
:message="
|
||||
s__(
|
||||
'Environments|This action will run the job defined by %{name} for commit %{linkStart}%{commitId}%{linkEnd} putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #name>{{ environment.name }}</template>
|
||||
<template #link>
|
||||
<gl-link :href="commitUrl" target="_blank" class="commit-sha mr-0">{{
|
||||
commitShortSha
|
||||
}}</gl-link>
|
||||
<template #docs="{ content }">
|
||||
<gl-link :href="$options.docsLink" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-modal>
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
<script>
|
||||
import { GlButton, GlIcon } from '@gitlab/ui';
|
||||
import { GlButton, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { uniqBy } from 'lodash';
|
||||
import { s__ } from '~/locale';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
collapseReplies: s__('Notes|Collapse replies'),
|
||||
expandReplies: s__('Notes|Expand replies'),
|
||||
lastReplyBy: s__('Notes|Last reply by %{name}'),
|
||||
},
|
||||
components: {
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
UserAvatarLink,
|
||||
TimeAgoTooltip,
|
||||
},
|
||||
|
@ -28,63 +35,83 @@ export default {
|
|||
uniqueAuthors() {
|
||||
const authors = this.replies.map((reply) => reply.author || {});
|
||||
|
||||
return uniqBy(authors, (author) => author.username);
|
||||
return uniqBy(authors, 'username');
|
||||
},
|
||||
className() {
|
||||
return this.collapsed ? 'collapsed' : 'expanded';
|
||||
liClasses() {
|
||||
return this.collapsed
|
||||
? 'gl-text-gray-500 gl-rounded-bottom-left-base gl-rounded-bottom-right-base'
|
||||
: 'gl-border-b';
|
||||
},
|
||||
buttonIcon() {
|
||||
return this.collapsed ? 'chevron-right' : 'chevron-down';
|
||||
},
|
||||
buttonLabel() {
|
||||
return this.collapsed ? this.$options.i18n.expandReplies : this.$options.i18n.collapseReplies;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.$refs.toggle.$el.focus();
|
||||
this.$emit('toggle');
|
||||
},
|
||||
},
|
||||
ICON_CLASS: 'gl-mr-3 gl-cursor-pointer',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li
|
||||
:class="className"
|
||||
class="replies-toggle js-toggle-replies gl-display-flex! gl-align-items-center gl-flex-wrap"
|
||||
:class="liClasses"
|
||||
class="gl-display-flex! gl-align-items-center gl-flex-wrap gl-bg-gray-10 gl-py-3 gl-px-5 gl-border-t"
|
||||
>
|
||||
<gl-button
|
||||
ref="toggle"
|
||||
class="gl-my-2 gl-mr-3 gl-p-0!"
|
||||
category="tertiary"
|
||||
:icon="buttonIcon"
|
||||
:aria-label="buttonLabel"
|
||||
@click="toggle"
|
||||
/>
|
||||
<template v-if="collapsed">
|
||||
<gl-icon :class="$options.ICON_CLASS" name="chevron-right" @click.native="toggle" />
|
||||
<div>
|
||||
<user-avatar-link
|
||||
v-for="author in uniqueAuthors"
|
||||
:key="author.username"
|
||||
:link-href="author.path"
|
||||
:img-alt="author.name"
|
||||
:img-src="author.avatar_url"
|
||||
:img-size="24"
|
||||
:tooltip-text="author.name"
|
||||
tooltip-placement="bottom"
|
||||
/>
|
||||
</div>
|
||||
<user-avatar-link
|
||||
v-for="author in uniqueAuthors"
|
||||
:key="author.username"
|
||||
class="gl-mr-3"
|
||||
:link-href="author.path"
|
||||
:img-alt="author.name"
|
||||
img-css-classes="gl-mr-0!"
|
||||
:img-src="author.avatar_url"
|
||||
:img-size="24"
|
||||
:tooltip-text="author.name"
|
||||
tooltip-placement="bottom"
|
||||
/>
|
||||
<gl-button
|
||||
class="js-replies-text gl-mr-2"
|
||||
category="tertiary"
|
||||
class="gl-mr-2"
|
||||
variant="link"
|
||||
data-qa-selector="expand_replies_button"
|
||||
@click="toggle"
|
||||
>
|
||||
{{ replies.length }} {{ n__('reply', 'replies', replies.length) }}
|
||||
{{ n__('%d reply', '%d replies', replies.length) }}
|
||||
</gl-button>
|
||||
{{ __('Last reply by') }}
|
||||
<a :href="lastReply.author.path" class="btn btn-link author-link gl-mx-2 gl-button">
|
||||
{{ lastReply.author.name }}
|
||||
</a>
|
||||
<gl-sprintf :message="$options.i18n.lastReplyBy">
|
||||
<template #name>
|
||||
<gl-link
|
||||
:href="lastReply.author.path"
|
||||
class="gl-text-body! gl-text-decoration-none! gl-mx-2"
|
||||
>
|
||||
{{ lastReply.author.name }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
<time-ago-tooltip :time="lastReply.created_at" tooltip-placement="bottom" />
|
||||
</template>
|
||||
<div
|
||||
<gl-button
|
||||
v-else
|
||||
class="collapse-replies-btn js-collapse-replies gl-display-flex align-items-center"
|
||||
class="gl-text-body! gl-text-decoration-none!"
|
||||
variant="link"
|
||||
data-qa-selector="collapse_replies_button"
|
||||
@click="toggle"
|
||||
>
|
||||
<gl-icon :class="$options.ICON_CLASS" name="chevron-down" />
|
||||
<span class="gl-cursor-pointer">{{ s__('Notes|Collapse replies') }}</span>
|
||||
</div>
|
||||
{{ $options.i18n.collapseReplies }}
|
||||
</gl-button>
|
||||
</li>
|
||||
</template>
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
}
|
||||
|
||||
.user-avatar-link {
|
||||
display: flow-root;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,41 +70,6 @@ $system-note-svg-size: 16px;
|
|||
}
|
||||
}
|
||||
|
||||
.replies-toggle {
|
||||
background-color: $gray-light;
|
||||
padding: $gl-padding-8 $gl-padding;
|
||||
border-top: 1px solid $gray-100;
|
||||
border-bottom: 1px solid $gray-100;
|
||||
|
||||
.collapse-replies-btn:hover {
|
||||
color: $blue-600;
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
color: $gl-text-color-secondary;
|
||||
border-radius: 0 0 $border-radius-default $border-radius-default;
|
||||
|
||||
img {
|
||||
margin: -2px 4px 0 0;
|
||||
}
|
||||
|
||||
.author-link {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.user-avatar-link {
|
||||
&:last-child img {
|
||||
margin-right: $gl-padding-8;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
border: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.discussion-toggle-replies {
|
||||
border-top: 0;
|
||||
border-radius: 4px 4px 0 0;
|
||||
|
|
|
@ -17,7 +17,7 @@ class Import::FogbugzController < Import::BaseController
|
|||
res = Gitlab::FogbugzImport::Client.new(import_params.to_h.symbolize_keys)
|
||||
rescue StandardError
|
||||
# If the URI is invalid various errors can occur
|
||||
return redirect_to new_import_fogbugz_path, alert: _('Could not connect to FogBugz, check your URL')
|
||||
return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: _('Could not connect to FogBugz, check your URL')
|
||||
end
|
||||
session[:fogbugz_token] = res.get_token
|
||||
session[:fogbugz_uri] = params[:uri]
|
||||
|
|
|
@ -321,5 +321,3 @@ class CommitStatus < Ci::ApplicationRecord
|
|||
script_failure? || missing_dependency_failure? || archived_failure? || scheduler_failure? || data_integrity_failure?
|
||||
end
|
||||
end
|
||||
|
||||
CommitStatus.prepend_mod_with('CommitStatus')
|
||||
|
|
|
@ -29,9 +29,12 @@ module Enums
|
|||
builds_disabled: 20,
|
||||
environment_creation_failure: 21,
|
||||
deployment_rejected: 22,
|
||||
protected_environment_failure: 1_000,
|
||||
insufficient_bridge_permissions: 1_001,
|
||||
downstream_bridge_project_not_found: 1_002,
|
||||
invalid_bridge_trigger: 1_003,
|
||||
upstream_bridge_project_not_found: 1_004,
|
||||
insufficient_upstream_permissions: 1_005,
|
||||
bridge_pipeline_is_child_pipeline: 1_006, # not used anymore, but cannot be deleted because of old data
|
||||
downstream_pipeline_creation_failed: 1_007,
|
||||
secrets_provider_not_found: 1_008,
|
||||
|
@ -41,5 +44,3 @@ module Enums
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Enums::Ci::CommitStatus.prepend_mod_with('Enums::Ci::CommitStatus')
|
||||
|
|
|
@ -16,8 +16,11 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
|
|||
data_integrity_failure: 'There has been a structural integrity problem detected, please contact system administrator',
|
||||
forward_deployment_failure: 'The deployment job is older than the previously succeeded deployment job, and therefore cannot be run',
|
||||
pipeline_loop_detected: 'This job could not be executed because it would create infinitely looping pipelines',
|
||||
insufficient_upstream_permissions: 'This job could not be executed because of insufficient permissions to track the upstream project.',
|
||||
upstream_bridge_project_not_found: 'This job could not be executed because upstream bridge project could not be found.',
|
||||
invalid_bridge_trigger: 'This job could not be executed because downstream pipeline trigger definition is invalid',
|
||||
downstream_bridge_project_not_found: 'This job could not be executed because downstream bridge project could not be found',
|
||||
protected_environment_failure: 'The environment this job is deploying to is protected. Only users with permission may successfully run this job.',
|
||||
insufficient_bridge_permissions: 'This job could not be executed because of insufficient permissions to create a downstream pipeline',
|
||||
bridge_pipeline_is_child_pipeline: 'This job belongs to a child pipeline and cannot create further child pipelines',
|
||||
downstream_pipeline_creation_failed: 'The downstream pipeline could not be created',
|
||||
|
@ -61,5 +64,3 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
|
|||
ActionController::Base.helpers.link_to('How do I fix it?', help_page_path(path, anchor: anchor))
|
||||
end
|
||||
end
|
||||
|
||||
CommitStatusPresenter.prepend_mod_with('CommitStatusPresenter')
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
- if bizible_enabled?
|
||||
<!-- Bizible -->
|
||||
= javascript_include_tag "https://cdn.bizible.com/scripts/bizible.js"
|
||||
= javascript_tag nonce: content_security_policy_nonce do
|
||||
:plain
|
||||
const bizibleScript = document.createElement('script');
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346257
|
|||
milestone: '14.6'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -27,9 +27,9 @@ alternatives to server hooks include:
|
|||
|
||||
[Geo](geo/index.md) doesn't replicate server hooks to secondary nodes.
|
||||
|
||||
## Create a server hook for a single repository
|
||||
## Create server hooks for a repository
|
||||
|
||||
To create a server hook for a single repository:
|
||||
To create server hooks for a repository:
|
||||
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. Go to **Overview > Projects** and select the project you want to add a server hook to.
|
||||
|
@ -41,16 +41,21 @@ To create a server hook for a single repository:
|
|||
- For Omnibus GitLab installations, the path is usually `/var/opt/gitlab/git-data/repositories/<group>/<project>.git`.
|
||||
- For an installation from source, the path is usually `/home/git/repositories/<group>/<project>.git`.
|
||||
1. On the file system, create a new directory in the correct location called `custom_hooks`.
|
||||
1. In the new `custom_hooks` directory, create a file with a name that matches the hook type. For example, for a
|
||||
`pre-receive` server hook, the filename should be `pre-receive` with no extension.
|
||||
1. Make the server hook file executable and ensure that it's owned by the Git user.
|
||||
1. In the new `custom_hooks` directory:
|
||||
- To create a single server hook, create a file with a name that matches the hook type. For example, for a
|
||||
`pre-receive` server hook, the filename should be `pre-receive` with no extension.
|
||||
- To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
|
||||
`pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that directory.
|
||||
1. Make the server hook files executable and ensure that they are owned by the Git user.
|
||||
1. Write the code to make the server hook function as expected. Server hooks can be in any programming language. Ensure
|
||||
the [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) at the top reflects the language type. For
|
||||
example, if the script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
|
||||
1. Make the hook file executable, ensure that it's owned by the Git user, and ensure it does not match the backup file
|
||||
pattern (`*~`).
|
||||
|
||||
If the server hook code is properly implemented, it should execute when the Git hook is next triggered.
|
||||
|
||||
## Create a global server hook for all repositories
|
||||
## Create global server hooks for all repositories
|
||||
|
||||
To create a Git hook that applies to all repositories, set a global server hook. The default global server hook directory
|
||||
is in the GitLab Shell directory. Any server hook added there applies to all repositories, including:
|
||||
|
@ -80,8 +85,11 @@ To use a different directory for global server hooks, set `custom_hooks_dir` in
|
|||
To create a global server hook for all repositories:
|
||||
|
||||
1. On the GitLab server, go to the configured global server hook directory.
|
||||
1. Create a new directory in this location called `pre-receive.d`, `post-receive.d`, or `update.d`, depending on the type
|
||||
of server hook. Any other names are ignored.
|
||||
1. In the configured global server hook directory:
|
||||
- To create a single server hook, create a file with a name that matches the hook type. For example, for a
|
||||
`pre-receive` server hook, the filename should be `pre-receive` with no extension.
|
||||
- To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
|
||||
`pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that directory.
|
||||
1. Inside this new directory, add your server hook. Server hooks can be in any programming language. Ensure the
|
||||
[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) at the top reflects the language type. For example, if the
|
||||
script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
|
||||
|
|
|
@ -20,10 +20,13 @@ module Gitlab
|
|||
scheduler_failure: 'scheduler failure',
|
||||
data_integrity_failure: 'data integrity failure',
|
||||
forward_deployment_failure: 'forward deployment failure',
|
||||
protected_environment_failure: 'protected environment failure',
|
||||
pipeline_loop_detected: 'job would create infinitely looping pipelines',
|
||||
invalid_bridge_trigger: 'downstream pipeline trigger definition is invalid',
|
||||
downstream_bridge_project_not_found: 'downstream project could not be found',
|
||||
upstream_bridge_project_not_found: 'upstream project could not be found',
|
||||
insufficient_bridge_permissions: 'no permissions to trigger downstream pipeline',
|
||||
insufficient_upstream_permissions: 'no permissions to read upstream project',
|
||||
bridge_pipeline_is_child_pipeline: 'creation of child pipeline not allowed from another child pipeline',
|
||||
downstream_pipeline_creation_failed: 'downstream pipeline can not be created',
|
||||
secrets_provider_not_found: 'secrets provider can not be found',
|
||||
|
@ -74,5 +77,3 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::Ci::Status::Build::Failed.prepend_mod_with('Gitlab::Ci::Status::Build::Failed')
|
||||
|
|
|
@ -483,6 +483,8 @@ module Gitlab
|
|||
raise Gitlab::Git::PreReceiveError.new(fallback_message: access_check_error.error_message)
|
||||
when :cherry_pick_conflict
|
||||
raise Gitlab::Git::Repository::CreateTreeError, 'CONFLICT'
|
||||
when :changes_already_applied
|
||||
raise Gitlab::Git::Repository::CreateTreeError, 'EMPTY'
|
||||
when :target_branch_diverged
|
||||
raise Gitlab::Git::CommitError, 'branch diverged'
|
||||
else
|
||||
|
|
|
@ -363,6 +363,11 @@ msgid_plural "%d remaining"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%d reply"
|
||||
msgid_plural "%d replies"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%d second"
|
||||
msgid_plural "%d seconds"
|
||||
msgstr[0] ""
|
||||
|
@ -14555,7 +14560,7 @@ msgstr ""
|
|||
msgid "Environments|Pod name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Re-deploy"
|
||||
msgid "Environments|Re-deploy environment"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Re-deploy environment %{name}?"
|
||||
|
@ -14564,9 +14569,6 @@ msgstr ""
|
|||
msgid "Environments|Re-deploy to environment"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Rollback"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Rollback environment"
|
||||
msgstr ""
|
||||
|
||||
|
@ -14594,10 +14596,10 @@ msgstr ""
|
|||
msgid "Environments|There was an error fetching the logs. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|This action will relaunch the job for commit %{linkStart}%{commitId}%{linkEnd}, putting the environment in a previous version. Are you sure you want to continue?"
|
||||
msgid "Environments|This action will %{docsStart}retry the latest deployment%{docsEnd} with the commit %{commitId}, for this environment. Are you sure you want to continue?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|This action will run the job defined by %{name} for commit %{linkStart}%{commitId}%{linkEnd} putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?"
|
||||
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Upcoming"
|
||||
|
@ -26080,9 +26082,15 @@ msgstr ""
|
|||
msgid "Notes|Collapse replies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Expand replies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Last reply by %{name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Make this an internal note"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -29,12 +29,21 @@ RSpec.describe Import::FogbugzController do
|
|||
expect(response).to redirect_to(new_user_map_import_fogbugz_path)
|
||||
end
|
||||
|
||||
it 'preserves namespace_id query param' do
|
||||
it 'preserves namespace_id query param on success' do
|
||||
post :callback, params: { uri: uri, email: 'test@example.com', password: 'mypassword', namespace_id: namespace_id }
|
||||
|
||||
expect(response).to redirect_to(new_user_map_import_fogbugz_path(namespace_id: namespace_id))
|
||||
end
|
||||
|
||||
it 'redirects to new page maintaining namespace_id when client raises standard error' do
|
||||
namespace_id = 5
|
||||
allow(::Gitlab::FogbugzImport::Client).to receive(:new).and_raise(StandardError)
|
||||
|
||||
post :callback, params: { uri: uri, email: 'test@example.com', password: 'mypassword', namespace_id: namespace_id }
|
||||
|
||||
expect(response).to redirect_to(new_import_fogbugz_url(namespace_id: namespace_id))
|
||||
end
|
||||
|
||||
it 'redirects to new page form when client raises authentication exception' do
|
||||
allow(::Gitlab::FogbugzImport::Client).to receive(:new).and_raise(::Fogbugz::AuthenticationException)
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ RSpec.describe 'Merge request > User scrolls to note on load', :js do
|
|||
note_element = find(collapsed_fragment_id)
|
||||
|
||||
expect(note_element.visible?).to eq(true)
|
||||
expect(note_element.sibling('.replies-toggle')[:class]).to include('expanded')
|
||||
expect(note_element.sibling('li:nth-child(2)')).to have_button s_('Notes|Collapse replies')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ import { GlModal, GlSprintf } from '@gitlab/ui';
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import ConfirmRollbackModal from '~/environments/components/confirm_rollback_modal.vue';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import eventHub from '~/environments/event_hub';
|
||||
|
@ -76,9 +77,9 @@ describe('Confirm Rollback Modal Component', () => {
|
|||
|
||||
expect(modal.attributes('title')).toContain('Rollback');
|
||||
expect(modal.attributes('title')).toContain('test');
|
||||
expect(modal.props('actionPrimary').text).toBe('Rollback');
|
||||
expect(modal.props('actionPrimary').text).toBe('Rollback environment');
|
||||
expect(modal.props('actionPrimary').attributes).toEqual(primaryPropsAttrs);
|
||||
expect(modal.text()).toContain('commit abc0123');
|
||||
expect(trimText(modal.text())).toContain('commit abc0123');
|
||||
expect(modal.text()).toContain('Are you sure you want to continue?');
|
||||
});
|
||||
|
||||
|
@ -95,8 +96,8 @@ describe('Confirm Rollback Modal Component', () => {
|
|||
|
||||
expect(modal.attributes('title')).toContain('Re-deploy');
|
||||
expect(modal.attributes('title')).toContain('test');
|
||||
expect(modal.props('actionPrimary').text).toBe('Re-deploy');
|
||||
expect(modal.text()).toContain('commit abc0123');
|
||||
expect(modal.props('actionPrimary').text).toBe('Re-deploy environment');
|
||||
expect(trimText(modal.text())).toContain('commit abc0123');
|
||||
expect(modal.text()).toContain('Are you sure you want to continue?');
|
||||
});
|
||||
|
||||
|
@ -156,7 +157,7 @@ describe('Confirm Rollback Modal Component', () => {
|
|||
);
|
||||
const modal = component.find(GlModal);
|
||||
|
||||
expect(modal.text()).toContain('commit abc0123');
|
||||
expect(trimText(modal.text())).toContain('commit abc0123');
|
||||
expect(modal.text()).toContain('Are you sure you want to continue?');
|
||||
});
|
||||
|
||||
|
@ -180,7 +181,7 @@ describe('Confirm Rollback Modal Component', () => {
|
|||
|
||||
expect(modal.attributes('title')).toContain('Rollback');
|
||||
expect(modal.attributes('title')).toContain('test');
|
||||
expect(modal.props('actionPrimary').text).toBe('Rollback');
|
||||
expect(modal.props('actionPrimary').text).toBe('Rollback environment');
|
||||
expect(modal.props('actionPrimary').attributes).toEqual(primaryPropsAttrs);
|
||||
});
|
||||
|
||||
|
@ -204,7 +205,7 @@ describe('Confirm Rollback Modal Component', () => {
|
|||
|
||||
expect(modal.attributes('title')).toContain('Re-deploy');
|
||||
expect(modal.attributes('title')).toContain('test');
|
||||
expect(modal.props('actionPrimary').text).toBe('Re-deploy');
|
||||
expect(modal.props('actionPrimary').text).toBe('Re-deploy environment');
|
||||
});
|
||||
|
||||
it('should commit the "rollback" mutation when "ok" is clicked', async () => {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import Vue from 'vue';
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import toggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import { note } from '../mock_data';
|
||||
|
||||
const deepCloneObject = (obj) => JSON.parse(JSON.stringify(obj));
|
||||
|
||||
describe('toggle replies widget for notes', () => {
|
||||
let vm;
|
||||
let ToggleRepliesWidget;
|
||||
let wrapper;
|
||||
|
||||
const deepCloneObject = (obj) => JSON.parse(JSON.stringify(obj));
|
||||
|
||||
const noteFromOtherUser = deepCloneObject(note);
|
||||
noteFromOtherUser.author.username = 'fatihacet';
|
||||
|
||||
|
@ -17,62 +18,62 @@ describe('toggle replies widget for notes', () => {
|
|||
|
||||
const replies = [note, note, note, noteFromOtherUser, noteFromAnotherUser];
|
||||
|
||||
beforeEach(() => {
|
||||
ToggleRepliesWidget = Vue.extend(toggleRepliesWidget);
|
||||
});
|
||||
const findCollapseToggleButton = () =>
|
||||
wrapper.findByRole('button', { text: ToggleRepliesWidget.i18n.collapseReplies });
|
||||
const findExpandToggleButton = () =>
|
||||
wrapper.findByRole('button', { text: ToggleRepliesWidget.i18n.expandReplies });
|
||||
const findRepliesButton = () => wrapper.findByRole('button', { text: '5 replies' });
|
||||
const findTimeAgoTooltip = () => wrapper.findComponent(TimeAgoTooltip);
|
||||
const findUserAvatarLink = () => wrapper.findAllComponents(UserAvatarLink);
|
||||
const findUserLink = () => wrapper.findByRole('link', { text: noteFromAnotherUser.author.name });
|
||||
|
||||
const mountComponent = ({ collapsed = false }) =>
|
||||
mountExtended(ToggleRepliesWidget, { propsData: { replies, collapsed } });
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('collapsed state', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(ToggleRepliesWidget, {
|
||||
replies,
|
||||
collapsed: true,
|
||||
});
|
||||
wrapper = mountComponent({ collapsed: true });
|
||||
});
|
||||
|
||||
it('should render the collapsed', () => {
|
||||
const vmTextContent = vm.$el.textContent.replace(/\s\s+/g, ' ');
|
||||
|
||||
expect(vm.$el.classList.contains('collapsed')).toEqual(true);
|
||||
expect(vm.$el.querySelectorAll('.user-avatar-link').length).toEqual(3);
|
||||
expect(vm.$el.querySelector('time')).not.toBeNull();
|
||||
expect(vmTextContent).toContain('5 replies');
|
||||
expect(vmTextContent).toContain(`Last reply by ${noteFromAnotherUser.author.name}`);
|
||||
it('renders collapsed state elements', () => {
|
||||
expect(findExpandToggleButton().exists()).toBe(true);
|
||||
expect(findUserAvatarLink()).toHaveLength(3);
|
||||
expect(findRepliesButton().exists()).toBe(true);
|
||||
expect(wrapper.text()).toContain('Last reply by');
|
||||
expect(findUserLink().exists()).toBe(true);
|
||||
expect(findTimeAgoTooltip().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should emit toggle event when the replies text clicked', () => {
|
||||
const spy = jest.spyOn(vm, '$emit');
|
||||
it('emits "toggle" event when expand toggle button is clicked', () => {
|
||||
findExpandToggleButton().trigger('click');
|
||||
|
||||
vm.$el.querySelector('.js-replies-text').click();
|
||||
expect(wrapper.emitted('toggle')).toEqual([[]]);
|
||||
});
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('toggle');
|
||||
it('emits "toggle" event when replies button is clicked', () => {
|
||||
findRepliesButton().trigger('click');
|
||||
|
||||
expect(wrapper.emitted('toggle')).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('expanded state', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(ToggleRepliesWidget, {
|
||||
replies,
|
||||
collapsed: false,
|
||||
});
|
||||
wrapper = mountComponent({ collapsed: false });
|
||||
});
|
||||
|
||||
it('should render expanded state', () => {
|
||||
const vmTextContent = vm.$el.textContent.replace(/\s\s+/g, ' ');
|
||||
|
||||
expect(vm.$el.querySelector('.collapse-replies-btn')).not.toBeNull();
|
||||
expect(vmTextContent).toContain('Collapse replies');
|
||||
it('renders expanded state elements', () => {
|
||||
expect(findCollapseToggleButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should emit toggle event when the collapse replies text called', () => {
|
||||
const spy = jest.spyOn(vm, '$emit');
|
||||
it('emits "toggle" event when collapse toggle button is clicked', () => {
|
||||
findCollapseToggleButton().trigger('click');
|
||||
|
||||
vm.$el.querySelector('.js-collapse-replies').click();
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('toggle');
|
||||
expect(wrapper.emitted('toggle')).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -193,8 +193,6 @@ RSpec.describe Gitlab::BareRepositoryImport::Importer, :seed_helper do
|
|||
def prepare_repository(project_path, source_project)
|
||||
repo_path = File.join(base_dir, project_path)
|
||||
|
||||
return create_bare_repository(repo_path) unless source_project
|
||||
|
||||
cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{source_project} #{repo_path})
|
||||
|
||||
system(git_env, *cmd, chdir: SEED_STORAGE_PATH, out: '/dev/null', err: '/dev/null')
|
||||
|
|
|
@ -59,18 +59,15 @@ RSpec.describe ::Gitlab::BareRepositoryImport::Repository do
|
|||
let(:root_path) { TestEnv.repos_path }
|
||||
let(:repo_path) { File.join(root_path, "#{hashed_path}.git") }
|
||||
let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
|
||||
let(:raw_repository) { Gitlab::Git::Repository.new('default', "#{hashed_path}.git", nil, nil) }
|
||||
|
||||
before do
|
||||
TestEnv.create_bare_repository(repo_path)
|
||||
|
||||
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
|
||||
repository = Rugged::Repository.new(repo_path)
|
||||
repository.config['gitlab.fullpath'] = 'to/repo'
|
||||
end
|
||||
raw_repository.create_repository
|
||||
raw_repository.set_full_path(full_path: 'to/repo')
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(repo_path)
|
||||
raw_repository.remove
|
||||
end
|
||||
|
||||
subject { described_class.new(root_path, repo_path) }
|
||||
|
|
|
@ -543,15 +543,15 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
end
|
||||
|
||||
context 'with legacy storage' do
|
||||
let(:fake_repo_path) { File.join(TestEnv.repos_path, user.namespace.full_path, 'existing.git') }
|
||||
let(:raw_fake_repo) { Gitlab::Git::Repository.new('default', File.join(user.namespace.full_path, 'existing.git'), nil, nil) }
|
||||
|
||||
before do
|
||||
stub_application_setting(hashed_storage_enabled: false)
|
||||
TestEnv.create_bare_repository(fake_repo_path)
|
||||
raw_fake_repo.create_repository
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(fake_repo_path)
|
||||
raw_fake_repo.remove
|
||||
end
|
||||
|
||||
it 'does not allow to create a project when path matches existing repository on disk' do
|
||||
|
@ -578,15 +578,15 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
context 'with hashed storage' do
|
||||
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
|
||||
let(:hashed_path) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
|
||||
let(:fake_repo_path) { File.join(TestEnv.repos_path, "#{hashed_path}.git") }
|
||||
let(:raw_fake_repo) { Gitlab::Git::Repository.new('default', "#{hashed_path}.git", nil, nil) }
|
||||
|
||||
before do
|
||||
allow(Digest::SHA2).to receive(:hexdigest) { hash }
|
||||
TestEnv.create_bare_repository(fake_repo_path)
|
||||
raw_fake_repo.create_repository
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(fake_repo_path)
|
||||
raw_fake_repo.remove
|
||||
end
|
||||
|
||||
it 'does not allow to create a project when path matches existing repository on disk' do
|
||||
|
|
|
@ -156,16 +156,16 @@ RSpec.describe Projects::ForkService do
|
|||
end
|
||||
|
||||
context 'repository in legacy storage already exists' do
|
||||
let(:fake_repo_path) { File.join(TestEnv.repos_path, @to_user.namespace.full_path, "#{@from_project.path}.git") }
|
||||
let(:raw_fake_repo) { Gitlab::Git::Repository.new('default', File.join(@to_user.namespace.full_path, "#{@from_project.path}.git"), nil, nil) }
|
||||
let(:params) { { namespace: @to_user.namespace, using_service: true } }
|
||||
|
||||
before do
|
||||
stub_application_setting(hashed_storage_enabled: false)
|
||||
TestEnv.create_bare_repository(fake_repo_path)
|
||||
raw_fake_repo.create_repository
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(fake_repo_path)
|
||||
raw_fake_repo.remove
|
||||
end
|
||||
|
||||
subject { fork_project(@from_project, @to_user, params) }
|
||||
|
|
|
@ -372,16 +372,16 @@ RSpec.describe Projects::TransferService do
|
|||
end
|
||||
|
||||
context 'namespace which contains orphan repository with same projects path name' do
|
||||
let(:fake_repo_path) { File.join(TestEnv.repos_path, group.full_path, "#{project.path}.git") }
|
||||
let(:raw_fake_repo) { Gitlab::Git::Repository.new('default', File.join(group.full_path, "#{project.path}.git"), nil, nil) }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
|
||||
TestEnv.create_bare_repository(fake_repo_path)
|
||||
raw_fake_repo.create_repository
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(fake_repo_path)
|
||||
raw_fake_repo.remove
|
||||
end
|
||||
|
||||
it 'does not allow the project transfer' do
|
||||
|
|
|
@ -348,17 +348,17 @@ RSpec.describe Projects::UpdateService do
|
|||
end
|
||||
|
||||
context 'when renaming a project' do
|
||||
let(:fake_repo_path) { File.join(TestEnv.repos_path, user.namespace.full_path, 'existing.git') }
|
||||
let(:raw_fake_repo) { Gitlab::Git::Repository.new('default', File.join(user.namespace.full_path, 'existing.git'), nil, nil) }
|
||||
|
||||
context 'with legacy storage' do
|
||||
let(:project) { create(:project, :legacy_storage, :repository, creator: user, namespace: user.namespace) }
|
||||
|
||||
before do
|
||||
TestEnv.create_bare_repository(fake_repo_path)
|
||||
raw_fake_repo.create_repository
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(fake_repo_path)
|
||||
raw_fake_repo.remove
|
||||
end
|
||||
|
||||
it 'does not allow renaming when new path matches existing repository on disk' do
|
||||
|
|
|
@ -310,14 +310,6 @@ module TestEnv
|
|||
end
|
||||
end
|
||||
|
||||
def create_bare_repository(path)
|
||||
FileUtils.mkdir_p(path)
|
||||
|
||||
system(git_env, *%W(#{Gitlab.config.git.bin_path} -C #{path} init --bare),
|
||||
out: '/dev/null',
|
||||
err: '/dev/null')
|
||||
end
|
||||
|
||||
def repos_path
|
||||
@repos_path ||= GitalySetup.repos_path
|
||||
end
|
||||
|
|
|
@ -293,7 +293,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
|
|||
it 'can be collapsed' do
|
||||
submit_reply('another text')
|
||||
|
||||
find('.js-collapse-replies').click
|
||||
click_button s_('Notes|Collapse replies'), match: :first
|
||||
expect(page).to have_css('.discussion-notes .note', count: 1)
|
||||
expect(page).to have_content '1 reply'
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue