Commit 8486c8e5 authored by Rémy Coutable's avatar Rémy Coutable

Merge remote-tracking branch 'origin/master' into ce-to-ee-2017-05-17

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parents ac4cbf2e 32ea87d3
......@@ -46,7 +46,8 @@ export default {
},
computed: {
showUnapproveButton() {
return this.userHasApproved && !this.userCanApprove;
const isMerged = this.mr.state === 'merged';
return this.userHasApproved && !this.userCanApprove && !isMerged;
},
},
methods: {
......
......@@ -24,15 +24,21 @@ module RoutableActions
end
end
def ensure_canonical_path(routable, requested_path)
def ensure_canonical_path(routable, requested_full_path)
return unless request.get?
canonical_path = routable.full_path
<<<<<<< HEAD
if canonical_path != requested_path
if canonical_path.casecmp(requested_path) != 0
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
=======
if canonical_path != requested_full_path
if canonical_path.casecmp(requested_full_path) != 0
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
>>>>>>> origin/master
end
redirect_to request.original_url.sub(requested_path, canonical_path)
redirect_to build_canonical_path(routable)
end
end
end
......@@ -31,4 +31,10 @@ class Groups::ApplicationController < ApplicationController
return render_403
end
end
def build_canonical_path(group)
params[:group_id] = group.to_param
url_for(params)
end
end
......@@ -176,4 +176,12 @@ class GroupsController < Groups::ApplicationController
@notification_setting = current_user.notification_settings_for(group)
end
end
def build_canonical_path(group)
return group_path(group) if action_name == 'show' # root group path
params[:id] = group.to_param
url_for(params)
end
end
......@@ -29,6 +29,13 @@ class Projects::ApplicationController < ApplicationController
@project = find_routable!(Project, path, extra_authorization_proc: auth_proc)
end
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:project_id] = project.to_param
url_for(params)
end
def repository
@repository ||= project.repository
end
......
......@@ -390,4 +390,11 @@ class ProjectsController < Projects::ApplicationController
def project_view_files_allowed?
!project.empty_repo? && can?(current_user, :download_code, project)
end
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:id] = project.to_param
url_for(params)
end
end
......@@ -138,4 +138,8 @@ class UsersController < ApplicationController
def projects_for_current_user
ProjectsFinder.new(current_user: current_user).execute
end
def build_canonical_path(user)
url_for(params.merge(username: user.to_param))
end
end
......@@ -591,6 +591,38 @@ exist, you should see something like:
![Environment groups](img/environments_dynamic_groups.png)
## Monitoring environments
>**Notes:**
>
- For the monitor dashboard to appear, you need to:
- Have enabled the [Kubernetes integration][kube]
- Have your app deployed on Kubernetes
- Have enabled the [Prometheus integration][prom]
- With GitLab 9.2, all deployments to an environment are shown directly on the
monitoring dashboard
If your application is deployed on Kubernetes and you have enabled Prometheus
collecting metrics, you can monitor the performance behavior of your app
through the environments.
Once configured, GitLab will attempt to retrieve performance metrics for any
environment which has had a successful deployment. If monitoring data was
successfully retrieved, a Monitoring button will appear on the environment's
detail page.
![Environment Detail with Metrics](img/prometheus_environment_detail_with_metrics.png)
Clicking on the Monitoring button will display a new page, showing up to the last
8 hours of performance data. It may take a minute or two for data to appear
after initial deployment.
All deployments to an environment are shown directly on the monitoring dashboard
which allows easy correlation between any changes in performance and a new
version of the app, all without leaving GitLab.
![Monitoring dashboard](img/environments_monitoring.png)
## Checkout deployments locally
Since 8.13, a reference in the git repository is saved for each deployment, so
......@@ -633,3 +665,5 @@ Below are some links you may find interesting:
[gitlab-flow]: ../workflow/gitlab_flow.md
[gitlab runner]: https://docs.gitlab.com/runner/
[git-strategy]: yaml/README.md#git-strategy
[kube]: ../user/project/integrations/kubernetes.md
[prom]: ../user/project/integrations/prometheus.md
......@@ -3,7 +3,8 @@
> **Notes:**
- GitLab Geo is part of [GitLab Enterprise Edition Premium][ee].
- Introduced in GitLab Enterprise Edition 8.9.
We recommend you use it with at least GitLab Enterprise Edition 8.14.
We recommend you use it with at least GitLab Enterprise Edition 8.14 for
basic Geo features, or latest version for a better experience.
- You should make sure that all nodes run the same GitLab version.
GitLab Geo allows you to replicate your GitLab instance to other geographical
......
......@@ -137,18 +137,6 @@ sensitive data in the database. Any secondary node must have the
sudo -i
```
1. Edit `/etc/gitlab/gitlab.rb`:
```
geo_postgresql['enable'] = true
```
1. Reconfigure GitLab:
```
sudo gitlab-ctl reconfigure
```
1. Get the contents of `id_rsa.pub` key that was pre-generated by Omnibus GitLab
and copy them:
......
......@@ -171,6 +171,7 @@ The following guide assumes that:
```ruby
geo_secondary_role['enable'] = true
geo_postgresql['enable'] = true
```
1. [Reconfigure GitLab][] for the changes to take effect.
......
......@@ -17,6 +17,7 @@ the settings page with a default template. To configure the template, see the
Integration with Prometheus requires the following:
1. GitLab 9.0 or higher
1. The [Kubernetes integration must be enabled][kube] on your project
1. Your app must be deployed on [Kubernetes][]
1. Prometheus must be configured to collect Kubernetes metrics
1. Each metric must be have a label to indicate the environment
......@@ -159,23 +160,28 @@ The queries utilized by GitLab are shown in the following table.
## Monitoring CI/CD Environments
Once configured, GitLab will attempt to retrieve performance metrics for any
environment which has had a successful deployment. If monitoring data was
successfully retrieved, a Monitoring button will appear on the environment's
detail page.
environment which has had a successful deployment.
![Environment Detail with Metrics](img/prometheus_environment_detail_with_metrics.png)
[Learn more about monitoring environments.](../../../ci/environments.md#monitoring-environments)
Clicking on the Monitoring button will display a new page, showing up to the last
8 hours of performance data. It may take a minute or two for data to appear
after initial deployment.
## Determining the performance impact of a merge
## Determining performance impact of a merge
> [Introduced][ce-10408] in GitLab 9.2.
> [Introduced][ce-10408] in GitLab 9.1.
Developers can view the performance impact of their changes within the merge
request workflow. When a source branch has been deployed to an environment, a
sparkline will appear showing the average memory consumption of the app. The dot
indicates when the current changes were deployed, with up to 30 minutes of
performance data displayed before and after. The sparkline will be updated after
each commit has been deployed.
After a merge request has been approved, a sparkline will appear on the merge request page displaying the average memory usage of the application. The sparkline includes thirty minutes of data prior to the merge, a dot to indicate the merge itself, and then will begin capturing thirty minutes of data after the merge.
Once merged and the target branch has been redeployed, the sparkline will switch
to show the new environments this revision has been deployed to.
This sparkline serves as a quick indicator of the impact on memory consumption of the recently merged changes. If there is a problem, action can then be taken to troubleshoot or revert the merge.
Performance data will be available for the duration it is persisted on the
Prometheus server.
![Merge Request with Performance Impact](img/merge_request_performance.png)
## Troubleshooting
......@@ -189,6 +195,7 @@ If the "Attempting to load performance data" screen continues to appear, it coul
[autodeploy]: ../../../ci/autodeploy/index.md
[kubernetes]: https://kubernetes.io
[kube]: ./kubernetes.md
[prometheus-k8s-sd]: https://prometheus.io/docs/operating/configuration/#<kubernetes_sd_config>
[prometheus]: https://prometheus.io
[gitlab-prometheus-k8s-monitor]: ../../../administration/monitoring/prometheus/index.md#configuring-prometheus-to-monitor-kubernetes
......
......@@ -38,11 +38,6 @@ it's reassigned to someone else to take it from there.
if a user is not member of that project, it can only be
assigned to them if they created the issue themselves.
In [GitLab Enterprise Edition Starter and up](https://about.gitlab.com/gitlab-ee/),
you can assign multiple people to an issue.
The interface is exactly the same, except that you can select multiple users in the dropdown.
The multiple assignees are also visible in issue lists and issue boards, and all get the same notifications.
#### 4. Milestone
- Select a [milestone](../milestones/index.md) to attribute that issue to.
......
......@@ -41,6 +41,10 @@ For more examples on artifacts, follow the artifacts reference in
## Browsing job artifacts
>**Note:**
With GitLab 9.2, PDFs, images, videos and other formats can be previewed directly
in the job artifacts browser without the need to download them.
After a job finishes, if you visit the job's specific page, you can see
that there are two buttons. One is for downloading the artifacts archive and
the other for browsing its contents.
......
## Advanced search syntax
# Advanced search syntax
If your site administrator has enabled [Elasticsearch integration](../../integration/elasticsearch.md)
then some advanced search functionality is available.
>**Notes:**
- Introduced in [GitLab Enterprise Premium][ee] 9.2
- The [Elasticsearch integration](../../integration/elasticsearch.md) needs to
be enabled
Full details can be found in the
[Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#_simple_query_string_syntax)
......@@ -16,3 +18,4 @@ but here's a quick guide:
* To match a partial word, use `*`: `bug find_by_*`
* To find a term containing one of these symbols, use `\`: `argument \-last`
[ee]: https://about.gitlab.com/gitlab-ee/
......@@ -98,3 +98,14 @@ you'll be able to, besides filtering them by **Name**, **Author**, **Assignee**,
and **Labels**, select multiple issues to add to a list of your choice:
![search and select issues to add to board](img/search_issues_board.png)
## Advanced search syntax
> Available in [GitLab Enterprise Edition Premium][ee].
If the [Elasticsearch integration](../../integration/elasticsearch.md) is
enabled, then some advanced search functionality is available.
[Learn how to use the advanced search syntax.](advanced_search_syntax.md)
[ee]: https://about.gitlab.com/gitlab-ee/
......@@ -21,7 +21,6 @@ describe Groups::MilestonesController do
sign_in(user)
group.add_owner(user)
project.team << [user, :master]
controller.instance_variable_set(:@group, group)
end
it_behaves_like 'milestone tabs'
......@@ -29,7 +28,7 @@ describe Groups::MilestonesController do
describe "#create" do
it "creates group milestone with Chinese title" do
post :create,
group_id: group.id,
group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).to redirect_to(group_milestone_path(group, title.to_slug.to_s, title: title))
......@@ -37,9 +36,139 @@ describe Groups::MilestonesController do
end
it "redirects to new when there are no project ids" do
post :create, group_id: group.id, milestone: { title: title, project_ids: [""] }
post :create, group_id: group.to_param, milestone: { title: title, project_ids: [""] }
expect(response).to render_template :new
expect(assigns(:milestone).errors).not_to be_nil
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :index, group_id: group.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :index, group_id: group.to_param.upcase
expect(response).to redirect_to(group_milestones_path(group.to_param))
expect(controller).not_to set_flash[:notice]
end
end
end
context 'show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :show, group_id: group.to_param, id: title
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :show, group_id: group.to_param.upcase, id: title
expect(response).to redirect_to(group_milestone_path(group.to_param, title))
expect(controller).not_to set_flash[:notice]
end
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups plus the new path' do
# I.e. /groups/oups/oup should not become /grfoos
let(:redirect_route) { group.redirect_routes.create(path: 'oups/oup') }
it 'does not modify the /groups part of the path' do
get :merge_requests, group_id: redirect_route.path, id: title
expect(response).to redirect_to(merge_requests_group_milestone_path(group.to_param, title))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end
end
end
context 'for a non-GET request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :create,
group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :create,
group_id: group.to_param,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
post :create,
group_id: redirect_route.path,
milestone: { project_ids: [project.id, project2.id], title: title }
expect(response).to have_http_status(404)
end
end
end
def group_moved_message(redirect_route, group)
"Group '#{redirect_route.path}' was moved to '#{group.full_path}'. Please update any links and bookmarks that may still have the old path."
end
end
......@@ -84,6 +84,7 @@ describe GroupsController do
expect(assigns(:issues)).to eq [issue_2, issue_1]
end
end
<<<<<<< HEAD
context 'when requesting the canonical path with different casing' do
it 'redirects to the correct casing' do
......@@ -104,6 +105,8 @@ describe GroupsController do
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
=======
>>>>>>> origin/master
end
describe 'GET #merge_requests' do
......@@ -129,6 +132,7 @@ describe GroupsController do
expect(assigns(:merge_requests)).to eq [merge_request_2, merge_request_1]
end
end
<<<<<<< HEAD
context 'when requesting the canonical path with different casing' do
it 'redirects to the correct casing' do
......@@ -149,6 +153,8 @@ describe GroupsController do
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
=======
>>>>>>> origin/master
end
describe 'DELETE #destroy' do
......@@ -178,30 +184,6 @@ describe GroupsController do
expect(response).to redirect_to(root_path)
end
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to redirect_to(group_path(group.to_param))
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
delete :destroy, id: redirect_route.path
expect(response).to have_http_status(404)
end
end
end
end
......@@ -224,30 +206,6 @@ describe GroupsController do
expect(assigns(:group).errors).not_to be_empty
expect(assigns(:group).path).not_to eq('new_path')
end
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' }
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' }
expect(response).not_to redirect_to(group_path(group.to_param))
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
post :update, id: redirect_route.path, group: { path: 'new_path' }
expect(response).to have_http_status(404)
end
end
end
describe 'POST create' do
......@@ -294,6 +252,202 @@ describe GroupsController do
end
end
<<<<<<< HEAD
=======
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting groups at the root path' do
before do
allow(request).to receive(:original_fullpath).and_return("/#{group_full_path}")
get :show, id: group_full_path
end
context 'when requesting the canonical path with different casing' do
let(:group_full_path) { group.to_param.upcase }
it 'redirects to the correct casing' do
expect(response).to redirect_to(group)
expect(controller).not_to set_flash[:notice]
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
let(:group_full_path) { redirect_route.path }
it 'redirects to the canonical path' do
expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
expect(response).to redirect_to(group)
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end
end
context 'when requesting groups under the /groups path' do
context 'when requesting the canonical path' do
context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :issues, id: group.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :issues, id: group.to_param.upcase
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).not_to set_flash[:notice]
end
end
end
context 'show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :show, id: group.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing at the root path' do
get :show, id: group.to_param.upcase
expect(response).to redirect_to(group)
expect(controller).not_to set_flash[:notice]
end
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
context 'when the old group path is a substring of the scheme or host' do
let(:redirect_route) { group.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups' do
# I.e. /groups/oups should not become /grfoo/oups
let(:redirect_route) { group.redirect_routes.create(path: 'oups') }
it 'does not modify the /groups part of the path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
context 'when the old group path is substring of groups plus the new path' do
# I.e. /groups/oups/oup should not become /grfoos
let(:redirect_route) { group.redirect_routes.create(path: 'oups/oup') }
it 'does not modify the /groups part of the path' do
get :issues, id: redirect_route.path
expect(response).to redirect_to(issues_group_path(group.to_param))
expect(controller).to set_flash[:notice].to(group_moved_message(redirect_route, group))
end
end
end
end
end
context 'for a POST request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' }
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :update, id: group.to_param.upcase, group: { path: 'new_path' }
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
post :update, id: redirect_route.path, group: { path: 'new_path' }
expect(response).to have_http_status(404)
end
end
end
context 'for a DELETE request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
delete :destroy, id: group.to_param.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { group.redirect_routes.create(path: 'old-path') }
it 'returns not found' do
delete :destroy, id: redirect_route.path
expect(response).to have_http_status(404)
end
end
end
end
>>>>>>> origin/master
def group_moved_message(redirect_route, group)
"Group '#{redirect_route.path}' was moved to '#{group.full_path}'. Please update any links and bookmarks that may still have the old path."
end
......
......@@ -157,4 +157,74 @@ describe Projects::LabelsController do
end
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context 'non-show path' do
context 'with exactly matching casing' do
it 'does not redirect' do
get :index, namespace_id: project.namespace, project_id: project.to_param
expect(response).not_to have_http_status(301)
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :index, namespace_id: project.namespace, project_id: project.to_param.upcase
expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
expect(controller).not_to set_flash[:notice]
end
end
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'redirects to the canonical path' do
get :index, namespace_id: project.namespace, project_id: project.to_param + 'old'
expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, project))
end
end
end
end
context 'for a non-GET request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :generate, namespace_id: project.namespace, project_id: project
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :generate, namespace_id: project.namespace, project_id: project
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'returns not found' do
post :generate, namespace_id: project.namespace, project_id: project.to_param + 'old'
expect(response).to have_http_status(404)
end
end
end
def project_moved_message(redirect_route, project)
"Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path."
end
end
......@@ -190,27 +190,6 @@ describe ProjectsController do
end
end
context "when requested with case sensitive namespace and project path" do
context "when there is a match with the same casing" do
it "loads the project" do
get :show, namespace_id: public_project.namespace, id: public_project
expect(assigns(:project)).to eq(public_project)
expect(response).to have_http_status(200)
end
end
context "when there is a match with different casing" do
it "redirects to the normalized path" do
get :show, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.full_path}")
expect(controller).not_to set_flash[:notice]
end
end
end
context "when the url contains .atom" do
let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') }
......@@ -240,6 +219,7 @@ describe ProjectsController do
expect(response).to redirect_to(namespace_project_path)
end
end
<<<<<<< HEAD
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
......@@ -251,6 +231,8 @@ describe ProjectsController do
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
end
=======
>>>>>>> origin/master
end
describe "#update" do
......@@ -277,34 +259,6 @@ describe ProjectsController do
expect(assigns(:repository).path).to eq(project.repository.path)
expect(response).to have_http_status(302)
end
context 'when requesting the canonical path' do
it "is case-insensitive" do
controller.instance_variable_set(:@project, project)
put :update,
namespace_id: 'FOo',
id: 'baR',
project: project_params
expect(project.repository.path).to include(new_path)
expect(assigns(:repository).path).to eq(project.repository.path)
expect(response).to have_http_status(302)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
put :update,
namespace_id: 'foo',
id: 'bar',
project: project_params
expect(response).to have_http_status(404)
end
end
end
describe "#destroy" do
......@@ -340,31 +294,6 @@ describe ProjectsController do
expect(merge_request.reload.state).to eq('closed')
end
end
context 'when requesting the canonical path' do
it "is case-insensitive" do
controller.instance_variable_set(:@project, project)
sign_in(admin)
orig_id = project.id
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect { Project.find(orig_id) }.to raise_error(ActiveRecord::RecordNotFound)
expect(response).to have_http_status(302)
expect(response).to redirect_to(dashboard_projects_path)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
sign_in(admin)
delete :destroy, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end
describe 'PUT #new_issue_address' do
......@@ -486,6 +415,7 @@ describe ProjectsController do
expect(parsed_body["Tags"]).to include("v1.0.0")
expect(parsed_body["Commits"]).to include("123456")
end
<<<<<<< HEAD
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
......@@ -497,6 +427,8 @@ describe ProjectsController do
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
end
=======
>>>>>>> origin/master
end
describe 'GET edit' do
......@@ -531,6 +463,112 @@ describe ProjectsController do
end
end
<<<<<<< HEAD
=======
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting the canonical path' do
context "with exactly matching casing" do
it "loads the project" do
get :show, namespace_id: public_project.namespace, id: public_project
expect(assigns(:project)).to eq(public_project)
expect(response).to have_http_status(200)
end
end
context "with different casing" do
it "redirects to the normalized path" do
get :show, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.full_path}")
expect(controller).not_to set_flash[:notice]
end
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
it 'redirects to the canonical path' do
get :show, namespace_id: 'foo', id: 'bar'
expect(response).to redirect_to(public_project)
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
it 'redirects to the canonical path (testing non-show action)' do
get :refs, namespace_id: 'foo', id: 'bar'
expect(response).to redirect_to(refs_namespace_project_path(namespace_id: public_project.namespace, id: public_project))
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
end
end
context 'for a POST request' do
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
post :toggle_star, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
post :toggle_star, namespace_id: public_project.namespace, id: public_project.path.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { public_project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
post :toggle_star, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end
context 'for a DELETE request' do
before do
sign_in(create(:admin))
end
context 'when requesting the canonical path with different casing' do
it 'does not 404' do
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect(response).not_to have_http_status(404)
end
it 'does not redirect to the correct casing' do
delete :destroy, namespace_id: project.namespace, id: project.path.upcase
expect(response).not_to have_http_status(301)
end
end
context 'when requesting a redirected path' do
let!(:redirect_route) { project.redirect_routes.create!(path: "foo/bar") }
it 'returns not found' do
delete :destroy, namespace_id: 'foo', id: 'bar'
expect(response).to have_http_status(404)
end
end
end
end
>>>>>>> origin/master
def project_moved_message(redirect_route, project)
"Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path."
end
......
......@@ -53,6 +53,7 @@ describe UsersController do
end
end
<<<<<<< HEAD
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
......@@ -87,6 +88,8 @@ describe UsersController do
end
end
=======
>>>>>>> origin/master
context 'when a user by that username does not exist' do
context 'when logged out' do
it 'redirects to login page' do
......@@ -131,6 +134,7 @@ describe UsersController do
expect(assigns(:contributions_calendar).projects.count).to eq(2)
end
end
<<<<<<< HEAD
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
......@@ -165,6 +169,8 @@ describe UsersController do
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
=======
>>>>>>> origin/master
end
describe 'GET #calendar_activities' do
......@@ -187,6 +193,7 @@ describe UsersController do
get :calendar_activities, username: user.username
expect(response).to render_template('calendar_activities')
end
<<<<<<< HEAD
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
......@@ -219,6 +226,8 @@ describe UsersController do
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
=======
>>>>>>> origin/master
end
describe 'GET #snippets' do
......@@ -241,6 +250,7 @@ describe UsersController do
expect(JSON.parse(response.body)).to have_key('html')
end
end
<<<<<<< HEAD
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
......@@ -273,6 +283,8 @@ describe UsersController do
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
=======
>>>>>>> origin/master
end
describe 'GET #exists' do
......@@ -321,6 +333,130 @@ describe UsersController do
end
end
<<<<<<< HEAD
=======
describe '#ensure_canonical_path' do
before do
sign_in(user)
end
context 'for a GET request' do
context 'when requesting users at the root path' do
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
context 'with exactly matching casing' do
it 'responds with success' do
get :show, username: user.username
expect(response).to be_success
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :show, username: user.username.downcase
expect(response).to redirect_to(user)
expect(controller).not_to set_flash[:notice]
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :show, username: redirect_route.path
expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
context 'when the old path is a substring of the scheme or host' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :show, username: redirect_route.path
expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
context 'when the old path is substring of users' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
it 'redirects to the canonical path' do
get :show, username: redirect_route.path
expect(response).to redirect_to(user)
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
end
end
context 'when requesting users under the /users path' do
context 'when requesting the canonical path' do
let(:user) { create(:user, username: 'CamelCaseUser') }
context 'with exactly matching casing' do
it 'responds with success' do
get :projects, username: user.username
expect(response).to be_success
end
end
context 'with different casing' do
it 'redirects to the correct casing' do
get :projects, username: user.username.downcase
expect(response).to redirect_to(user_projects_path(user))
expect(controller).not_to set_flash[:notice]
end
end
end
context 'when requesting a redirected path' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-path') }
it 'redirects to the canonical path' do
get :projects, username: redirect_route.path
expect(response).to redirect_to(user_projects_path(user))
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
context 'when the old path is a substring of the scheme or host' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'http') }
it 'does not modify the requested host' do
get :projects, username: redirect_route.path
expect(response).to redirect_to(user_projects_path(user))
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
context 'when the old path is substring of users' do
let(:redirect_route) { user.namespace.redirect_routes.create(path: 'ser') }
# I.e. /users/ser should not become /ufoos/ser
it 'does not modify the /users part of the path' do
get :projects, username: redirect_route.path
expect(response).to redirect_to(user_projects_path(user))
expect(controller).to set_flash[:notice].to(user_moved_message(redirect_route, user))
end
end
end
end
end
end
>>>>>>> origin/master
def user_moved_message(redirect_route, user)
"User '#{redirect_route.path}' was moved to '#{user.full_path}'. Please update any links and bookmarks that may still have the old path."
end
......
......@@ -21,6 +21,10 @@ import ApprovalsFooter from '~/vue_merge_request_widget/ee/components/approvals/
`);
this.initialData = {
mr: {
state: 'readyToMerge',
},
service: {},
userCanApprove: false,
userHasApproved: true,
approvedBy: [],
......@@ -53,7 +57,9 @@ import ApprovalsFooter from '~/vue_merge_request_widget/ee/components/approvals/
describe('Computed properties', function () {
it('should correctly set showUnapproveButton when the user can unapprove', function () {
expect(this.approvalsFooter.showUnapproveButton).toBe(true);
expect(this.approvalsFooter.showUnapproveButton).toBeTruthy();
this.approvalsFooter.mr.state = 'merged';
expect(this.approvalsFooter.showUnapproveButton).toBeFalsy();
});
it('should correctly set showUnapproveButton when the user can not unapprove', function (done) {
......
shared_examples 'milestone tabs' do
def go(path, extra_params = {})
params = if milestone.is_a?(GlobalMilestone)
{ group_id: group.id, id: milestone.safe_title, title: milestone.title }
{ group_id: group.to_param, id: milestone.safe_title, title: milestone.title }
else
{ namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
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