Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-02-10 16:56:27 +0300
committerJames Lopez <james@jameslopez.es>2016-02-10 16:56:27 +0300
commit3753c1e03edb516033b4ef856aed63668de59cf3 (patch)
tree5afd055252b3bd6e3545f0f522ce168736522e7d
parentf7c06ecdde1740d3dc61d6b2063af1b41ea4ad95 (diff)
parent10aa99a30c311c59358d1547ebcbe0f6a92227a7 (diff)
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/cross-reference-notes-forks
-rw-r--r--.gitlab-ci.yml89
-rw-r--r--CHANGELOG17
-rw-r--r--CONTRIBUTING.md126
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/admin.js.coffee13
-rw-r--r--app/assets/javascripts/application.js.coffee89
-rw-r--r--app/assets/javascripts/broadcast_message.js.coffee22
-rw-r--r--app/assets/javascripts/dashboard.js.coffee34
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee4
-rw-r--r--app/assets/javascripts/logo.js.coffee6
-rw-r--r--app/assets/javascripts/projects_list.js.coffee34
-rw-r--r--app/assets/javascripts/shortcuts_issuable.coffee19
-rw-r--r--app/assets/stylesheets/framework/header.scss9
-rw-r--r--app/assets/stylesheets/framework/nav.scss4
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss15
-rw-r--r--app/assets/stylesheets/framework/variables.scss4
-rw-r--r--app/assets/stylesheets/pages/admin.scss10
-rw-r--r--app/assets/stylesheets/pages/issuable.scss21
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb6
-rw-r--r--app/controllers/application_controller.rb3
-rw-r--r--app/controllers/ci/application_controller.rb47
-rw-r--r--app/controllers/ci/projects_controller.rb5
-rw-r--r--app/controllers/dashboard/projects_controller.rb26
-rw-r--r--app/controllers/explore/projects_controller.rb44
-rw-r--r--app/controllers/groups_controller.rb18
-rw-r--r--app/controllers/projects/application_controller.rb5
-rw-r--r--app/controllers/projects/artifacts_controller.rb12
-rw-r--r--app/controllers/projects/builds_controller.rb9
-rw-r--r--app/controllers/projects/commit_controller.rb14
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/runner_projects_controller.rb2
-rw-r--r--app/controllers/projects/runners_controller.rb2
-rw-r--r--app/controllers/projects/triggers_controller.rb2
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/users_controller.rb3
-rw-r--r--app/helpers/broadcast_messages_helper.rb6
-rw-r--r--app/helpers/nav_helper.rb6
-rw-r--r--app/helpers/projects_helper.rb6
-rw-r--r--app/helpers/snippets_helper.rb6
-rw-r--r--app/models/ability.rb80
-rw-r--r--app/models/application_setting.rb5
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/repository.rb54
-rw-r--r--app/services/git_push_service.rb9
-rw-r--r--app/views/admin/application_settings/_form.html.haml10
-rw-r--r--app/views/admin/broadcast_messages/_form.html.haml7
-rw-r--r--app/views/admin/broadcast_messages/index.html.haml2
-rw-r--r--app/views/admin/broadcast_messages/preview.js.haml1
-rw-r--r--app/views/admin/builds/_build.html.haml6
-rw-r--r--app/views/admin/builds/index.html.haml13
-rw-r--r--app/views/dashboard/_projects_head.html.haml3
-rw-r--r--app/views/dashboard/issues.html.haml16
-rw-r--r--app/views/dashboard/merge_requests.html.haml7
-rw-r--r--app/views/dashboard/projects/_projects.html.haml3
-rw-r--r--app/views/explore/projects/_filter.html.haml8
-rw-r--r--app/views/explore/projects/_projects.html.haml2
-rw-r--r--app/views/explore/projects/index.html.haml1
-rw-r--r--app/views/explore/projects/starred.html.haml3
-rw-r--r--app/views/explore/projects/trending.html.haml2
-rw-r--r--app/views/groups/_projects.html.haml17
-rw-r--r--app/views/groups/issues.html.haml16
-rw-r--r--app/views/groups/merge_requests.html.haml7
-rw-r--r--app/views/groups/show.html.haml2
-rw-r--r--app/views/layouts/_page.html.haml3
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/ci/_page.html.haml3
-rw-r--r--app/views/notify/_note_message.html.haml3
-rw-r--r--app/views/notify/new_issue_email.html.haml3
-rw-r--r--app/views/notify/new_merge_request_email.html.haml3
-rw-r--r--app/views/projects/builds/index.html.haml2
-rw-r--r--app/views/projects/builds/show.html.haml5
-rw-r--r--app/views/projects/commit/_builds.html.haml2
-rw-r--r--app/views/projects/commit_statuses/_commit_status.html.haml10
-rw-r--r--app/views/projects/edit.html.haml8
-rw-r--r--app/views/projects/forks/index.html.haml2
-rw-r--r--app/views/projects/issues/index.html.haml21
-rw-r--r--app/views/projects/issues/show.html.haml9
-rw-r--r--app/views/projects/merge_requests/index.html.haml17
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml5
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml5
-rw-r--r--app/views/projects/show.atom.builder2
-rw-r--r--app/views/projects/tree/_readme.html.haml2
-rw-r--r--app/views/projects/variables/show.html.haml4
-rw-r--r--app/views/search/results/_snippet_blob.html.haml44
-rw-r--r--app/views/shared/_import_form.html.haml2
-rw-r--r--app/views/shared/_logo.svg28
-rw-r--r--app/views/shared/issuable/_filter.html.haml29
-rw-r--r--app/views/shared/issuable/_nav.html.haml25
-rw-r--r--app/views/shared/issuable/_search_form.html.haml17
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml4
-rw-r--r--app/views/shared/projects/_list.html.haml27
-rw-r--r--config/application.rb18
-rw-r--r--config/gitlab.yml.example8
-rw-r--r--config/initializers/smtp_settings.rb.sample2
-rw-r--r--config/routes.rb6
-rw-r--r--config/unicorn.rb.example9
-rw-r--r--db/fixtures/production/001_admin.rb4
-rw-r--r--db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb5
-rw-r--r--db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb2
-rw-r--r--db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb5
-rw-r--r--db/migrate/20160209130428_add_index_to_snippet.rb5
-rw-r--r--db/schema.rb5
-rw-r--r--doc/api/merge_requests.md126
-rw-r--r--doc/api/projects.md10
-rw-r--r--doc/ci/variables/README.md5
-rw-r--r--doc/development/doc_styleguide.md11
-rw-r--r--doc/install/installation.md18
-rw-r--r--doc/install/relative_url.md126
-rw-r--r--doc/install/requirements.md2
-rw-r--r--doc/markdown/markdown.md8
-rw-r--r--doc/permissions/permissions.md9
-rw-r--r--doc/project_services/jira.md9
-rw-r--r--doc/ssh/README.md21
-rw-r--r--doc/update/8.4-to-8.5.md106
-rw-r--r--features/admin/broadcast_messages.feature6
-rw-r--r--features/project/builds/permissions.feature35
-rw-r--r--features/steps/admin/broadcast_messages.rb14
-rw-r--r--features/steps/project/builds/summary.rb8
-rw-r--r--features/steps/shared/builds.rb17
-rw-r--r--features/steps/shared/project.rb12
-rw-r--r--lib/api/builds.rb29
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/projects.rb12
-rw-r--r--lib/api/triggers.rb8
-rw-r--r--lib/api/variables.rb2
-rw-r--r--lib/backup/manager.rb3
-rw-r--r--lib/banzai/pipeline/broadcast_message_pipeline.rb16
-rw-r--r--lib/gitlab/backend/shell.rb2
-rw-r--r--lib/gitlab/current_settings.rb4
-rw-r--r--lib/gitlab/git.rb6
-rw-r--r--lib/gitlab/snippet_search_results.rb10
-rwxr-xr-xlib/support/init.d/gitlab4
-rwxr-xr-xlib/support/init.d/gitlab.default.example13
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb28
-rw-r--r--spec/factories/ci/builds.rb42
-rw-r--r--spec/features/admin/admin_builds_spec.rb12
-rw-r--r--spec/features/builds_spec.rb2
-rw-r--r--spec/features/commits_spec.rb152
-rw-r--r--spec/features/security/project/public_access_spec.rb54
-rw-r--r--spec/javascripts/fixtures/project_title.html.haml4
-rw-r--r--spec/mailers/notify_spec.rb37
-rw-r--r--spec/models/application_setting_spec.rb8
-rw-r--r--spec/models/milestone_spec.rb14
-rw-r--r--spec/models/repository_spec.rb121
-rw-r--r--spec/requests/api/builds_spec.rb8
-rw-r--r--spec/requests/api/commit_status_spec.rb48
-rw-r--r--spec/requests/api/merge_requests_spec.rb1
-rw-r--r--spec/requests/ci/api/builds_spec.rb106
-rw-r--r--spec/services/git_push_service_spec.rb30
155 files changed, 1952 insertions, 759 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dbdbae9d787..5dfeb8a1f90 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -137,23 +137,104 @@ bundler:audit:
# Ruby 2.1 jobs
-spec:ruby21:
+spec:feature:ruby21:
image: ruby:2.1
+ only:
+ - master
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
+ tags:
+ - ruby
+ - mysql
+
+spec:api:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
+ tags:
+ - ruby
+ - mysql
+
+spec:models:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
tags:
- ruby
- mysql
+
+spec:lib:ruby21:
+ image: ruby:2.1
only:
- master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
+ tags:
+ - ruby
+ - mysql
-spinach:ruby21:
+spec:services:ruby21:
image: ruby:2.1
+ only:
+ - master
script:
- - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
tags:
- ruby
- mysql
+
+spec:benchmark:ruby21:
+ image: ruby:2.1
only:
- master
+ script:
+ - RAILS_ENV=test bundle exec rake spec:benchmark
+ tags:
+ - ruby
+ - mysql
+ allow_failure: true
+
+spec:other:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
+ tags:
+ - ruby
+ - mysql
+
+spinach:project:half:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
+ tags:
+ - ruby
+ - mysql
+
+spinach:project:rest:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
+ tags:
+ - ruby
+ - mysql
+
+spinach:other:ruby21:
+ image: ruby:2.1
+ only:
+ - master
+ script:
+ - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
+ tags:
+ - ruby
+ - mysql
diff --git a/CHANGELOG b/CHANGELOG
index 4f45f30f1da..c39588e978e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,13 +1,16 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.5.0 (unreleased)
+ - Cache various Repository methods to improve performance (Yorick Peterse)
- Ensure rake tasks that don't need a DB connection can be run without one
- Update New Relic gem to 3.14.1.311 (Stan Hu)
- Add "visibility" flag to GET /projects api endpoint
+ - Add an option to supply root email through an environmental variable (Koichiro Mikami)
- Ignore binary files in code search to prevent Error 500 (Stan Hu)
- Render sanitized SVG images (Stan Hu)
- Support download access by PRIVATE-TOKEN header (Stan Hu)
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
+ - Add option to include the sender name in body of Notify email (Jason Lee)
- New UI for pagination
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
set it up
@@ -15,14 +18,18 @@ v 8.5.0 (unreleased)
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
- Fix label links for a merge request pointing to issues list
- Don't vendor minified JS
+ - Increase project import timeout to 15 minutes
- Display 404 error on group not found
- Track project import failure
- Support Two-factor Authentication for LDAP users
- Display database type and version in Administration dashboard
+ - Allow limited Markdown in Broadcast Messages
- Fix visibility level text in admin area (Zeger-Jan van de Weg)
- Warn admin during OAuth of granting admin rights (Zeger-Jan van de Weg)
- Update the ExternalIssue regex pattern (Blake Hitchcock)
+ - Remember user's inline/side-by-side diff view preference in a cookie (Kirill Katsnelson)
- Optimized performance of finding issues to be closed by a merge request
+ - API: Expose MergeRequest#merge_status (Andrei Dziahel)
- Revert "Add IP check against DNSBLs at account sign-up"
- Fix API to keep request parameters in Link header (Michael Potthoff)
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
@@ -32,9 +39,19 @@ v 8.5.0 (unreleased)
- Support Akismet spam checking for creation of issues via API (Stan Hu)
- Improve UI consistency between projects and groups lists
- Add sort dropdown to dashboard projects page
+ - Fixed logo animation on Safari (Roman Rott)
- Hide remove source branch button when the MR is merged but new commits are pushed (Zeger-Jan van de Weg)
- In seach autocomplete show only groups and projects you are member of
- Don't process cross-reference notes from forks
+ - Fix: init.d script not working on OS X
+ - Faster snippet search
+ - Title for milestones should be unique (Zeger-Jan van de Weg)
+ - Validate correctness of maximum attachment size application setting
+
+v 8.4.4
+ - Update omniauth-saml gem to 1.4.2
+ - Prevent long-running backup tasks from timing out the database connection
+ - Add a Project setting to allow guests to view build logs (defaults to true)
v 8.4.3
- Increase lfs_objects size column to 8-byte integer to allow files larger
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a7a2307492f..263f98b1e57 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,29 @@
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Contribute to GitLab](#contribute-to-gitlab)
+ - [Contributor license agreement](#contributor-license-agreement)
+ - [Security vulnerability disclosure](#security-vulnerability-disclosure)
+ - [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
+ - [Helping others](#helping-others)
+ - [I want to contribute!](#i-want-to-contribute)
+ - [Issue tracker](#issue-tracker)
+ - [Feature proposals](#feature-proposals)
+ - [Issue tracker guidelines](#issue-tracker-guidelines)
+ - [Issue weight](#issue-weight)
+ - [Regression issues](#regression-issues)
+ - [Merge requests](#merge-requests)
+ - [Merge request guidelines](#merge-request-guidelines)
+ - [Merge request description format](#merge-request-description-format)
+ - [Contribution acceptance criteria](#contribution-acceptance-criteria)
+ - [Changes for Stable Releases](#changes-for-stable-releases)
+ - [Definition of done](#definition-of-done)
+ - [Style guides](#style-guides)
+ - [Code of conduct](#code-of-conduct)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
# Contribute to GitLab
Thank you for your interest in contributing to GitLab. This guide details how
@@ -234,15 +260,17 @@ request is as follows:
1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you are changing the README, some documentation or other things which
have no effect on the tests, add `[ci skip]` somewhere in the commit message
+ and make sure to read the [documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash]
1. Push the commit(s) to your fork
1. Submit a merge request (MR) to the master branch
1. The MR title should describe the change you want to make
1. The MR description should give a motive for your change and the method you
- used to achieve it
+ used to achieve it, see the [merge request description format]
+ (#merge-request-description-format)
1. If the MR changes the UI it should include before and after screenshots
-1. If the MR changes CSS classes please include the list of affected pages
+1. If the MR changes CSS classes please include the list of affected pages,
`grep css-class ./app -R`
1. Link any relevant [issues][ce-tracker] in the merge request description and
leave a comment on them with a link back to the MR
@@ -275,7 +303,55 @@ For examples of feedback on merge requests please look at already
request feel free to mention one of the Merge Marshalls of the [core team][].
Please ensure that your merge request meets the contribution acceptance criteria.
-When having your code reviewed and when reviewing merge requests please take the [thoughtbot code review guidelines](https://github.com/thoughtbot/guides/tree/master/code-review) into account.
+When having your code reviewed and when reviewing merge requests please take the
+[thoughtbot code review guidelines](https://github.com/thoughtbot/guides/tree/master/code-review)
+into account.
+
+### Merge request description format
+
+Please submit merge requests using the following template in the merge request
+description area. Copy-paste it to retain the markdown format.
+
+```
+## What does this MR do?
+
+## Are there points in the code the reviewer needs to double check?
+
+## Why was this MR needed?
+
+## What are the relevant issue numbers?
+
+## Screenshots (if relevant)
+```
+
+### Contribution acceptance criteria
+
+1. The change is as small as possible
+1. Include proper tests and make all tests pass (unless it contains a test
+ exposing a bug in existing code)
+1. If you suspect a failing CI build is unrelated to your contribution, you may
+ try and restart the failing CI job or ask a developer to fix the
+ aforementioned failing test
+1. Your MR initially contains a single commit (please use `git rebase -i` to
+ squash commits)
+1. Your changes can merge without problems (if not please merge `master`, never
+ rebase commits pushed to the remote server)
+1. Does not break any existing functionality
+1. Fixes one specific issue or implements one specific feature (do not combine
+ things, send separate merge requests if needed)
+1. Migrations should do only one thing (e.g., either create a table, move data
+ to a new table or remove an old table) to aid retrying on failure
+1. Keeps the GitLab code base clean and well structured
+1. Contains functionality we think other users will benefit from too
+1. Doesn't add configuration options since they complicate future changes
+1. Changes after submitting the merge request should be in separate commits
+ (no squashing). If necessary, you will be asked to squash when the review is
+ over, before merging.
+1. It conforms to the [style guides](#style-guides) and the following:
+ - If your change touches a line that does not follow the style, modify the
+ entire line to follow it. This prevents linting tools from generating warnings.
+ - Don't touch neighbouring lines. As an exception, automatic mass
+ refactoring modifications may leave style non-compliant.
## Changes for Stable Releases
@@ -298,7 +374,7 @@ the feature you contribute through all of these steps.
1. Description explaining the relevancy (see following item)
1. Working and clean code that is commented where needed
1. Unit and integration tests that pass on the CI server
-1. Documented in the /doc directory
+1. [Documented][doc-styleguide] in the /doc directory
1. Changelog entry added
1. Reviewed and any concerns are addressed
1. Merged by the project lead
@@ -319,43 +395,6 @@ merge request:
1. Test suite https://gitlab.com/gitlab-org/gitlab-ce/blob/master/scripts/prepare_build.sh
1. Omnibus package creator https://gitlab.com/gitlab-org/omnibus-gitlab
-## Merge request description format
-
-1. What does this MR do?
-1. Are there points in the code the reviewer needs to double check?
-1. Why was this MR needed?
-1. What are the relevant issue numbers?
-1. Screenshots (if relevant)
-
-## Contribution acceptance criteria
-
-1. The change is as small as possible (see the above paragraph for details)
-1. Include proper tests and make all tests pass (unless it contains a test
- exposing a bug in existing code)
-1. If you suspect a failing CI build is unrelated to your contribution, you may
- try and restart the failing CI job or ask a developer to fix the
- aforementioned failing test
-1. Your MR initially contains a single commit (please use `git rebase -i` to
- squash commits)
-1. Your changes can merge without problems (if not please merge `master`, never
- rebase commits pushed to the remote server)
-1. Does not break any existing functionality
-1. Fixes one specific issue or implements one specific feature (do not combine
- things, send separate merge requests if needed)
-1. Migrations should do only one thing (eg: either create a table, move data to
- a new table or remove an old table) to aid retrying on failure
-1. Keeps the GitLab code base clean and well structured
-1. Contains functionality we think other users will benefit from too
-1. Doesn't add configuration options since they complicate future changes
-1. Changes after submitting the merge request should be in separate commits
- (no squashing). If necessary, you will be asked to squash when the review is
- over, before merging.
-1. It conforms to the following style guides:
- * If your change touches a line that does not follow the style, modify the
- entire line to follow it. This prevents linting tools from generating warnings.
- * Don't touch neighbouring lines. As an exception, automatic mass
- refactoring modifications may leave style non-compliant.
-
## Style guides
1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
@@ -370,7 +409,7 @@ merge request:
contributors to enhance security
1. [Database Migrations](doc/development/migration_style_guide.md)
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
-1. [Documentation styleguide](doc/development/doc_styleguide.md)
+1. [Documentation styleguide][doc-styleguide]
1. Interface text should be written subjectively instead of objectively. It
should be the GitLab core team addressing a person. It should be written in
present time and never use past tense (has been/was). For example instead
@@ -411,7 +450,7 @@ reported by emailing `contact@gitlab.com`.
This Code of Conduct is adapted from the [Contributor Covenant][], version 1.1.0,
available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/).
-[core team]: https://about.gitlab.com/core-team/
+[core-team]: https://about.gitlab.com/core-team/
[getting help page]: https://about.gitlab.com/getting-help/
[Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
@@ -432,3 +471,4 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[Contributor Covenant]: http://contributor-covenant.org
[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
+[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
diff --git a/Gemfile b/Gemfile
index ff119a6d687..a13f49ad50e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -50,7 +50,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 8.0.0'
+gem "gitlab_git", '~> 8.1'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
diff --git a/Gemfile.lock b/Gemfile.lock
index a7a5db29e35..df5099c7581 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -357,7 +357,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.2.0)
gemojione (~> 2.1)
- gitlab_git (8.0.0)
+ gitlab_git (8.1.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@@ -932,7 +932,7 @@ DEPENDENCIES
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.2.0)
- gitlab_git (~> 8.0.0)
+ gitlab_git (~> 8.1)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index eb951f71711..b2b8e1b7ffb 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -12,19 +12,6 @@ class @Admin
e.preventDefault()
$('.js-toggle-colors-container').toggle()
- $('input#broadcast_message_color').on 'input', ->
- previewColor = $(@).val()
- $('div.broadcast-message-preview').css('background-color', previewColor)
-
- $('input#broadcast_message_font').on 'input', ->
- previewColor = $(@).val()
- $('div.broadcast-message-preview').css('color', previewColor)
-
- $('textarea#broadcast_message_message').on 'input', ->
- previewMessage = $(@).val()
- previewMessage = "Your message here" if previewMessage.trim() == ''
- $('div.broadcast-message-preview span').text(previewMessage)
-
$('.log-tabs a').click (e) ->
e.preventDefault()
$(this).tab('show')
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index e54bfce058a..367bd098bfd 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -211,44 +211,51 @@ $ ->
$this.attr 'value', $this.val()
return
- $(document).on 'keyup', 'input[type="search"]' , (e) ->
- $this = $(this)
- $this.attr 'value', $this.val()
-
- $(document).on 'breakpoint:change', (e, breakpoint) ->
- if breakpoint is 'sm' or breakpoint is 'xs'
- $gutterIcon = $('.gutter-toggle').find('i')
- if $gutterIcon.hasClass('fa-angle-double-right')
- $gutterIcon.closest('a').trigger('click')
-
-
- $(document).on 'click', 'aside .gutter-toggle', (e) ->
- e.preventDefault()
- $this = $(this)
- $thisIcon = $this.find 'i'
- if $thisIcon.hasClass('fa-angle-double-right')
- $thisIcon.removeClass('fa-angle-double-right')
- .addClass('fa-angle-double-left')
- $this
- .closest('aside')
- .removeClass('right-sidebar-expanded')
- .addClass('right-sidebar-collapsed')
- $('.page-with-sidebar')
- .removeClass('right-sidebar-expanded')
- .addClass('right-sidebar-collapsed')
- else
- $thisIcon.removeClass('fa-angle-double-left')
- .addClass('fa-angle-double-right')
- $this
- .closest('aside')
- .removeClass('right-sidebar-collapsed')
- .addClass('right-sidebar-expanded')
- $('.page-with-sidebar')
- .removeClass('right-sidebar-collapsed')
- .addClass('right-sidebar-expanded')
- $.cookie("collapsed_gutter",
- $('.right-sidebar')
- .hasClass('right-sidebar-collapsed'), { path: '/' })
+ $(document)
+ .off 'keyup', 'input[type="search"]'
+ .on 'keyup', 'input[type="search"]' , (e) ->
+ $this = $(this)
+ $this.attr 'value', $this.val()
+
+ $(document)
+ .off 'breakpoint:change'
+ .on 'breakpoint:change', (e, breakpoint) ->
+ if breakpoint is 'sm' or breakpoint is 'xs'
+ $gutterIcon = $('.gutter-toggle').find('i')
+ if $gutterIcon.hasClass('fa-angle-double-right')
+ $gutterIcon.closest('a').trigger('click')
+
+ $(document)
+ .off 'click', 'aside .gutter-toggle'
+ .on 'click', 'aside .gutter-toggle', (e) ->
+ e.preventDefault()
+ $this = $(this)
+ $thisIcon = $this.find 'i'
+ if $thisIcon.hasClass('fa-angle-double-right')
+ $thisIcon
+ .removeClass('fa-angle-double-right')
+ .addClass('fa-angle-double-left')
+ $this
+ .closest('aside')
+ .removeClass('right-sidebar-expanded')
+ .addClass('right-sidebar-collapsed')
+ $('.page-with-sidebar')
+ .removeClass('right-sidebar-expanded')
+ .addClass('right-sidebar-collapsed')
+ else
+ $thisIcon
+ .removeClass('fa-angle-double-left')
+ .addClass('fa-angle-double-right')
+ $this
+ .closest('aside')
+ .removeClass('right-sidebar-collapsed')
+ .addClass('right-sidebar-expanded')
+ $('.page-with-sidebar')
+ .removeClass('right-sidebar-collapsed')
+ .addClass('right-sidebar-expanded')
+ $.cookie("collapsed_gutter",
+ $('.right-sidebar')
+ .hasClass('right-sidebar-collapsed'), { path: '/' })
bootstrapBreakpoint = undefined;
checkBootstrapBreakpoints = ->
@@ -282,8 +289,10 @@ $ ->
if bootstrapBreakpoint is "xs" or "sm"
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
- $(window).on "resize", (e) ->
- fitSidebarForSize()
+ $(window)
+ .off "resize"
+ .on "resize", (e) ->
+ fitSidebarForSize()
setBootstrapBreakpoints()
checkInitialSidebarSize()
diff --git a/app/assets/javascripts/broadcast_message.js.coffee b/app/assets/javascripts/broadcast_message.js.coffee
new file mode 100644
index 00000000000..a38a329c4c2
--- /dev/null
+++ b/app/assets/javascripts/broadcast_message.js.coffee
@@ -0,0 +1,22 @@
+$ ->
+ $('input#broadcast_message_color').on 'input', ->
+ previewColor = $(@).val()
+ $('div.broadcast-message-preview').css('background-color', previewColor)
+
+ $('input#broadcast_message_font').on 'input', ->
+ previewColor = $(@).val()
+ $('div.broadcast-message-preview').css('color', previewColor)
+
+ previewPath = $('textarea#broadcast_message_message').data('preview-path')
+
+ $('textarea#broadcast_message_message').on 'input', ->
+ message = $(@).val()
+
+ if message == ''
+ $('.js-broadcast-message-preview').text("Your message here")
+ else
+ $.ajax(
+ url: previewPath
+ type: "POST"
+ data: { broadcast_message: { message: message } }
+ )
diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee
index 00ee503ff16..62143e66cfe 100644
--- a/app/assets/javascripts/dashboard.js.coffee
+++ b/app/assets/javascripts/dashboard.js.coffee
@@ -1,3 +1,31 @@
-class @Dashboard
- constructor: ->
- new ProjectsList()
+@Dashboard =
+ init: ->
+ $(".projects-list-filter").off('keyup')
+ this.initSearch()
+
+ initSearch: ->
+ @timer = null
+ $(".projects-list-filter").on('keyup', ->
+ clearTimeout(@timer)
+ @timer = setTimeout(Dashboard.filterResults, 500)
+ )
+
+ filterResults: =>
+ $('.projects-list-holder').fadeTo(250, 0.5)
+
+ form = null
+ form = $("form#project-filter-form")
+ search = $(".projects-list-filter").val()
+ project_filter_url = form.attr('action') + '?' + form.serialize()
+
+ $.ajax
+ type: "GET"
+ url: form.attr('action')
+ data: form.serialize()
+ complete: ->
+ $('.projects-list-holder').fadeTo(250, 1)
+ success: (data) ->
+ $('.projects-list-holder').replaceWith(data.html)
+ # Change url so if user reload a page - search results are saved
+ history.replaceState {page: project_filter_url}, document.title, project_filter_url
+ dataType: "json"
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 2cdf01d874c..b17f8e51470 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -16,6 +16,8 @@ class Dispatcher
shortcut_handler = null
switch page
+ when 'explore:projects:index', 'explore:projects:starred', 'explore:projects:trending'
+ Dashboard.init()
when 'projects:issues:index'
Issues.init()
shortcut_handler = new ShortcutsNavigation()
@@ -58,7 +60,7 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
MergeRequests.init()
when 'dashboard:show', 'root:show'
- new Dashboard()
+ Dashboard.init()
when 'dashboard:activity'
new Activities()
when 'dashboard:projects:starred'
diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee
index a5879c8b793..35b2fbbba07 100644
--- a/app/assets/javascripts/logo.js.coffee
+++ b/app/assets/javascripts/logo.js.coffee
@@ -42,3 +42,9 @@ work = ->
$(document).on('page:fetch', start)
$(document).on('page:change', stop)
+
+$ ->
+ # Make logo clickable as part of a workaround for Safari visited
+ # link behaviour (See !2690).
+ $('#logo').on 'click', ->
+ $('#js-shortcuts-home').get(0).click()
diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee
index b71509dbc5a..eab34be652a 100644
--- a/app/assets/javascripts/projects_list.js.coffee
+++ b/app/assets/javascripts/projects_list.js.coffee
@@ -3,24 +3,24 @@ class @ProjectsList
$(".projects-list .js-expand").on 'click', (e) ->
e.preventDefault()
list = $(this).closest('.projects-list')
- list.find("li").show()
- list.find("li.bottom").hide()
- $(".projects-list-filter").keyup ->
- terms = $(this).val()
- uiBox = $('div.projects-list-holder')
- filterSelector = $(this).data('filter-selector') || 'span.filter-title'
+ $("#filter_projects").on 'keyup', ->
+ ProjectsList.filter_results($("#filter_projects"))
- if terms == "" || terms == undefined
- uiBox.find("ul.projects-list li").show()
- else
- uiBox.find("ul.projects-list li").each (index) ->
- name = $(this).find(filterSelector).text()
-
- if name.toLowerCase().search(terms.toLowerCase()) == -1
- $(this).hide()
- else
- $(this).show()
- uiBox.find("ul.projects-list li.bottom").hide()
+ @filter_results: ($element) ->
+ terms = $element.val()
+ filterSelector = $element.data('filter-selector') || 'span.filter-title'
+ if not terms
+ $(".projects-list li").show()
+ $('.gl-pagination').show()
+ else
+ $(".projects-list li").each (index) ->
+ $this = $(this)
+ name = $this.find(filterSelector).text()
+ if name.toLowerCase().indexOf(terms.toLowerCase()) == -1
+ $this.hide()
+ else
+ $this.show()
+ $('.gl-pagination').hide()
diff --git a/app/assets/javascripts/shortcuts_issuable.coffee b/app/assets/javascripts/shortcuts_issuable.coffee
index f717a753cf8..cefa1857d7f 100644
--- a/app/assets/javascripts/shortcuts_issuable.coffee
+++ b/app/assets/javascripts/shortcuts_issuable.coffee
@@ -16,12 +16,31 @@ class @ShortcutsIssuable extends ShortcutsNavigation
@replyWithSelectedText()
return false
)
+ Mousetrap.bind('j', =>
+ @prevIssue()
+ return false
+ )
+ Mousetrap.bind('k', =>
+ @nextIssue()
+ return false
+ )
+
if isMergeRequest
@enabledHelp.push('.hidden-shortcut.merge_requests')
else
@enabledHelp.push('.hidden-shortcut.issues')
+ prevIssue: ->
+ $prevBtn = $('.prev-btn')
+ if not $prevBtn.hasClass('disabled')
+ Turbolinks.visit($prevBtn.attr('href'))
+
+ nextIssue: ->
+ $nextBtn = $('.next-btn')
+ if not $nextBtn.hasClass('disabled')
+ Turbolinks.visit($nextBtn.attr('href'))
+
replyWithSelectedText: ->
if window.getSelection
selected = window.getSelection().toString()
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 7871a33b6c5..a81e258573d 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -91,8 +91,17 @@ header {
.dropdown-toggle-caret {
position: relative;
top: -2px;
+ width: 12px;
+ line-height: 12px;
margin-left: 5px;
font-size: 10px;
+ text-align: center;
+ cursor: pointer;
+ }
+
+ .project-item-select {
+ right: auto;
+ left: 0;
}
}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index e6c59f5a291..252a586358c 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -85,6 +85,10 @@
display: inline-block;
}
+ > form {
+ display: inline-block;
+ }
+
input {
height: 34px;
display: inline-block;
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index b7f532c0771..b141928f706 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -45,6 +45,19 @@
overflow: hidden;
transition-duration: .3s;
+ .home {
+ z-index: 1;
+ position: absolute;
+ left: 0px;
+ }
+
+ #logo {
+ z-index: 2;
+ position: absolute;
+ width: 58px;
+ cursor: pointer;
+ }
+
a {
float: left;
height: $header-height;
@@ -70,7 +83,7 @@
width: 158px;
float: left;
margin: 0;
- margin-left: 14px;
+ margin-left: 50px;
font-size: 19px;
line-height: 41px;
font-weight: normal;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index efc3366e99c..b8386362637 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -13,8 +13,8 @@ $list-font-size: 15px;
$sidebar_collapsed_width: 62px;
$sidebar_width: 230px;
$gutter_collapsed_width: 62px;
-$gutter_width: 312px;
-$gutter_inner_width: 280px;
+$gutter_width: 290px;
+$gutter_inner_width: 258px;
$avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
diff --git a/app/assets/stylesheets/pages/admin.scss b/app/assets/stylesheets/pages/admin.scss
index 144852e7874..a61161810a3 100644
--- a/app/assets/stylesheets/pages/admin.scss
+++ b/app/assets/stylesheets/pages/admin.scss
@@ -55,6 +55,16 @@
@extend .alert-warning;
padding: 10px;
text-align: center;
+
+ > div, p {
+ display: inline;
+ margin: 0;
+
+ a {
+ color: inherit;
+ text-decoration: underline;
+ }
+ }
}
.broadcast-message-preview {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 3bfbd9e17b7..9d5dc42b6cc 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -29,17 +29,6 @@
}
}
-.project-issuable-filter {
- .controls {
- float: right;
- margin-top: 11px;
- }
-
- .nav-links {
- text-align: left;
- }
-}
-
.issuable-details {
section {
.issuable-discussion {
@@ -72,7 +61,7 @@
@include clearfix;
padding: $gl-padding 0;
border-bottom: 1px solid $border-gray-light;
- // This prevents the mess when resizing the sidebar
+ // This prevents the mess when resizing the sidebar
// of elements repositioning themselves..
width: $gutter_inner_width;
overflow-x: hidden;
@@ -206,7 +195,7 @@
}
&.right-sidebar-collapsed {
- .issuable-count,
+ .issuable-count,
.issuable-nav,
.assignee > *,
.milestone > *,
@@ -243,4 +232,10 @@
display: none;
}
}
+}
+
+.detail-page-description {
+ small {
+ color: $gray-darkest;
+ }
} \ No newline at end of file
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 1515086b16d..04a99d8c84a 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -81,6 +81,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:sentry_dsn,
:akismet_enabled,
:akismet_api_key,
+ :email_author_in_body,
restricted_visibility_levels: [],
import_sources: []
)
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index 4735b27c65d..fc342924987 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -2,7 +2,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
before_action :finder, only: [:edit, :update, :destroy]
def index
- @broadcast_messages = BroadcastMessage.reorder("starts_at ASC").page(params[:page])
+ @broadcast_messages = BroadcastMessage.reorder("ends_at DESC").page(params[:page])
@broadcast_message = BroadcastMessage.new
end
@@ -36,6 +36,10 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end
end
+ def preview
+ @message = broadcast_message_params[:message]
+ end
+
protected
def finder
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7fa2f68ef07..48b1f95acb9 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -277,9 +277,10 @@ class ApplicationController < ActionController::Base
}
end
- def view_to_html_string(partial)
+ def view_to_html_string(partial, locals = {})
render_to_string(
partial,
+ locals: locals,
layout: false,
formats: [:html]
)
diff --git a/app/controllers/ci/application_controller.rb b/app/controllers/ci/application_controller.rb
index c420b59c3a2..5bb7d499cdc 100644
--- a/app/controllers/ci/application_controller.rb
+++ b/app/controllers/ci/application_controller.rb
@@ -3,52 +3,5 @@ module Ci
def self.railtie_helpers_paths
"app/helpers/ci"
end
-
- private
-
- def authorize_access_project!
- unless can?(current_user, :read_project, project)
- return page_404
- end
- end
-
- def authorize_manage_builds!
- unless can?(current_user, :manage_builds, project)
- return page_404
- end
- end
-
- def authenticate_admin!
- return render_404 unless current_user.is_admin?
- end
-
- def authorize_manage_project!
- unless can?(current_user, :admin_project, project)
- return page_404
- end
- end
-
- def page_404
- render file: "#{Rails.root}/public/404.html", status: 404, layout: false
- end
-
- def default_headers
- headers['X-Frame-Options'] = 'DENY'
- headers['X-XSS-Protection'] = '1; mode=block'
- end
-
- # JSON for infinite scroll via Pager object
- def pager_json(partial, count)
- html = render_to_string(
- partial,
- layout: false,
- formats: [:html]
- )
-
- render json: {
- html: html,
- count: count
- }
- end
end
end
diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb
index 3004c2d27f0..711c2847d5e 100644
--- a/app/controllers/ci/projects_controller.rb
+++ b/app/controllers/ci/projects_controller.rb
@@ -1,8 +1,7 @@
module Ci
class ProjectsController < Ci::ApplicationController
- before_action :project, except: [:index]
- before_action :authenticate_user!, except: [:index, :build, :badge]
- before_action :authorize_access_project!, except: [:index, :badge]
+ before_action :project
+ before_action :authorize_read_project!, except: [:badge]
before_action :no_cache, only: [:badge]
protect_from_forgery
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 721e2a6bcbd..2df6924b13d 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -5,6 +5,14 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace)
+
+ terms = params['filter_projects']
+
+ if terms.present?
+ @projects = @projects.search(terms)
+ end
+
+ @projects = @projects.page(params[:page]).per(PER_PAGE) if terms.blank?
@last_push = current_user.recent_push
respond_to do |format|
@@ -14,6 +22,11 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
load_events
render layout: false
end
+ format.json do
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
+ end
end
end
@@ -21,6 +34,14 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
@projects = current_user.starred_projects
@projects = @projects.includes(:namespace, :forked_from_project, :tags)
@projects = @projects.sort(@sort = params[:sort])
+
+ terms = params['filter_projects']
+
+ if terms.present?
+ @projects = @projects.search(terms)
+ end
+
+ @projects = @projects.page(params[:page]).per(PER_PAGE) if terms.blank?
@last_push = current_user.recent_push
@groups = []
@@ -28,8 +49,9 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
format.html
format.json do
- load_events
- pager_json("events/_events", @events.count)
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
end
end
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index a5aeaed66c5..a384f3004db 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -6,19 +6,49 @@ class Explore::ProjectsController < Explore::ApplicationController
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.non_archived
@projects = @projects.search(params[:search]) if params[:search].present?
+ @projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
@projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
+ @projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
+ end
+ end
end
def trending
- @trending_projects = TrendingProjectsFinder.new.execute(current_user)
- @trending_projects = @trending_projects.non_archived
- @trending_projects = @trending_projects.page(params[:page]).per(PER_PAGE)
+ @projects = TrendingProjectsFinder.new.execute(current_user)
+ @projects = @projects.non_archived
+ @projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
+ @projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
+ end
+ end
end
def starred
- @starred_projects = ProjectsFinder.new.execute(current_user)
- @starred_projects = @starred_projects.reorder('star_count DESC')
- @starred_projects = @starred_projects.page(params[:page]).per(PER_PAGE)
+ @projects = ProjectsFinder.new.execute(current_user)
+ @projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
+ @projects = @projects.reorder('star_count DESC')
+ @projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
+ end
+ end
end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index ad6b3eae932..ca5ce1e2046 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -14,7 +14,7 @@ class GroupsController < Groups::ApplicationController
# Load group projects
before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete]
- before_action :event_filter, only: :show
+ before_action :event_filter, only: [:show, :events]
layout :determine_layout
@@ -41,13 +41,16 @@ class GroupsController < Groups::ApplicationController
def show
@last_push = current_user.recent_push if current_user
@projects = @projects.includes(:namespace)
+ @projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
+ @projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
respond_to do |format|
format.html
format.json do
- load_events
- pager_json("events/_events", @events.count)
+ render json: {
+ html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
+ }
end
format.atom do
@@ -57,6 +60,15 @@ class GroupsController < Groups::ApplicationController
end
end
+ def events
+ respond_to do |format|
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
+ end
+ end
+
def edit
end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index dd32d509191..a326bc58215 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -28,6 +28,11 @@ class Projects::ApplicationController < ApplicationController
private
+ def apply_diff_view_cookie!
+ view = params[:view] || cookies[:diff_view]
+ cookies.permanent[:diff_view] = params[:view] = view if view
+ end
+
def builds_enabled
return render_404 unless @project.builds_enabled?
end
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index f159a6d6dc6..cfea1266516 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -1,6 +1,6 @@
class Projects::ArtifactsController < Projects::ApplicationController
layout 'project'
- before_action :authorize_read_build_artifacts!
+ before_action :authorize_read_build!
def download
unless artifacts_file.file_storage?
@@ -43,14 +43,4 @@ class Projects::ArtifactsController < Projects::ApplicationController
def artifacts_file
@artifacts_file ||= build.artifacts_file
end
-
- def authorize_read_build_artifacts!
- unless can?(current_user, :read_build_artifacts, @project)
- if current_user.nil?
- return authenticate_user!
- else
- return render_404
- end
- end
- end
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 92d9699fe84..9e89296e71d 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,7 +1,8 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all]
- before_action :authorize_manage_builds!, except: [:index, :show, :status]
+ before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry]
+ before_action :authorize_update_build!, except: [:index, :show, :status]
layout "project"
@@ -69,10 +70,4 @@ class Projects::BuildsController < Projects::ApplicationController
def build_path(build)
namespace_project_build_path(build.project.namespace, build.project, build)
end
-
- def authorize_manage_builds!
- unless can?(current_user, :manage_builds, project)
- return render_404
- end
- end
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index f5a169e5aa9..21f4d9f44ec 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -4,15 +4,17 @@
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
- before_action :authorize_download_code!, except: [:cancel_builds]
- before_action :authorize_manage_builds!, only: [:cancel_builds]
+ before_action :authorize_download_code!, except: [:cancel_builds, :retry_builds]
+ before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds]
+ before_action :authorize_read_commit_status!, only: [:builds]
before_action :commit
- before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
def show
return git_not_found! unless @commit
+ apply_diff_view_cookie!
+
@line_notes = commit.notes.inline
@note = @project.build_commit_note(commit)
@notes = commit.notes.not_inline.fresh
@@ -77,10 +79,4 @@ class Projects::CommitController < Projects::ApplicationController
@statuses = ci_commit.statuses if ci_commit
end
-
- def authorize_manage_builds!
- unless can?(current_user, :manage_builds, project)
- return render_404
- end
- end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index ed3050d59aa..9d588c370aa 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -57,6 +57,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def diffs
+ apply_diff_view_cookie!
+
@commit = @merge_request.last_commit
@base_commit = @merge_request.diff_base_commit
diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb
index e2785caa2fb..bedeb4a295c 100644
--- a/app/controllers/projects/runner_projects_controller.rb
+++ b/app/controllers/projects/runner_projects_controller.rb
@@ -1,5 +1,5 @@
class Projects::RunnerProjectsController < Projects::ApplicationController
- before_action :authorize_admin_project!
+ before_action :authorize_admin_build!
layout 'project_settings'
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 4993b2648a5..0dd2d6a99be 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -1,6 +1,6 @@
class Projects::RunnersController < Projects::ApplicationController
+ before_action :authorize_admin_build!
before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
- before_action :authorize_admin_project!
layout 'project_settings'
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index 30adfad1daa..92359745cec 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -1,5 +1,5 @@
class Projects::TriggersController < Projects::ApplicationController
- before_action :authorize_admin_project!
+ before_action :authorize_admin_build!
layout 'project_settings'
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 10efafea9db..00234654578 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -1,5 +1,5 @@
class Projects::VariablesController < Projects::ApplicationController
- before_action :authorize_admin_project!
+ before_action :authorize_admin_build!
layout 'project_settings'
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 4df5095bd94..14ca7426c2f 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -227,6 +227,7 @@ class ProjectsController < ApplicationController
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
+ :public_builds,
)
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 280228dbcc0..6055b606086 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -4,8 +4,9 @@ class UsersController < ApplicationController
def show
@contributed_projects = contributed_projects.joined(@user).reject(&:forked?)
-
+
@projects = PersonalProjectsFinder.new(@user).execute(current_user)
+ @projects = @projects.page(params[:page]).per(PER_PAGE)
@groups = @user.groups.order_id_desc
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index 1ed8c710f77..43a29c96bca 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -3,7 +3,7 @@ module BroadcastMessagesHelper
return unless message.present?
content_tag :div, class: 'broadcast-message', style: broadcast_message_style(message) do
- icon('bullhorn') << ' ' << message.message
+ icon('bullhorn') << ' ' << render_broadcast_message(message.message)
end
end
@@ -31,4 +31,8 @@ module BroadcastMessagesHelper
'Pending'
end
end
+
+ def render_broadcast_message(message)
+ Banzai.render(message, pipeline: :broadcast_message).html_safe
+ end
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 2c299d1d794..75f2ed5e054 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -32,8 +32,10 @@ module NavHelper
end
def page_gutter_class
-
- if current_path?('merge_requests#show') || current_path?('issues#show')
+ if current_path?('merge_requests#show') ||
+ current_path?('merge_requests#diffs') ||
+ current_path?('merge_requests#commits') ||
+ current_path?('issues#show')
if cookies[:collapsed_gutter] == 'true'
"page-gutter right-sidebar-collapsed"
else
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 2e9741a8622..cc1c61e9ec0 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -59,9 +59,8 @@ module ProjectsHelper
link_to(simple_sanitize(owner.name), user_path(owner))
end
- project_link = link_to project_path(project), { class: "project-item-select-holder #{"js-projects-dropdown-toggle" if current_user}" } do
+ project_link = link_to project_path(project), { class: "project-item-select-holder" } do
link_output = simple_sanitize(project.name)
- link_output += content_tag :span, nil, { class: "fa fa-chevron-down dropdown-toggle-caret" } if current_user
if current_user
link_output += project_select_tag :project_path,
@@ -71,6 +70,7 @@ module ProjectsHelper
link_output
end
+ project_link += icon "chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle" if current_user
full_title = namespace_link + ' / ' + project_link
full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url) if name
@@ -141,7 +141,7 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
- if project.builds_enabled? && can?(current_user, :read_build, project)
+ if can?(current_user, :read_build, project)
nav_tabs << :builds
end
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index bc36434f549..41ae4048992 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -33,7 +33,7 @@ module SnippetsHelper
# surrounding code.
#
# @returns Array, unique and sorted.
- def matching_lines(lined_content, surrounding_lines)
+ def matching_lines(lined_content, surrounding_lines, query)
used_lines = []
lined_content.each_with_index do |line, line_number|
used_lines.concat bounded_line_numbers(
@@ -51,9 +51,9 @@ module SnippetsHelper
# surrounding_lines() worth of unmatching lines.
#
# @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
- def chunk_snippet(snippet, surrounding_lines = 3)
+ def chunk_snippet(snippet, query, surrounding_lines = 3)
lined_content = snippet.content.split("\n")
- used_lines = matching_lines(lined_content, surrounding_lines)
+ used_lines = matching_lines(lined_content, surrounding_lines, query)
snippet_chunk = []
snippet_chunks = []
diff --git a/app/models/ability.rb b/app/models/ability.rb
index ab59a3506a2..a866eadeebb 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -5,17 +5,18 @@ class Ability
return [] unless user.is_a?(User)
return [] if user.blocked?
- case subject.class.name
- when "Project" then project_abilities(user, subject)
- when "Issue" then issue_abilities(user, subject)
- when "Note" then note_abilities(user, subject)
- when "ProjectSnippet" then project_snippet_abilities(user, subject)
- when "PersonalSnippet" then personal_snippet_abilities(user, subject)
- when "MergeRequest" then merge_request_abilities(user, subject)
- when "Group" then group_abilities(user, subject)
- when "Namespace" then namespace_abilities(user, subject)
- when "GroupMember" then group_member_abilities(user, subject)
- when "ProjectMember" then project_member_abilities(user, subject)
+ case subject
+ when CommitStatus then commit_status_abilities(user, subject)
+ when Project then project_abilities(user, subject)
+ when Issue then issue_abilities(user, subject)
+ when Note then note_abilities(user, subject)
+ when ProjectSnippet then project_snippet_abilities(user, subject)
+ when PersonalSnippet then personal_snippet_abilities(user, subject)
+ when MergeRequest then merge_request_abilities(user, subject)
+ when Group then group_abilities(user, subject)
+ when Namespace then namespace_abilities(user, subject)
+ when GroupMember then group_member_abilities(user, subject)
+ when ProjectMember then project_member_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
@@ -25,6 +26,8 @@ class Ability
case true
when subject.is_a?(PersonalSnippet)
anonymous_personal_snippet_abilities(subject)
+ when subject.is_a?(CommitStatus)
+ anonymous_commit_status_abilities(subject)
when subject.is_a?(Project) || subject.respond_to?(:project)
anonymous_project_abilities(subject)
when subject.is_a?(Group) || subject.respond_to?(:group)
@@ -52,16 +55,26 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
- :read_build,
+ :read_commit_status,
:download_code
]
+ # Allow to read builds by anonymous user if guests are allowed
+ rules << :read_build if project.public_builds?
+
rules - project_disabled_features_rules(project)
else
[]
end
end
+ def anonymous_commit_status_abilities(subject)
+ rules = anonymous_project_abilities(subject.project)
+ # If subject is Ci::Build which inherits from CommitStatus filter the abilities
+ rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
+ rules
+ end
+
def anonymous_group_abilities(subject)
group = if subject.is_a?(Group)
subject
@@ -113,6 +126,9 @@ class Ability
if project.public? || project.internal?
rules.push(*public_project_rules)
+
+ # Allow to read builds for internal projects
+ rules << :read_build if project.public_builds?
end
if project.owner == user || user.admin?
@@ -134,7 +150,8 @@ class Ability
def public_project_rules
@public_project_rules ||= project_guest_rules + [
:download_code,
- :fork_project
+ :fork_project,
+ :read_commit_status,
]
end
@@ -149,7 +166,6 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
- :read_build,
:create_project,
:create_issue,
:create_note
@@ -158,24 +174,26 @@ class Ability
def project_report_rules
@project_report_rules ||= project_guest_rules + [
- :create_commit_status,
- :read_commit_statuses,
- :read_build_artifacts,
:download_code,
:fork_project,
:create_project_snippet,
:update_issue,
:admin_issue,
- :admin_label
+ :admin_label,
+ :read_commit_status,
+ :read_build,
]
end
def project_dev_rules
@project_dev_rules ||= project_report_rules + [
:admin_merge_request,
+ :create_commit_status,
+ :update_commit_status,
+ :create_build,
+ :update_build,
:create_merge_request,
:create_wiki,
- :manage_builds,
:push_code
]
end
@@ -201,7 +219,9 @@ class Ability
:admin_merge_request,
:admin_note,
:admin_wiki,
- :admin_project
+ :admin_project,
+ :admin_commit_status,
+ :admin_build
]
end
@@ -240,6 +260,10 @@ class Ability
rules += named_abilities('wiki')
end
+ unless project.builds_enabled
+ rules += named_abilities('build')
+ end
+
rules
end
@@ -376,6 +400,22 @@ class Ability
rules
end
+ def commit_status_abilities(user, subject)
+ rules = project_abilities(user, subject.project)
+ # If subject is Ci::Build which inherits from CommitStatus filter the abilities
+ rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
+ rules
+ end
+
+ def filter_build_abilities(rules)
+ # If we can't read build we should also not have that
+ # ability when looking at this in context of commit_status
+ %w(read create update admin).each do |rule|
+ rules.delete(:"#{rule}_commit_status") unless rules.include?(:"#{rule}_build")
+ end
+ rules
+ end
+
def abilities
@abilities ||= begin
abilities = Six.new
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 9cafc78f761..fa48fe5b9e4 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -43,6 +43,7 @@
# metrics_port :integer default(8089)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
+# email_author_in_body :boolean default(FALSE)
#
class ApplicationSetting < ActiveRecord::Base
@@ -92,6 +93,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
if: :akismet_enabled
+ validates :max_attachment_size,
+ presence: true,
+ numericality: { only_integer: true, greater_than: 0 }
+
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
diff --git a/app/models/event.rb b/app/models/event.rb
index 4be23a1cf72..9a0bbf50f8b 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -49,7 +49,7 @@ class Event < ActiveRecord::Base
scope :code_push, -> { where(action: PUSHED) }
scope :in_projects, ->(projects) do
- where(project_id: projects.select(:id).reorder(nil)).recent
+ where(project_id: projects.map(&:id)).recent
end
scope :with_associations, -> { includes(project: :namespace) }
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index c9a0ad8b9b6..9c4476c768e 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -34,7 +34,7 @@ class Milestone < ActiveRecord::Base
scope :closed, -> { with_state(:closed) }
scope :of_projects, ->(ids) { where(project_id: ids) }
- validates :title, presence: true
+ validates :title, presence: true, uniqueness: { scope: :project_id }
validates :project, presence: true
strip_attributes :title
diff --git a/app/models/project.rb b/app/models/project.rb
index 043f08b9a13..f11c6d7c6be 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -790,6 +790,8 @@ class Project < ActiveRecord::Base
def change_head(branch)
# Cached divergent commit counts are based on repository head
repository.expire_branch_cache
+ repository.expire_root_ref_cache
+
gitlab_shell.update_repository_head(self.path_with_namespace, branch)
reload_default_branch
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 130daddd9d1..0e17d2b669a 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -44,7 +44,9 @@ class Repository
end
def empty?
- raw_repository.empty?
+ return @empty unless @empty.nil?
+
+ @empty = cache.fetch(:empty?) { raw_repository.empty? }
end
#
@@ -57,7 +59,11 @@ class Repository
# This method return true if repository contains some content visible in project page.
#
def has_visible_content?
- raw_repository.branch_count > 0
+ return @has_visible_content unless @has_visible_content.nil?
+
+ @has_visible_content = cache.fetch(:has_visible_content?) do
+ raw_repository.branch_count > 0
+ end
end
def commit(id = 'HEAD')
@@ -184,8 +190,11 @@ class Repository
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
# Rugged seems to throw a `ReferenceError` when given branch_names rather
# than SHA-1 hashes
- number_commits_behind = commits_between(branch.target, root_ref_hash).size
- number_commits_ahead = commits_between(root_ref_hash, branch.target).size
+ number_commits_behind = raw_repository.
+ count_commits_between(branch.target, root_ref_hash)
+
+ number_commits_ahead = raw_repository.
+ count_commits_between(root_ref_hash, branch.target)
{ behind: number_commits_behind, ahead: number_commits_ahead }
end
@@ -196,12 +205,6 @@ class Repository
readme version contribution_guide changelog license)
end
- def branch_cache_keys
- branches.map do |branch|
- :"diverging_commit_counts_#{branch.name}"
- end
- end
-
def build_cache
cache_keys.each do |key|
unless cache.exist?(key)
@@ -226,20 +229,39 @@ class Repository
@branches = nil
end
- def expire_cache
+ def expire_cache(branch_name = nil)
cache_keys.each do |key|
cache.expire(key)
end
- expire_branch_cache
+ expire_branch_cache(branch_name)
end
- def expire_branch_cache
- branches.each do |branch|
- cache.expire(:"diverging_commit_counts_#{branch.name}")
+ def expire_branch_cache(branch_name = nil)
+ # When we push to the root branch we have to flush the cache for all other
+ # branches as their statistics are based on the commits relative to the
+ # root branch.
+ if !branch_name || branch_name == root_ref
+ branches.each do |branch|
+ cache.expire(:"diverging_commit_counts_#{branch.name}")
+ end
+ # In case a commit is pushed to a non-root branch we only have to flush the
+ # cache for said branch.
+ else
+ cache.expire(:"diverging_commit_counts_#{branch_name}")
end
end
+ def expire_root_ref_cache
+ cache.expire(:root_ref)
+ @root_ref = nil
+ end
+
+ def expire_has_visible_content_cache
+ cache.expire(:has_visible_content?)
+ @has_visible_content = nil
+ end
+
def rebuild_cache
cache_keys.each do |key|
cache.expire(key)
@@ -477,7 +499,7 @@ class Repository
end
def root_ref
- @root_ref ||= raw_repository.root_ref
+ @root_ref ||= cache.fetch(:root_ref) { raw_repository.root_ref }
end
def commit_dir(user, path, message, branch)
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index d7ea30bc315..e3bf14966c8 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -18,18 +18,23 @@ class GitPushService
def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user
- project.repository.expire_cache
+ branch_name = Gitlab::Git.ref_name(ref)
+
+ project.repository.expire_cache(branch_name)
if push_remove_branch?(ref, newrev)
+ project.repository.expire_has_visible_content_cache
+
@push_commits = []
elsif push_to_new_branch?(ref, oldrev)
+ project.repository.expire_has_visible_content_cache
+
# Re-find the pushed commits.
if is_default_branch?(ref)
# Initial push to the default branch. Take the full history of that branch as "newly pushed".
@push_commits = project.repository.commits(newrev)
# Ensure HEAD points to the default branch in case it is not master
- branch_name = Gitlab::Git.ref_name(ref)
project.change_head(branch_name)
# Set protection on the default branch if configured
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index b4e3d96d405..b30dfd109ea 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -48,6 +48,16 @@
= f.check_box :version_check_enabled
Version check enabled
.form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :email_author_in_body do
+ = f.check_box :email_author_in_body
+ Include author name in notification email body
+ .help-block
+ Some email servers do not support overriding the email sender name.
+ Enable this option to include the name of the author of the issue,
+ merge request or comment in the email body instead.
+ .form-group
= f.label :admin_notification_email, class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :admin_notification_email, class: 'form-control'
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index 953b8b69368..5c9403fa0c2 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -1,6 +1,7 @@
.broadcast-message-preview{ style: broadcast_message_style(@broadcast_message) }
= icon('bullhorn')
- %span= @broadcast_message.message || "Your message here"
+ .js-broadcast-message-preview
+ = render_broadcast_message(@broadcast_message.message.presence || "Your message here")
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-requires-input'} do |f|
-if @broadcast_message.errors.any?
@@ -10,7 +11,9 @@
.form-group
= f.label :message, class: 'control-label'
.col-sm-10
- = f.text_area :message, class: "form-control js-quick-submit", rows: 2, required: true
+ = f.text_area :message, class: "form-control js-quick-submit js-autosize",
+ required: true,
+ data: { preview_path: preview_admin_broadcast_messages_path }
.form-group.js-toggle-colors-container
.col-sm-10.col-sm-offset-2
= link_to 'Customize colors', '#', class: 'js-toggle-colors-link'
diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml
index 49e33698b63..c05538a393c 100644
--- a/app/views/admin/broadcast_messages/index.html.haml
+++ b/app/views/admin/broadcast_messages/index.html.haml
@@ -34,4 +34,4 @@
= link_to icon('pencil-square-o'), edit_admin_broadcast_message_path(message), title: 'Edit', class: 'btn btn-xs'
= link_to icon('times'), admin_broadcast_message_path(message), method: :delete, remote: true, title: 'Remove', class: 'js-remove-tr btn btn-xs btn-danger'
- = paginate @broadcast_messages
+ = paginate @broadcast_messages, theme: 'gitlab'
diff --git a/app/views/admin/broadcast_messages/preview.js.haml b/app/views/admin/broadcast_messages/preview.js.haml
new file mode 100644
index 00000000000..fbc9453c72e
--- /dev/null
+++ b/app/views/admin/broadcast_messages/preview.js.haml
@@ -0,0 +1 @@
+$('.js-broadcast-message-preview').html("#{j(render_broadcast_message(@message))}");
diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml
index c395bd908c3..34d955568f2 100644
--- a/app/views/admin/builds/_build.html.haml
+++ b/app/views/admin/builds/_build.html.haml
@@ -4,7 +4,7 @@
= ci_status_with_icon(build.status)
%td.build-link
- - if build.target_url
+ - if can?(current_user, :read_build, project) && build.target_url
= link_to build.target_url do
%strong Build ##{build.id}
- else
@@ -60,10 +60,10 @@
%td
.pull-right
- - if current_user && can?(current_user, :read_build_artifacts, project) && build.artifacts?
+ - if can?(current_user, :read_build, project) && build.artifacts?
= link_to build.artifacts_download_url, title: 'Download artifacts' do
%i.fa.fa-download
- - if current_user && can?(current_user, :manage_builds, build.project)
+ - if can?(current_user, :update_build, build.project)
- if build.active?
- if build.cancel_url
= link_to build.cancel_url, method: :post, title: 'Cancel' do
diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml
index ebf2b7b60e7..5931efdefe6 100644
--- a/app/views/admin/builds/index.html.haml
+++ b/app/views/admin/builds/index.html.haml
@@ -1,9 +1,4 @@
-.project-issuable-filter
- .controls
- .pull-left.hidden-xs
- - if @all_builds.running_or_pending.any?
- = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
-
+.top-area
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
= link_to admin_builds_path do
@@ -20,7 +15,11 @@
Finished
%span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id))
-.gray-content-block
+ .nav-controls
+ - if @all_builds.running_or_pending.any?
+ = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
+
+.gray-content-block.second-block
#{(@scope || 'running').capitalize} builds
%ul.content-list
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index d865a2c6fae..4bc761b3738 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -13,7 +13,8 @@
Explore Projects
.nav-controls
- = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs input-short', spellcheck: false
+ = form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
+ = search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'project-filter-form-field form-control input-short projects-list-filter', spellcheck: false, id: 'project-filter-form-field'
= render 'explore/projects/dropdown'
- if current_user.can_create_project?
= link_to new_project_path, class: 'btn btn-new' do
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index f363f035974..dfa5f80eef8 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -4,17 +4,15 @@
- if current_user
= auto_discovery_link_tag(:atom, issues_dashboard_url(format: :atom, private_token: current_user.private_token), title: "#{current_user.name} issues")
-.project-issuable-filter
- .controls
- .pull-left
- - if current_user
- .hidden-xs.pull-left
- = link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
- %i.fa.fa-rss
-
+.top-area
+ = render 'shared/issuable/nav', type: :issues
+ .nav-controls
+ - if current_user
+ = link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
- = render 'shared/issuable/filter', type: :issues
+= render 'shared/issuable/filter', type: :issues
.prepend-top-default
= render 'shared/issues'
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index bbe4cc1f824..fb016599fef 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -1,11 +1,12 @@
- page_title "Merge Requests"
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
-.project-issuable-filter
- .controls
+.top-area
+ = render 'shared/issuable/nav', type: :merge_requests
+ .nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New Merge Request"
- = render 'shared/issuable/filter', type: :merge_requests
+= render 'shared/issuable/filter', type: :merge_requests
.prepend-top-default
= render 'shared/merge_requests'
diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml
index cea9ffcc748..933a3edd0f0 100644
--- a/app/views/dashboard/projects/_projects.html.haml
+++ b/app/views/dashboard/projects/_projects.html.haml
@@ -1,3 +1,6 @@
.projects-list-holder
= render 'shared/projects/list', projects: @projects, ci: true
+
+ :javascript
+ Dashboard.init()
diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml
index 66a4b535ae5..c248dbb695f 100644
--- a/app/views/explore/projects/_filter.html.haml
+++ b/app/views/explore/projects/_filter.html.haml
@@ -1,11 +1,3 @@
-.pull-left
- = form_tag explore_projects_filter_path, method: :get, class: 'form-inline form-tiny' do |f|
- .form-group
- = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search", spellcheck: false
- = hidden_field_tag :sort, @sort
- .form-group
- = button_tag 'Search', class: "btn"
-
.pull-right.hidden-sm.hidden-xs
- if current_user
.dropdown.inline.append-right-10
diff --git a/app/views/explore/projects/_projects.html.haml b/app/views/explore/projects/_projects.html.haml
index 669079e9521..999a933390b 100644
--- a/app/views/explore/projects/_projects.html.haml
+++ b/app/views/explore/projects/_projects.html.haml
@@ -1,5 +1,5 @@
- if projects.any?
- .public-projects
+ .projects-list-holder
= render 'shared/projects/list', projects: projects
- else
.nothing-here-block
diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml
index bee8518d57a..dca75498573 100644
--- a/app/views/explore/projects/index.html.haml
+++ b/app/views/explore/projects/index.html.haml
@@ -13,4 +13,3 @@
= render 'filter'
= render 'projects', projects: @projects
-= paginate @projects, theme: "gitlab"
diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml
index 16f52f7a530..ec461755103 100644
--- a/app/views/explore/projects/starred.html.haml
+++ b/app/views/explore/projects/starred.html.haml
@@ -7,5 +7,4 @@
= render 'explore/head'
= render 'explore/projects/nav'
-= render 'projects', projects: @starred_projects
-= paginate @starred_projects, theme: 'gitlab'
+= render 'projects', projects: @projects
diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml
index adcda810061..ec461755103 100644
--- a/app/views/explore/projects/trending.html.haml
+++ b/app/views/explore/projects/trending.html.haml
@@ -7,4 +7,4 @@
= render 'explore/head'
= render 'explore/projects/nav'
-= render 'projects', projects: @trending_projects
+= render 'projects', projects: @projects
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index a829479bb38..9c16ab7e30f 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,10 +1,11 @@
-.projects-list-holder.prepend-top-default
- .input-group
- = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
- - if can? current_user, :create_projects, @group
- %span.input-group-btn
- = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new' do
- = icon('plus')
- New Project
+.top-area
+ .nav-controls
+ = form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
+ = search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'input-short project-filter-form-field form-control projects-list-filter', spellcheck: false, id: 'project-filter-form-field'
+ - if current_user && current_user.can_create_project?
+ = link_to new_project_path, class: 'btn btn-new' do
+ = icon('plus')
+ New Project
+.projects-list-holder
= render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false, skip_namespace: true
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 90ade1e1680..b0805593fdc 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -4,17 +4,15 @@
- if current_user
= auto_discovery_link_tag(:atom, issues_group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} issues")
-.project-issuable-filter
- .controls
- .pull-left
- - if current_user
- .hidden-xs.pull-left
- = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
- %i.fa.fa-rss
-
+.top-area
+ = render 'shared/issuable/nav', type: :issues
+ .nav-controls
+ - if current_user
+ = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
- = render 'shared/issuable/filter', type: :issues
+= render 'shared/issuable/filter', type: :issues
.gray-content-block.second-block
Only issues from
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index f662f5a8c17..e1c9dd931ee 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -1,11 +1,12 @@
- page_title "Merge Requests"
- header_title group_title(@group, "Merge Requests", merge_requests_group_path(@group))
-.project-issuable-filter
- .controls
+.top-area
+ = render 'shared/issuable/nav', type: :merge_requests
+ .nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New Merge Request"
- = render 'shared/issuable/filter', type: :merge_requests
+= render 'shared/issuable/filter', type: :merge_requests
.gray-content-block.second-block
Only merge requests from
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index ebb3df7dca3..a0ba11b11a1 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -47,7 +47,7 @@
= render 'shared/event_filter'
- .content_list
+ .content_list{data: {href: events_group_path}}
= spinner
.tab-pane#projects
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 0c1b5eec95a..e53d5b07801 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -2,8 +2,9 @@
= render "layouts/broadcast"
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
.header-logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
+ %a#logo
= brand_header_logo
+ = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 659f5a7756b..20042e21bf2 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,6 +1,6 @@
.search
= form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f|
- = search_field_tag "search", nil, placeholder: 'search', class: "search-input form-control", spellcheck: false
+ = search_field_tag "search", nil, placeholder: 'Search', class: "search-input form-control", spellcheck: false
= hidden_field_tag :group_id, @group.try(:id)
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
diff --git a/app/views/layouts/ci/_page.html.haml b/app/views/layouts/ci/_page.html.haml
index 7e90af21b21..3cfd36720f0 100644
--- a/app/views/layouts/ci/_page.html.haml
+++ b/app/views/layouts/ci/_page.html.haml
@@ -2,8 +2,9 @@
= render "layouts/broadcast"
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
.header-logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
+ %a#logo
= brand_header_logo
+ = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 00cb4aa24cc..12ded41fbf2 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,5 @@
+- if current_application_settings.email_author_in_body
+ %div
+ #{link_to @note.author_name, user_url(@note.author)} wrote:
%div
= markdown(@note.note, pipeline: :email)
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index d3b799fca23..ad3ab2525bb 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,3 +1,6 @@
+- if current_application_settings.email_author_in_body
+ %div
+ #{link_to @issue.author_name, user_url(@issue.author)} wrote:
-if @issue.description
= markdown(@issue.description, pipeline: :email)
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index 90ebdfc3fe2..23423e7d981 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -1,3 +1,6 @@
+- if current_application_settings.email_author_in_body
+ %div
+ #{link_to @merge_request.author_name, user_url(@merge_request.author)} wrote:
%p.details
!= merge_path_description(@merge_request, '&rarr;')
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 630d0286f25..5e3bd14565e 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -22,7 +22,7 @@
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls
- - if can?(current_user, :manage_builds, @project)
+ - if can?(current_user, :update_build, @project)
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index ba1fdc6f0e7..ca1441a20d8 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -89,8 +89,7 @@
Test coverage
%h1 #{@build.coverage}%
- - if current_user && can?(current_user, :read_build_artifacts, @project) && @build.artifacts?
-
+ - if can?(current_user, :read_build, @project) && @build.artifacts?
.build-widget.artifacts
%h4.title Build artifacts
.center
@@ -102,7 +101,7 @@
.build-widget
%h4.title
Build ##{@build.id}
- - if current_user && can?(current_user, :manage_builds, @project)
+ - if can?(current_user, :update_build, @project)
.pull-right
- if @build.cancel_url
= link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post
diff --git a/app/views/projects/commit/_builds.html.haml b/app/views/projects/commit/_builds.html.haml
index 329aaa0bb8b..befad27666c 100644
--- a/app/views/projects/commit/_builds.html.haml
+++ b/app/views/projects/commit/_builds.html.haml
@@ -1,6 +1,6 @@
.gray-content-block.middle-block
.pull-right
- - if can?(current_user, :manage_builds, @ci_commit.project)
+ - if can?(current_user, :update_build, @ci_commit.project)
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml
index 2e3c956ddc4..a3449d1ae05 100644
--- a/app/views/projects/commit_statuses/_commit_status.html.haml
+++ b/app/views/projects/commit_statuses/_commit_status.html.haml
@@ -1,6 +1,6 @@
%tr.commit_status
%td.status
- - if commit_status.target_url
+ - if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
= link_to commit_status.target_url, class: "ci-status ci-#{commit_status.status}" do
= ci_icon_for_status(commit_status.status)
= commit_status.status
@@ -8,14 +8,14 @@
= ci_status_with_icon(commit_status.status)
%td.commit_status-link
- - if commit_status.target_url
+ - if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
= link_to commit_status.target_url do
%strong ##{commit_status.id}
- else
%strong ##{commit_status.id}
- if commit_status.show_warning?
- %i.fa.fa-warning.text-warning
+ %i.fa.fa-warning.text-warning{data: { toggle: "tooltip" }, title: "This build is stuck, open it to know more"}
- if defined?(commit_sha) && commit_sha
%td
@@ -66,10 +66,10 @@
%td
.pull-right
- - if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts_download_url
+ - if can?(current_user, :read_commit_status, commit_status) && commit_status.artifacts_download_url
= link_to commit_status.artifacts_download_url, title: 'Download artifacts' do
%i.fa.fa-download
- - if current_user && can?(current_user, :manage_builds, commit_status.project)
+ - if can?(current_user, :update_commit_status, commit_status)
- if commit_status.active?
- if commit_status.cancel_url
= link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 8a99aceef7f..fdcb6987471 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -130,6 +130,7 @@
%strong git fetch
%br
%span.descr Faster
+
.form-group
= f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
.col-sm-10
@@ -158,6 +159,13 @@
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :public_builds do
+ = f.check_box :public_builds
+ %strong Public builds
+ .help-block Allow everyone to access builds for Public and Internal projects
%fieldset.features
%legend
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index acb2353d3ca..c834bf63b28 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -6,7 +6,7 @@
== #{pluralize(@all_forks.size, 'fork')}: #{full_count_title}
.nav-controls
- = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control input-short',
+ = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short',
spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' }
.dropdown
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index d6260ab2900..fde9304c0f8 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -5,22 +5,19 @@
- if current_user
= auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
-.project-issuable-filter
- .controls
- .pull-left
- - if current_user
- .hidden-xs.pull-left
- = link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
- %i.fa.fa-rss
-
+.top-area
+ = render 'shared/issuable/nav', type: :issues
+ .nav-controls
+ - if current_user
+ = link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
+ = icon('rss')
= render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
-
- if can? current_user, :create_issue, @project
- = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
- %i.fa.fa-plus
+ = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
+ = icon('plus')
New Issue
- = render 'shared/issuable/filter', type: :issues
+= render 'shared/issuable/filter', type: :issues
.issues-holder
= render "issues"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 030f4a2e644..121c775560f 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -15,11 +15,6 @@
opened by #{link_to_member(@project, @issue.author, size: 24)}
&middot;
= time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
- - if @issue.updated_at != @issue.created_at
- %span
- &middot;
- = icon('edit', title: 'edited')
- = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
.pull-right
- if can?(current_user, :create_issue, @project)
@@ -46,6 +41,10 @@
= markdown(@issue.description, cache_key: [@issue, "description"])
%textarea.hidden.js-task-list-field
= @issue.description
+ - if @issue.updated_at != @issue.created_at
+ %small
+ Edited
+ = time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
.merge-requests
= render 'merge_requests'
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 8d5d0394a82..e56a44e0a79 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -2,16 +2,19 @@
= render "header_title"
= render 'projects/last_push'
-.project-issuable-filter
- .controls
+
+.top-area
+ = render 'shared/issuable/nav', type: :merge_requests
+ .nav-controls
= render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project
- .pull-left.hidden-xs
- = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do
- %i.fa.fa-plus
- New Merge Request
- = render 'shared/issuable/filter', type: :merge_requests
+ = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do
+ = icon('plus')
+ New Merge Request
+
+= render 'shared/issuable/filter', type: :merge_requests
+
.merge-requests-holder
= render 'merge_requests'
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 905823f79d9..602f787e6cf 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -10,3 +10,8 @@
= markdown(@merge_request.description, cache_key: [@merge_request, "description"])
%textarea.hidden.js-task-list-field
= @merge_request.description
+
+ - if @merge_request.updated_at != @merge_request.created_at
+ %small
+ Edited
+ = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom')
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index fc6fb2a0d42..473fbff721b 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -8,11 +8,6 @@
opened by #{link_to_member(@project, @merge_request.author, size: 24)}
&middot;
= time_ago_with_tooltip(@merge_request.created_at)
- - if @merge_request.updated_at != @merge_request.created_at
- %span
- &middot;
- = icon('edit', title: 'edited')
- = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom')
.issue-btn-group.pull-right
- if can?(current_user, :update_merge_request, @merge_request)
diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder
index 2468509242a..9b3d3f069d9 100644
--- a/app/views/projects/show.atom.builder
+++ b/app/views/projects/show.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_url(@project.namespace, @project)
- xml.updated @events[0].updated_at.xmlschema if @events[0?
+ xml.updated @events[0].updated_at.xmlschema if @events[0]
@events.each do |event|
event_to_atom(xml, event)
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index 3c5edf4b033..baaa2caa6de 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,7 +1,7 @@
%article.file-holder.readme-holder
.file-title
= blob_icon readme.mode, readme.name
- = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, @path, readme.name)) do
%strong
= readme.name
.file-content.wiki
diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml
index e80dffc1ced..efe1e6f24c2 100644
--- a/app/views/projects/variables/show.html.haml
+++ b/app/views/projects/variables/show.html.haml
@@ -3,9 +3,11 @@
Secret Variables
%p.light
- These variables will be set to environment by the runner and will be hidden in the build log.
+ These variables will be set to environment by the runner.
%br
So you can use them for passwords, secret keys or whatever you want.
+ %br
+ The value of the variable can be visible in build log if explicitly asked to do so.
%hr
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index dcd61199717..6b77d24f50c 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -1,46 +1,50 @@
+- snippet_blob = chunk_snippet(snippet_blob, @search_term)
+- snippet = snippet_blob[:snippet_object]
+- snippet_chunks = snippet_blob[:snippet_chunks]
+
.search-result-row
%span
- = snippet_blob[:snippet_object].title
+ = snippet.title
by
- = link_to user_snippets_path(snippet_blob[:snippet_object].author) do
- = image_tag avatar_icon(snippet_blob[:snippet_object].author_email), class: "avatar avatar-inline s16", alt: ''
- = snippet_blob[:snippet_object].author_name
- %span.light #{time_ago_with_tooltip(snippet_blob[:snippet_object].created_at)}
+ = link_to user_snippets_path(snippet.author) do
+ = image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16", alt: ''
+ = snippet.author_name
+ %span.light #{time_ago_with_tooltip(snippet.created_at)}
%h4.snippet-title
- - snippet_path = reliable_snippet_path(snippet_blob[:snippet_object])
+ - snippet_path = reliable_snippet_path(snippet)
= link_to snippet_path do
.file-holder
.file-title
%i.fa.fa-file
- %strong= snippet_blob[:snippet_object].file_name
- - if markup?(snippet_blob[:snippet_object].file_name)
+ %strong= snippet.file_name
+ - if markup?(snippet.file_name)
.file-content.wiki
- - snippet_blob[:snippet_chunks].each do |snippet|
- - unless snippet[:data].empty?
- = render_markup(snippet_blob[:snippet_object].file_name, snippet[:data])
+ - snippet_chunks.each do |chunk|
+ - unless chunk[:data].empty?
+ = render_markup(snippet.file_name, chunk[:data])
- else
.file-content.code
.nothing-here-block Empty file
- else
.file-content.code.js-syntax-highlight
.line-numbers
- - snippet_blob[:snippet_chunks].each do |snippet|
- - unless snippet[:data].empty?
- - snippet[:data].lines.to_a.size.times do |index|
- - offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
+ - snippet_chunks.each do |chunk|
+ - unless chunk[:data].empty?
+ - chunk[:data].lines.to_a.size.times do |index|
+ - offset = defined?(chunk[:start_line]) ? chunk[:start_line] : 1
- i = index + offset
= link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
%i.fa.fa-link
= i
- - unless snippet == snippet_blob[:snippet_chunks].last
+ - unless snippet == snippet_chunks.last
%a.diff-line-num
= "."
%pre.code
%code
- - snippet_blob[:snippet_chunks].each do |snippet|
- - unless snippet[:data].empty?
- = snippet[:data]
- - unless snippet == snippet_blob[:snippet_chunks].last
+ - snippet_chunks.each do |chunk|
+ - unless chunk[:data].empty?
+ = chunk[:data]
+ - unless chunk == snippet_chunks.last
%a
= "..."
- else
diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml
index 285af56ad73..627814bcfae 100644
--- a/app/views/shared/_import_form.html.haml
+++ b/app/views/shared/_import_form.html.haml
@@ -11,6 +11,6 @@
%li
If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.
%li
- The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+ The import will time out after 15 minutes. For repositories that take longer, use a clone/push combination.
%li
To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}.
diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg
index 3d279ec228c..b07f1c5603e 100644
--- a/app/views/shared/_logo.svg
+++ b/app/views/shared/_logo.svg
@@ -1,21 +1,9 @@
-<svg width="36px" height="36px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="tanuki-logo">
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
- <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
- <g id="Page-1" sketch:type="MSShapeGroup">
- <g id="Fill-1-+-Group-24">
- <g id="Group-24">
- <g id="Group">
- <path id="tanuki-right-ear" d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
- <path id="tanuki-right-cheek" d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
- <path id="tanuki-right-eye" d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
- <path id="tanuki-nose" d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" fill="#E24329" class="tanuki-shape"></path>
- <path id="tanuki-left-eye" d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
- <path id="tanuki-left-cheek" d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
- <path id="tanuki-left-ear" d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
- </g>
- </g>
- </g>
- </g>
- </g>
- </g>
+<svg width="36" height="36" id="tanuki-logo">
+ <path id="tanuki-right-ear" class="tanuki-shape" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
+ <path id="tanuki-left-ear" class="tanuki-shape" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
+ <path id="tanuki-nose" class="tanuki-shape" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>
+ <path id="tanuki-right-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 11.38,14 2,14 6,25Z"/>
+ <path id="tanuki-left-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 24.62,14 34,14 30,25Z"/>
+ <path id="tanuki-right-cheek" class="tanuki-shape" fill="#fca326" d="M2 14L.1 20.16c-.18.565 0 1.2.5 1.56l17.42 12.66z"/>
+ <path id="tanuki-left-cheek" class="tanuki-shape" fill="#fca326" d="M34 14l1.9 6.16c.18.565 0 1.2-.5 1.56L18 34.38z"/>
</svg>
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 8d6f47b38ef..b7e350d27af 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -1,32 +1,5 @@
.issues-filters
- .issues-state-filters
- %ul.nav-links
- - if defined?(type) && type == :merge_requests
- - page_context_word = 'merge requests'
- - else
- - page_context_word = 'issues'
- %li{class: ("active" if params[:state] == 'opened')}
- = link_to page_filter_path(state: 'opened'), title: "Filter by #{page_context_word} that are currently opened." do
- #{state_filters_text_for(:opened, @project)}
-
- - if defined?(type) && type == :merge_requests
- %li{class: ("active" if params[:state] == 'merged')}
- = link_to page_filter_path(state: 'merged'), title: 'Filter by merge requests that are currently merged.' do
- #{state_filters_text_for(:merged, @project)}
-
- %li{class: ("active" if params[:state] == 'closed')}
- = link_to page_filter_path(state: 'closed'), title: 'Filter by merge requests that are currently closed and unmerged.' do
- #{state_filters_text_for(:closed, @project)}
- - else
- %li{class: ("active" if params[:state] == 'closed')}
- = link_to page_filter_path(state: 'closed'), title: 'Filter by issues that are currently closed.' do
- #{state_filters_text_for(:closed, @project)}
-
- %li{class: ("active" if params[:state] == 'all')}
- = link_to page_filter_path(state: 'all'), title: "Show all #{page_context_word}." do
- #{state_filters_text_for(:all, @project)}
-
- .issues-details-filters.gray-content-block
+ .issues-details-filters.gray-content-block.second-block
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.check-all-holder
diff --git a/app/views/shared/issuable/_nav.html.haml b/app/views/shared/issuable/_nav.html.haml
new file mode 100644
index 00000000000..a6970b7eebb
--- /dev/null
+++ b/app/views/shared/issuable/_nav.html.haml
@@ -0,0 +1,25 @@
+%ul.nav-links.issues-state-filters
+ - if defined?(type) && type == :merge_requests
+ - page_context_word = 'merge requests'
+ - else
+ - page_context_word = 'issues'
+ %li{class: ("active" if params[:state] == 'opened')}
+ = link_to page_filter_path(state: 'opened'), title: "Filter by #{page_context_word} that are currently opened." do
+ #{state_filters_text_for(:opened, @project)}
+
+ - if defined?(type) && type == :merge_requests
+ %li{class: ("active" if params[:state] == 'merged')}
+ = link_to page_filter_path(state: 'merged'), title: 'Filter by merge requests that are currently merged.' do
+ #{state_filters_text_for(:merged, @project)}
+
+ %li{class: ("active" if params[:state] == 'closed')}
+ = link_to page_filter_path(state: 'closed'), title: 'Filter by merge requests that are currently closed and unmerged.' do
+ #{state_filters_text_for(:closed, @project)}
+ - else
+ %li{class: ("active" if params[:state] == 'closed')}
+ = link_to page_filter_path(state: 'closed'), title: 'Filter by issues that are currently closed.' do
+ #{state_filters_text_for(:closed, @project)}
+
+ %li{class: ("active" if params[:state] == 'all')}
+ = link_to page_filter_path(state: 'all'), title: "Show all #{page_context_word}." do
+ #{state_filters_text_for(:all, @project)}
diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml
index 6672ea79629..afad48499b7 100644
--- a/app/views/shared/issuable/_search_form.html.haml
+++ b/app/views/shared/issuable/_search_form.html.haml
@@ -1,9 +1,8 @@
-= form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do
- .append-right-10.hidden-xs.hidden-sm
- = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input', spellcheck: false }
- = hidden_field_tag :state, params['state']
- = hidden_field_tag :scope, params['scope']
- = hidden_field_tag :assignee_id, params['assignee_id']
- = hidden_field_tag :author_id, params['author_id']
- = hidden_field_tag :milestone_id, params['milestone_id']
- = hidden_field_tag :label_id, params['label_id']
+= form_tag(path, method: :get, id: "issue_search_form", class: 'issue-search-form') do
+ = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input input-short', spellcheck: false }
+ = hidden_field_tag :state, params['state']
+ = hidden_field_tag :scope, params['scope']
+ = hidden_field_tag :assignee_id, params['assignee_id']
+ = hidden_field_tag :author_id, params['author_id']
+ = hidden_field_tag :milestone_id, params['milestone_id']
+ = hidden_field_tag :label_id, params['label_id']
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 75a7d9be2c1..ae96a45453f 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -13,12 +13,12 @@
= icon('angle-double-right')
.issuable-nav.pull-right.btn-group{role: 'group', "aria-label" => '...'}
- if has_prev_issuable?(@project, issuable.id)
- = link_to 'Prev', issuable_link_prev(@project, issuable), class: 'btn btn-default'
+ = link_to 'Prev', issuable_link_prev(@project, issuable), class: 'btn btn-default prev-btn'
- else
%a.btn.btn-default.disabled{href: '#'}
Prev
- if has_next_issuable?(@project, issuable.id)
- = link_to 'Next', issuable_link_next(@project, issuable), class: 'btn btn-default'
+ = link_to 'Next', issuable_link_next(@project, issuable), class: 'btn btn-default next-btn'
- else
%a.btn.btn-default.disabled{href: '#'}
Next
diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
index b3f45373f6b..75684b972f1 100644
--- a/app/views/shared/projects/_list.html.haml
+++ b/app/views/shared/projects/_list.html.haml
@@ -8,18 +8,23 @@
- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true
%ul.projects-list
- - projects.each_with_index do |project, i|
- - css_class = (i >= projects_limit) ? 'hide' : nil
- = render "shared/projects/project", project: project, skip_namespace: skip_namespace,
- avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar,
- forks: forks, show_last_commit_as_description: show_last_commit_as_description
+ - if projects.any?
+ - projects.each_with_index do |project, i|
+ - css_class = (i >= projects_limit) ? 'hide' : nil
+ = render "shared/projects/project", project: project, skip_namespace: skip_namespace,
+ avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar,
+ forks: forks, show_last_commit_as_description: show_last_commit_as_description
- - if projects.size > projects_limit
- %li.bottom.center
- .light
- #{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
- = link_to '#', class: 'js-expand' do
- Show all
+ - if projects.size > projects_limit && projects.kind_of?(Array)
+ %li.bottom.center
+ .light
+ #{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
+ = link_to '#', class: 'js-expand' do
+ Show all
+ = paginate projects, theme: "gitlab" if projects.respond_to? :total_pages
+ - else
+ %h3 No projects found
:javascript
new ProjectsList();
+ Dashboard.init();
diff --git a/config/application.rb b/config/application.rb
index d255ff0719f..1e9ec74cdbf 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -31,7 +31,7 @@ module Gitlab
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
- config.filter_parameters.push(:password, :password_confirmation, :private_token, :otp_attempt)
+ config.filter_parameters.push(:password, :password_confirmation, :private_token, :otp_attempt, :variables)
# Enable escaping HTML in JSON.
config.active_support.escape_html_entities_in_json = true
@@ -52,17 +52,11 @@ module Gitlab
config.action_view.sanitized_allowed_protocols = %w(smb)
- # Relative url support
- # Uncomment and customize the last line to run in a non-root path
- # WARNING: We recommend creating a FQDN to host GitLab in a root path instead of this.
- # Note that following settings need to be changed for this to work.
- # 1) In your application.rb file: config.relative_url_root = "/gitlab"
- # 2) In your gitlab.yml file: relative_url_root: /gitlab
- # 3) In your unicorn.rb: ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"
- # 4) In ../gitlab-shell/config.yml: gitlab_url: "http://127.0.0.1/gitlab"
- # 5) In lib/support/nginx/gitlab : do not use asset gzipping, remove block starting with "location ~ ^/(assets)/"
- #
- # To update the path, run: sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+ # Relative URL support
+ # WARNING: We recommend using an FQDN to host GitLab in a root path instead
+ # of using a relative URL.
+ # Documentation: http://doc.gitlab.com/ce/install/relative_url.html
+ # Uncomment and customize the following line to run in a non-root path
#
# config.relative_url_root = "/gitlab"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index d6e2c9380a5..faf05ecd466 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -38,8 +38,12 @@ production: &base
# Otherwise, ssh host will be set to the `host:` value above
# ssh_host: ssh.host_example.com
- # WARNING: See config/application.rb under "Relative url support" for the list of
- # other files that need to be changed for relative url support
+ # Relative URL support
+ # WARNING: We recommend using an FQDN to host GitLab in a root path instead
+ # of using a relative URL.
+ # Documentation: http://doc.gitlab.com/ce/install/relative_url.html
+ # Uncomment and customize the following line to run in a non-root path
+ #
# relative_url_root: /gitlab
# Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
diff --git a/config/initializers/smtp_settings.rb.sample b/config/initializers/smtp_settings.rb.sample
index ec182502d4e..2287a76fca7 100644
--- a/config/initializers/smtp_settings.rb.sample
+++ b/config/initializers/smtp_settings.rb.sample
@@ -12,7 +12,7 @@ if Rails.env.production?
ActionMailer::Base.smtp_settings = {
address: "email.server.com",
- port: 456,
+ port: 465,
user_name: "smtp",
password: "123456",
domain: "gitlab.company.com",
diff --git a/config/routes.rb b/config/routes.rb
index 034bfaf1bcd..3f6561a1fe0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -227,7 +227,10 @@ Rails.application.routes.draw do
get :test
end
- resources :broadcast_messages, only: [:index, :edit, :create, :update, :destroy]
+ resources :broadcast_messages, only: [:index, :edit, :create, :update, :destroy] do
+ post :preview, on: :collection
+ end
+
resource :logs, only: [:show]
resource :background_jobs, controller: 'background_jobs', only: [:show]
@@ -349,6 +352,7 @@ Rails.application.routes.draw do
get :issues
get :merge_requests
get :projects
+ get :events
end
scope module: :groups do
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
index b937b092789..e5058cebce8 100644
--- a/config/unicorn.rb.example
+++ b/config/unicorn.rb.example
@@ -10,9 +10,12 @@
# Note: If you change this file in a Merge Request, please also create a
# Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
-#
-# WARNING: See config/application.rb under "Relative url support" for the list of
-# other files that need to be changed for relative url support
+
+# Relative URL support
+# WARNING: We recommend using an FQDN to host GitLab in a root path instead
+# of using a relative URL.
+# Documentation: http://doc.gitlab.com/ce/install/relative_url.html
+# Uncomment and customize the following line to run in a non-root path
#
# ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"
diff --git a/db/fixtures/production/001_admin.rb b/db/fixtures/production/001_admin.rb
index b0c0b6450f6..308b0528c9b 100644
--- a/db/fixtures/production/001_admin.rb
+++ b/db/fixtures/production/001_admin.rb
@@ -6,8 +6,10 @@ else
expire_time = nil
end
+email = ENV['GITLAB_ROOT_EMAIL'].presence || 'admin@example.com'
+
admin = User.create(
- email: "admin@example.com",
+ email: email,
name: "Administrator",
username: 'root',
password: password,
diff --git a/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb b/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb
new file mode 100644
index 00000000000..d50791410f9
--- /dev/null
+++ b/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb
@@ -0,0 +1,5 @@
+class AddEmailAuthorInBodyToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :email_author_in_body, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb b/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb
index 091de54978b..d3ea956952e 100644
--- a/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb
+++ b/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb
@@ -48,7 +48,7 @@ class RemoveDotAtomPathEndingOfProjects < ActiveRecord::Migration
end
def projects_with_dot_atom
- select_all("SELECT p.id, p.path, n.path as namespace_path, n.id as namespace_id FROM projects p inner join namespaces n on n.id = p.namespace_id WHERE lower(p.path) LIKE '%.atom'")
+ select_all("SELECT p.id, p.path, n.path as namespace_path, n.id as namespace_id FROM projects p inner join namespaces n on n.id = p.namespace_id WHERE p.path LIKE '%.atom'")
end
def up
diff --git a/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb b/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb
new file mode 100644
index 00000000000..793984343b4
--- /dev/null
+++ b/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb
@@ -0,0 +1,5 @@
+class AddAllowGuestToAccessBuildsProject < ActiveRecord::Migration
+ def change
+ add_column :projects, :public_builds, :boolean, default: true, null: false
+ end
+end
diff --git a/db/migrate/20160209130428_add_index_to_snippet.rb b/db/migrate/20160209130428_add_index_to_snippet.rb
new file mode 100644
index 00000000000..95d5719be59
--- /dev/null
+++ b/db/migrate/20160209130428_add_index_to_snippet.rb
@@ -0,0 +1,5 @@
+class AddIndexToSnippet < ActiveRecord::Migration
+ def change
+ add_index :snippets, :updated_at
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d4710346b82..689a8c3ecc5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160129135155) do
+ActiveRecord::Schema.define(version: 20160209130428) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -66,6 +66,7 @@ ActiveRecord::Schema.define(version: 20160129135155) do
t.string "sentry_dsn"
t.boolean "akismet_enabled", default: false
t.string "akismet_api_key"
+ t.boolean "email_author_in_body", default: false
end
create_table "audit_events", force: :cascade do |t|
@@ -680,6 +681,7 @@ ActiveRecord::Schema.define(version: 20160129135155) do
t.boolean "build_allow_git_fetch", default: true, null: false
t.integer "build_timeout", default: 3600, null: false
t.boolean "pending_delete", default: false
+ t.boolean "public_builds", default: true, null: false
end
add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree
@@ -770,6 +772,7 @@ ActiveRecord::Schema.define(version: 20160129135155) do
add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
+ add_index "snippets", ["updated_at"], name: "index_snippets_on_updated_at", using: :btree
add_index "snippets", ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree
create_table "spam_logs", force: :cascade do |t|
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 85ed31320b9..b4dca6dd35e 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -2,7 +2,7 @@
## List merge requests
-Get all merge requests for this project.
+Get all merge requests for this project.
The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.
@@ -49,8 +49,24 @@ Parameters:
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
+ "source_project_id": "2",
+ "target_project_id": "3",
+ "labels": [ ],
"description":"fixed login page css paddings",
- "work_in_progress": false
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
]
```
@@ -95,8 +111,24 @@ Parameters:
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
+ "source_project_id": "2",
+ "target_project_id": "3",
+ "labels": [ ],
"description":"fixed login page css paddings",
- "work_in_progress": false
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
```
@@ -156,8 +188,6 @@ Parameters:
"iid": 1,
"project_id": 4,
"title": "Blanditiis beatae suscipit hic assumenda et molestias nisi asperiores repellat et.",
- "description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Optio velit qui distinctio.",
- "work_in_progress": false,
"state": "reopened",
"created_at": "2015-02-02T19:49:39.159Z",
"updated_at": "2015-02-02T20:08:49.959Z",
@@ -182,6 +212,8 @@ Parameters:
"source_project_id": 4,
"target_project_id": 4,
"labels": [ ],
+ "description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Optio velit qui distinctio.",
+ "work_in_progress": false,
"milestone": {
"id": 5,
"iid": 1,
@@ -193,6 +225,8 @@ Parameters:
"updated_at": "2015-02-02T19:49:26.013Z",
"due_date": null
},
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged",
"changes": [
{
"old_path": "VERSION",
@@ -252,7 +286,24 @@ Parameters:
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
- "description":"fixed login page css paddings"
+ "source_project_id": 4,
+ "target_project_id": 4,
+ "labels": [ ],
+ "description":"fixed login page css paddings",
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 4,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
```
@@ -284,7 +335,6 @@ Parameters:
"target_branch": "master",
"project_id": 3,
"title": "test1",
- "description": "description1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
@@ -303,7 +353,25 @@ Parameters:
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
- }
+ },
+ "source_project_id": 4,
+ "target_project_id": 4,
+ "labels": [ ],
+ "description": "description1",
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 4,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
```
@@ -359,7 +427,25 @@ Parameters:
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
- }
+ },
+ "source_project_id": 4,
+ "target_project_id": 4,
+ "labels": [ ],
+ "description":"fixed login page css paddings",
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 4,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
```
@@ -387,7 +473,7 @@ Parameters:
"source_branch": "test1",
"project_id": 3,
"title": "test1",
- "state": "merged",
+ "state": "opened",
"upvotes": 0,
"downvotes": 0,
"author": {
@@ -405,7 +491,25 @@ Parameters:
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
- }
+ },
+ "source_project_id": 4,
+ "target_project_id": 4,
+ "labels": [ ],
+ "description":"fixed login page css paddings",
+ "work_in_progress": false,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 4,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": null
+ },
+ "merge_when_build_succeeds": true,
+ "merge_status": "can_be_merged"
}
```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 3f372c955d2..9e9486cd87a 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -80,7 +80,9 @@ Parameters:
"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",
"shared_runners_enabled": true,
"forks_count": 0,
- "star_count": 0
+ "star_count": 0,
+ "runners_token": "b8547b1dc37721d05889db52fa2f02",
+ "public_builds": true
},
{
"id": 6,
@@ -137,7 +139,8 @@ Parameters:
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 0,
- "runners_token": "b8547b1dc37721d05889db52fa2f02"
+ "runners_token": "b8547b1dc37721d05889db52fa2f02",
+ "public_builds": true
}
]
```
@@ -424,6 +427,7 @@ Parameters:
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
- `import_url` (optional)
+- `public_builds` (optional)
### Create project for user
@@ -446,6 +450,7 @@ Parameters:
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
- `import_url` (optional)
+- `public_builds` (optional)
### Edit project
@@ -469,6 +474,7 @@ Parameters:
- `snippets_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
+- `public_builds` (optional)
On success, method returns 200 with the updated project. If parameters are
invalid, 400 is returned.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 862cacda586..018d1898594 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -77,9 +77,12 @@ More information about Docker integration can be found in [Using Docker Images](
GitLab CI allows you to define per-project **Secure Variables** that are set in build environment.
The secure variables are stored out of the repository (the `.gitlab-ci.yml`).
-These variables are securely stored in GitLab CI database and are hidden in the build log.
+The variables are securely passed to GitLab Runner and are available in build environment.
It's desired method to use them for storing passwords, secret keys or whatever you want.
+**The value of the variable can be shown in build log if explicitly asked to do so.**
+If your project is public or internal you can make the builds private.
+
Secure Variables can added by going to `Project > Variables > Add Variable`.
They will be available for all subsequent builds.
diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md
index caaa4032db2..96d1dffbc52 100644
--- a/doc/development/doc_styleguide.md
+++ b/doc/development/doc_styleguide.md
@@ -120,6 +120,17 @@ Inside the document:
`http://doc.gitlab.com/ce/administration/restart_gitlab.html`.
Replace `reconfigure` with `restart` where appropriate.
+## Installation guide
+
+- **Ruby:**
+ In [step 2 of the installation guide](../install/installation.md#2-ruby),
+ we install Ruby from source. Whenever there is a new version that needs to
+ be updated, remember to change it throughout the codeblock and also replace
+ the sha256sum (it can be found in the [downloads page][ruby-dl] of the Ruby
+ website).
+
+[ruby-dl]: https://www.ruby-lang.org/en/downloads/ "Ruby download website"
+
## API
Here is a list of must-have items. Use them in the exact order that appears
diff --git a/doc/install/installation.md b/doc/install/installation.md
index a2c23bd52e5..fe614df91fd 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -124,7 +124,7 @@ Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
curl -O --progress https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.4.tar.gz
- echo 'e2e195a4a58133e3ad33b955c829bb536fa3c075 ruby-2.2.4.tar.gz' | shasum -c - && tar xzf ruby-2.2.4.tar.gz
+ echo 'b6eff568b48e0fda76e5a36333175df049b204e91217aa32a65153cc0cdcb761 ruby-2.2.4.tar.gz' | sha256sum -c - && tar xzf ruby-2.2.4.tar.gz
cd ruby-2.2.4
./configure --disable-install-rdoc
make
@@ -238,9 +238,9 @@ sudo usermod -aG redis git
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-4-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-5-stable gitlab
-**Note:** You can change `8-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `8-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
@@ -267,6 +267,9 @@ sudo usermod -aG redis git
sudo chmod -R u+rwX tmp/pids/
sudo chmod -R u+rwX tmp/sockets/
+ # Create the public/uploads/ directory
+ sudo -u git -H mkdir public/uploads/
+
# Make sure GitLab can write to the public/uploads/ directory
sudo chmod -R u+rwX public/uploads
@@ -370,9 +373,9 @@ GitLab Shell is an SSH access and repository management software developed speci
# When done you see 'Administrator account created:'
-**Note:** You can set the Administrator/root password by supplying it in environmental variable `GITLAB_ROOT_PASSWORD` as seen below. If you don't set the password (and it is set to the default one) please wait with exposing GitLab to the public internet until the installation is done and you've logged into the server the first time. During the first login you'll be forced to change the default password.
+**Note:** You can set the Administrator/root password and e-mail by supplying them in environmental variables, `GITLAB_ROOT_PASSWORD` and `GITLAB_ROOT_EMAIL` respectively, as seen below. If you don't set the password (and it is set to the default one) please wait with exposing GitLab to the public internet until the installation is done and you've logged into the server the first time. During the first login you'll be forced to change the default password.
- sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword
+ sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword GITLAB_ROOT_EMAIL=youremail
### Secure secrets.yml
@@ -481,6 +484,11 @@ You can use `sudo service gitlab start` and `sudo service gitlab stop` to start
## Advanced Setup Tips
+### Relative URL support
+
+See the [Relative URL documentation](relative_url.md) for more information on
+how to configure GitLab with a relative URL.
+
### Using HTTPS
To use GitLab with HTTPS:
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
new file mode 100644
index 00000000000..b341b6311c6
--- /dev/null
+++ b/doc/install/relative_url.md
@@ -0,0 +1,126 @@
+## Install GitLab under a relative URL
+
+_**Note:**
+This document describes how to run GitLab under a relative URL for installations
+from source. If you are using an Omnibus package,
+[the steps are different][omnibus-rel]. Use this guide along with the
+[installation guide](installation.md) if you are installing GitLab for the
+first time._
+
+---
+
+While it is recommended to install GitLab on its own (sub)domain, sometimes
+this is not possible due to a variety of reasons. In that case, GitLab can also
+be installed under a relative URL, for example `https://example.com/gitlab`.
+
+There is no limit to how deeply nested the relative URL can be. For example you
+could serve GitLab under `/foo/bar/gitlab/git` without any issues.
+
+Note that by changing the URL on an existing GitLab installation, all remote
+URLs will change, so you'll have to manually edit them in any local repository
+that points to your GitLab instance.
+
+---
+
+The TL;DR list of configuration files that you need to change in order to
+serve GitLab under a relative URL is:
+
+- `/home/git/gitlab/config/application.rb`
+- `/home/git/gitlab/config/gitlab.yml`
+- `/home/git/gitlab/config/unicorn.rb`
+- `/home/git/gitlab-shell/config.yml`
+- `/etc/default/gitlab`
+
+After all the changes you need to recompile the assets and [restart GitLab].
+
+### Relative URL requirements
+
+If you configure GitLab with a relative URL, the assets (JavaScript, CSS, fonts,
+images, etc.) will need to be recompiled, which is a task which consumes a lot
+of CPU and memory resources. To avoid out-of-memory errors, you should have at
+least 2GB of RAM available on your system, while we recommend 4GB RAM, and 4 or
+8 CPU cores.
+
+See the [requirements](requirements.md) document for more information.
+
+### Enable relative URL in GitLab
+
+_**Note:**
+Do not make any changes to your web server configuration file regarding
+relative URL. The relative URL support is implemented by GitLab Workhorse._
+
+---
+
+Before following the steps below to enable relative URL in GitLab, some
+assumptions are made:
+
+- GitLab is served under `/gitlab`
+- The directory under which GitLab is installed is `/home/git/`
+
+Make sure to follow all steps below:
+
+1. (Optional) If you run short on resources, you can temporarily free up some
+ memory by shutting down the GitLab service with the following command:
+
+ ```shell
+ sudo service gitlab stop
+ ```
+
+1. Edit `/home/git/gitlab/config/application.rb` and uncomment/change the
+ following line:
+
+ ```ruby
+ config.relative_url_root = "/gitlab"
+ ```
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and uncomment/change the
+ following line:
+
+ ```yaml
+ relative_url_root: /gitlab
+ ```
+
+1. Edit `/home/git/gitlab/config/unicorn.rb` and uncomment/change the
+ following line:
+
+ ```ruby
+ ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"
+ ```
+
+1. Edit `/home/git/gitlab-shell/config.yml` and append the relative path to
+ the following line:
+
+ ```yaml
+ gitlab_url: http://127.0.0.1/gitlab
+ ```
+
+1. Make sure you have copied the supplied init script and the defaults file
+ as stated in the [installation guide](installation.md#install-init-script).
+ Then, edit `/etc/default/gitlab` and set in `gitlab_workhorse_options` the
+ `-authBackend` setting to read like:
+
+ ```shell
+ -authBackend http://127.0.0.1:8080/gitlab
+ ```
+
+ **Note:**
+ If you are using a custom init script, make sure to edit the above
+ gitlab-workhorse setting as needed.
+
+1. After all the above changes recompile the assets. This is an important task
+ and will take some time to complete depending on the server resources:
+
+ ```
+ cd /home/git/gitlab
+ sudo -u git -H bundle exec rake assets:clean assets:precompile RAILS_ENV=production
+ ```
+
+1. [Restart GitLab][] for the changes to take effect.
+
+### Disable relative URL in GitLab
+
+To disable the relative URL, follow the same steps as above and set up the
+GitLab URL to one that doesn't contain a relative path.
+
+[omnibus-rel]: http://doc.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab "How to setup relative URL in Omnibus GitLab"
+[restart gitlab]: ../administration/restart_gitlab.md#installations-from-source "How to restart GitLab"
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 006dae8ca9a..c6a1c20d02f 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -66,7 +66,7 @@ If you have enough RAM memory and a recent CPU the speed of GitLab is mainly lim
You need at least 2GB of addressable memory (RAM + swap) to install and use GitLab!
With less memory GitLab will give strange errors during the reconfigure run and 500 errors during usage.
-- 512MB RAM + 1.5GB of swap is the absolute minimum but we strongly **advise against** this amount of memory. See the unicorn worker section below for more advise.
+- 512MB RAM + 1.5GB of swap is the absolute minimum but we strongly **advise against** this amount of memory. See the unicorn worker section below for more advice.
- 1GB RAM + 1GB swap supports up to 100 users but it will be slow
- **2GB RAM** is the **recommended** memory size and supports up to 100 users
- 4GB RAM supports up to 1,000 users
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 83c77742b19..f6bffba9fdb 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -424,24 +424,24 @@ will point the link to `wikis/style` when the link is inside of a wiki markdown
Here's our logo (hover to see the title text):
Inline-style:
- ![alt text](assets/logo-white.png)
+ ![alt text](assets/logo.svg)
Reference-style:
![alt text1][logo]
- [logo]: assets/logo-white.png
+ [logo]: assets/logo.svg
Here's our logo:
Inline-style:
-![alt text](/assets/logo-white.png)
+![alt text](/assets/logo.svg)
Reference-style:
![alt text][logo]
-[logo]: /assets/logo-white.png
+[logo]: /assets/logo.svg
## Blockquotes
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 1be78ac1823..168e7d143ee 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -18,6 +18,9 @@ documentation](../workflow/add-user/add-user.md).
|---------------------------------------|---------|------------|-------------|----------|--------|
| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ |
+| See a list of builds | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
+| See a build log | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
+| Download and browse build artifacts | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
| Pull project code | | ✓ | ✓ | ✓ | ✓ |
| Download project | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
@@ -31,6 +34,7 @@ documentation](../workflow/add-user/add-user.md).
| Remove non-protected branches | | | ✓ | ✓ | ✓ |
| Add tags | | | ✓ | ✓ | ✓ |
| Write a wiki | | | ✓ | ✓ | ✓ |
+| Cancel and retry builds | | | ✓ | ✓ | ✓ |
| Create new milestones | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
@@ -40,12 +44,17 @@ documentation](../workflow/add-user/add-user.md).
| Edit project | | | | ✓ | ✓ |
| Add deploy keys to project | | | | ✓ | ✓ |
| Configure project hooks | | | | ✓ | ✓ |
+| Manage runners | | | | ✓ | ✓ |
+| Manage build triggers | | | | ✓ | ✓ |
+| Manage variables | | | | ✓ | ✓ |
| Switch visibility level | | | | | ✓ |
| Transfer project to another namespace | | | | | ✓ |
| Remove project | | | | | ✓ |
| Force push to protected branches | | | | | |
| Remove protected branches | | | | | |
+[^1]: If **Allow guest to access builds** is enabled in CI settings
+
## Group
In order for a group to appear as public and be browsable, it must contain at
diff --git a/doc/project_services/jira.md b/doc/project_services/jira.md
index d6b2e7f521b..7c12557a321 100644
--- a/doc/project_services/jira.md
+++ b/doc/project_services/jira.md
@@ -1,5 +1,12 @@
# GitLab JIRA integration
+_**Note:**
+Full JIRA integration was previously exclusive to GitLab Enterprise Edition.
+With [GitLab 8.3 forward][8_3_post], this feature in now [backported][jira-ce]
+to GitLab Community Edition as well._
+
+---
+
GitLab can be configured to interact with [JIRA Core] either using an
on-premises instance or the SaaS solution that Atlassian offers. Configuration
happens via username and password on a per-project basis. Connecting to a JIRA
@@ -210,3 +217,5 @@ You can see from the above image that there are four references to GitLab:
[services-templates]: ../project_services/services_templates.md "Services templates documentation"
[JIRA Core]: https://www.atlassian.com/software/jira/core "The JIRA Core website"
+[jira-ce]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2146 "MR - Backport JIRA service"
+[8_3_post]: https://about.gitlab.com/2015/12/22/gitlab-8-3-released/ "GitLab 8.3 release post"
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 77eb53427e2..a1198e5878f 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -5,6 +5,12 @@
An SSH key allows you to establish a secure connection between your
computer and GitLab. Before generating an SSH key in your shell, check if your system
already has one by running the following command:
+
+**Windows Command Line:**
+```bash
+type %userprofile%\.ssh\id_rsa.pub
+```
+**GNU/Linux/Mac/PowerShell:**
```bash
cat ~/.ssh/id_rsa.pub
```
@@ -25,6 +31,12 @@ press enter to use the default. If you use a different name, the key will not
be used automatically.
Use the command below to show your public key:
+
+**Windows Command Line:**
+```bash
+type %userprofile%\.ssh\id_rsa.pub
+```
+**GNU/Linux/Mac/PowerShell:**
```bash
cat ~/.ssh/id_rsa.pub
```
@@ -36,9 +48,14 @@ with your username and host.
To copy your public key to the clipboard, use the code below. Depending on your
OS you'll need to use a different command:
-**Windows:**
+**Windows Command Line:**
+```bash
+type %userprofile%\.ssh\id_rsa.pub | clip
+```
+
+**Windows PowerShell:**
```bash
-clip < ~/.ssh/id_rsa.pub
+cat ~/.ssh/id_rsa.pub | clip
```
**Mac:**
diff --git a/doc/update/8.4-to-8.5.md b/doc/update/8.4-to-8.5.md
new file mode 100644
index 00000000000..6e035047b24
--- /dev/null
+++ b/doc/update/8.4-to-8.5.md
@@ -0,0 +1,106 @@
+# From 8.4 to 8.5
+
+### 1. Stop server
+
+ sudo service gitlab stop
+
+### 2. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Get latest code
+
+```bash
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 8-5-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 8-5-stable-ee
+```
+
+### 4. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout v2.6.10
+```
+
+### 5. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. This requires
+[Go 1.5](https://golang.org/dl) which should already be on your system from
+GitLab 8.1.
+
+```bash
+cd /home/git/gitlab-workhorse
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout 0.6.3
+sudo -u git -H make
+```
+
+### 6. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+```
+
+### 7. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 8. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (8.4)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 8.3 to 8.4](8.3-to-8.4.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
diff --git a/features/admin/broadcast_messages.feature b/features/admin/broadcast_messages.feature
index fd3bac77f86..4f9c651561e 100644
--- a/features/admin/broadcast_messages.feature
+++ b/features/admin/broadcast_messages.feature
@@ -25,3 +25,9 @@ Feature: Admin Broadcast Messages
When I remove an existing broadcast message
Then I should be redirected to admin messages page
And I should not see the removed broadcast message
+
+ @javascript
+ Scenario: Live preview a customized broadcast message
+ When I visit admin messages page
+ And I enter a broadcast message with Markdown
+ Then I should see a live preview of the rendered broadcast message
diff --git a/features/project/builds/permissions.feature b/features/project/builds/permissions.feature
index 1193bcd74f6..3c7f72335d9 100644
--- a/features/project/builds/permissions.feature
+++ b/features/project/builds/permissions.feature
@@ -5,6 +5,41 @@ Feature: Project Builds Permissions
And project has CI enabled
And project has a recent build
+ Scenario: I try to visit build details as guest
+ Given I am member of a project with a guest role
+ When I visit recent build details page
+ Then page status code should be 404
+
+ Scenario: I try to visit project builds page as guest
+ Given I am member of a project with a guest role
+ When I visit project builds page
+ Then page status code should be 404
+
+ Scenario: I try to visit build details of internal project without access to builds
+ Given The project is internal
+ And public access for builds is disabled
+ When I visit recent build details page
+ Then page status code should be 404
+
+ Scenario: I try to visit internal project builds page without access to builds
+ Given The project is internal
+ And public access for builds is disabled
+ When I visit project builds page
+ Then page status code should be 404
+
+ Scenario: I try to visit build details of internal project with access to builds
+ Given The project is internal
+ And public access for builds is enabled
+ When I visit recent build details page
+ Then I see details of a build
+ And I see build trace
+
+ Scenario: I try to visit internal project builds page with access to builds
+ Given The project is internal
+ And public access for builds is enabled
+ When I visit project builds page
+ Then I see the build
+
Scenario: I try to download build artifacts as guest
Given I am member of a project with a guest role
And recent build has artifacts available
diff --git a/features/steps/admin/broadcast_messages.rb b/features/steps/admin/broadcast_messages.rb
index 6cacdf4764c..af2b4a29313 100644
--- a/features/steps/admin/broadcast_messages.rb
+++ b/features/steps/admin/broadcast_messages.rb
@@ -19,7 +19,7 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
end
step 'submit form with new customized broadcast message' do
- fill_in 'broadcast_message_message', with: 'Application update from 4:00 CST to 5:00 CST'
+ fill_in 'broadcast_message_message', with: 'Application update from **4:00 CST to 5:00 CST**'
fill_in 'broadcast_message_color', with: '#f2dede'
fill_in 'broadcast_message_font', with: '#b94a48'
select Date.today.next_year.year, from: "broadcast_message_ends_at_1i"
@@ -28,6 +28,7 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
step 'I should see a customized broadcast message' do
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
+ expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST'
expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
end
@@ -51,4 +52,15 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
step 'I should not see the removed broadcast message' do
expect(page).not_to have_content 'Migration to new server'
end
+
+ step 'I enter a broadcast message with Markdown' do
+ fill_in 'broadcast_message_message', with: "Live **Markdown** previews. :tada:"
+ end
+
+ step 'I should see a live preview of the rendered broadcast message' do
+ page.within('.broadcast-message-preview') do
+ expect(page).to have_selector('strong', text: 'Markdown')
+ expect(page).to have_selector('img.emoji')
+ end
+ end
end
diff --git a/features/steps/project/builds/summary.rb b/features/steps/project/builds/summary.rb
index 4bc670fdfcb..4f94fc96354 100644
--- a/features/steps/project/builds/summary.rb
+++ b/features/steps/project/builds/summary.rb
@@ -4,14 +4,6 @@ class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps
include SharedBuilds
include RepoHelpers
- step 'I see details of a build' do
- expect(page).to have_content "Build ##{@build.id}"
- end
-
- step 'I see build trace' do
- expect(page).to have_css '#build-trace'
- end
-
step 'I see button to CI Lint' do
page.within('.nav-controls') do
ci_lint_tool_link = page.find_link('CI Lint')
diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb
index 92bf362879b..726e2e814ad 100644
--- a/features/steps/shared/builds.rb
+++ b/features/steps/shared/builds.rb
@@ -38,4 +38,21 @@ module SharedBuilds
step 'I access artifacts download page' do
visit download_namespace_project_build_artifacts_path(@project.namespace, @project, @build)
end
+
+ step 'I see details of a build' do
+ expect(page).to have_content "Build ##{@build.id}"
+ end
+
+ step 'I see build trace' do
+ expect(page).to have_css '#build-trace'
+ end
+
+ step 'I see the build' do
+ page.within('.commit_status') do
+ expect(page).to have_content "##{@build.id}"
+ expect(page).to have_content @build.sha[0..7]
+ expect(page).to have_content @build.ref
+ expect(page).to have_content @build.name
+ end
+ end
end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index d9c75d12238..b13e82f276b 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -240,6 +240,18 @@ module SharedProject
end
end
+ step 'The project is internal' do
+ @project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ end
+
+ step 'public access for builds is enabled' do
+ @project.update(public_builds: true)
+ end
+
+ step 'public access for builds is disabled' do
+ @project.update(public_builds: false)
+ end
+
def user_owns_project(user_name:, project_name:, visibility: :private)
user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore)
project = Project.find_by(name: project_name)
diff --git a/lib/api/builds.rb b/lib/api/builds.rb
index d293f988165..a8bd3842ce4 100644
--- a/lib/api/builds.rb
+++ b/lib/api/builds.rb
@@ -13,11 +13,12 @@ module API
# Example Request:
# GET /projects/:id/builds
get ':id/builds' do
+
builds = user_project.builds.order('id DESC')
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
- user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
+ user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
# Get builds for a specific commit of a project
@@ -30,6 +31,8 @@ module API
# Example Request:
# GET /projects/:id/repository/commits/:sha/builds
get ':id/repository/commits/:sha/builds' do
+ authorize_read_builds!
+
commit = user_project.ci_commits.find_by_sha(params[:sha])
return not_found! unless commit
@@ -37,7 +40,7 @@ module API
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
- user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
+ user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
# Get a specific build of a project
@@ -48,11 +51,13 @@ module API
# Example Request:
# GET /projects/:id/builds/:build_id
get ':id/builds/:build_id' do
+ authorize_read_builds!
+
build = get_build(params[:build_id])
return not_found!(build) unless build
present build, with: Entities::Build,
- user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
+ user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
# Get a trace of a specific build of a project
@@ -67,6 +72,8 @@ module API
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
get ':id/builds/:build_id/trace' do
+ authorize_read_builds!
+
build = get_build(params[:build_id])
return not_found!(build) unless build
@@ -86,7 +93,7 @@ module API
# example request:
# post /projects/:id/build/:build_id/cancel
post ':id/builds/:build_id/cancel' do
- authorize_manage_builds!
+ authorize_update_builds!
build = get_build(params[:build_id])
return not_found!(build) unless build
@@ -94,7 +101,7 @@ module API
build.cancel
present build, with: Entities::Build,
- user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
+ user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
# Retry a specific build of a project
@@ -105,7 +112,7 @@ module API
# example request:
# post /projects/:id/build/:build_id/retry
post ':id/builds/:build_id/retry' do
- authorize_manage_builds!
+ authorize_update_builds!
build = get_build(params[:build_id])
return forbidden!('Build is not retryable') unless build && build.retryable?
@@ -113,7 +120,7 @@ module API
build = Ci::Build.retry(build)
present build, with: Entities::Build,
- user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
+ user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
end
@@ -141,8 +148,12 @@ module API
builds.where(status: available_statuses && scope)
end
- def authorize_manage_builds!
- authorize! :manage_builds, user_project
+ def authorize_read_builds!
+ authorize! :read_build, user_project
+ end
+
+ def authorize_update_builds!
+ authorize! :update_build, user_project
end
end
end
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 1162271f5fc..9422d438d21 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -18,7 +18,7 @@ module API
# Examples:
# GET /projects/:id/repository/commits/:sha/statuses
get ':id/repository/commits/:sha/statuses' do
- authorize! :read_commit_statuses, user_project
+ authorize! :read_commit_status, user_project
sha = params[:sha]
ci_commit = user_project.ci_commit(sha)
not_found! 'Commit' unless ci_commit
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 82a75734de0..a9c09ffdb31 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -72,6 +72,7 @@ module API
expose :star_count, :forks_count
expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? }
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
+ expose :public_builds
end
class ProjectMember < UserBasic
@@ -175,6 +176,7 @@ module API
expose :work_in_progress?, as: :work_in_progress
expose :milestone, using: Entities::Milestone
expose :merge_when_build_succeeds
+ expose :merge_status
end
class MergeRequestChanges < MergeRequest
@@ -383,7 +385,7 @@ module API
# for downloading of artifacts (see: https://gitlab.com/gitlab-org/gitlab-ce/issues/4255)
expose :download_url do |repo_obj, options|
if options[:user_can_download_artifacts]
- repo_obj.download_url
+ repo_obj.artifacts_download_url
end
end
expose :commit, with: RepoCommit do |repo_obj, _options|
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 1f991e600e3..6067c8b4a5e 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -99,6 +99,7 @@ module API
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - 0 by default
# import_url (optional)
+ # public_builds (optional)
# Example Request
# POST /projects
post do
@@ -115,7 +116,8 @@ module API
:namespace_id,
:public,
:visibility_level,
- :import_url]
+ :import_url,
+ :public_builds]
attrs = map_public_to_visibility_level(attrs)
@project = ::Projects::CreateService.new(current_user, attrs).execute
if @project.saved?
@@ -145,6 +147,7 @@ module API
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional)
# import_url (optional)
+ # public_builds (optional)
# Example Request
# POST /projects/user/:user_id
post "user/:user_id" do
@@ -161,7 +164,8 @@ module API
:shared_runners_enabled,
:public,
:visibility_level,
- :import_url]
+ :import_url,
+ :public_builds]
attrs = map_public_to_visibility_level(attrs)
@project = ::Projects::CreateService.new(user, attrs).execute
if @project.saved?
@@ -205,6 +209,7 @@ module API
# shared_runners_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - visibility level of a project
+ # public_builds (optional)
# Example Request
# PUT /projects/:id
put ':id' do
@@ -219,7 +224,8 @@ module API
:snippets_enabled,
:shared_runners_enabled,
:public,
- :visibility_level]
+ :visibility_level,
+ :public_builds]
attrs = map_public_to_visibility_level(attrs)
authorize_admin_project
authorize! :rename_project, user_project if attrs[:name].present?
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index 5e4964f446c..d1d07394e92 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -54,7 +54,7 @@ module API
# GET /projects/:id/triggers
get ':id/triggers' do
authenticate!
- authorize_admin_project
+ authorize! :admin_build, user_project
triggers = user_project.triggers.includes(:trigger_requests)
triggers = paginate(triggers)
@@ -71,7 +71,7 @@ module API
# GET /projects/:id/triggers/:token
get ':id/triggers/:token' do
authenticate!
- authorize_admin_project
+ authorize! :admin_build, user_project
trigger = user_project.triggers.find_by(token: params[:token].to_s)
return not_found!('Trigger') unless trigger
@@ -87,7 +87,7 @@ module API
# POST /projects/:id/triggers
post ':id/triggers' do
authenticate!
- authorize_admin_project
+ authorize! :admin_build, user_project
trigger = user_project.triggers.create
@@ -103,7 +103,7 @@ module API
# DELETE /projects/:id/triggers/:token
delete ':id/triggers/:token' do
authenticate!
- authorize_admin_project
+ authorize! :admin_build, user_project
trigger = user_project.triggers.find_by(token: params[:token].to_s)
return not_found!('Trigger') unless trigger
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index d9a055f6c92..f6495071a11 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -2,7 +2,7 @@ module API
# Projects variables API
class Variables < Grape::API
before { authenticate! }
- before { authorize_admin_project }
+ before { authorize! :admin_build, user_project }
resource :projects do
# Get project variables
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 099062eeb8b..4962f5e53ce 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -1,6 +1,9 @@
module Backup
class Manager
def pack
+ # Make sure there is a connection
+ ActiveRecord::Base.connection.reconnect!
+
# saving additional informations
s = {}
s[:db_version] = "#{ActiveRecord::Migrator.current_version}"
diff --git a/lib/banzai/pipeline/broadcast_message_pipeline.rb b/lib/banzai/pipeline/broadcast_message_pipeline.rb
new file mode 100644
index 00000000000..4bb85e24c38
--- /dev/null
+++ b/lib/banzai/pipeline/broadcast_message_pipeline.rb
@@ -0,0 +1,16 @@
+module Banzai
+ module Pipeline
+ class BroadcastMessagePipeline < DescriptionPipeline
+ def self.filters
+ @filters ||= [
+ Filter::MarkdownFilter,
+ Filter::SanitizationFilter,
+
+ Filter::EmojiFilter,
+ Filter::AutolinkFilter,
+ Filter::ExternalLinkFilter
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index f751458ac66..b9bb6e76081 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -36,7 +36,7 @@ module Gitlab
# import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git")
#
def import_repository(name, url)
- output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', "#{name}.git", url, '240'])
+ output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', "#{name}.git", url, '900'])
raise Error, output unless status.zero?
true
end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 8531c7e87e1..761b63e98f6 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -7,8 +7,8 @@ module Gitlab
settings = nil
if connect_to_db?
- settings = ApplicationSetting.current
- settings ||= ApplicationSetting.create_from_defaults unless ActiveRecord::Migrator.needs_migration?
+ settings = ::ApplicationSetting.current
+ settings ||= ::ApplicationSetting.create_from_defaults unless ActiveRecord::Migrator.needs_migration?
end
settings || fake_application_settings
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index f065cc5e9e9..191bea86ac3 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -1,8 +1,8 @@
module Gitlab
module Git
- BLANK_SHA = '0' * 40
- TAG_REF_PREFIX = "refs/tags/"
- BRANCH_REF_PREFIX = "refs/heads/"
+ BLANK_SHA = ('0' * 40).freeze
+ TAG_REF_PREFIX = "refs/tags/".freeze
+ BRANCH_REF_PREFIX = "refs/heads/".freeze
class << self
def ref_name(ref)
diff --git a/lib/gitlab/snippet_search_results.rb b/lib/gitlab/snippet_search_results.rb
index 38364a0b151..addda95be2b 100644
--- a/lib/gitlab/snippet_search_results.rb
+++ b/lib/gitlab/snippet_search_results.rb
@@ -12,9 +12,9 @@ module Gitlab
def objects(scope, page = nil)
case scope
when 'snippet_titles'
- Kaminari.paginate_array(snippet_titles).page(page).per(per_page)
+ snippet_titles.page(page).per(per_page)
when 'snippet_blobs'
- Kaminari.paginate_array(snippet_blobs).page(page).per(per_page)
+ snippet_blobs.page(page).per(per_page)
else
super
end
@@ -39,11 +39,7 @@ module Gitlab
end
def snippet_blobs
- search = Snippet.where(id: limit_snippet_ids).search_code(query)
- search = search.order('updated_at DESC').to_a
- snippets = []
- search.each { |e| snippets << chunk_snippet(e) }
- snippets
+ Snippet.where(id: limit_snippet_ids).search_code(query).order('updated_at DESC')
end
def default_scope
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index 9e90a99f15b..d95e7023d2e 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -38,7 +38,7 @@ web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid"
-gitlab_workhorse_dir=$(cd $app_root/../gitlab-workhorse && pwd)
+gitlab_workhorse_dir=$(cd $app_root/../gitlab-workhorse 2> /dev/null && pwd)
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $rails_socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
@@ -49,7 +49,7 @@ test -f /etc/default/gitlab && . /etc/default/gitlab
# Switch to the app_user if it is not he/she who is running the script.
if [ `whoami` != "$app_user" ]; then
- eval su - "$app_user" -s $shell_path -c $(echo \")$0 "$@"$(echo \"); exit;
+ eval su - "$app_user" -c $(echo \")$shell_path -l -c \'$0 "$@"\'$(echo \"); exit;
fi
# Switch to the gitlab path, exit on failure.
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index 4e6e56ac2db..cc8617b72ca 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -34,11 +34,16 @@ sidekiq_pid_path="$pid_path/sidekiq.pid"
# /home/git/gitlab-workhorse .
gitlab_workhorse_dir=$(cd $app_root/../gitlab-workhorse && pwd)
gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
+
# The -listenXxx settings determine where gitlab-workhorse
-# listens for connections from NGINX. To listen on localhost:8181, write
-# '-listenNetwork tcp -listenAddr localhost:8181'.
-# The -authBackend setting tells gitlab-workhorse where it can reach
-# Unicorn.
+# listens for connections from the web server. By default it listens to a
+# socket. To listen on TCP connections (needed by Apache) change to:
+# '-listenNetwork tcp -listenAddr 127.0.0.1:8181'
+#
+# The -authBackend setting tells gitlab-workhorse where it can reach Unicorn.
+# For relative URL support change to:
+# '-authBackend http://127.0.0.1/8080/gitlab'
+# Read more in http://doc.gitlab.com/ce/install/relative_url.html
gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080 -authSocket $socket_path/gitlab.socket -documentRoot $app_root/public"
gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 6aaec224f6e..9450a389d81 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -188,7 +188,7 @@ describe Projects::MergeRequestsController do
expect(response).to render_template('diffs')
end
end
-
+
context 'as json' do
it 'renders the diffs template to a string' do
go format: 'json'
@@ -199,6 +199,32 @@ describe Projects::MergeRequestsController do
end
end
+ describe 'GET diffs with view' do
+ def go(extra_params = {})
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: merge_request.iid
+ }
+
+ get :diffs, params.merge(extra_params)
+ end
+
+ it 'saves the preferred diff view in a cookie' do
+ go view: 'parallel'
+
+ expect(response.cookies['diff_view']).to eq('parallel')
+ end
+
+ it 'assigns :view param based on cookie' do
+ request.cookies['diff_view'] = 'parallel'
+
+ go
+
+ expect(controller.params[:view]).to eq 'parallel'
+ end
+ end
+
describe 'GET commits' do
def go(format: 'html')
get :commits,
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index d2db77f6286..c1b6ecd329a 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -1,30 +1,3 @@
-# == Schema Information
-#
-# Table name: builds
-#
-# id :integer not null, primary key
-# project_id :integer
-# status :string(255)
-# finished_at :datetime
-# trace :text
-# created_at :datetime
-# updated_at :datetime
-# started_at :datetime
-# runner_id :integer
-# commit_id :integer
-# coverage :float
-# commands :text
-# job_id :integer
-# name :string(255)
-# deploy :boolean default(FALSE)
-# options :text
-# allow_failure :boolean default(FALSE), not null
-# stage :string(255)
-# trigger_request_id :integer
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
FactoryGirl.define do
factory :ci_build, class: Ci::Build do
name 'test'
@@ -65,5 +38,20 @@ FactoryGirl.define do
build.trace = 'BUILD TRACE'
end
end
+
+ trait :artifacts do
+ after(:create) do |build, _|
+ build.artifacts_file =
+ fixture_file_upload(Rails.root +
+ 'spec/fixtures/ci_build_artifacts.zip',
+ 'application/zip')
+
+ build.artifacts_metadata =
+ fixture_file_upload(Rails.root +
+ 'spec/fixtures/ci_build_artifacts_metadata.gz',
+ 'application/x-gzip')
+ build.save!
+ end
+ end
end
end
diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index b955d0b0c46..2e9851fb442 100644
--- a/spec/features/admin/admin_builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -18,7 +18,7 @@ describe 'Admin Builds' do
visit admin_builds_path
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'All')
+ expect(page).to have_selector('.nav-links li.active', text: 'All')
expect(page.all('.build-link').size).to eq(4)
expect(page).to have_link 'Cancel all'
end
@@ -28,7 +28,7 @@ describe 'Admin Builds' do
it 'shows a message' do
visit admin_builds_path
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'All')
+ expect(page).to have_selector('.nav-links li.active', text: 'All')
expect(page).to have_content 'No builds to show'
expect(page).not_to have_link 'Cancel all'
end
@@ -44,7 +44,7 @@ describe 'Admin Builds' do
visit admin_builds_path(scope: :running)
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'Running')
+ expect(page).to have_selector('.nav-links li.active', text: 'Running')
expect(page.find('.build-link')).to have_content(build1.id)
expect(page.find('.build-link')).not_to have_content(build2.id)
expect(page.find('.build-link')).not_to have_content(build3.id)
@@ -58,7 +58,7 @@ describe 'Admin Builds' do
visit admin_builds_path(scope: :running)
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'Running')
+ expect(page).to have_selector('.nav-links li.active', text: 'Running')
expect(page).to have_content 'No builds to show'
expect(page).not_to have_link 'Cancel all'
end
@@ -74,7 +74,7 @@ describe 'Admin Builds' do
visit admin_builds_path(scope: :finished)
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'Finished')
+ expect(page).to have_selector('.nav-links li.active', text: 'Finished')
expect(page.find('.build-link')).not_to have_content(build1.id)
expect(page.find('.build-link')).not_to have_content(build2.id)
expect(page.find('.build-link')).to have_content(build3.id)
@@ -88,7 +88,7 @@ describe 'Admin Builds' do
visit admin_builds_path(scope: :finished)
- expect(page).to have_selector('.project-issuable-filter li.active', text: 'Finished')
+ expect(page).to have_selector('.nav-links li.active', text: 'Finished')
expect(page).to have_content 'No builds to show'
expect(page).to have_link 'Cancel all'
end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index 5b6f3cb3f15..6da3a857b3f 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -8,7 +8,7 @@ describe "Builds" do
@commit = FactoryGirl.create :ci_commit
@build = FactoryGirl.create :ci_build, commit: @commit
@project = @commit.project
- @project.team << [@user, :master]
+ @project.team << [@user, :developer]
end
describe "GET /:project/builds" do
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 5a62da10619..dacaa96d760 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -8,7 +8,6 @@ describe 'Commits' do
describe 'CI' do
before do
login_as :user
- project.team << [@user, :master]
stub_ci_commit_to_return_yaml_file
end
@@ -19,6 +18,10 @@ describe 'Commits' do
context 'commit status is Generic Commit Status' do
let!(:status) { FactoryGirl.create :generic_commit_status, commit: commit }
+ before do
+ project.team << [@user, :reporter]
+ end
+
describe 'Commit builds' do
before do
visit ci_status_path(commit)
@@ -37,85 +40,126 @@ describe 'Commits' do
context 'commit status is Ci Build' do
let!(:build) { FactoryGirl.create :ci_build, commit: commit }
+ let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
- describe 'Project commits' do
+ context 'when logged as developer' do
before do
- visit namespace_project_commits_path(project.namespace, project, :master)
+ project.team << [@user, :developer]
end
- it 'should show build status' do
- page.within("//li[@id='commit-#{commit.short_sha}']") do
- expect(page).to have_css(".ci-status-link")
+ describe 'Project commits' do
+ before do
+ visit namespace_project_commits_path(project.namespace, project, :master)
end
- end
- end
- describe 'Commit builds' do
- before do
- visit ci_status_path(commit)
+ it 'should show build status' do
+ page.within("//li[@id='commit-#{commit.short_sha}']") do
+ expect(page).to have_css(".ci-status-link")
+ end
+ end
end
- it { expect(page).to have_content commit.sha[0..7] }
- it { expect(page).to have_content commit.git_commit_message }
- it { expect(page).to have_content commit.git_author_name }
- end
-
- context 'Download artifacts' do
- let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
-
- before do
- build.update_attributes(artifacts_file: artifacts_file)
- end
+ describe 'Commit builds' do
+ before do
+ visit ci_status_path(commit)
+ end
- it do
- visit ci_status_path(commit)
- click_on 'Download artifacts'
- expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
+ it { expect(page).to have_content commit.sha[0..7] }
+ it { expect(page).to have_content commit.git_commit_message }
+ it { expect(page).to have_content commit.git_author_name }
end
- end
- describe 'Cancel all builds' do
- it 'cancels commit' do
- visit ci_status_path(commit)
- click_on 'Cancel running'
- expect(page).to have_content 'canceled'
- end
- end
+ context 'Download artifacts' do
+ before do
+ build.update_attributes(artifacts_file: artifacts_file)
+ end
- describe 'Cancel build' do
- it 'cancels build' do
- visit ci_status_path(commit)
- click_on 'Cancel'
- expect(page).to have_content 'canceled'
+ it do
+ visit ci_status_path(commit)
+ click_on 'Download artifacts'
+ expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
+ end
end
- end
- describe '.gitlab-ci.yml not found warning' do
- context 'ci builds enabled' do
- it "does not show warning" do
+ describe 'Cancel all builds' do
+ it 'cancels commit' do
visit ci_status_path(commit)
- expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ click_on 'Cancel running'
+ expect(page).to have_content 'canceled'
end
+ end
- it 'shows warning' do
- stub_ci_commit_yaml_file(nil)
+ describe 'Cancel build' do
+ it 'cancels build' do
visit ci_status_path(commit)
- expect(page).to have_content '.gitlab-ci.yml not found in this commit'
+ click_on 'Cancel'
+ expect(page).to have_content 'canceled'
end
end
- context 'ci builds disabled' do
- before do
- stub_ci_builds_disabled
- stub_ci_commit_yaml_file(nil)
- visit ci_status_path(commit)
+ describe '.gitlab-ci.yml not found warning' do
+ context 'ci builds enabled' do
+ it "does not show warning" do
+ visit ci_status_path(commit)
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
+
+ it 'shows warning' do
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ expect(page).to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
- it 'does not show warning' do
- expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ context 'ci builds disabled' do
+ before do
+ stub_ci_builds_disabled
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ end
+
+ it 'does not show warning' do
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
end
end
+
+ context "when logged as reporter" do
+ before do
+ project.team << [@user, :reporter]
+ build.update_attributes(artifacts_file: artifacts_file)
+ visit ci_status_path(commit)
+ end
+
+ it do
+ expect(page).to have_content commit.sha[0..7]
+ expect(page).to have_content commit.git_commit_message
+ expect(page).to have_content commit.git_author_name
+ expect(page).to have_link('Download artifacts')
+ expect(page).to_not have_link('Cancel running')
+ expect(page).to_not have_link('Retry failed')
+ end
+ end
+
+ context 'when accessing internal project with disallowed access' do
+ before do
+ project.update(
+ visibility_level: Gitlab::VisibilityLevel::INTERNAL,
+ public_builds: false)
+ build.update_attributes(artifacts_file: artifacts_file)
+ visit ci_status_path(commit)
+ end
+
+ it do
+ expect(page).to have_content commit.sha[0..7]
+ expect(page).to have_content commit.git_commit_message
+ expect(page).to have_content commit.git_author_name
+ expect(page).to_not have_link('Download artifacts')
+ expect(page).to_not have_link('Cancel running')
+ expect(page).to_not have_link('Retry failed')
+ end
+ end
end
end
end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 655d2c8b7d9..b98476f854e 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -96,6 +96,60 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
+ describe "GET /:project_path/builds" do
+ subject { namespace_project_builds_path(project.namespace, project) }
+
+ context "when allowed for public" do
+ before { project.update(public_builds: true) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context "when disallowed for public" do
+ before { project.update(public_builds: false) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
+ describe "GET /:project_path/builds/:id" do
+ let(:commit) { create(:ci_commit, project: project) }
+ let(:build) { create(:ci_build, commit: commit) }
+ subject { namespace_project_build_path(project.namespace, project, build.id) }
+
+ context "when allowed for public" do
+ before { project.update(public_builds: true) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context "when disallowed for public" do
+ before { project.update(public_builds: false) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
describe "GET /:project_path/blob" do
before do
commit = project.repository.commit
diff --git a/spec/javascripts/fixtures/project_title.html.haml b/spec/javascripts/fixtures/project_title.html.haml
index 4286d1be669..e5850b62659 100644
--- a/spec/javascripts/fixtures/project_title.html.haml
+++ b/spec/javascripts/fixtures/project_title.html.haml
@@ -1,7 +1,7 @@
%h1.title
%a
GitLab Org
- %a.project-item-select-holder.js-projects-dropdown-toggle{href: "/gitlab-org/gitlab-test"}
+ %a.project-item-select-holder{href: "/gitlab-org/gitlab-test"}
GitLab Test
- %span.fa.fa-chevron-down.dropdown-toggle-caret
%input#project_path.project-item-select.js-projects-dropdown.ajax-project-select{type: "hidden", name: "project_path", "data-include-groups" => "false"}
+ %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 7289e596ef3..82bd057b16c 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -270,6 +270,17 @@ describe Notify do
it 'contains a link to the new issue' do
is_expected.to have_body_text /#{namespace_project_issue_path project.namespace, project, issue}/
end
+
+ context 'when enabled email_author_in_body' do
+ before do
+ allow(current_application_settings).to receive(:email_author_in_body).and_return(true)
+ end
+
+ it 'contains a link to note author' do
+ is_expected.to have_body_text issue.author_name
+ is_expected.to have_body_text /wrote\:/
+ end
+ end
end
describe 'that are new with a description' do
@@ -377,6 +388,17 @@ describe Notify do
it 'has the correct message-id set' do
is_expected.to have_header 'Message-ID', "<merge_request_#{merge_request.id}@#{Gitlab.config.gitlab.host}>"
end
+
+ context 'when enabled email_author_in_body' do
+ before do
+ allow(current_application_settings).to receive(:email_author_in_body).and_return(true)
+ end
+
+ it 'contains a link to note author' do
+ is_expected.to have_body_text merge_request.author_name
+ is_expected.to have_body_text /wrote\:/
+ end
+ end
end
describe 'that are new with a description' do
@@ -550,6 +572,21 @@ describe Notify do
it 'contains the message from the note' do
is_expected.to have_body_text /#{note.note}/
end
+
+ it 'not contains note author' do
+ is_expected.not_to have_body_text /wrote\:/
+ end
+
+ context 'when enabled email_author_in_body' do
+ before do
+ allow(current_application_settings).to receive(:email_author_in_body).and_return(true)
+ end
+
+ it 'contains a link to note author' do
+ is_expected.to have_body_text note.author_name
+ is_expected.to have_body_text /wrote\:/
+ end
+ end
end
describe 'on a commit' do
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index f4c58882757..161a32c51e6 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -66,6 +66,14 @@ describe ApplicationSetting, models: true do
it { is_expected.to allow_value(http).for(:after_sign_out_path) }
it { is_expected.to allow_value(https).for(:after_sign_out_path) }
it { is_expected.not_to allow_value(ftp).for(:after_sign_out_path) }
+
+ it { is_expected.to validate_presence_of(:max_attachment_size) }
+
+ it do
+ is_expected.to validate_numericality_of(:max_attachment_size)
+ .only_integer
+ .is_greater_than(0)
+ end
end
context 'restricted signup domains' do
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 30a71987d86..1b1380ce4e2 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -33,6 +33,20 @@ describe Milestone, models: true do
let(:milestone) { create(:milestone) }
let(:issue) { create(:issue) }
+ describe "unique milestone title per project" do
+ it "shouldn't accept the same title in a project twice" do
+ new_milestone = Milestone.new(project: milestone.project, title: milestone.title)
+ expect(new_milestone).not_to be_valid
+ end
+
+ it "should accept the same title in another project" do
+ project = build(:project)
+ new_milestone = Milestone.new(project: project, title: milestone.title)
+
+ expect(new_milestone).to be_valid
+ end
+ end
+
describe "#percent_complete" do
it "should not count open issues" do
milestone.issues << issue
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index c484ae8fc8c..72b4ac6d660 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -232,11 +232,126 @@ describe Repository, models: true do
end
describe 'when there are branches' do
- before do
- allow(repository.raw_repository).to receive(:branch_count).and_return(3)
+ it 'returns true' do
+ expect(repository.raw_repository).to receive(:branch_count).and_return(3)
+
+ expect(subject).to eq(true)
end
- it { is_expected.to eq(true) }
+ it 'caches the output' do
+ expect(repository.raw_repository).to receive(:branch_count).
+ once.
+ and_return(3)
+
+ repository.has_visible_content?
+ repository.has_visible_content?
+ end
+ end
+ end
+
+ describe '#empty?' do
+ let(:empty_repository) { create(:project_empty_repo).repository }
+
+ it 'returns true for an empty repository' do
+ expect(empty_repository.empty?).to eq(true)
+ end
+
+ it 'returns false for a non-empty repository' do
+ expect(repository.empty?).to eq(false)
+ end
+
+ it 'caches the output' do
+ expect(repository.raw_repository).to receive(:empty?).
+ once.
+ and_return(false)
+
+ repository.empty?
+ repository.empty?
+ end
+ end
+
+ describe '#root_ref' do
+ it 'returns a branch name' do
+ expect(repository.root_ref).to be_an_instance_of(String)
+ end
+
+ it 'caches the output' do
+ expect(repository.raw_repository).to receive(:root_ref).
+ once.
+ and_return('master')
+
+ repository.root_ref
+ repository.root_ref
+ end
+ end
+
+ describe '#expire_cache' do
+ it 'expires all caches' do
+ expect(repository).to receive(:expire_branch_cache)
+
+ repository.expire_cache
+ end
+
+ it 'expires the caches for a specific branch' do
+ expect(repository).to receive(:expire_branch_cache).with('master')
+
+ repository.expire_cache('master')
+ end
+ end
+
+ describe '#expire_root_ref_cache' do
+ it 'expires the root reference cache' do
+ repository.root_ref
+
+ expect(repository.raw_repository).to receive(:root_ref).
+ once.
+ and_return('foo')
+
+ repository.expire_root_ref_cache
+
+ expect(repository.root_ref).to eq('foo')
+ end
+ end
+
+ describe '#expire_has_visible_content_cache' do
+ it 'expires the visible content cache' do
+ repository.has_visible_content?
+
+ expect(repository.raw_repository).to receive(:branch_count).
+ once.
+ and_return(0)
+
+ repository.expire_has_visible_content_cache
+
+ expect(repository.has_visible_content?).to eq(false)
+ end
+ end
+
+ describe '#expire_branch_ache' do
+ # This method is private but we need it for testing purposes. Sadly there's
+ # no other proper way of testing caching operations.
+ let(:cache) { repository.send(:cache) }
+
+ it 'expires the cache for all branches' do
+ expect(cache).to receive(:expire).
+ at_least(repository.branches.length).
+ times
+
+ repository.expire_branch_cache
+ end
+
+ it 'expires the cache for all branches when the root branch is given' do
+ expect(cache).to receive(:expire).
+ at_least(repository.branches.length).
+ times
+
+ repository.expire_branch_cache(repository.root_ref)
+ end
+
+ it 'expires the cache for a specific branch' do
+ expect(cache).to receive(:expire).once
+
+ repository.expire_branch_cache('foo')
end
end
end
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index 8c9f5a382b7..6c07802db8b 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -113,7 +113,7 @@ describe API::API, api: true do
describe 'POST /projects/:id/builds/:build_id/cancel' do
context 'authorized user' do
- context 'user with :manage_builds persmission' do
+ context 'user with :update_build persmission' do
it 'should cancel running or pending build' do
post api("/projects/#{project.id}/builds/#{build.id}/cancel", user)
@@ -122,7 +122,7 @@ describe API::API, api: true do
end
end
- context 'user without :manage_builds permission' do
+ context 'user without :update_build permission' do
it 'should not cancel build' do
post api("/projects/#{project.id}/builds/#{build.id}/cancel", user2)
@@ -142,7 +142,7 @@ describe API::API, api: true do
describe 'POST /projects/:id/builds/:build_id/retry' do
context 'authorized user' do
- context 'user with :manage_builds persmission' do
+ context 'user with :update_build persmission' do
it 'should retry non-running build' do
post api("/projects/#{project.id}/builds/#{build_canceled.id}/retry", user)
@@ -152,7 +152,7 @@ describe API::API, api: true do
end
end
- context 'user without :manage_builds permission' do
+ context 'user without :update_build permission' do
it 'should not retry build' do
post api("/projects/#{project.id}/builds/#{build_canceled.id}/retry", user2)
diff --git a/spec/requests/api/commit_status_spec.rb b/spec/requests/api/commit_status_spec.rb
index 21482fc1070..89b554622ef 100644
--- a/spec/requests/api/commit_status_spec.rb
+++ b/spec/requests/api/commit_status_spec.rb
@@ -2,18 +2,17 @@ require 'spec_helper'
describe API::CommitStatus, api: true do
include ApiHelpers
- let(:user) { create(:user) }
- let(:user2) { create(:user) }
- let!(:project) { create(:project, creator_id: user.id) }
- let!(:reporter) { create(:project_member, user: user, project: project, access_level: ProjectMember::REPORTER) }
- let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) }
+ let!(:project) { create(:project) }
let(:commit) { project.repository.commit }
let!(:ci_commit) { project.ensure_ci_commit(commit.id) }
let(:commit_status) { create(:commit_status, commit: ci_commit) }
+ let(:guest) { create_user(ProjectMember::GUEST) }
+ let(:reporter) { create_user(ProjectMember::REPORTER) }
+ let(:developer) { create_user(ProjectMember::DEVELOPER) }
describe "GET /projects/:id/repository/commits/:sha/statuses" do
it_behaves_like 'a paginated resources' do
- let(:request) { get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user) }
+ let(:request) { get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", reporter) }
end
context "reporter user" do
@@ -29,7 +28,7 @@ describe API::CommitStatus, api: true do
end
it "should return latest commit statuses" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user)
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", reporter)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
@@ -39,7 +38,7 @@ describe API::CommitStatus, api: true do
end
it "should return all commit statuses" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?all=1", user)
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?all=1", reporter)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
@@ -47,7 +46,7 @@ describe API::CommitStatus, api: true do
end
it "should return latest commit statuses for specific ref" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?ref=develop", user)
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?ref=develop", reporter)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
@@ -55,7 +54,7 @@ describe API::CommitStatus, api: true do
end
it "should return latest commit statuses for specific name" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?name=coverage", user)
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?name=coverage", reporter)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
@@ -65,7 +64,7 @@ describe API::CommitStatus, api: true do
context "guest user" do
it "should not return project commits" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user2)
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", guest)
expect(response.status).to eq(403)
end
end
@@ -81,10 +80,10 @@ describe API::CommitStatus, api: true do
describe 'POST /projects/:id/statuses/:sha' do
let(:post_url) { "/projects/#{project.id}/statuses/#{commit.id}" }
- context 'reporter user' do
+ context 'developer user' do
context 'should create commit status' do
it 'with only required parameters' do
- post api(post_url, user), state: 'success'
+ post api(post_url, developer), state: 'success'
expect(response.status).to eq(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
@@ -95,7 +94,7 @@ describe API::CommitStatus, api: true do
end
it 'with all optional parameters' do
- post api(post_url, user), state: 'success', context: 'coverage', ref: 'develop', target_url: 'url', description: 'test'
+ post api(post_url, developer), state: 'success', context: 'coverage', ref: 'develop', target_url: 'url', description: 'test'
expect(response.status).to eq(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
@@ -108,25 +107,32 @@ describe API::CommitStatus, api: true do
context 'should not create commit status' do
it 'with invalid state' do
- post api(post_url, user), state: 'invalid'
+ post api(post_url, developer), state: 'invalid'
expect(response.status).to eq(400)
end
it 'without state' do
- post api(post_url, user)
+ post api(post_url, developer)
expect(response.status).to eq(400)
end
it 'invalid commit' do
- post api("/projects/#{project.id}/statuses/invalid_sha", user), state: 'running'
+ post api("/projects/#{project.id}/statuses/invalid_sha", developer), state: 'running'
expect(response.status).to eq(404)
end
end
end
+ context 'reporter user' do
+ it 'should not create commit status' do
+ post api(post_url, reporter)
+ expect(response.status).to eq(403)
+ end
+ end
+
context 'guest user' do
it 'should not create commit status' do
- post api(post_url, user2)
+ post api(post_url, guest)
expect(response.status).to eq(403)
end
end
@@ -138,4 +144,10 @@ describe API::CommitStatus, api: true do
end
end
end
+
+ def create_user(access_level)
+ user = create(:user)
+ create(:project_member, user: user, project: project, access_level: access_level)
+ user
+ end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index d7bfa17b0b1..a91a8696831 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -115,6 +115,7 @@ describe API::API, api: true do
expect(response.status).to eq(200)
expect(json_response['title']).to eq(merge_request.title)
expect(json_response['iid']).to eq(merge_request.iid)
+ expect(json_response['merge_status']).to eq('can_be_merged')
end
it 'should return merge_request by iid' do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 244947762dd..01b369720ca 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -151,8 +151,8 @@ describe Ci::API::API do
context "Artifacts" do
let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
+ let(:commit) { create(:ci_commit, project: project) }
+ let(:build) { create(:ci_build, commit: commit, runner_id: runner.id) }
let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") }
let(:post_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") }
@@ -160,12 +160,10 @@ describe Ci::API::API do
let(:headers) { { "GitLab-Workhorse" => "1.0" } }
let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token) }
+ before { build.run! }
+
describe "POST /builds/:id/artifacts/authorize" do
context "should authorize posting artifact to running build" do
- before do
- build.run!
- end
-
it "using token as parameter" do
post authorize_url, { token: build.token }, headers
expect(response.status).to eq(200)
@@ -180,10 +178,6 @@ describe Ci::API::API do
end
context "should fail to post too large artifact" do
- before do
- build.run!
- end
-
it "using token as parameter" do
stub_application_setting(max_artifacts_size: 0)
post authorize_url, { token: build.token, filesize: 100 }, headers
@@ -197,8 +191,8 @@ describe Ci::API::API do
end
end
- context "should get denied" do
- it do
+ context 'token is invalid' do
+ it 'should respond with forbidden'do
post authorize_url, { token: 'invalid', filesize: 100 }
expect(response.status).to eq(403)
end
@@ -206,17 +200,13 @@ describe Ci::API::API do
end
describe "POST /builds/:id/artifacts" do
- context "Disable sanitizer" do
+ context "disable sanitizer" do
before do
# by configuring this path we allow to pass temp file from any path
allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return('/')
end
context "should post artifact to running build" do
- before do
- build.run!
- end
-
it "uses regual file post" do
upload_artifacts(file_upload, headers_with_token, false)
expect(response.status).to eq(201)
@@ -244,10 +234,7 @@ describe Ci::API::API do
let(:stored_artifacts_file) { build.reload.artifacts_file.file }
let(:stored_metadata_file) { build.reload.artifacts_metadata.file }
- before do
- build.run!
- post(post_url, post_data, headers_with_token)
- end
+ before { post(post_url, post_data, headers_with_token) }
context 'post data accelerated by workhorse is correct' do
let(:post_data) do
@@ -257,11 +244,8 @@ describe Ci::API::API do
'metadata.name' => metadata.original_filename }
end
- it 'responds with valid status' do
- expect(response.status).to eq(201)
- end
-
it 'stores artifacts and artifacts metadata' do
+ expect(response.status).to eq(201)
expect(stored_artifacts_file.original_filename).to eq(artifacts.original_filename)
expect(stored_metadata_file.original_filename).to eq(metadata.original_filename)
end
@@ -282,56 +266,42 @@ describe Ci::API::API do
end
end
-
- context "should fail to post too large artifact" do
- before do
- build.run!
- end
-
- it do
+ context "artifacts file is too large" do
+ it "should fail to post too large artifact" do
stub_application_setting(max_artifacts_size: 0)
upload_artifacts(file_upload, headers_with_token)
expect(response.status).to eq(413)
end
end
- context "should fail to post artifacts without file" do
- before do
- build.run!
- end
-
- it do
+ context "artifacts post request does not contain file" do
+ it "should fail to post artifacts without file" do
post post_url, {}, headers_with_token
expect(response.status).to eq(400)
end
end
- context "should fail to post artifacts without GitLab-Workhorse" do
- before do
- build.run!
- end
-
- it do
+ context 'GitLab Workhorse is not configured' do
+ it "should fail to post artifacts without GitLab-Workhorse" do
post post_url, { token: build.token }, {}
expect(response.status).to eq(403)
end
end
end
- context "should fail to post artifacts for outside of tmp path" do
+ context "artifacts are being stored outside of tmp path" do
before do
# by configuring this path we allow to pass file from @tmpdir only
# but all temporary files are stored in system tmp directory
@tmpdir = Dir.mktmpdir
allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir)
- build.run!
end
after do
FileUtils.remove_entry @tmpdir
end
- it do
+ it "should fail to post artifacts for outside of tmp path" do
upload_artifacts(file_upload, headers_with_token)
expect(response.status).to eq(400)
end
@@ -349,33 +319,37 @@ describe Ci::API::API do
end
end
- describe "DELETE /builds/:id/artifacts" do
- before do
- build.run!
- post delete_url, token: build.token, file: file_upload
- end
+ describe 'DELETE /builds/:id/artifacts' do
+ let(:build) { create(:ci_build, :artifacts) }
+ before { delete delete_url, token: build.token }
- it "should delete artifact build" do
- build.success
- delete delete_url, token: build.token
+ it 'should remove build artifacts' do
expect(response.status).to eq(200)
+ expect(build.artifacts_file.exists?).to be_falsy
+ expect(build.artifacts_metadata.exists?).to be_falsy
end
end
- describe "GET /builds/:id/artifacts" do
- before do
- build.run!
- end
+ describe 'GET /builds/:id/artifacts' do
+ before { get get_url, token: build.token }
- it "should download artifact" do
- build.update_attributes(artifacts_file: file_upload)
- get get_url, token: build.token
- expect(response.status).to eq(200)
+ context 'build has artifacts' do
+ let(:build) { create(:ci_build, :artifacts) }
+ let(:download_headers) do
+ { 'Content-Transfer-Encoding'=>'binary',
+ 'Content-Disposition'=>'attachment; filename=ci_build_artifacts.zip' }
+ end
+
+ it 'should download artifact' do
+ expect(response.status).to eq(200)
+ expect(response.headers).to include download_headers
+ end
end
- it "should fail to download if no artifact uploaded" do
- get get_url, token: build.token
- expect(response.status).to eq(404)
+ context 'build does not has artifacts' do
+ it 'should respond with not found' do
+ expect(response.status).to eq(404)
+ end
end
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index c1080ef190a..eb3a5fe43f5 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -21,6 +21,18 @@ describe GitPushService, services: true do
end
it { is_expected.to be_truthy }
+
+ it 'flushes general cached data' do
+ expect(project.repository).to receive(:expire_cache).with('master')
+
+ subject
+ end
+
+ it 'flushes the visible content cache' do
+ expect(project.repository).to receive(:expire_has_visible_content_cache)
+
+ subject
+ end
end
context 'existing branch' do
@@ -29,6 +41,12 @@ describe GitPushService, services: true do
end
it { is_expected.to be_truthy }
+
+ it 'flushes general cached data' do
+ expect(project.repository).to receive(:expire_cache).with('master')
+
+ subject
+ end
end
context 'rm branch' do
@@ -37,6 +55,18 @@ describe GitPushService, services: true do
end
it { is_expected.to be_truthy }
+
+ it 'flushes the visible content cache' do
+ expect(project.repository).to receive(:expire_has_visible_content_cache)
+
+ subject
+ end
+
+ it 'flushes general cached data' do
+ expect(project.repository).to receive(:expire_cache).with('master')
+
+ subject
+ end
end
end