Commit ef326e80 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 7515ec41
...@@ -13,6 +13,7 @@ export default class AvailableDropdownMappings { ...@@ -13,6 +13,7 @@ export default class AvailableDropdownMappings {
runnerTagsEndpoint, runnerTagsEndpoint,
labelsEndpoint, labelsEndpoint,
milestonesEndpoint, milestonesEndpoint,
releasesEndpoint,
groupsOnly, groupsOnly,
includeAncestorGroups, includeAncestorGroups,
includeDescendantGroups, includeDescendantGroups,
...@@ -21,6 +22,7 @@ export default class AvailableDropdownMappings { ...@@ -21,6 +22,7 @@ export default class AvailableDropdownMappings {
this.runnerTagsEndpoint = runnerTagsEndpoint; this.runnerTagsEndpoint = runnerTagsEndpoint;
this.labelsEndpoint = labelsEndpoint; this.labelsEndpoint = labelsEndpoint;
this.milestonesEndpoint = milestonesEndpoint; this.milestonesEndpoint = milestonesEndpoint;
this.releasesEndpoint = releasesEndpoint;
this.groupsOnly = groupsOnly; this.groupsOnly = groupsOnly;
this.includeAncestorGroups = includeAncestorGroups; this.includeAncestorGroups = includeAncestorGroups;
this.includeDescendantGroups = includeDescendantGroups; this.includeDescendantGroups = includeDescendantGroups;
...@@ -70,6 +72,19 @@ export default class AvailableDropdownMappings { ...@@ -70,6 +72,19 @@ export default class AvailableDropdownMappings {
}, },
element: this.container.querySelector('#js-dropdown-milestone'), element: this.container.querySelector('#js-dropdown-milestone'),
}, },
release: {
reference: null,
gl: DropdownNonUser,
extraArguments: {
endpoint: this.getReleasesEndpoint(),
symbol: '',
// The DropdownNonUser class is hardcoded to look for and display a
// "title" property, so we need to add this property to each release object
preprocessing: releases => releases.map(r => ({ ...r, title: r.tag })),
},
element: this.container.querySelector('#js-dropdown-release'),
},
label: { label: {
reference: null, reference: null,
gl: DropdownNonUser, gl: DropdownNonUser,
...@@ -130,6 +145,10 @@ export default class AvailableDropdownMappings { ...@@ -130,6 +145,10 @@ export default class AvailableDropdownMappings {
return `${this.milestonesEndpoint}.json`; return `${this.milestonesEndpoint}.json`;
} }
getReleasesEndpoint() {
return `${this.releasesEndpoint}.json`;
}
getLabelsEndpoint() { getLabelsEndpoint() {
let endpoint = `${this.labelsEndpoint}.json?`; let endpoint = `${this.labelsEndpoint}.json?`;
......
...@@ -11,6 +11,7 @@ export default class FilteredSearchDropdownManager { ...@@ -11,6 +11,7 @@ export default class FilteredSearchDropdownManager {
runnerTagsEndpoint = '', runnerTagsEndpoint = '',
labelsEndpoint = '', labelsEndpoint = '',
milestonesEndpoint = '', milestonesEndpoint = '',
releasesEndpoint = '',
tokenizer, tokenizer,
page, page,
isGroup, isGroup,
...@@ -18,10 +19,13 @@ export default class FilteredSearchDropdownManager { ...@@ -18,10 +19,13 @@ export default class FilteredSearchDropdownManager {
isGroupDecendent, isGroupDecendent,
filteredSearchTokenKeys, filteredSearchTokenKeys,
}) { }) {
const removeTrailingSlash = url => url.replace(/\/$/, '');
this.container = FilteredSearchContainer.container; this.container = FilteredSearchContainer.container;
this.runnerTagsEndpoint = runnerTagsEndpoint.replace(/\/$/, ''); this.runnerTagsEndpoint = removeTrailingSlash(runnerTagsEndpoint);
this.labelsEndpoint = labelsEndpoint.replace(/\/$/, ''); this.labelsEndpoint = removeTrailingSlash(labelsEndpoint);
this.milestonesEndpoint = milestonesEndpoint.replace(/\/$/, ''); this.milestonesEndpoint = removeTrailingSlash(milestonesEndpoint);
this.releasesEndpoint = removeTrailingSlash(releasesEndpoint);
this.tokenizer = tokenizer; this.tokenizer = tokenizer;
this.filteredSearchTokenKeys = filteredSearchTokenKeys || FilteredSearchTokenKeys; this.filteredSearchTokenKeys = filteredSearchTokenKeys || FilteredSearchTokenKeys;
this.filteredSearchInput = this.container.querySelector('.filtered-search'); this.filteredSearchInput = this.container.querySelector('.filtered-search');
...@@ -54,6 +58,7 @@ export default class FilteredSearchDropdownManager { ...@@ -54,6 +58,7 @@ export default class FilteredSearchDropdownManager {
this.runnerTagsEndpoint, this.runnerTagsEndpoint,
this.labelsEndpoint, this.labelsEndpoint,
this.milestonesEndpoint, this.milestonesEndpoint,
this.releasesEndpoint,
this.groupsOnly, this.groupsOnly,
this.includeAncestorGroups, this.includeAncestorGroups,
this.includeDescendantGroups, this.includeDescendantGroups,
......
...@@ -89,6 +89,7 @@ export default class FilteredSearchManager { ...@@ -89,6 +89,7 @@ export default class FilteredSearchManager {
this.filteredSearchInput.getAttribute('data-runner-tags-endpoint') || '', this.filteredSearchInput.getAttribute('data-runner-tags-endpoint') || '',
labelsEndpoint: this.filteredSearchInput.getAttribute('data-labels-endpoint') || '', labelsEndpoint: this.filteredSearchInput.getAttribute('data-labels-endpoint') || '',
milestonesEndpoint: this.filteredSearchInput.getAttribute('data-milestones-endpoint') || '', milestonesEndpoint: this.filteredSearchInput.getAttribute('data-milestones-endpoint') || '',
releasesEndpoint: this.filteredSearchInput.getAttribute('data-releases-endpoint') || '',
tokenizer: this.tokenizer, tokenizer: this.tokenizer,
page: this.page, page: this.page,
isGroup: this.isGroup, isGroup: this.isGroup,
......
import FilteredSearchTokenKeys from './filtered_search_token_keys'; import FilteredSearchTokenKeys from './filtered_search_token_keys';
import { __ } from '~/locale'; import { __ } from '~/locale';
export const tokenKeys = [ export const tokenKeys = [];
tokenKeys.push(
{ {
key: 'author', key: 'author',
type: 'string', type: 'string',
...@@ -26,15 +28,27 @@ export const tokenKeys = [ ...@@ -26,15 +28,27 @@ export const tokenKeys = [
icon: 'clock', icon: 'clock',
tag: '%milestone', tag: '%milestone',
}, },
{ );
key: 'label',
type: 'array', if (gon && gon.features && gon.features.releaseSearchFilter) {
param: 'name[]', tokenKeys.push({
symbol: '~', key: 'release',
icon: 'labels', type: 'string',
tag: '~label', param: 'tag',
}, symbol: '',
]; icon: 'rocket',
tag: __('tag name'),
});
}
tokenKeys.push({
key: 'label',
type: 'array',
param: 'name[]',
symbol: '~',
icon: 'labels',
tag: '~label',
});
if (gon.current_user_id) { if (gon.current_user_id) {
// Appending tokenkeys only logged-in // Appending tokenkeys only logged-in
...@@ -88,6 +102,16 @@ export const conditions = [ ...@@ -88,6 +102,16 @@ export const conditions = [
tokenKey: 'milestone', tokenKey: 'milestone',
value: __('Started'), value: __('Started'),
}, },
{
url: 'release_tag=None',
tokenKey: 'release',
value: __('None'),
},
{
url: 'release_tag=Any',
tokenKey: 'release',
value: __('Any'),
},
{ {
url: 'label_name[]=None', url: 'label_name[]=None',
tokenKey: 'label', tokenKey: 'label',
......
...@@ -76,7 +76,7 @@ export default { ...@@ -76,7 +76,7 @@ export default {
}, },
shouldShowEditButton() { shouldShowEditButton() {
return Boolean( return Boolean(
this.glFeatures.releaseEditPage && this.release._links && this.release._links.edit, this.glFeatures.releaseEditPage && this.release._links && this.release._links.edit_url,
); );
}, },
}, },
...@@ -108,7 +108,7 @@ export default { ...@@ -108,7 +108,7 @@ export default {
v-gl-tooltip v-gl-tooltip
class="btn btn-default js-edit-button ml-2" class="btn btn-default js-edit-button ml-2"
:title="__('Edit this release')" :title="__('Edit this release')"
:href="release._links.edit" :href="release._links.edit_url"
> >
<icon name="pencil" /> <icon name="pencil" />
</gl-link> </gl-link>
......
...@@ -44,6 +44,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -44,6 +44,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action do before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, project.group) push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
push_frontend_feature_flag(:release_search_filter, project)
end end
respond_to :html respond_to :html
......
...@@ -2,12 +2,24 @@ ...@@ -2,12 +2,24 @@
class Projects::ReleasesController < Projects::ApplicationController class Projects::ReleasesController < Projects::ApplicationController
# Authorize # Authorize
before_action :require_non_empty_project before_action :require_non_empty_project, except: [:index]
before_action :authorize_read_release! before_action :authorize_read_release!
before_action do before_action do
push_frontend_feature_flag(:release_edit_page, project) push_frontend_feature_flag(:release_edit_page, project)
end end
def index def index
respond_to do |format|
format.html do
require_non_empty_project
end
format.json { render json: releases }
end
end
protected
def releases
ReleasesFinder.new(@project, current_user).execute
end end
end end
...@@ -236,6 +236,7 @@ module SearchHelper ...@@ -236,6 +236,7 @@ module SearchHelper
opts[:data]['project-id'] = @project.id opts[:data]['project-id'] = @project.id
opts[:data]['labels-endpoint'] = project_labels_path(@project) opts[:data]['labels-endpoint'] = project_labels_path(@project)
opts[:data]['milestones-endpoint'] = project_milestones_path(@project) opts[:data]['milestones-endpoint'] = project_milestones_path(@project)
opts[:data]['releases-endpoint'] = project_releases_path(@project)
elsif @group.present? elsif @group.present?
opts[:data]['group-id'] = @group.id opts[:data]['group-id'] = @group.id
opts[:data]['labels-endpoint'] = group_labels_path(@group) opts[:data]['labels-endpoint'] = group_labels_path(@group)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Clusters module Clusters
module Applications module Applications
class Runner < ApplicationRecord class Runner < ApplicationRecord
VERSION = '0.10.0' VERSION = '0.10.1'
self.table_name = 'clusters_applications_runners' self.table_name = 'clusters_applications_runners'
......
...@@ -91,6 +91,19 @@ ...@@ -91,6 +91,19 @@
%li.filter-dropdown-item %li.filter-dropdown-item
%button.btn.btn-link.js-data-value{ type: 'button' } %button.btn.btn-link.js-data-value{ type: 'button' }
{{title}} {{title}}
#js-dropdown-release.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } }
%button.btn.btn-link{ type: 'button' }
= _('None')
%li.filter-dropdown-item{ data: { value: 'Any' } }
%button.btn.btn-link{ type: 'button' }
= _('Any')
%li.divider.droplab-item-ignore
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
%button.btn.btn-link.js-data-value{ type: 'button' }
{{title}}
#js-dropdown-label.filtered-search-input-dropdown-menu.dropdown-menu #js-dropdown-label.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } } %ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { value: 'None' } } %li.filter-dropdown-item{ data: { value: 'None' } }
......
---
title: Enable image link and lazy loading in AsciiDoc documents
merge_request: 18164
author: Guillaume Grossetie
type: fixed
---
title: Add "release" filter to issue search page
merge_request: 18761
author:
type: added
---
title: Allow release block edit button to be visible
merge_request: 19226
author:
type: fixed
---
title: Update GitLab Runner Helm Chart to 0.10.1
merge_request: 19232
author:
type: other
This diff is collapsed.
...@@ -166,12 +166,11 @@ end ...@@ -166,12 +166,11 @@ end
Normally, GitLab CE/EE tests use a local clone of Gitaly in Normally, GitLab CE/EE tests use a local clone of Gitaly in
`tmp/tests/gitaly` pinned at the version specified in `tmp/tests/gitaly` pinned at the version specified in
`GITALY_SERVER_VERSION`. The `GITALY_SERVER_VERSION` file supports `GITALY_SERVER_VERSION`. The `GITALY_SERVER_VERSION` file supports also
`=my-branch` syntax to use a custom branch in <https://gitlab.com/gitlab-org/gitaly>. If branches and SHA to use a custom commit in <https://gitlab.com/gitlab-org/gitaly>. If
you want to run tests locally against a modified version of Gitaly you you want to run tests locally against a modified version of Gitaly you
can replace `tmp/tests/gitaly` with a symlink. This is much faster can replace `tmp/tests/gitaly` with a symlink. This is much faster
because the `=my-branch` syntax forces a Gitaly re-install each time because if will avoid a Gitaly re-install each time you run `rspec`.
you run `rspec`.
```shell ```shell
rm -rf tmp/tests/gitaly rm -rf tmp/tests/gitaly
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
In April 2019, Francisco Javier López hosted a [Deep Dive] on GitLab's [Git LFS] implementation to share his domain specific knowledge with anyone who may work in this part of the code base in the future. You can find the [recording on YouTube], and the slides on [Google Slides] and in [PDF]. Everything covered in this deep dive was accurate as of GitLab 11.10, and while specific details may have changed since then, it should still serve as a good introduction. In April 2019, Francisco Javier López hosted a [Deep Dive] on GitLab's [Git LFS] implementation to share his domain specific knowledge with anyone who may work in this part of the code base in the future. You can find the [recording on YouTube], and the slides on [Google Slides] and in [PDF]. Everything covered in this deep dive was accurate as of GitLab 11.10, and while specific details may have changed since then, it should still serve as a good introduction.
[Deep Dive]: https://gitlab.com/gitlab-org/create-stage/issues/1 [Deep Dive]: https://gitlab.com/gitlab-org/create-stage/issues/1
[Git LFS]: ../workflow/lfs/manage_large_binaries_with_git_lfs.html [Git LFS]: ../administration/lfs/manage_large_binaries_with_git_lfs.md
[recording on YouTube]: https://www.youtube.com/watch?v=Yyxwcksr0Qc [recording on YouTube]: https://www.youtube.com/watch?v=Yyxwcksr0Qc
[Google Slides]: https://docs.google.com/presentation/d/1E-aw6-z0rYd0346YhIWE7E9A65zISL9iIMAOq2zaw9E/edit [Google Slides]: https://docs.google.com/presentation/d/1E-aw6-z0rYd0346YhIWE7E9A65zISL9iIMAOq2zaw9E/edit
[PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/07a89257a140db067bdfb484aecd35e1/Git_LFS_Deep_Dive__Create_.pdf [PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/07a89257a140db067bdfb484aecd35e1/Git_LFS_Deep_Dive__Create_.pdf
...@@ -136,7 +136,7 @@ If you want to import projects from Bitbucket, but don't want to enable signing ...@@ -136,7 +136,7 @@ If you want to import projects from Bitbucket, but don't want to enable signing
you can [disable Sign-Ins in the admin panel](omniauth.md#enable-or-disable-sign-in-with-an-omniauth-provider-without-disabling-import-sources). you can [disable Sign-Ins in the admin panel](omniauth.md#enable-or-disable-sign-in-with-an-omniauth-provider-without-disabling-import-sources).
[init-oauth]: omniauth.md#initial-omniauth-configuration [init-oauth]: omniauth.md#initial-omniauth-configuration
[bb-import]: ../workflow/importing/import_projects_from_bitbucket.md [bb-import]: ../user/project/import/bitbucket.md
[bb-old]: https://gitlab.com/gitlab-org/gitlab/blob/8-14-stable/doc/integration/bitbucket.md [bb-old]: https://gitlab.com/gitlab-org/gitlab/blob/8-14-stable/doc/integration/bitbucket.md
[bitbucket-docs]: https://confluence.atlassian.com/bitbucket/use-the-ssh-protocol-with-bitbucket-cloud-221449711.html#UsetheSSHprotocolwithBitbucketCloud-KnownhostorBitbucket%27spublickeyfingerprints [bitbucket-docs]: https://confluence.atlassian.com/bitbucket/use-the-ssh-protocol-with-bitbucket-cloud-221449711.html#UsetheSSHprotocolwithBitbucketCloud-KnownhostorBitbucket%27spublickeyfingerprints
[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure [reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
......
...@@ -18,7 +18,7 @@ Create issues, labels, milestones, cast your vote, and review issues. ...@@ -18,7 +18,7 @@ Create issues, labels, milestones, cast your vote, and review issues.
- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue) - [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue)
- [Assign labels to issues](../user/project/labels.md) - [Assign labels to issues](../user/project/labels.md)
- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md) - [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md)
- [Use voting to express your like/dislike to issues and merge requests](../workflow/award_emoji.md) - [Use voting to express your like/dislike to issues and merge requests](../user/award_emojis.md)
## Collaborate ## Collaborate
......
...@@ -85,7 +85,7 @@ The following relate to Git Large File Storage: ...@@ -85,7 +85,7 @@ The following relate to Git Large File Storage:
- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/) - [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- [Migrate an existing Git repo with Git LFS](migrate_to_git_lfs/index.md) - [Migrate an existing Git repo with Git LFS](migrate_to_git_lfs/index.md)
- [GitLab Git LFS user documentation](../../workflow/lfs/manage_large_binaries_with_git_lfs.md) - [GitLab Git LFS user documentation](../../administration/lfs/manage_large_binaries_with_git_lfs.md)
- [GitLab Git LFS admin documentation](../../workflow/lfs/lfs_administration.md) - [GitLab Git LFS admin documentation](../../administration/lfs/lfs_administration.md)
- [git-annex to Git-LFS migration guide](../../workflow/lfs/migrate_from_git_annex_to_git_lfs.md) - [git-annex to Git-LFS migration guide](../../administration/lfs/migrate_from_git_annex_to_git_lfs.md)
- [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/) - [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
...@@ -170,7 +170,7 @@ Some tickets need specific knowledge or a deep understanding of a particular com ...@@ -170,7 +170,7 @@ Some tickets need specific knowledge or a deep understanding of a particular com
Move on to understanding some of GitLab's more advanced features. You can make use of GitLab.com to understand the features from an end-user perspective and then use your own instance to understand setup and configuration of the feature from an Administrative perspective Move on to understanding some of GitLab's more advanced features. You can make use of GitLab.com to understand the features from an end-user perspective and then use your own instance to understand setup and configuration of the feature from an Administrative perspective
- Set up and try [Git LFS](../../workflow/lfs/manage_large_binaries_with_git_lfs.md) - Set up and try [Git LFS](../../administration/lfs/manage_large_binaries_with_git_lfs.md)
- Get to know the [GitLab API](../../api/README.md), its capabilities and shortcomings - Get to know the [GitLab API](../../api/README.md), its capabilities and shortcomings
- Learn how to [migrate from SVN to Git](../../user/project/import/svn.md) - Learn how to [migrate from SVN to Git](../../user/project/import/svn.md)
- Set up [GitLab CI](../../ci/quick_start/README.md) - Set up [GitLab CI](../../ci/quick_start/README.md)
......
# Dependency Proxy **(PREMIUM)** # Dependency Proxy **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11.
......
...@@ -22,12 +22,12 @@ For an overview, see the video [Design Management (GitLab 12.2)](https://www.you ...@@ -22,12 +22,12 @@ For an overview, see the video [Design Management (GitLab 12.2)](https://www.you
## Requirements ## Requirements
Design Management requires Design Management requires
[Large File Storage (LFS)](../../../workflow/lfs/manage_large_binaries_with_git_lfs.md) [Large File Storage (LFS)](../../../administration/lfs/manage_large_binaries_with_git_lfs.md)
to be enabled: to be enabled:
- For GitLab.com, LFS is already enabled. - For GitLab.com, LFS is already enabled.
- For self-managed instances, a GitLab administrator must have - For self-managed instances, a GitLab administrator must have
[enabled LFS globally](../../../workflow/lfs/lfs_administration.md). [enabled LFS globally](../../../administration/lfs/lfs_administration.md).
- For both GitLab.com and self-managed instances: LFS must be enabled for the project itself. - For both GitLab.com and self-managed instances: LFS must be enabled for the project itself.
If enabled globally, LFS will be enabled by default to all projects. To enable LFS on the If enabled globally, LFS will be enabled by default to all projects. To enable LFS on the
project level, navigate to your project's **Settings > General**, expand **Visibility, project features, permissions** project level, navigate to your project's **Settings > General**, expand **Visibility, project features, permissions**
......
...@@ -15,7 +15,7 @@ project. ...@@ -15,7 +15,7 @@ project.
![Find file button](img/file_finder_find_button.png) ![Find file button](img/file_finder_find_button.png)
For those who prefer to keep their fingers on the keyboard, there is a For those who prefer to keep their fingers on the keyboard, there is a
[shortcut button](../../../workflow/shortcuts.md) as well, which you can invoke from _anywhere_ [shortcut button](../../shortcuts.md) as well, which you can invoke from _anywhere_
in a project. in a project.
Press `t` to launch the File search function when in **Issues**, Press `t` to launch the File search function when in **Issues**,
......
...@@ -7,7 +7,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/forking_workflow.html' ...@@ -7,7 +7,7 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/forking_workflow.html'
Forking a project to your own namespace is useful if you have no write Forking a project to your own namespace is useful if you have no write
access to the project you want to contribute to. If you do have write access to the project you want to contribute to. If you do have write
access or can request it, we recommend working together in the same access or can request it, we recommend working together in the same
repository since it is simpler. See our [GitLab Flow](../../../workflow/gitlab_flow.md) repository since it is simpler. See our [GitLab Flow](../../../topics/gitlab_flow.md)
document more information about using branches to work together. document more information about using branches to work together.
## Creating a fork ## Creating a fork
......
...@@ -43,7 +43,7 @@ A To Do displays on your To-Do List when: ...@@ -43,7 +43,7 @@ A To Do displays on your To-Do List when:
- The author - The author
- Have set it to automatically merge once the pipeline succeeds - Have set it to automatically merge once the pipeline succeeds
To-do triggers are not affected by [GitLab Notification Email settings](../workflow/notifications.md). To-do triggers are not affected by [GitLab Notification Email settings](profile/notifications.md).
NOTE: **Note:** NOTE: **Note:**
When a user no longer has access to a resource related to a To Do (like an issue, merge request, project, or group) the related To-Do items are deleted within the next hour for security reasons. The delete is delayed to prevent data loss, in case the user's access was revoked by mistake. When a user no longer has access to a resource related to a To Do (like an issue, merge request, project, or group) the related To-Do items are deleted within the next hour for security reasons. The delete is delayed to prevent data loss, in case the user's access was revoked by mistake.
......
...@@ -2,43 +2,10 @@ ...@@ -2,43 +2,10 @@
comments: false comments: false
--- ---
# Workflow # Workflow (Deprecated)
- [Automatic issue closing](../user/project/issues/managing_issues.md#closing-issues-automatically) This page was deprecated, with all content previously stored under the `/workflow` path moved
- [Cycle Analytics](../user/project/cycle_analytics.md) to other locations in the documentation site, organized by topic. You can use the search
- [Description templates](../user/project/description_templates.md) box to find the content you are looking for, browse the main [GitLab Documentation page](../README.md),
- [Feature branch workflow](../gitlab-basics/feature_branch_workflow.md) or view the [issue that deprecated this page](https://gitlab.com/gitlab-org/gitlab/issues/32940)
- [Groups](../user/group/index.md) for more details.
- Issues - The GitLab Issue Tracker is an advanced and complete tool for
tracking the evolution of a new idea or the process of solving a problem.
- [Exporting Issues](../user/project/issues/csv_export.md) **(STARTER)** Export issues as a CSV, emailed as an attachment.
- [Confidential issues](../user/project/issues/confidential_issues.md)
- [Due date for issues](../user/project/issues/due_dates.md)
- [Issue Board](../user/project/issue_board.md)
- [File finder](../user/project/repository/file_finder.md)
- [File lock](../user/project/file_lock.md) **(PREMIUM)**
- [Labels](../user/project/labels.md)
- [Projects](../user/project/index.md)
- [Project forking workflow](../user/project/repository/forking_workflow.md)
- [Project users](../user/project/members/index.md)
- [Protected branches](../user/project/protected_branches.md)
- [Protected tags](../user/project/protected_tags.md)
- [Quick Actions](../user/project/quick_actions.md)
- [Sharing projects with groups](../user/project/members/share_project_with_groups.md)
- [Web Editor](../user/project/repository/web_editor.md)
- [Milestones](../user/project/milestones/index.md)
- [Merge Requests](../user/project/merge_requests/index.md)
- [Authorization for merge requests](../user/project/merge_requests/authorization_for_merge_requests.md)
- [Cherry-pick changes](../user/project/merge_requests/cherry_pick_changes.md)
- [Merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- [Resolve threads in merge requests reviews](../user/discussions/index.md)
- [Resolve merge conflicts in the UI](../user/project/merge_requests/resolve_conflicts.md)
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
- ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
- [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- [Merge request approvals](../user/project/merge_requests/merge_request_approvals.md) **(STARTER)**
- [Service Desk](../user/project/service_desk.md) **(PREMIUM)**
- [Importing from SVN, GitHub, Bitbucket, etc](../user/project/import/index.md)
- [Snippets](../user/snippets.md)
- [Subgroups](../user/group/subgroups/index.md)
...@@ -11,6 +11,8 @@ module Banzai ...@@ -11,6 +11,8 @@ module Banzai
Filter::ExternalLinkFilter, Filter::ExternalLinkFilter,
Filter::PlantumlFilter, Filter::PlantumlFilter,
Filter::ColorFilter, Filter::ColorFilter,
Filter::ImageLazyLoadFilter,
Filter::ImageLinkFilter,
Filter::AsciiDocPostProcessingFilter Filter::AsciiDocPostProcessingFilter
] ]
end end
......
...@@ -158,15 +158,17 @@ module Gitlab ...@@ -158,15 +158,17 @@ module Gitlab
end end
def checkout_or_clone_version(version:, repo:, target_dir:) def checkout_or_clone_version(version:, repo:, target_dir:)
version =
if version.starts_with?("=")
version.sub(/\A=/, '') # tag or branch
else
"v#{version}" # tag
end
clone_repo(repo, target_dir) unless Dir.exist?(target_dir) clone_repo(repo, target_dir) unless Dir.exist?(target_dir)
checkout_version(version, target_dir) checkout_version(get_version(version), target_dir)
end
# this function implements the same logic we have in omnibus for dealing with components version
def get_version(component_version)
# If not a valid version string following SemVer it is probably a branch name or a SHA
# commit of one of our own component so it doesn't need `v` prepended
return component_version unless /^\d+\.\d+\.\d+(-rc\d+)?$/.match?(component_version)
"v#{component_version}"
end end
def clone_repo(repo, target_dir) def clone_repo(repo, target_dir)
......
...@@ -20497,6 +20497,9 @@ msgstr "" ...@@ -20497,6 +20497,9 @@ msgstr ""
msgid "syntax is incorrect" msgid "syntax is incorrect"
msgstr "" msgstr ""
msgid "tag name"
msgstr ""
msgid "this document" msgid "this document"
msgstr "" msgstr ""
......
...@@ -14,10 +14,10 @@ gitlab: ...@@ -14,10 +14,10 @@ gitlab:
gitaly: gitaly:
resources: resources:
requests: requests:
cpu: 300m cpu: 600m
memory: 200M memory: 200M
limits: limits:
cpu: 600m cpu: 1200m
memory: 420M memory: 420M
persistence: persistence:
size: 10G size: 10G
...@@ -46,10 +46,10 @@ gitlab: ...@@ -46,10 +46,10 @@ gitlab:
sidekiq: sidekiq:
resources: resources:
requests: requests:
cpu: 300m cpu: 500m
memory: 800M memory: 800M
limits: limits:
cpu: 400m cpu: 1000m
memory: 1.6G memory: 1.6G
task-runner: task-runner:
resources: resources:
......
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
require 'spec_helper' require 'spec_helper'
describe Projects::ReleasesController do describe Projects::ReleasesController do
let!(:project) { create(:project, :repository, :public) } let!(:project) { create(:project, :repository, :public) }
let!(:user) { create(:user) } let!(:private_project) { create(:project, :repository, :private) }
let!(:user) { create(:user) }
let!(:release_1) { create(:release, project: project, released_at: Time.zone.parse('2018-10-18')) }
let!(:release_2) { create(:release, project: project, released_at: Time.zone.parse('2019-10-19')) }
describe 'GET #index' do shared_examples 'common access controls' do
it 'renders a 200' do it 'renders a 200' do
get_index get_index
...@@ -14,17 +17,14 @@ describe Projects::ReleasesController do ...@@ -14,17 +17,14 @@ describe Projects::ReleasesController do
end end
context 'when the project is private' do context 'when the project is private' do
let!(:project) { create(:project, :repository, :private) } let(:project) { private_project }
it 'renders a 302' do
get_index
expect(response.status).to eq(302) before do
sign_in(user)
end end
it 'renders a 200 for a logged in developer' do it 'renders a 200 for a logged in developer' do
project.add_developer(user) project.add_developer(user)
sign_in(user)
get_index get_index
...@@ -32,8 +32,6 @@ describe Projects::ReleasesController do ...@@ -32,8 +32,6 @@ describe Projects::ReleasesController do
end end
it 'renders a 404 when logged in but not in the project' do it 'renders a 404 when logged in but not in the project' do
sign_in(user)
get_index get_index
expect(response.status).to eq(404) expect(response.status).to eq(404)
...@@ -41,9 +39,55 @@ describe Projects::ReleasesController do ...@@ -41,9 +39,55 @@ describe Projects::ReleasesController do
end end
end end
describe 'GET #index' do
before do
get_index
end
context 'as html' do
let(:format) { :html }
it 'returns a text/html content_type' do
expect(response.content_type).to eq 'text/html'
end
it_behaves_like 'common access controls'
context 'when the project is private and the user is not logged in' do
let(:project) { private_project }
it 'renders a 302' do
expect(response.status).to eq(302)
end
end
end
context 'as json' do
let(:format) { :json }
it 'returns an application/json content_type' do
expect(response.content_type).to eq 'application/json'
end
it "returns the project's releases as JSON, ordered by released_at" do
expect(response.body).to eq([release_2, release_1].to_json)
end
it_behaves_like 'common access controls'
context 'when the project is private and the user is not logged in' do
let(:project) { private_project }
it 'renders a 401' do
expect(response.status).to eq(401)
end
end
end
end
private private
def get_index def get_index
get :index, params: { namespace_id: project.namespace, project_id: project } get :index, params: { namespace_id: project.namespace, project_id: project, format: format }
end end
end end
...@@ -68,7 +68,7 @@ describe 'Dropdown hint', :js do ...@@ -68,7 +68,7 @@ describe 'Dropdown hint', :js do
it 'filters with text' do it 'filters with text' do
filtered_search.set('a') filtered_search.set('a')
expect(find(js_dropdown_hint)).to have_selector('.filter-dropdown .filter-dropdown-item', count: 5) expect(find(js_dropdown_hint)).to have_selector('.filter-dropdown .filter-dropdown-item', count: 6)
end end
end end
...@@ -104,6 +104,15 @@ describe 'Dropdown hint', :js do ...@@ -104,6 +104,15 @@ describe 'Dropdown hint', :js do
expect_filtered_search_input_empty expect_filtered_search_input_empty
end end
it 'opens the release dropdown when you click on release' do
click_hint('release')
expect(page).to have_css(js_dropdown_hint, visible: false)
expect(page).to have_css('#js-dropdown-release', visible: true)
expect_tokens([{ name: 'Release' }])
expect_filtered_search_input_empty
end
it 'opens the label dropdown when you click on label' do it 'opens the label dropdown when you click on label' do
click_hint('label') click_hint('label')
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Dropdown release', :js do
include FilteredSearchHelpers
let!(:project) { create(:project, :repository) }
let!(:user) { create(:user) }
let!(:release) { create(:release, tag: 'v1.0', project: project) }
let!(:crazy_release) { create(:release, tag: '☺!/"#%&\'{}+,-.<>;=@]_`{|}🚀', project: project) }
def filtered_search
find('.filtered-search')
end
def filter_dropdown
find('#js-dropdown-release .filter-dropdown')
end
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end
describe 'behavior' do
before do
filtered_search.set('release:')
end
def expect_results(count)
expect(filter_dropdown).to have_selector('.filter-dropdown .filter-dropdown-item', count: count)
end
it 'loads all the releases when opened' do
expect_results(2)
end
it 'filters by tag name' do
filtered_search.send_keys("☺")
expect_results(1)
end
it 'fills in the release name when the autocomplete hint is clicked' do
find('#js-dropdown-release .filter-dropdown-item', text: crazy_release.tag).click
expect(page).to have_css('#js-dropdown-release', visible: false)
expect_tokens([release_token(crazy_release.tag)])
expect_filtered_search_input_empty
end
end
end
...@@ -73,7 +73,7 @@ describe('Release block', () => { ...@@ -73,7 +73,7 @@ describe('Release block', () => {
it('renders an edit button that links to the "Edit release" page', () => { it('renders an edit button that links to the "Edit release" page', () => {
expect(editButton().exists()).toBe(true); expect(editButton().exists()).toBe(true);
expect(editButton().attributes('href')).toBe(release._links.edit); expect(editButton().attributes('href')).toBe(release._links.edit_url);
}); });
it('renders release name', () => { it('renders release name', () => {
...@@ -180,7 +180,7 @@ describe('Release block', () => { ...@@ -180,7 +180,7 @@ describe('Release block', () => {
}); });
}); });
it("does not render an edit button if release._links.edit isn't a string", () => { it("does not render an edit button if release._links.edit_url isn't a string", () => {
delete releaseClone._links; delete releaseClone._links;
return factory(releaseClone).then(() => { return factory(releaseClone).then(() => {
......
...@@ -95,6 +95,6 @@ export const release = { ...@@ -95,6 +95,6 @@ export const release = {
], ],
}, },
_links: { _links: {
edit: 'http://0.0.0.0:3001/root/release-test/-/releases/v0.3/edit', edit_url: 'http://0.0.0.0:3001/root/release-test/-/releases/v0.3/edit',
}, },
}; };
...@@ -167,6 +167,7 @@ describe SearchHelper do ...@@ -167,6 +167,7 @@ describe SearchHelper do
expect(search_filter_input_options('')[:data]['runner-tags-endpoint']).to eq(tag_list_admin_runners_path) expect(search_filter_input_options('')[:data]['runner-tags-endpoint']).to eq(tag_list_admin_runners_path)
expect(search_filter_input_options('')[:data]['labels-endpoint']).to eq(project_labels_path(@project)) expect(search_filter_input_options('')[:data]['labels-endpoint']).to eq(project_labels_path(@project))
expect(search_filter_input_options('')[:data]['milestones-endpoint']).to eq(project_milestones_path(@project)) expect(search_filter_input_options('')[:data]['milestones-endpoint']).to eq(project_milestones_path(@project))
expect(search_filter_input_options('')[:data]['releases-endpoint']).to eq(project_releases_path(@project))
end end
it 'includes autocomplete=off flag' do it 'includes autocomplete=off flag' do
......
...@@ -58,7 +58,7 @@ module Gitlab ...@@ -58,7 +58,7 @@ module Gitlab
}, },
'image with onerror' => { 'image with onerror' => {
input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]', input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]',
output: "<div>\n<p><span><img src=\"https://localhost.com/image.png\" alt='Alt text\" onerror=\"alert(7)'></span></p>\n</div>" output: "<div>\n<p><span><a class=\"no-attachment-icon\" href=\"https://localhost.com/image.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt='Alt text\" onerror=\"alert(7)' class=\"lazy\" data-src=\"https://localhost.com/image.png\"></a></span></p>\n</div>"
}, },
'fenced code with inline script' => { 'fenced code with inline script' => {
input: '```mypre"><script>alert(3)</script>', input: '```mypre"><script>alert(3)</script>',
...@@ -73,6 +73,20 @@ module Gitlab ...@@ -73,6 +73,20 @@ module Gitlab
end end
end end
context "images" do
it "does lazy load and link image" do
input = 'image:https://localhost.com/image.png[]'
output = "<div>\n<p><span><a class=\"no-attachment-icon\" href=\"https://localhost.com/image.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"image\" class=\"lazy\" data-src=\"https://localhost.com/image.png\"></a></span></p>\n</div>"
expect(render(input, context)).to include(output)
end
it "does not automatically link image if link is explicitly defined" do
input = 'image:https://localhost.com/image.png[link=https://gitlab.com]'
output = "<div>\n<p><span><a href=\"https://gitlab.com\" rel=\"nofollow noreferrer noopener\" target=\"_blank\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"image\" class=\"lazy\" data-src=\"https://localhost.com/image.png\"></a></span></p>\n</div>"
expect(render(input, context)).to include(output)
end
end
context 'with admonition' do context 'with admonition' do
it 'preserves classes' do it 'preserves classes' do
input = <<~ADOC input = <<~ADOC
...@@ -107,7 +121,7 @@ module Gitlab ...@@ -107,7 +121,7 @@ module Gitlab
ADOC ADOC
output = <<~HTML output = <<~HTML
<h2>Title</h2> <h2>Title</h2>
HTML HTML
expect(render(input, context)).to include(output.strip) expect(render(input, context)).to include(output.strip)
...@@ -149,15 +163,15 @@ module Gitlab ...@@ -149,15 +163,15 @@ module Gitlab
ADOC ADOC
output = <<~HTML output = <<~HTML
<div> <div>
<p>This paragraph has a footnote.<sup>[<a id="_footnoteref_1" href="#_footnotedef_1" title="View footnote.">1</a>]</sup></p> <p>This paragraph has a footnote.<sup>[<a id="_footnoteref_1" href="#_footnotedef_1" title="View footnote.">1</a>]</sup></p>
</div> </div>
<div> <div>
<hr> <hr>
<div id="_footnotedef_1"> <div id="_footnotedef_1">
<a href="#_footnoteref_1">1</a>. This is the text of the footnote. <a href="#_footnoteref_1">1</a>. This is the text of the footnote.
</div> </div>
</div> </div>
HTML HTML
expect(render(input, context)).to include(output.strip) expect(render(input, context)).to include(output.strip)
...@@ -183,34 +197,34 @@ module Gitlab ...@@ -183,34 +197,34 @@ module Gitlab
ADOC ADOC
output = <<~HTML output = <<~HTML
<h1>Title</h1> <h1>Title</h1>
<div> <div>
<h2 id="user-content-first-section"> <h2 id="user-content-first-section">
<a class="anchor" href="#user-content-first-section"></a>First section</h2> <a class="anchor" href="#user-content-first-section"></a>First section</h2>
<div> <div>
<div> <div>
<p>This is the first section.</p> <p>This is the first section.</p>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<h2 id="user-content-second-section"> <h2 id="user-content-second-section">
<a class="anchor" href="#user-content-second-section"></a>Second section</h2> <a class="anchor" href="#user-content-second-section"></a>Second section</h2>
<div> <div>
<div> <div>
<p>This is the second section.</p> <p>This is the second section.</p>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<h2 id="user-content-thunder"> <h2 id="user-content-thunder">
<a class="anchor" href="#user-content-thunder"></a>Thunder ⚡ !</h2> <a class="anchor" href="#user-content-thunder"></a>Thunder ⚡ !</h2>
<div> <div>
<div> <div>
<p>This is the third section.</p> <p>This is the third section.</p>
</div> </div>
</div> </div>
</div> </div>
HTML HTML
expect(render(input, context)).to include(output.strip) expect(render(input, context)).to include(output.strip)
......
...@@ -114,6 +114,10 @@ module FilteredSearchHelpers ...@@ -114,6 +114,10 @@ module FilteredSearchHelpers
create_token('Milestone', milestone_name, symbol) create_token('Milestone', milestone_name, symbol)
end end
def release_token(release_tag = nil)
create_token('Release', release_tag)
end
def label_token(label_name = nil, has_symbol = true) def label_token(label_name = nil, has_symbol = true)
symbol = has_symbol ? '~' : nil symbol = has_symbol ? '~' : nil
create_token('Label', label_name, symbol) create_token('Label', label_name, symbol)
......
...@@ -20,22 +20,12 @@ describe Gitlab::TaskHelpers do ...@@ -20,22 +20,12 @@ describe Gitlab::TaskHelpers do
end end
it 'checkout the version and reset to it' do it 'checkout the version and reset to it' do
expect(subject).to receive(:get_version).with(version).and_call_original
expect(subject).to receive(:checkout_version).with(tag, clone_path) expect(subject).to receive(:checkout_version).with(tag, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path) subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end end
context 'with a branch version' do
let(:version) { '=branch_name' }
let(:branch) { 'branch_name' }
it 'checkout the version and reset to it with a branch name' do
expect(subject).to receive(:checkout_version).with(branch, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end
end
context "target_dir doesn't exist" do context "target_dir doesn't exist" do
it 'clones the repo' do it 'clones the repo' do
expect(subject).to receive(:clone_repo).with(repo, clone_path) expect(subject).to receive(:clone_repo).with(repo, clone_path)
...@@ -96,4 +86,19 @@ describe Gitlab::TaskHelpers do ...@@ -96,4 +86,19 @@ describe Gitlab::TaskHelpers do
expect { subject.run_command!(['bash', '-c', 'exit 1']) }.to raise_error Gitlab::TaskFailedError expect { subject.run_command!(['bash', '-c', 'exit 1']) }.to raise_error Gitlab::TaskFailedError
end end
end end
describe '#get_version' do
using RSpec::Parameterized::TableSyntax
where(:version, :result) do
'1.1.1' | 'v1.1.1'
'master' | 'master'
'12.4.0-rc7' | 'v12.4.0-rc7'
'594c3ea3e0e5540e5915bd1c49713a0381459dd6' | '594c3ea3e0e5540e5915bd1c49713a0381459dd6'
end
with_them do
it { expect(subject.get_version(version)).to eq(result) }
end
end
end end
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