Commit 67a2efce authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 26f4a225 a6e75cfe
<script>
import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
import uploadDesignMutation from '../../graphql/mutations/upload_design.mutation.graphql';
import { UPLOAD_DESIGN_INVALID_FILETYPE_ERROR } from '../../utils/error_messages';
import { isValidDesignFile } from '../../utils/design_management_utils';
......@@ -56,7 +56,7 @@ export default {
const { files } = dataTransfer;
if (!this.isValidUpload(Array.from(files))) {
createFlash(UPLOAD_DESIGN_INVALID_FILETYPE_ERROR);
createFlash({ message: UPLOAD_DESIGN_INVALID_FILETYPE_ERROR });
return;
}
......
import { propertyOf } from 'lodash';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash, { FLASH_TYPES } from '~/flash';
import { s__ } from '~/locale';
import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
import allVersionsMixin from './all_versions';
......@@ -36,20 +36,20 @@ export default {
},
result() {
if (this.$route.query.version && !this.hasValidVersion) {
createFlash(
s__(
createFlash({
message: s__(
'DesignManagement|Requested design version does not exist. Showing latest version instead',
),
);
});
this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
}
if (this.designCollection.copyState === 'ERROR') {
createFlash(
s__(
createFlash({
message: s__(
'DesignManagement|There was an error moving your designs. Please upload your designs below.',
),
'warning',
);
type: FLASH_TYPES.WARNING,
});
}
},
},
......
......@@ -2,7 +2,7 @@
import Mousetrap from 'mousetrap';
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { ApolloMutation } from 'vue-apollo';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
import { fetchPolicies } from '~/lib/graphql';
import allVersionsMixin from '../../mixins/all_versions';
import Toolbar from '../../components/toolbar/index.vue';
......@@ -230,7 +230,7 @@ export default {
onQueryError(message) {
// because we redirect user to /designs (the issue page),
// we want to create these flashes on the issue page
createFlash(message);
createFlash({ message });
this.$router.push({ name: this.$options.DESIGNS_ROUTE_NAME });
},
onError(message, e) {
......
<script>
import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
import VueDraggable from 'vuedraggable';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash, { FLASH_TYPES } from '~/flash';
import { s__, sprintf } from '~/locale';
import { getFilename } from '~/lib/utils/file_upload';
import UploadButton from '../components/upload/button.vue';
......@@ -139,8 +139,8 @@ export default {
if (!this.canCreateDesign) return false;
if (files.length > MAXIMUM_FILE_UPLOAD_LIMIT) {
createFlash(
sprintf(
createFlash({
message: sprintf(
s__(
'DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again.',
),
......@@ -148,7 +148,7 @@ export default {
upload_limit: MAXIMUM_FILE_UPLOAD_LIMIT,
},
),
);
});
return false;
}
......@@ -191,7 +191,7 @@ export default {
const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || [];
const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles);
if (skippedWarningMessage) {
createFlash(skippedWarningMessage, 'warning');
createFlash({ message: skippedWarningMessage, types: FLASH_TYPES.WARNING });
}
// if this upload resulted in a new version being created, redirect user to the latest version
......@@ -214,7 +214,7 @@ export default {
},
onUploadDesignError() {
this.resetFilesToBeSaved();
createFlash(UPLOAD_DESIGN_ERROR);
createFlash({ message: UPLOAD_DESIGN_ERROR });
},
changeSelectedDesigns(filename) {
if (this.isDesignSelected(filename)) {
......@@ -245,18 +245,18 @@ export default {
},
onDesignDeleteError() {
const errorMessage = designDeletionError({ singular: this.selectedDesigns.length === 1 });
createFlash(errorMessage);
createFlash({ message: errorMessage });
},
onExistingDesignDropzoneChange(files, existingDesignFilename) {
const filesArr = Array.from(files);
if (filesArr.length > 1) {
createFlash(EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE);
createFlash({ message: EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE });
return;
}
if (!filesArr.some(({ name }) => existingDesignFilename === name)) {
createFlash(EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE);
createFlash({ message: EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE });
return;
}
......@@ -307,7 +307,7 @@ export default {
optimisticResponse: moveDesignOptimisticResponse(this.reorderedDesigns),
})
.catch(() => {
createFlash(MOVE_DESIGN_ERROR);
createFlash({ message: MOVE_DESIGN_ERROR });
})
.finally(() => {
this.isReorderingInProgress = false;
......
......@@ -2,7 +2,7 @@
import { differenceBy } from 'lodash';
import produce from 'immer';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
import { extractCurrentDiscussion, extractDesign, extractDesigns } from './design_management_utils';
import {
ADD_IMAGE_DIFF_NOTE_ERROR,
......@@ -237,7 +237,7 @@ export const deletePendingTodoFromStore = (store, todoMarkDone, query, queryVari
};
const onError = (data, message) => {
createFlash(message);
createFlash({ message });
throw new Error(data.errors);
};
......@@ -286,7 +286,7 @@ export const updateStoreAfterUploadDesign = (store, data, query) => {
export const updateDesignsOnStoreAfterReorder = (store, data, query) => {
if (hasErrors(data)) {
createFlash(data.errors[0]);
createFlash({ message: data.errors[0] });
} else {
moveDesignInStore(store, data, query);
}
......
<script>
/* eslint-disable vue/no-v-html */
import { groupBy } from 'lodash';
import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
import tooltip from '~/vue_shared/directives/tooltip';
import { GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { glEmojiTag } from '../../emoji';
import { __, sprintf } from '~/locale';
......@@ -15,7 +14,7 @@ export default {
GlLoadingIcon,
},
directives: {
tooltip,
GlTooltip: GlTooltipDirective,
},
props: {
awards: {
......@@ -154,10 +153,9 @@ export default {
<button
v-for="awardList in groupedAwards"
:key="awardList.name"
v-tooltip
v-gl-tooltip.viewport
:class="awardList.classes"
:title="awardList.title"
data-boundary="viewport"
data-testid="award-button"
class="btn award-control"
type="button"
......@@ -168,12 +166,11 @@ export default {
</button>
<div v-if="canAwardEmoji" class="award-menu-holder">
<button
v-tooltip
v-gl-tooltip.viewport
:class="addButtonClass"
class="award-control btn js-add-award"
title="Add reaction"
:aria-label="__('Add reaction')"
data-boundary="viewport"
type="button"
>
<span class="award-control-icon award-control-icon-neutral">
......
......@@ -6,7 +6,7 @@
- if verification_enabled && domain_presenter.unverified?
= content_for :flash_message do
.alert.alert-warning
.gl-alert.gl-alert-warning
.container-fluid.container-limited
= _("This domain is not verified. You will need to verify ownership before access is enabled.")
......
---
title: Download LFS files when importing from Bitbucket Server
merge_request: 45908
author:
type: fixed
---
title: Migrate tooltip in app/assets/javascripts/vue_shared/components/awards_list.vue
merge_request: 46171
author:
type: other
......@@ -2,7 +2,7 @@
PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE = <<~MSG
For the following files, a review from the [Data team and Product Analytics team](https://gitlab.com/groups/gitlab-org/growth/product_analytics/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
Please check the ~"product analytics(telemetry)" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<product_analytics_engineers_group>s group for a review.
Please check the ~"product analytics" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<product_analytics_engineers_group>s group for a review.
%<changed_files>s
......@@ -41,8 +41,8 @@ if changed_files.any?
warn format(PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files), product_analytics_engineers_group: mention)
warn format(UPDATE_METRICS_DEFINITIONS_MESSAGE) unless helper.changed_files(/usage_ping\.md/).any?
product_analytics_labels = ['product analytics(telemetry)']
product_analytics_labels << 'product analytics(telemetry)::review pending' unless helper.mr_has_labels?('product analytics(telemetry)::reviewed')
product_analytics_labels = ['product analytics']
product_analytics_labels << 'product analytics::review pending' unless helper.mr_has_labels?('product analytics::reviewed')
markdown(helper.prepare_labels_for_mr(product_analytics_labels))
end
......@@ -14,5 +14,5 @@ link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert
level: error
scope: raw
raw:
- '((NOTE|TIP|CAUTION|DANGER): \*\*.*\*\*.+)|'
- '(\n(NOTE|TIP|CAUTION|DANGER): \*\*.*\*\*.+)|'
- '((\n[> ]*(\*){1,2}(NOTE|Note|note|TIP|Tip|tip|CAUTION|Caution|caution|DANGER|Danger|danger):(\*){1,2}))'
......@@ -5,9 +5,10 @@
#
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
extends: substitution
message: 'Use "%s" instead of "%s" unless referring to the "Add a To Do" button in the UI.'
message: 'Use "to-do item" in most cases, or "Add a to do" if referring to the UI button.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#feature-names
level: warning
ignorecase: true
ignorecase: false
swap:
'to dos': to-do items
'[Tt]o [Dd]o [Ii]tems?': to-do item
'\w* [Aa] [Tt]o [Dd]o': Add a to do
......@@ -424,10 +424,10 @@ DELETE /groups/:id/epics/:epic_iid
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics/5"
```
## Create a to do
## Create a to-do item
Manually creates a to do for the current user on an epic. If
there already exists a to do for the user on that epic, status code `304` is
Manually creates a to-do item for the current user on an epic. If
there already exists a to-do item for the user on that epic, status code `304` is
returned.
```plaintext
......
......@@ -1507,10 +1507,10 @@ Example response:
}
```
## Create a to do
## Create a to-do item
Manually creates a to do for the current user on an issue. If
there already exists a to do for the user on that issue, status code `304` is
Manually creates a to-do item for the current user on an issue. If
there already exists a to-do item for the user on that issue, status code `304` is
returned.
```plaintext
......
......@@ -2089,10 +2089,10 @@ the `approvals_before_merge` parameter:
}
```
## Create a to do
## Create a to-do item
Manually creates a to do for the current user on a merge request.
If there already exists a to do for the user on that merge request,
Manually creates a to-do item for the current user on a merge request.
If there already exists a to-do item for the user on that merge request,
status code `304` is returned.
```plaintext
......
......@@ -26,7 +26,7 @@ Parameters:
| `project_id` | integer | no | The ID of a project |
| `group_id` | integer | no | The ID of a group |
| `state` | string | no | The state of the to do. Can be either `pending` or `done` |
| `type` | string | no | The type of a to do. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
| `type` | string | no | The type of to-do item. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos"
......@@ -187,7 +187,7 @@ Example Response:
]
```
## Mark a to do as done
## Mark a to-do item as done
Marks a single pending to do given by its ID for the current user as done. The
to do marked as done is returned in the response.
......@@ -200,7 +200,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a to do |
| `id` | integer | yes | The ID of to-do item |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos/130/mark_as_done"
......
......@@ -186,19 +186,19 @@ After completing their portion of investigating or fixing the alert, users can
unassign themselves from the alert. To remove an assignee, select **Edit** next to the **Assignee** dropdown menu
and deselect the user from the list of assignees, or select **Unassigned**.
### Create a to do from an alert
### Create a to-do item from an alert
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
You can manually create [To-Do list items](../../user/todos.md) for yourself
from the Alert details screen, and view them later on your **To-Do List**. To
add a to do:
add a to-do item:
1. To display the list of current alerts, navigate to **Operations > Alerts**.
1. Select your desired alert to display its **Alert Management Details View**.
1. Select the **Add a To-Do** button in the right sidebar:
![Alert Details Add A To Do](./img/alert_detail_add_todo_v13_1.png)
![Alert Details Add a To-Do](./img/alert_detail_add_todo_v13_1.png)
Select the **To-Do List** **{todo-done}** in the navigation bar to view your current to-do list.
......
......@@ -190,7 +190,7 @@ adds a `missed::SLA` label to the incident.
## Incident Actions
There are different actions avilable to help triage and respond to incidents.
There are different actions available to help triage and respond to incidents.
### Assign incidents
......@@ -200,9 +200,9 @@ Assign incidents to users that are actively responding. Select **Edit** in the r
See [Incident List](#incident-list) for a full description of the severities available. Select **Edit** in the right-hand side bar to change the severity of an incident.
### Add a to do
### Add a to-do item
Add a to-do for incidents that you want to track in your to-do list. Clicke the **Add a to do** button at the top of the right-hand side bar to add a to do.
Add a to-do for incidents that you want to track in your to-do list. Click the **Add a to do** button at the top of the right-hand side bar to add a to-do item.
### Manage incidents from Slack
......
......@@ -47,3 +47,32 @@ If you see a **Revoke** button, you can revoke that user's PAT. Whether you see
You can **Delete** a user's SSH key by navigating to the credentials inventory's SSH Keys tab.
![Credentials inventory page - SSH keys](img/credentials_inventory_ssh_keys_v13_5.png)
## Revocation or deletion notification
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250354) in GitLab 13.6.
> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-revocation-or-deletion-notification).
CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
### Enable or disable revocation or deletion notification **(ULTIMATE ONLY)**
Revocation or deletion notification is under development and not ready for production use. It is deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can enable it.
To enable it:
```ruby
Feature.enable(:credentials_inventory_revocation_emails)
```
To disable it:
```ruby
Feature.disable(:credentials_inventory_revocation_emails)
```
......@@ -228,7 +228,7 @@ available in the **Resolved Comment** area at the bottom of the right sidebar.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198439) in GitLab 13.4.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/245074) in GitLab 13.5.
Add a to do for a design by clicking **Add a To Do** on the design sidebar:
Add a to-do item for a design by clicking **Add a to do** on the design sidebar:
![To-do button](img/design_todo_button_v13_5.png)
......
......@@ -265,6 +265,25 @@ Once the Code Quality job has completed:
[downloadable artifact](../../../ci/pipelines/job_artifacts.md#downloading-artifacts)
for the `code_quality` job.
### Generating an HTML report
In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/ci-cd/codequality/-/issues/10),
it is possible to generate an HTML report file by setting the `REPORT_FORMAT`
variable to `html`. This is useful if you just want to view the report in a more
human-readable format or to publish this artifact on GitLab Pages for even
easier reviewing.
```yaml
include:
- template: Code-Quality.gitlab-ci.yml
code_quality:
variables:
REPORT_FORMAT: html
artifacts:
paths: [gl-code-quality-report.html]
```
## Extending functionality
### Using Analysis Plugins
......
......@@ -74,7 +74,7 @@ The following quick actions are applicable to descriptions, discussions and thre
| `/tableflip <comment>` | ✓ | ✓ | ✓ | Append the comment with `(╯°□°)╯︵ ┻━┻`. |
| `/target_branch <local branch name>` | | ✓ | | Set target branch. |
| `/title <new title>` | ✓ | ✓ | ✓ | Change title. |
| `/todo` | ✓ | ✓ | ✓ | Add a to do. |
| `/todo` | ✓ | ✓ | ✓ | Add a to-do item. |
| `/unassign @user1 @user2` | ✓ | ✓ | | Remove specific assignees. **(STARTER)** |
| `/unassign` | ✓ | ✓ | | Remove all assignees. |
| `/unlabel ~label1 ~label2` or `/remove_label ~label1 ~label2` | ✓ | ✓ | ✓ | Remove specified labels. |
......
......@@ -15,9 +15,9 @@ spend your time. This can include taking an action, or keeping track of things
do your work, being able to get started quickly is important.
Your *To-Do List* offers a chronological list of items waiting for your input
(known as *to do items*) in a single dashboard.
(known as *to-do items*) in a single dashboard.
The To-Do List supports tracking [actions](#what-triggers-a-to-do) related to
The To-Do List supports tracking [actions](#what-triggers-a-to-do-item) related to
the following:
- Issues
......@@ -27,17 +27,17 @@ the following:
![to-do screenshot showing a list of items to check on](img/todos_index.png)
You can access your To-Do List by clicking the To-Do List icon (**{task-done}**)
next to the search bar in the top navigation. If the to do item count is:
next to the search bar in the top navigation. If the to-do item count is:
- *Less than 100*, the number in blue is the number of to do items.
- *Less than 100*, the number in blue is the number of to-do items.
- *100 or more*, the number displays as 99+. The exact number displays in the
To-Do List.
![To Do icon](img/todos_icon.png)
## What triggers a to do
## What triggers a to-do item
A to do item appears on your To-Do List when:
A to-do item appears on your To-Do List when:
- An issue or merge request is assigned to you.
- You're `@mentioned` in the description or comment of an issue or merge request
......@@ -60,19 +60,19 @@ When several trigger actions occur for the same user on the same object (for
example, an issue), GitLab displays only the first action as a single to do
item.
To do item triggers aren't affected by [GitLab notification email settings](profile/notifications.md).
To-do item triggers aren't affected by [GitLab notification email settings](profile/notifications.md).
NOTE: **Note:**
When a user no longer has access to a resource related to a to do item (such as
When a user no longer has access to a resource related to a to-do item (such as
an issue, merge request, project, or group), for security reasons GitLab
deletes any related to do items within the next hour. Deletion is delayed to
deletes any related to-do items within the next hour. Deletion is delayed to
prevent data loss, in the case where a user's access is accidentally revoked.
### Directly addressing a to do
### Directly addressing a to-do item
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7926) in GitLab 9.0.
If you're mentioned at the start of a line, the to do item you receive will be
If you're mentioned at the start of a line, the to-do item you receive will be
listed as *directly addressed*. For example, in the following comment:
```markdown
......@@ -87,11 +87,11 @@ listed as *directly addressed*. For example, in the following comment:
@erin @frank thank you!
```
The people receiving directly addressed to do items are `@alice`, `@erin`, and
`@frank`. Directly addressed to do items only differ from mentions in their type
The people receiving directly addressed to-do items are `@alice`, `@erin`, and
`@frank`. Directly addressed to-do items only differ from mentions in their type
for filtering purposes; otherwise, they appear as normal.
### Manually creating a to do
### Manually creating a to-do item
You can also add the following to your To-Do List by clicking the **Add a to do** button on an:
......@@ -100,14 +100,14 @@ You can also add the following to your To-Do List by clicking the **Add a to do*
- [Epic](group/epics/index.md) **(ULTIMATE)**
- [Design](project/issues/design_management.md)
![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
![Adding a to-do item from the issuable sidebar](img/todos_add_todo_sidebar.png)
## Marking a to do as done
## Marking a to-do item as done
Any action to an issue or merge request (or epic **(ULTIMATE)**) will mark its
corresponding to do item as done.
corresponding to-do item as done.
Actions that dismiss to do items include:
Actions that dismiss to-do items include:
- Changing the assignee
- Changing the milestone
......@@ -115,28 +115,28 @@ Actions that dismiss to do items include:
- Commenting on the issue
Your To-Do List is personal, and items are only marked as done if you take
action. If you close the issue or merge request, your to do item is marked as
action. If you close the issue or merge request, your to-do item is marked as
done.
To prevent other users from closing issues without you being notified, if
someone else closes, merges, or takes action on an issue or merge request (or
epic **(ULTIMATE)**), your to do item remains pending.
epic **(ULTIMATE)**), your to-do item remains pending.
There's just one to do item for each of these, so mentioning a user many times
in an issue only triggers one to do item.
There's just one to-do item for each of these, so mentioning a user many times
in an issue only triggers one to-do item.
If no action is needed, you can manually mark the to do item as done by
If no action is needed, you can manually mark the to-do item as done by
clicking its corresponding **Done** button to have GitLab remove the item from
your To-Do List.
![A to do in the To-Do List](img/todos_todo_list_item.png)
You can also mark a to do item as done by clicking the **Mark as done** button
You can also mark a to-do item as done by clicking the **Mark as done** button
in the sidebar of an issue or merge request (or epic **(ULTIMATE)**).
![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
You can mark all your to do items as done at once by clicking the
You can mark all your to-do items as done at once by clicking the
**Mark all as done** button.
## Filtering your To-Do List
......@@ -152,7 +152,7 @@ You can use the following types of filters with your To-Do List:
| Action | Filter by the action that triggered the to do. |
You can also filter by more than one of these at the same time. The previously
described [triggering actions](#what-triggers-a-to-do) include:
described [triggering actions](#what-triggers-a-to-do-item) include:
- Any action
- Assigned
......
......@@ -19,6 +19,7 @@ module CredentialsInventoryActions
alert = if key.present?
if Keys::DestroyService.new(current_user).execute(key)
notify_deleted_or_revoked_credential(key)
_('User key was successfully removed.')
else
_('Failed to remove user key.')
......@@ -33,7 +34,12 @@ module CredentialsInventoryActions
def revoke
personal_access_token = PersonalAccessTokensFinder.new({ user: users, impersonation: false }, current_user).find(params[:id])
service = PersonalAccessTokens::RevokeService.new(current_user, token: personal_access_token).execute
service.success? ? flash[:notice] = service.message : flash[:alert] = service.message
if service.success?
flash[:notice] = service.message
notify_deleted_or_revoked_credential(personal_access_token)
else
flash[:alert] = service.message
end
redirect_to credentials_inventory_path(page: params[:page])
end
......@@ -48,6 +54,16 @@ module CredentialsInventoryActions
end
end
def notify_deleted_or_revoked_credential(credential)
return unless Feature.enabled?(:credentials_inventory_revocation_emails, credential.user)
if credential.is_a?(Key)
CredentialsInventoryMailer.ssh_key_deleted_email(key: credential, deleted_by: current_user).deliver_later
elsif credential.is_a?(PersonalAccessToken)
CredentialsInventoryMailer.personal_access_token_revoked_email(token: credential, revoked_by: current_user).deliver_later
end
end
def users
raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
......
---
name: credentials_inventory_revocation_emails
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46033
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/271577
type: development
group: group::compliance
default_enabled: false
......@@ -164,6 +164,24 @@ RSpec.describe Admin::CredentialsController do
expect(response).to redirect_to(admin_credentials_path)
expect(flash[:notice]).to eql 'Revoked personal access token %{personal_access_token_name}!' % { personal_access_token_name: personal_access_token.name }
end
it 'informs the token owner' do
expect(CredentialsInventoryMailer).to receive_message_chain(:personal_access_token_revoked_email, :deliver_later)
put :revoke, params: { id: personal_access_token.id }
end
context 'when credentials_inventory_revocation_emails flag is disabled' do
before do
stub_feature_flags(credentials_inventory_revocation_emails: false)
end
it 'does not inform the token owner' do
expect do
put :revoke, params: { id: personal_access_token.id }
end.not_to change { ActionMailer::Base.deliveries.size }
end
end
end
end
end
......
......@@ -24,6 +24,7 @@ RSpec.describe GitlabSchema.types['Mutation'] do
where(:alias_name, :canonical_name) do
'DismissVulnerability' | 'VulnerabilityDismiss'
'RevertVulnerabilityToDetected' | 'VulnerabilityRevertToDetected'
end
with_them do
......
......@@ -31,12 +31,26 @@ RSpec.describe 'SAST.gitlab-ci.yml' do
end
end
context 'when SAST_EXPERIMENTAL_FEATURES is disabled for iOS projects' do
let(:files) { { 'a.xcodeproj/x.pbxproj' => '' } }
before do
create(:ci_variable, project: project, key: 'SAST_EXPERIMENTAL_FEATURES', value: 'false')
end
it 'includes no jobs' do
expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
end
end
context 'by default' do
describe 'language detection' do
using RSpec::Parameterized::TableSyntax
where(:case_name, :files, :variables, :include_build_names) do
'Android' | { 'AndroidManifest.xml' => '', 'a.java' => '' } | { 'SAST_EXPERIMENTAL_FEATURES' => 'true' } | %w(mobsf-android-sast)
'Android' | { 'app/src/main/AndroidManifest.xml' => '' } | { 'SAST_EXPERIMENTAL_FEATURES' => 'true' } | %w(mobsf-android-sast)
'Android' | { 'a/b/AndroidManifest.xml' => '' } | { 'SAST_EXPERIMENTAL_FEATURES' => 'true' } | %w(mobsf-android-sast)
'Apex' | { 'app.cls' => '' } | {} | %w(pmd-apex-sast)
'C' | { 'app.c' => '' } | {} | %w(flawfinder-sast)
'C++' | { 'app.cpp' => '' } | {} | %w(flawfinder-sast)
......
......@@ -33,6 +33,24 @@ RSpec.shared_examples_for 'credentials inventory controller delete SSH key' do |
expect(response).to redirect_to(credentials_path)
expect(flash[:notice]).to eql 'User key was successfully removed.'
end
it 'notifies the key owner' do
expect(CredentialsInventoryMailer).to receive_message_chain(:ssh_key_deleted_email, :deliver_later)
subject
end
context 'when credentials_inventory_revocation_emails is disabled' do
before do
stub_feature_flags(credentials_inventory_revocation_emails: false)
end
it 'does not notify the key owner' do
expect(CredentialsInventoryMailer).not_to receive(:ssh_key_deleted_email)
subject
end
end
end
context 'and it fails to remove the key' do
......
......@@ -41,6 +41,7 @@ module Gitlab
def execute
import_repository
import_pull_requests
download_lfs_objects
delete_temp_branches
handle_errors
metrics.track_finished_import
......@@ -148,6 +149,14 @@ module Gitlab
raise
end
def download_lfs_objects
result = Projects::LfsPointers::LfsImportService.new(project).execute
if result[:status] == :error
errors << { type: :lfs_objects, errors: "The Lfs import process failed. #{result[:message]}" }
end
end
# Bitbucket Server keeps tracks of references for open pull requests in
# refs/heads/pull-requests, but closed and merged requests get moved
# into hidden internal refs under stash-refs/pull-requests. Unless the
......
......@@ -34,6 +34,7 @@ code_quality:
CODECLIMATE_DEBUG \
CODECLIMATE_DEV \
REPORT_STDOUT \
REPORT_FORMAT \
ENGINE_MEMORY_LIMIT_BYTES \
) \
--volume "$PWD":/code \
......
import { shallowMount } from '@vue/test-utils';
import { GlIcon } from '@gitlab/ui';
import DesignDropzone from '~/design_management/components/upload/design_dropzone.vue';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
jest.mock('~/flash');
......
......@@ -2,7 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueRouter from 'vue-router';
import { GlAlert } from '@gitlab/ui';
import { ApolloMutation } from 'vue-apollo';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
import DesignIndex from '~/design_management/pages/design/index.vue';
import DesignSidebar from '~/design_management/components/design_sidebar.vue';
import DesignPresentation from '~/design_management/components/design_presentation.vue';
......@@ -295,7 +295,7 @@ describe('Design management design index page', () => {
wrapper.vm.onDesignQueryResult({ data: mockResponseNoDesigns, loading: false });
return wrapper.vm.$nextTick().then(() => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(DESIGN_NOT_FOUND_ERROR);
expect(createFlash).toHaveBeenCalledWith({ message: DESIGN_NOT_FOUND_ERROR });
expect(router.push).toHaveBeenCalledTimes(1);
expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
});
......@@ -316,7 +316,7 @@ describe('Design management design index page', () => {
wrapper.vm.onDesignQueryResult({ data: mockResponseWithDesigns, loading: false });
return wrapper.vm.$nextTick().then(() => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(DESIGN_VERSION_NOT_EXIST_ERROR);
expect(createFlash).toHaveBeenCalledWith({ message: DESIGN_VERSION_NOT_EXIST_ERROR });
expect(router.push).toHaveBeenCalledTimes(1);
expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
});
......
......@@ -16,7 +16,7 @@ import {
EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE,
EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
} from '~/design_management/utils/error_messages';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
import createRouter from '~/design_management/router';
import * as utils from '~/design_management/utils/design_management_utils';
import {
......@@ -443,10 +443,10 @@ describe('Design management index page', () => {
return uploadDesign.then(() => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(
'Upload skipped. test.jpg did not change.',
'warning',
);
expect(createFlash).toHaveBeenCalledWith({
message: 'Upload skipped. test.jpg did not change.',
types: 'warning',
});
});
});
......@@ -482,7 +482,7 @@ describe('Design management index page', () => {
designDropzone.vm.$emit('change', eventPayload);
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(message);
expect(createFlash).toHaveBeenCalledWith({ message });
});
});
......@@ -747,7 +747,7 @@ describe('Design management index page', () => {
await wrapper.vm.$nextTick();
expect(createFlash).toHaveBeenCalledWith('Houston, we have a problem');
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
});
it('displays flash if mutation had a non-recoverable error', async () => {
......@@ -761,9 +761,9 @@ describe('Design management index page', () => {
await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
await wrapper.vm.$nextTick(); // kick off the DOM update for flash
expect(createFlash).toHaveBeenCalledWith(
'Something went wrong when reordering designs. Please try again',
);
expect(createFlash).toHaveBeenCalledWith({
message: 'Something went wrong when reordering designs. Please try again',
});
});
});
});
......@@ -11,7 +11,7 @@ import {
UPDATE_IMAGE_DIFF_NOTE_ERROR,
} from '~/design_management/utils/error_messages';
import design from '../mock_data/design';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import createFlash from '~/flash';
jest.mock('~/flash.js');
......@@ -35,7 +35,7 @@ describe('Design Management cache update', () => {
expect(createFlash).not.toHaveBeenCalled();
expect(() => subject(mockStore, { errors: mockErrors }, {}, ...extraArgs)).toThrow();
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(errorMessage);
expect(createFlash).toHaveBeenCalledWith({ message: errorMessage });
});
});
});
......@@ -92,15 +92,14 @@ describe('note_awards_list component', () => {
}).$mount();
};
const findTooltip = () =>
vm.$el.querySelector('[data-original-title]').getAttribute('data-original-title');
const findTooltip = () => vm.$el.querySelector('[title]').getAttribute('title');
it('should only escape & and " characters', () => {
awardsMock = [...new Array(1)].map(createAwardEmoji);
mountComponent();
const escapedName = awardsMock[0].user.name.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
expect(vm.$el.querySelector('[data-original-title]').outerHTML).toContain(escapedName);
expect(vm.$el.querySelector('[title]').outerHTML).toContain(escapedName);
});
it('should not escape special HTML characters twice when only 1 person awarded', () => {
......
......@@ -6,10 +6,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
>
<button
class="btn award-control"
data-boundary="viewport"
data-original-title="Ada, Leonardo, and Marie"
data-testid="award-button"
title=""
title="Ada, Leonardo, and Marie"
type="button"
>
<span
......@@ -32,10 +30,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control active"
data-boundary="viewport"
data-original-title="You, Ada, and Marie"
data-testid="award-button"
title=""
title="You, Ada, and Marie"
type="button"
>
<span
......@@ -58,10 +54,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control"
data-boundary="viewport"
data-original-title="Ada and Jane"
data-testid="award-button"
title=""
title="Ada and Jane"
type="button"
>
<span
......@@ -84,10 +78,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control active"
data-boundary="viewport"
data-original-title="You, Ada, Jane, and Leonardo"
data-testid="award-button"
title=""
title="You, Ada, Jane, and Leonardo"
type="button"
>
<span
......@@ -110,10 +102,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control active"
data-boundary="viewport"
data-original-title="You"
data-testid="award-button"
title=""
title="You"
type="button"
>
<span
......@@ -136,10 +126,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control"
data-boundary="viewport"
data-original-title="Marie"
data-testid="award-button"
title=""
title="Marie"
type="button"
>
<span
......@@ -162,10 +150,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
</button>
<button
class="btn award-control active"
data-boundary="viewport"
data-original-title="You"
data-testid="award-button"
title=""
title="You"
type="button"
>
<span
......@@ -193,9 +179,7 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<button
aria-label="Add reaction"
class="award-control btn js-add-award js-test-add-button-class"
data-boundary="viewport"
data-original-title="Add reaction"
title=""
title="Add reaction"
type="button"
>
<span
......
......@@ -62,7 +62,7 @@ describe('vue_shared/components/awards_list', () => {
findAwardButtons().wrappers.map(x => {
return {
classes: x.classes(),
title: x.attributes('data-original-title'),
title: x.attributes('title'),
html: x.find('[data-testid="award-html"]').element.innerHTML,
count: Number(x.find('.js-counter').text()),
};
......
......@@ -525,4 +525,36 @@ RSpec.describe Gitlab::BitbucketServerImport::Importer do
expect { subject.execute }.to change { MergeRequest.count }.by(1)
end
end
context "lfs files" do
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
allow(subject).to receive(:import_repository)
allow(subject).to receive(:import_pull_requests)
end
it "downloads lfs objects if lfs_enabled is enabled for project" do
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |lfs_import_service|
expect(lfs_import_service).to receive(:execute).and_return(status: :success)
end
subject.execute
end
it "adds the error message when the lfs download fails" do
allow_next_instance_of(Projects::LfsPointers::LfsImportService) do |lfs_import_service|
expect(lfs_import_service).to receive(:execute).and_return(status: :error, message: "LFS server not reachable")
end
subject.execute
expect(project.import_state.reload.last_error).to eq(Gitlab::Json.dump({
message: "The remote data could not be fully imported.",
errors: [{
type: "lfs_objects",
errors: "The Lfs import process failed. LFS server not reachable"
}]
}))
end
end
end
......@@ -32,16 +32,8 @@ module SnowplowHelpers
# end
# end
def expect_snowplow_event(category:, action:, **kwargs)
# This check will no longer be needed with Ruby 2.7 which
# would not pass any arguments when using **kwargs.
# https://gitlab.com/gitlab-org/gitlab/-/issues/263430
if kwargs.present?
expect(Gitlab::Tracking).to have_received(:event) # rubocop:disable RSpec/ExpectGitlabTracking
.with(category, action, **kwargs).at_least(:once)
else
expect(Gitlab::Tracking).to have_received(:event) # rubocop:disable RSpec/ExpectGitlabTracking
.with(category, action).at_least(:once)
end
expect(Gitlab::Tracking).to have_received(:event) # rubocop:disable RSpec/ExpectGitlabTracking
.with(category, action, **kwargs).at_least(:once)
end
# Asserts that no call to `Gitlab::Tracking#event` was made.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment