summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG45
-rw-r--r--CONTRIBUTING.md9
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock34
-rw-r--r--README.md2
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/application.js.coffee4
-rw-r--r--app/assets/javascripts/notes.js.coffee8
-rw-r--r--app/assets/javascripts/wikis.js.coffee18
-rw-r--r--app/assets/javascripts/zen_mode.js.coffee27
-rw-r--r--app/assets/stylesheets/generic/forms.scss1
-rw-r--r--app/assets/stylesheets/generic/header.scss11
-rw-r--r--app/assets/stylesheets/pages/notes.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss6
-rw-r--r--app/controllers/passwords_controller.rb20
-rw-r--r--app/controllers/projects/hooks_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb10
-rw-r--r--app/controllers/projects/merge_requests_controller.rb10
-rw-r--r--app/helpers/application_helper.rb18
-rw-r--r--app/helpers/blob_helper.rb8
-rw-r--r--app/helpers/diff_helper.rb4
-rw-r--r--app/helpers/emails_helper.rb19
-rw-r--r--app/helpers/gitlab_markdown_helper.rb15
-rw-r--r--app/helpers/labels_helper.rb38
-rw-r--r--app/helpers/projects_helper.rb16
-rw-r--r--app/helpers/selects_helper.rb5
-rw-r--r--app/helpers/tree_helper.rb8
-rw-r--r--app/models/ability.rb32
-rw-r--r--app/models/concerns/participable.rb20
-rw-r--r--app/models/group_milestone.rb2
-rw-r--r--app/models/hooks/project_hook.rb2
-rw-r--r--app/models/hooks/service_hook.rb1
-rw-r--r--app/models/hooks/system_hook.rb1
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/models/project_wiki.rb2
-rw-r--r--app/models/tree.rb6
-rw-r--r--app/services/notes/create_service.rb2
-rw-r--r--app/services/notification_service.rb23
-rw-r--r--app/views/dashboard/issues.atom.builder2
-rw-r--r--app/views/dashboard/show.atom.builder2
-rw-r--r--app/views/devise/passwords/new.html.haml2
-rw-r--r--app/views/events/_event_push.atom.haml2
-rw-r--r--app/views/groups/show.atom.builder2
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/notify/new_user_email.html.haml4
-rw-r--r--app/views/notify/new_user_email.text.erb2
-rw-r--r--app/views/projects/_aside.html.haml2
-rw-r--r--app/views/projects/_dropdown.html.haml37
-rw-r--r--app/views/projects/_issuable_form.html.haml11
-rw-r--r--app/views/projects/blob/_text.html.haml6
-rw-r--r--app/views/projects/blob/diff.html.haml4
-rw-r--r--app/views/projects/commits/show.atom.builder2
-rw-r--r--app/views/projects/diffs/_match_line.html.haml8
-rw-r--r--app/views/projects/diffs/_text_file.html.haml4
-rw-r--r--app/views/projects/hooks/index.html.haml9
-rw-r--r--app/views/projects/issues/_discussion.html.haml3
-rw-r--r--app/views/projects/issues/_issue.html.haml3
-rw-r--r--app/views/projects/issues/index.atom.builder2
-rw-r--r--app/views/projects/labels/_label.html.haml4
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml3
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml3
-rw-r--r--app/views/projects/merge_requests/show/_context.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_accept.html.haml8
-rw-r--r--app/views/projects/milestones/show.html.haml5
-rw-r--r--app/views/projects/show.atom.builder2
-rw-r--r--app/views/projects/wikis/_new.html.haml2
-rw-r--r--app/views/search/results/_snippet_blob.html.haml11
-rw-r--r--app/views/shared/_visibility_radios.html.haml2
-rw-r--r--app/views/shared/snippets/_blob.html.haml6
-rw-r--r--app/views/shared/snippets/_form.html.haml2
-rwxr-xr-xbin/rake5
-rwxr-xr-xbin/spring11
-rw-r--r--config/gitlab.yml.example4
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--config/initializers/gitlab_shell_secret_token.rb8
-rw-r--r--db/fixtures/development/04_project.rb4
-rw-r--r--db/fixtures/development/05_users.rb6
-rw-r--r--db/fixtures/development/07_milestones.rb2
-rw-r--r--db/fixtures/development/09_issues.rb4
-rw-r--r--db/fixtures/development/10_merge_requests.rb4
-rw-r--r--db/fixtures/development/12_snippets.rb4
-rw-r--r--db/fixtures/development/13_comments.rb4
-rw-r--r--db/migrate/20150406133311_add_invite_data_to_member.rb13
-rw-r--r--db/migrate/20150417122318_remove_import_data_from_project.rb6
-rw-r--r--db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb6
-rw-r--r--db/migrate/20150516060434_add_note_events_to_web_hooks.rb9
-rw-r--r--db/schema.rb3
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/db_dump.md45
-rw-r--r--doc/markdown/markdown.md22
-rw-r--r--doc/raketasks/backup_restore.md4
-rw-r--r--doc/release/monthly.md5
-rw-r--r--doc/web_hooks/web_hooks.md279
-rw-r--r--doc/workflow/README.md4
-rw-r--r--doc/workflow/shortcuts.md5
-rw-r--r--doc/workflow/shortcuts.pngbin0 -> 78736 bytes
-rw-r--r--doc/workflow/timezone.md18
-rw-r--r--doc_styleguide.md22
-rw-r--r--docker/single/Dockerfile1
-rw-r--r--docker/single/assets/gitlab.rb37
-rw-r--r--features/project/forked_merge_requests.feature12
-rw-r--r--features/project/project.feature6
-rw-r--r--features/project/wiki.feature5
-rw-r--r--features/steps/project/forked_merge_requests.rb15
-rw-r--r--features/steps/project/hooks.rb2
-rw-r--r--features/steps/project/project.rb8
-rw-r--r--features/steps/project/wiki.rb10
-rw-r--r--features/steps/shared/project.rb6
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/api/project_hooks.rb6
-rw-r--r--lib/gitlab/asciidoc.rb60
-rw-r--r--lib/gitlab/backend/grack_auth.rb1
-rw-r--r--lib/gitlab/backend/rack_attack_helpers.rb31
-rw-r--r--lib/gitlab/markdown.rb4
-rw-r--r--lib/gitlab/markdown/label_reference_filter.rb6
-rw-r--r--lib/gitlab/markdown/sanitization_filter.rb35
-rw-r--r--lib/gitlab/markdown/task_list_filter.rb23
-rw-r--r--lib/gitlab/markup_helper.rb (renamed from lib/gitlab/markdown_helper.rb)19
-rw-r--r--lib/gitlab/search_results.rb16
-rw-r--r--spec/factories.rb16
-rw-r--r--spec/features/admin/admin_hooks_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb16
-rw-r--r--spec/helpers/diff_helper_spec.rb10
-rw-r--r--spec/helpers/emails_helper_spec.rb46
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb8
-rw-r--r--spec/helpers/labels_helper_spec.rb68
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb59
-rw-r--r--spec/lib/gitlab/backend/grack_auth_spec.rb2
-rw-r--r--spec/lib/gitlab/backend/rack_attack_helpers_spec.rb35
-rw-r--r--spec/lib/gitlab/gitlab_markdown_helper_spec.rb28
-rw-r--r--spec/lib/gitlab/markdown/label_reference_filter_spec.rb7
-rw-r--r--spec/lib/gitlab/markdown/task_list_filter_spec.rb14
-rw-r--r--spec/lib/gitlab/markup_helper_spec.rb40
-rw-r--r--spec/mailers/notify_spec.rb62
-rw-r--r--spec/models/hooks/project_hook_spec.rb1
-rw-r--r--spec/models/hooks/service_hook_spec.rb1
-rw-r--r--spec/models/hooks/system_hook_spec.rb1
-rw-r--r--spec/models/hooks/web_hook_spec.rb1
-rw-r--r--spec/models/milestone_spec.rb2
-rw-r--r--spec/requests/api/internal_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb4
-rw-r--r--spec/services/issues/close_service_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb15
146 files changed, 1416 insertions, 442 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ade877feb9a..df598502820 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,30 @@
Please view this file on the master branch, on stable branches it's out of date.
-v 7.11.0 (unreleased)
+v 7.12.0 (unreleased)
+ - Refactor permission checks with issues and merge requests project settings (Stan Hu)
+ - Fix Markdown preview not working in Edit Milestone page (Stan Hu)
+ - Fix Zen Mode not closing with ESC key (Stan Hu)
+ - Add web hook support for note events (Stan Hu)
+ - Disable "New Issue" and "New Merge Request" buttons when features are disabled in project settings (Stan Hu)
+ - Remove Rack Attack monkey patches and bump to version 4.3.0 (Stan Hu)
+ - Allow to configure location of the `.gitlab_shell_secret` file. (Jakub Jirutka)
+ - Disabled expansion of top/bottom blobs for new file diffs
+ - Update Asciidoctor gem to version 1.5.2. (Jakub Jirutka)
+ - Fix resolving of relative links to repository files in AsciiDoc documents. (Jakub Jirutka)
+ - Use the user list from the target project in a merge request (Stan Hu)
+ - Default extention for wiki pages is now .md instead of .markdown (Jeroen van Baarsen)
+ - Add validation to wiki page creation (only [a-zA-Z0-9/_-] are allowed) (Jeroen van Baarsen)
+ - Fix new/empty milestones showing 100% completion value (Jonah Bishop)
+
+v 7.11.2
+ - no changes
+
+v 7.11.1
+ - no changes
+
+v 7.11.0
+ - Fall back to Plaintext when Syntaxhighlighting doesn't work. Fixes some buggy lexers (Hannes Rosenögger)
+ - Get editing comments to work in Chrome 43 again.
- Fix broken view when viewing history of a file that includes a path that used to be another file (Stan Hu)
- Don't show duplicate deploy keys
- Fix commit time being displayed in the wrong timezone in some cases (Hannes Rosenögger)
@@ -11,8 +35,6 @@ v 7.11.0 (unreleased)
- Don't allow a merge request to be merged when its title starts with "WIP".
- Add a page title to every page.
- Allow primary email to be set to an email that you've already added.
- - Fix Error 500 when searching Wiki pages (Stan Hu)
- - Get Gitorious importer to work again.
- Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
- Ignore invalid lines in .gitmodules
- Fix "Cannot move project" error message from popping up after a successful transfer (Stan Hu)
@@ -21,7 +43,6 @@ v 7.11.0 (unreleased)
- Fix "Revspec not found" errors when viewing diffs in a forked project with submodules (Stan Hu)
- Improve project page UI
- Fix broken file browsing with relative submodule in personal projects (Stan Hu)
- - Fix DB error when trying to tag a repository (Stan Hu)
- Add "Reply quoting selected text" shortcut key (`r`)
- Fix bug causing `@whatever` inside an issue's first code block to be picked up as a user mention.
- Fix bug causing `@whatever` inside an inline code snippet (backtick-style) to be picked up as a user mention.
@@ -32,20 +53,19 @@ v 7.11.0 (unreleased)
- Show Atom feed buttons everywhere where applicable.
- Add project activity atom feed.
- Don't crash when an MR from a fork has a cross-reference comment from the target project on one of its commits.
+ - Explain how to get a new password reset token in welcome emails
- Include commit comments in MR from a forked project.
- - Fix adding new group members from admin area
- Group milestones by title in the dashboard and all other issue views.
- Query issues, merge requests and milestones with their IID through API (Julien Bianchi)
- Add default project and snippet visibility settings to the admin web UI.
- Show incompatible projects in Google Code import status (Stan Hu)
- Fix bug where commit data would not appear in some subdirectories (Stan Hu)
- - Unescape branch names in compare commit (Stan Hu)
- Task lists are now usable in comments, and will show up in Markdown previews.
- Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu)
- Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu)
- Protect OmniAuth request phase against CSRF.
- -
- -
+ - Don't send notifications to mentioned users that don't have access to the project in question.
+ - Add search issues/MR by number
- Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller)
@@ -68,6 +88,15 @@ v 7.11.0 (unreleased)
- Fix reference links in dashboard activity and ATOM feeds.
- Ensure that the first added admin performs repository imports
+v 7.10.4
+ - Fix migrations broken in 7.10.2
+ - Make tags for GitLab installations running on MySQL case sensitive
+ - Get Gitorious importer to work again.
+ - Fix adding new group members from admin area
+ - Fix DB error when trying to tag a repository (Stan Hu)
+ - Fix Error 500 when searching Wiki pages (Stan Hu)
+ - Unescape branch names in compare commit (Stan Hu)
+
v 7.10.2
- Fix CI links on MR page
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 895202b58e2..8059b95609a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,7 +86,9 @@ If you can, please submit a merge request with the fix or improvements including
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
-The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
+The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
+Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
+After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? Can you do part of the refactor? The increased reviewability of small MR's that leads to higher code quality is more important to us than having a minimal commit log. The smaller a MR is the more likely it is it will be merged (quickly), after that you can send more MR's to enhance it.
@@ -160,8 +162,9 @@ If you add a dependency in GitLab (such as an operating system package) please c
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
+1. [Database Migrations](doc/development/migration_style_guide.md)
+1. [Documentation styleguide](doc_styleguide.md)
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 of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
-1. [Migrations](doc/development/migration_style_guide.md)
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
@@ -177,4 +180,4 @@ Project maintainers have the right and responsibility to remove, edit, or reject
Instances of abusive, harassing, or otherwise unacceptable behavior can be
reported by emailing contact@gitlab.com
-This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
+This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) \ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 84007d4a776..8eb1f04000c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -44,7 +44,7 @@ gem "browser"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.1.12'
+gem "gitlab_git", '~> 7.1.13'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.2', require: 'grack'
@@ -94,7 +94,7 @@ gem "seed-fu"
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
-gem 'task_list', '~> 1.0.0', require: 'task_list/railtie'
+gem 'task_list', '1.0.2', require: 'task_list/railtie'
gem 'github-markup'
gem 'redcarpet', '~> 3.2.3'
gem 'RedCloth'
@@ -102,7 +102,7 @@ gem 'rdoc', '~>3.6'
gem 'org-ruby', '= 0.9.12'
gem 'creole', '~>0.3.6'
gem 'wikicloth', '=0.8.1'
-gem 'asciidoctor', '= 0.1.4'
+gem 'asciidoctor', '~> 1.5.2'
# Diffs
gem 'diffy', '~> 3.0.3'
@@ -172,7 +172,7 @@ gem "underscore-rails", "~> 1.4.4"
gem "sanitize", '~> 2.0'
# Protect against bruteforcing
-gem "rack-attack"
+gem "rack-attack", '~> 4.3.0'
# Ace editor
gem 'ace-rails-ap'
@@ -239,7 +239,7 @@ group :development, :test do
gem 'minitest', '~> 5.3.0'
# Generate Fake data
- gem "ffaker"
+ gem 'ffaker', '~> 2.0.0'
# Guard
gem 'guard-rspec'
diff --git a/Gemfile.lock b/Gemfile.lock
index 571ab27ea71..80e4a44c1da 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -42,7 +42,7 @@ GEM
arel (5.0.1.20140414130214)
asana (0.0.6)
activeresource (>= 3.2.3)
- asciidoctor (0.1.4)
+ asciidoctor (1.5.2)
ast (2.0.0)
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
@@ -176,7 +176,7 @@ GEM
faraday_middleware (0.9.0)
faraday (>= 0.7.4, < 0.9)
fastercsv (1.5.5)
- ffaker (1.22.1)
+ ffaker (2.0.0)
ffi (1.9.8)
fog (1.21.0)
fog-brightbox
@@ -225,11 +225,11 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.1.0)
gemojione (~> 2.0)
- gitlab_git (7.1.12)
+ gitlab_git (7.1.13)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
- rugged (~> 0.21.2)
+ rugged (~> 0.22.2)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9)
@@ -338,7 +338,7 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
- mini_portile (0.6.1)
+ mini_portile (0.6.2)
minitest (5.3.5)
mousetrap-rails (1.4.6)
multi_json (1.10.1)
@@ -350,7 +350,7 @@ GEM
net-ssh (>= 2.6.5)
net-ssh (2.8.0)
newrelic_rpm (3.9.4.245)
- nokogiri (1.6.5)
+ nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
nprogress-rails (0.1.2.3)
oauth (0.4.7)
@@ -421,7 +421,7 @@ GEM
rack (1.5.2)
rack-accept (0.4.5)
rack (>= 0.4)
- rack-attack (4.2.0)
+ rack-attack (4.3.0)
rack
rack-cors (0.2.9)
rack-mini-profiler (0.9.0)
@@ -530,7 +530,7 @@ GEM
sexp_processor (~> 4.1)
rubyntlm (0.5.0)
rubypants (0.2.0)
- rugged (0.21.4)
+ rugged (0.22.2)
rugments (1.0.0.beta6)
safe_yaml (0.9.7)
sanitize (2.1.0)
@@ -547,9 +547,9 @@ GEM
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
- seed-fu (2.3.1)
- activerecord (>= 3.1, < 4.2)
- activesupport (>= 3.1, < 4.2)
+ seed-fu (2.3.5)
+ activerecord (>= 3.1, < 4.3)
+ activesupport (>= 3.1, < 4.3)
select2-rails (3.5.2)
thor (~> 0.14)
settingslogic (2.0.9)
@@ -589,7 +589,7 @@ GEM
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
- spring (1.3.3)
+ spring (1.3.6)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
spring-commands-spinach (1.0.0)
@@ -683,7 +683,7 @@ DEPENDENCIES
addressable
annotate (~> 2.6.0.beta2)
asana (~> 0.0.6)
- asciidoctor (= 0.1.4)
+ asciidoctor (~> 1.5.2)
attr_encrypted (= 1.3.4)
awesome_print
better_errors
@@ -713,7 +713,7 @@ DEPENDENCIES
email_spec
enumerize
factory_girl_rails
- ffaker
+ ffaker (~> 2.0.0)
fog (~> 1.14)
font-awesome-rails (~> 4.2)
foreman
@@ -723,7 +723,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
- gitlab_git (~> 7.1.12)
+ gitlab_git (~> 7.1.13)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2)
@@ -764,7 +764,7 @@ DEPENDENCIES
poltergeist (~> 1.5.1)
pry-rails
quiet_assets (~> 1.0.1)
- rack-attack
+ rack-attack (~> 4.3.0)
rack-cors
rack-mini-profiler
rack-oauth2 (~> 1.0.5)
@@ -802,7 +802,7 @@ DEPENDENCIES
spring-commands-spinach (= 1.0.0)
stamp
state_machine
- task_list (~> 1.0.0)
+ task_list (= 1.0.2)
test_after_commit
thin
tinder (~> 1.9.2)
diff --git a/README.md b/README.md
index 1ceac4621d9..85ea5c876af 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ There are two editions of GitLab.
*GitLab [Community Edition](https://about.gitlab.com/features/) (CE)* is available without any costs under an MIT license.
*GitLab Enterprise Edition (EE)* includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
-To get access to the EE and support please [become a subscriber](https://about.gitlab.com/pricing/).
+To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
## Code status
diff --git a/VERSION b/VERSION
index e85691e6ff7..5f0902c7c6a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.11.0.pre
+7.12.0.pre \ No newline at end of file
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index bb9da147018..caf18c0d860 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -140,8 +140,8 @@ $ ->
# Place the logo tooltip on the right when collapsed, bottom when expanded
$el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom'
else
- # Otherwise use the data-placement attribute like normal
- $el.data('placement')
+ # Otherwise use the data-placement attribute, or 'bottom' if undefined
+ $el.data('placement') or 'bottom'
})
# Form submitter
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index c25b1ddb066..f186fec2a0c 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -312,6 +312,14 @@ class @Notes
form.show()
textarea = form.find("textarea")
textarea.focus()
+
+ # HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
+ # The textarea has the correct value, Chrome just won't show it unless we
+ # modify it, so let's clear it and re-set it!
+ value = textarea.val()
+ textarea.val ""
+ textarea.val value
+
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
###
diff --git a/app/assets/javascripts/wikis.js.coffee b/app/assets/javascripts/wikis.js.coffee
index 66757565d3a..81cfc37b956 100644
--- a/app/assets/javascripts/wikis.js.coffee
+++ b/app/assets/javascripts/wikis.js.coffee
@@ -1,9 +1,17 @@
class @Wikis
constructor: ->
- $('.build-new-wiki').bind "click", ->
+ $('.build-new-wiki').bind "click", (e) ->
+ $('[data-error~=slug]').addClass("hidden")
+ $('p.hint').show()
field = $('#new_wiki_path')
- slug = field.val()
- path = field.attr('data-wikis-path')
+ valid_slug_pattern = /^[\w\/-]+$/
- if(slug.length > 0)
- location.href = path + "/" + slug
+ slug = field.val()
+ if slug.match valid_slug_pattern
+ path = field.attr('data-wikis-path')
+ if(slug.length > 0)
+ location.href = path + "/" + slug
+ else
+ e.preventDefault()
+ $('p.hint').hide()
+ $('[data-error~=slug]').removeClass("hidden")
diff --git a/app/assets/javascripts/zen_mode.js.coffee b/app/assets/javascripts/zen_mode.js.coffee
index 0fb8f7ed75f..dc6a84c6c52 100644
--- a/app/assets/javascripts/zen_mode.js.coffee
+++ b/app/assets/javascripts/zen_mode.js.coffee
@@ -1,6 +1,4 @@
class @ZenMode
- @fullscreen_prefix = 'fullscreen_'
-
constructor: ->
@active_zen_area = null
@active_checkbox = null
@@ -12,18 +10,18 @@ class @ZenMode
$('body').on 'click', '.zen-enter-link', (e) =>
e.preventDefault()
- $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true)
+ $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true).change()
$('body').on 'click', '.zen-leave-link', (e) =>
e.preventDefault()
- $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false)
+ $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false).change()
$('body').on 'change', '.zen-toggle-comment', (e) =>
checkbox = e.currentTarget
if checkbox.checked
# Disable other keyboard shortcuts in ZEN mode
Mousetrap.pause()
- @udpateActiveZenArea(checkbox)
+ @updateActiveZenArea(checkbox)
else
@exitZenMode()
@@ -32,14 +30,11 @@ class @ZenMode
@exitZenMode()
e.preventDefault()
- $(window).on 'hashchange', @updateZenModeFromLocationHash
-
- udpateActiveZenArea: (checkbox) =>
+ updateActiveZenArea: (checkbox) =>
@active_checkbox = $(checkbox)
@active_checkbox.prop('checked', true)
@active_zen_area = @active_checkbox.parent().find('textarea')
@active_zen_area.focus()
- window.location.hash = ZenMode.fullscreen_prefix + @active_checkbox.prop('id')
exitZenMode: =>
if @active_zen_area isnt null
@@ -51,17 +46,3 @@ class @ZenMode
window.scrollTo(window.pageXOffset, @scroll_position)
# Enable dropzone when leaving ZEN mode
Dropzone.forElement('.div-dropzone').enable()
-
- checkboxFromLocationHash: (e) ->
- id = $.trim(window.location.hash.replace('#' + ZenMode.fullscreen_prefix, ''))
- if id
- return $('.zennable input[type=checkbox]#' + id)[0]
- else
- return null
-
- updateZenModeFromLocationHash: (e) =>
- checkbox = @checkboxFromLocationHash()
- if checkbox
- @udpateActiveZenArea(checkbox)
- else
- @exitZenMode()
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index 266041403e0..7e070b4f386 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -89,7 +89,6 @@ label {
@include box-shadow(none);
}
-.issuable-description,
.wiki-content {
margin-top: 35px;
}
diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss
index fcd62373bfd..c4bafad6906 100644
--- a/app/assets/stylesheets/generic/header.scss
+++ b/app/assets/stylesheets/generic/header.scss
@@ -184,28 +184,17 @@ header {
padding: 4px 6px;
padding-left: 25px;
font-size: 13px;
- @include border-radius(3px);
- border: 1px solid #DDD;
- box-shadow: none;
- @include transition(all 0.15s ease-in 0s);
- background-color: #f5f5f5;
}
}
}
.search .search-input {
width: 300px;
- &:focus {
- width: 330px;
- }
}
@media (max-width: 1200px) {
.search .search-input {
width: 200px;
- &:focus {
- width: 230px;
- }
}
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index e943be67dbf..42b8ecabb38 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -79,11 +79,11 @@ ul.notes {
word-wrap: break-word;
@include md-typography;
- // Reduce left padding of first ul element
+ // Reduce left padding of first task list ul element
ul.task-list:first-child {
padding-left: 10px;
- // sub-lists should be padded normally
+ // sub-tasks should be padded normally
ul {
padding-left: 20px;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 49e5aad1f67..83771480cbd 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -129,7 +129,7 @@
}
.option-descr {
- margin-left: 24px;
+ margin-left: 36px;
color: $gray;
}
}
@@ -230,6 +230,10 @@ ul.nav.nav-projects-tabs {
margin: 10px 0;
}
}
+
+ .ci-status-image {
+ max-height: 22px;
+ }
}
.transfer-project .select2-container {
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 88459d4080a..145f27b67dd 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -36,4 +36,24 @@ class PasswordsController < Devise::PasswordsController
end
end
end
+
+ def edit
+ super
+ reset_password_token = Devise.token_generator.digest(
+ User,
+ :reset_password_token,
+ resource.reset_password_token
+ )
+
+ unless reset_password_token.nil?
+ user = User.where(
+ reset_password_token: reset_password_token
+ ).first_or_initialize
+
+ unless user.reset_password_period_valid?
+ flash[:alert] = 'Your password reset token has expired.'
+ redirect_to(new_user_password_url(user_email: user['email']))
+ end
+ end
+ end
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 57fc48ac7da..76062446c92 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -53,6 +53,6 @@ class Projects::HooksController < Projects::ApplicationController
end
def hook_params
- params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events)
+ params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events)
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index c524e1a0ea3..7d168aa827b 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -19,7 +19,15 @@ class Projects::IssuesController < Projects::ApplicationController
def index
terms = params['issue_search']
@issues = get_issues_collection
- @issues = @issues.full_search(terms) if terms.present?
+
+ if terms.present?
+ if terms =~ /\A#(\d+)\z/
+ @issues = @issues.where(iid: $1)
+ else
+ @issues = @issues.full_search(terms)
+ end
+ end
+
@issues = @issues.page(params[:page]).per(PER_PAGE)
respond_to do |format|
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 5b93e95866a..c7467e9b2f5 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -19,7 +19,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def index
terms = params['issue_search']
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.full_search(terms) if terms.present?
+
+ if terms.present?
+ if terms =~ /\A[#!](\d+)\z/
+ @merge_requests = @merge_requests.where(iid: $1)
+ else
+ @merge_requests = @merge_requests.full_search(terms)
+ end
+ end
+
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
respond_to do |format|
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index ea9722b9bef..bcd400b7e7b 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -222,18 +222,28 @@ module ApplicationHelper
end
def render_markup(file_name, file_content)
- GitHub::Markup.render(file_name, file_content).
- force_encoding(file_content.encoding).html_safe
+ if gitlab_markdown?(file_name)
+ Haml::Helpers.preserve(markdown(file_content))
+ elsif asciidoc?(file_name)
+ asciidoc(file_content)
+ else
+ GitHub::Markup.render(file_name, file_content).
+ force_encoding(file_content.encoding).html_safe
+ end
rescue RuntimeError
simple_format(file_content)
end
def markup?(filename)
- Gitlab::MarkdownHelper.markup?(filename)
+ Gitlab::MarkupHelper.markup?(filename)
end
def gitlab_markdown?(filename)
- Gitlab::MarkdownHelper.gitlab_markdown?(filename)
+ Gitlab::MarkupHelper.gitlab_markdown?(filename)
+ end
+
+ def asciidoc?(filename)
+ Gitlab::MarkupHelper.asciidoc?(filename)
end
# Overrides ActionView::Helpers::UrlHelper#link_to to add `rel="nofollow"` to
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 4ea838ca447..9fe5f82f02f 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -9,11 +9,13 @@ module BlobHelper
begin
lexer = Rugments::Lexer.guess(filename: blob_name, source: blob_content)
- rescue Rugments::Lexer::AmbiguousGuess
+ result = formatter.format(lexer.lex(blob_content)).html_safe
+ rescue
lexer = Rugments::Lexers::PlainText
+ result = formatter.format(lexer.lex(blob_content)).html_safe
end
- formatter.format(lexer.lex(blob_content)).html_safe
+ result
end
def no_highlight_files
@@ -55,7 +57,7 @@ module BlobHelper
end
def editing_preview_title(filename)
- if Gitlab::MarkdownHelper.previewable?(filename)
+ if Gitlab::MarkupHelper.previewable?(filename)
'Preview'
else
'Preview changes'
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 1b10795bb7b..1bd3ec5e0e0 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -101,6 +101,10 @@ module DiffHelper
(bottom) ? 'js-unfold-bottom' : ''
end
+ def unfold_class(unfold)
+ (unfold) ? 'unfold js-unfold' : ''
+ end
+
def diff_line_content(line)
if line.blank?
" &nbsp;"
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 0df3ecc90b7..128de18bc47 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -35,4 +35,23 @@ module EmailsHelper
lexer = Rugments::Lexers::Diff.new
raw formatter.format(lexer.lex(diffcontent))
end
+
+ def password_reset_token_valid_time
+ valid_hours = Devise.reset_password_within / 60 / 60
+ if valid_hours >= 24
+ unit = 'day'
+ valid_length = (valid_hours / 24).floor
+ else
+ unit = 'hour'
+ valid_length = valid_hours.floor
+ end
+
+ pluralize(valid_length, unit)
+ end
+
+ def reset_token_expire_message
+ link_tag = link_to('request a new one', new_user_password_url(user_email: @user.email))
+ msg = "This link is valid for #{password_reset_token_valid_time}. "
+ msg << "After it expires, you can #{link_tag}."
+ end
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 846aded4bda..7bcc011fd5f 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -56,6 +56,16 @@ module GitlabMarkdownHelper
@markdown.render(text).html_safe
end
+ def asciidoc(text)
+ Gitlab::Asciidoc.render(text, {
+ commit: @commit,
+ project: @project,
+ project_wiki: @project_wiki,
+ requested_path: @path,
+ ref: @ref
+ })
+ end
+
# Return the first line of +text+, up to +max_chars+, after parsing the line
# as Markdown. HTML tags in the parsed output are not counted toward the
# +max_chars+ limit. If the length limit falls within a tag's contents, then
@@ -67,8 +77,11 @@ module GitlabMarkdownHelper
end
def render_wiki_content(wiki_page)
- if wiki_page.format == :markdown
+ case wiki_page.format
+ when :markdown
markdown(wiki_page.content)
+ when :asciidoc
+ asciidoc(wiki_page.content)
else
wiki_page.formatted_content.html_safe
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 8272c177d59..8036303851b 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -1,6 +1,44 @@
module LabelsHelper
include ActionView::Helpers::TagHelper
+ # Link to a Label
+ #
+ # label - Label object to link to
+ # project - Project object which will be used as the context for the label's
+ # link. If omitted, defaults to `@project`, or the label's own
+ # project.
+ # block - An optional block that will be passed to `link_to`, forming the
+ # body of the link element. If omitted, defaults to
+ # `render_colored_label`.
+ #
+ # Examples:
+ #
+ # # Allow the generated link to use the label's own project
+ # link_to_label(label)
+ #
+ # # Force the generated link to use @project
+ # @project = Project.first
+ # link_to_label(label)
+ #
+ # # Force the generated link to use a provided project
+ # link_to_label(label, project: Project.last)
+ #
+ # # Customize link body with a block
+ # link_to_label(label) { "My Custom Label Text" }
+ #
+ # Returns a String
+ def link_to_label(label, project: nil, &block)
+ project ||= @project || label.project
+ link = namespace_project_issues_path(project.namespace, project,
+ label_name: label.name)
+
+ if block_given?
+ link_to link, &block
+ else
+ link_to render_colored_label(label), link
+ end
+ end
+
def project_label_names
@project.labels.pluck(:title)
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 96d2606f1a1..f8df39d236a 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -148,7 +148,7 @@ module ProjectsHelper
nav_tabs << [:files, :commits, :network, :graphs]
end
- if project.repo_exists? && project.merge_requests_enabled
+ if project.repo_exists? && can?(current_user, :read_merge_request, project)
nav_tabs << :merge_requests
end
@@ -156,11 +156,19 @@ module ProjectsHelper
nav_tabs << :settings
end
- [:issues, :wiki, :snippets].each do |feature|
- nav_tabs << feature if project.send :"#{feature}_enabled"
+ if can?(current_user, :read_issue, project)
+ nav_tabs << :issues
end
- if project.issues_enabled || project.merge_requests_enabled
+ if can?(current_user, :read_wiki, project)
+ nav_tabs << :wiki
+ end
+
+ if can?(current_user, :read_project_snippet, project)
+ nav_tabs << :snippets
+ end
+
+ if can?(current_user, :read_milestone, project)
nav_tabs << [:milestones, :labels]
end
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index bec8f2f1aa7..2b99a398049 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -10,6 +10,7 @@ module SelectsHelper
any_user = opts[:any_user] || false
email_user = opts[:email_user] || false
first_user = opts[:first_user] && current_user ? current_user.username : false
+ project = opts[:project] || @project
html = {
class: css_class,
@@ -21,8 +22,8 @@ module SelectsHelper
}
unless opts[:scope] == :all
- if @project
- html['data-project-id'] = @project.id
+ if project
+ html['data-project-id'] = project.id
elsif @group
html['data-group-id'] = @group.id
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 6dd9b6f017c..03a49e119b8 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -25,13 +25,7 @@ module TreeHelper
end
def render_readme(readme)
- if gitlab_markdown?(readme.name)
- preserve(markdown(readme.data))
- elsif markup?(readme.name)
- render_markup(readme.name, readme.data)
- else
- simple_format(readme.data)
- end
+ render_markup(readme.name, readme.data)
end
# Return an image icon depending on the file type and mode
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 85a15596f8d..e166b4197fd 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -101,6 +101,27 @@ class Ability
rules -= project_archived_rules
end
+ unless project.issues_enabled
+ rules -= named_abilities('issue')
+ end
+
+ unless project.merge_requests_enabled
+ rules -= named_abilities('merge_request')
+ end
+
+ unless project.issues_enabled or project.merge_requests_enabled
+ rules -= named_abilities('label')
+ rules -= named_abilities('milestone')
+ end
+
+ unless project.snippets_enabled
+ rules -= named_abilities('snippet')
+ end
+
+ unless project.wiki_enabled
+ rules -= named_abilities('wiki')
+ end
+
rules
end
end
@@ -272,5 +293,16 @@ class Ability
abilities
end
end
+
+ private
+
+ def named_abilities(name)
+ [
+ :"read_#{name}",
+ :"write_#{name}",
+ :"modify_#{name}",
+ :"admin_#{name}"
+ ]
+ end
end
end
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index a4832204f7b..9f667f47e0d 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -35,8 +35,8 @@ module Participable
end
end
- def participants(current_user = self.author)
- self.class.participant_attrs.flat_map do |attr|
+ def participants(current_user = self.author, project = self.project)
+ participants = self.class.participant_attrs.flat_map do |attr|
meth = method(attr)
value =
@@ -46,20 +46,28 @@ module Participable
meth.call
end
- participants_for(value, current_user)
+ participants_for(value, current_user, project)
end.compact.uniq
+
+ if project
+ participants.select! do |user|
+ user.can?(:read_project, project)
+ end
+ end
+
+ participants
end
private
- def participants_for(value, current_user = nil)
+ def participants_for(value, current_user = nil, project = nil)
case value
when User
[value]
when Enumerable, ActiveRecord::Relation
- value.flat_map { |v| participants_for(v, current_user) }
+ value.flat_map { |v| participants_for(v, current_user, project) }
when Participable
- value.participants(current_user)
+ value.participants(current_user, project)
end
end
end
diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb
index 7e4f16ebf16..ab055f6b80b 100644
--- a/app/models/group_milestone.rb
+++ b/app/models/group_milestone.rb
@@ -44,7 +44,7 @@ class GroupMilestone
def percent_complete
((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError
- 100
+ 0
end
def state
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
index 21867a9316c..ca7066b959a 100644
--- a/app/models/hooks/project_hook.rb
+++ b/app/models/hooks/project_hook.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
class ProjectHook < WebHook
@@ -21,5 +22,6 @@ class ProjectHook < WebHook
scope :push_hooks, -> { where(push_events: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true) }
scope :issue_hooks, -> { where(issues_events: true) }
+ scope :note_hooks, -> { where(note_events: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
end
diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
index 5b38ade2e6b..b55e217975f 100644
--- a/app/models/hooks/service_hook.rb
+++ b/app/models/hooks/service_hook.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
class ServiceHook < WebHook
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
index ee32b49bc66..6fb2d421026 100644
--- a/app/models/hooks/system_hook.rb
+++ b/app/models/hooks/system_hook.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
class SystemHook < WebHook
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index e9fd441352d..46fb85336e5 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
class WebHook < ActiveRecord::Base
@@ -21,6 +22,7 @@ class WebHook < ActiveRecord::Base
default_value_for :push_events, true
default_value_for :issues_events, false
+ default_value_for :note_events, false
default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 9bbb2bafb98..9c543b37023 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -66,7 +66,7 @@ class Milestone < ActiveRecord::Base
def percent_complete
((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError
- 100
+ 0
end
def expires_at
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 0706a1ca0d1..231973fa543 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -2,7 +2,7 @@ class ProjectWiki
include Gitlab::ShellAdapter
MARKUPS = {
- 'Markdown' => :markdown,
+ 'Markdown' => :md,
'RDoc' => :rdoc,
'AsciiDoc' => :asciidoc
} unless defined?(MARKUPS)
diff --git a/app/models/tree.rb b/app/models/tree.rb
index f279e896cda..93b3246a668 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -1,11 +1,11 @@
class Tree
- include Gitlab::MarkdownHelper
+ include Gitlab::MarkupHelper
attr_accessor :repository, :sha, :path, :entries
def initialize(repository, sha, path = '/')
path = '/' if path.blank?
-
+
@repository = repository
@sha = sha
@path = path
@@ -20,7 +20,7 @@ class Tree
available_readmes = blobs.select(&:readme?)
if available_readmes.count == 0
- return @readme = nil
+ return @readme = nil
end
# Take the first previewable readme, or the first available readme, if we
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index d19a6c2eca3..0ff37c41743 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -31,7 +31,7 @@ module Notes
def execute_hooks(note)
note_data = hook_data(note)
- # TODO: Support Webhooks
+ note.project.execute_hooks(note_data, :note_hooks)
note.project.execute_services(note_data, :note_hooks)
end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 0d7ffbeebd9..312b56eb87b 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -91,10 +91,14 @@ class NotificationService
# * project team members with notification level higher then Participating
#
def merge_mr(merge_request, current_user)
- recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
+ recipients = [merge_request.author, merge_request.assignee]
+
+ recipients = add_project_watchers(recipients, merge_request.target_project)
+ recipients = reject_muted_users(recipients, merge_request.target_project)
+
recipients = add_subscribed_users(recipients, merge_request)
recipients = reject_unsubscribed_users(recipients, merge_request)
- recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
+
recipients.delete(current_user)
recipients.each do |recipient|
@@ -137,20 +141,17 @@ class NotificationService
recipients = recipients.concat(participants)
# Merge project watchers
- recipients = recipients.concat(project_watchers(note.project)).compact.uniq
+ recipients = add_project_watchers(recipients, note.project)
# Reject users with Mention notification level, except those mentioned in _this_ note.
recipients = reject_mention_users(recipients - note.mentioned_users, note.project)
recipients = recipients + note.mentioned_users
- # Reject mutes users
recipients = reject_muted_users(recipients, note.project)
recipients = add_subscribed_users(recipients, note.noteable)
-
recipients = reject_unsubscribed_users(recipients, note.noteable)
- # Reject author
recipients.delete(note.author)
# build notify method like 'note_commit_email'
@@ -287,6 +288,10 @@ class NotificationService
users
end
+ def add_project_watchers(recipients, project)
+ recipients.concat(project_watchers(project)).compact.uniq
+ end
+
# Remove users with disabled notifications from array
# Also remove duplications and nil recipients
def reject_muted_users(users, project = nil)
@@ -403,11 +408,13 @@ class NotificationService
[target.author, target.assignee]
end
- recipients = reject_muted_users(recipients, project)
+ recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project)
+ recipients = reject_muted_users(recipients, project)
+
recipients = add_subscribed_users(recipients, target)
- recipients = recipients.concat(project_watchers(project)).uniq
recipients = reject_unsubscribed_users(recipients, target)
+
recipients
end
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index 6e88fc9be40..07bda1c77f8 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{current_user.name} issues"
- xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
diff --git a/app/views/dashboard/show.atom.builder b/app/views/dashboard/show.atom.builder
index 71edb73cd8a..e9a612231d5 100644
--- a/app/views/dashboard/show.atom.builder
+++ b/app/views/dashboard/show.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Activity"
- xml.link href: dashboard_url(format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: dashboard_url, rel: "alternate", type: "text/html"
xml.id dashboard_url
xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml
index e8820daf58f..29ffe8a8be3 100644
--- a/app/views/devise/passwords/new.html.haml
+++ b/app/views/devise/passwords/new.html.haml
@@ -6,7 +6,7 @@
.devise-errors
= devise_error_messages!
.clearfix.append-bottom-20
- = f.email_field :email, placeholder: "Email", class: "form-control", required: true
+ = f.email_field :email, placeholder: "Email", class: "form-control", required: true, value: params[:user_email]
.clearfix
= f.submit "Reset password", class: "btn-primary btn"
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 42762e04b51..3625cb49d8b 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -6,7 +6,7 @@
%i
at
= commit[:timestamp].to_time.to_s(:short)
- %blockquote= markdown(escape_once(commit[:message]), xhtml: true, reference_only_path: false, project: note.project)
+ %blockquote= markdown(escape_once(commit[:message]), xhtml: true, reference_only_path: false, project: event.project)
- if event.commits_count > 15
%p
%i
diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder
index b52e78faaa3..a91d1a6e94b 100644
--- a/app/views/groups/show.atom.builder
+++ b/app/views/groups/show.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@group.name} activity"
- xml.link href: group_url(@group, format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: group_url(@group), rel: "alternate", type: "text/html"
xml.id group_url(@group)
xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 04f79846858..e2d2dec7ab8 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_placeholder, class: "search-input"
+ = search_field_tag "search", nil, placeholder: search_placeholder, class: "search-input form-control"
= hidden_field_tag :group_id, @group.try(:id)
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml
index ebbe98dd472..4feacdaacff 100644
--- a/app/views/notify/new_user_email.html.haml
+++ b/app/views/notify/new_user_email.html.haml
@@ -11,4 +11,6 @@
- if @user.created_by_id
%p
- = link_to "Click here to set your password", edit_password_url(@user, :reset_password_token => @token)
+ = link_to "Click here to set your password", edit_password_url(@user, reset_password_token: @token)
+ %p
+ = reset_token_expire_message
diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb
index 96b26879a77..dd9b71e3b84 100644
--- a/app/views/notify/new_user_email.text.erb
+++ b/app/views/notify/new_user_email.text.erb
@@ -5,4 +5,6 @@ The Administrator created an account for you. Now you are a member of the compan
login.................. <%= @user.email %>
<% if @user.created_by_id %>
<%= link_to "Click here to set your password", edit_password_url(@user, :reset_password_token => @token) %>
+
+ <%= reset_token_expire_message %>
<% end %>
diff --git a/app/views/projects/_aside.html.haml b/app/views/projects/_aside.html.haml
index 333a1e6156d..e90c7b26dd2 100644
--- a/app/views/projects/_aside.html.haml
+++ b/app/views/projects/_aside.html.haml
@@ -57,7 +57,7 @@
.pull-right
- if ci_service.respond_to?(:status_img_path)
= link_to ci_service.builds_path, :'data-no-turbolink' => 'data-no-turbolink' do
- = image_tag ci_service.status_img_path, alt: "build status"
+ = image_tag ci_service.status_img_path, alt: "build status", class: 'ci-status-image'
- else
= link_to 'view builds', ci_service.builds_path, :'data-no-turbolink' => 'data-no-turbolink'
diff --git a/app/views/projects/_dropdown.html.haml b/app/views/projects/_dropdown.html.haml
deleted file mode 100644
index d623a3716ed..00000000000
--- a/app/views/projects/_dropdown.html.haml
+++ /dev/null
@@ -1,37 +0,0 @@
-- if current_user
- .dropdown.pull-right
- %a.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-bars
- %ul.dropdown-menu
- - if @project.issues_enabled && can?(current_user, :write_issue, @project)
- %li
- = link_to url_for_new_issue(@project, only_path: true), title: "New Issue" do
- %i.fa.fa-fw.fa-exclamation-circle
- New issue
- - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
- %li
- = link_to new_namespace_project_merge_request_path(@project.namespace, @project), title: "New Merge Request" do
- %i.fa.fa-fw.fa-tasks
- New merge request
- - if @project.snippets_enabled && can?(current_user, :write_snippet, @project)
- %li
- = link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
- %i.fa.fa-fw.fa-file-text-o
- New snippet
- - if can?(current_user, :admin_project_member, @project)
- %li
- = link_to namespace_project_project_members_path(@project.namespace, @project), title: "New project member" do
- %i.fa.fa-fw.fa-users
- New project member
- - if can? current_user, :push_code, @project
- %li.divider
- %li
- = link_to new_namespace_project_branch_path(@project.namespace, @project) do
- %i.fa.fa-fw.fa-code-fork
- New branch
- %li
- = link_to new_namespace_project_tag_path(@project.namespace, @project) do
- %i.fa.fa-fw.fa-tag
- New tag
-
-
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml
index e321a84974e..2292aaaa214 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/projects/_issuable_form.html.haml
@@ -11,6 +11,15 @@
.col-sm-10
= f.text_field :title, maxlength: 255, autofocus: true,
class: 'form-control pad js-gfm-input', required: true
+
+ - if issuable.is_a?(MergeRequest)
+ %p.help-block
+ - if issuable.work_in_progress?
+ This merge request is marked a <strong>Work In Progress</strong>.
+ When it's ready, remove the <code>WIP</code> prefix from the title to allow it to be accepted.
+ - else
+ To prevent this merge request from being accepted before it's ready,
+ mark it a <strong>Work In Progress</strong> by starting the title with <code>[WIP]</code> or <code>WIP:</code>.
.form-group.issuable-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
@@ -37,7 +46,7 @@
.col-sm-10
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
- selected: issuable.assignee_id)
+ selected: issuable.assignee_id, project: @target_project || @project)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml
index f6bd62f239b..4429c395aee 100644
--- a/app/views/projects/blob/_text.html.haml
+++ b/app/views/projects/blob/_text.html.haml
@@ -1,8 +1,4 @@
-- if gitlab_markdown?(blob.name)
- .file-content.wiki
- = preserve do
- = markdown(blob.data)
-- elsif markup?(blob.name)
+- if markup?(blob.name)
.file-content.wiki
= render_markup(blob.name, blob.data)
- else
diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml
index 5c79d0ef11f..84742608986 100644
--- a/app/views/projects/blob/diff.html.haml
+++ b/app/views/projects/blob/diff.html.haml
@@ -2,7 +2,7 @@
- if @form.unfold? && @form.since != 1 && !@form.bottom?
%tr.line_holder{ id: @form.since }
= render "projects/diffs/match_line", {line: @match_line,
- line_old: @form.since, line_new: @form.since, bottom: false}
+ line_old: @form.since, line_new: @form.since, bottom: false, new_file: false}
- @lines.each_with_index do |line, index|
- line_new = index + @form.since
@@ -16,4 +16,4 @@
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
%tr.line_holder{ id: @form.to }
= render "projects/diffs/match_line", {line: @match_line,
- line_old: @form.to, line_new: @form.to, bottom: true}
+ line_old: @form.to, line_new: @form.to, bottom: true, new_file: false}
diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder
index 01edd9447ce..3854ad5d611 100644
--- a/app/views/projects/commits/show.atom.builder
+++ b/app/views/projects/commits/show.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name}:#{@ref} commits"
- xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html"
xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?
diff --git a/app/views/projects/diffs/_match_line.html.haml b/app/views/projects/diffs/_match_line.html.haml
index 4ebe3379733..d1f897b99f7 100644
--- a/app/views/projects/diffs/_match_line.html.haml
+++ b/app/views/projects/diffs/_match_line.html.haml
@@ -1,7 +1,7 @@
-%td.old_line.diff-line-num.unfold.js-unfold{data: {linenumber: line_old},
- class: unfold_bottom_class(bottom)}
+%td.old_line.diff-line-num{data: {linenumber: line_old},
+ class: [unfold_bottom_class(bottom), unfold_class(!new_file)]}
\...
-%td.new_line.diff-line-num.unfold.js-unfold{data: {linenumber: line_new},
- class: unfold_bottom_class(bottom)}
+%td.new_line.diff-line-num{data: {linenumber: line_new},
+ class: [unfold_bottom_class(bottom), unfold_class(!new_file)]}
\...
%td.line_content.matched= line
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index e6dfbfd6511..a6373181b45 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -12,7 +12,7 @@
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
= render "projects/diffs/match_line", {line: line.text,
- line_old: line_old, line_new: line.new_pos, bottom: false}
+ line_old: line_old, line_new: line.new_pos, bottom: false, new_file: diff_file.new_file}
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
@@ -29,7 +29,7 @@
- if last_line > 0
= render "projects/diffs/match_line", {line: "",
- line_old: last_line, line_new: last_line, bottom: true}
+ line_old: last_line, line_new: last_line, bottom: true, new_file: diff_file.new_file}
- if diff_file.diff.blank? && diff_file.mode_changed?
.file-mode-changed
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 808c03148f4..eadbf61fdd4 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -35,6 +35,13 @@
%p.light
This url will be triggered when a new tag is pushed to the repository
%div
+ = f.check_box :note_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :note_events, class: 'list-label' do
+ %strong Comments
+ %p.light
+ This url will be triggered when someone adds a comment
+ %div
= f.check_box :issues_events, class: 'pull-left'
.prepend-left-20
= f.label :issues_events, class: 'list-label' do
@@ -64,6 +71,6 @@
.clearfix
%span.monospace= hook.url
%p
- - %w(push_events tag_push_events issues_events merge_requests_events).each do |trigger|
+ - %w(push_events tag_push_events issues_events note_events merge_requests_events).each do |trigger|
- if hook.send(trigger)
%span.label.label-gray= trigger.titleize
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 2016f5c709c..48858fa32da 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -30,5 +30,4 @@
%label Labels
.issue-show-labels
- @issue.labels.each do |label|
- = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do
- = render_colored_label(label)
+ = link_to_label(label)
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index ef36d1f9547..a4e25e5ce88 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -8,8 +8,7 @@
= link_to_gfm issue.title, issue_path(issue), class: "row_title"
.issue-labels
- issue.labels.each do |label|
- = link_to namespace_project_issues_path(issue.project.namespace, issue.project, label_name: label.name) do
- = render_colored_label(label)
+ = link_to_label(label, project: issue.project)
.pull-right.light
- if issue.closed?
%span
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index 5fa8fbdf893..dc8e477185b 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name} issues"
- xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_issues_url(@project.namespace, @project)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
diff --git a/app/views/projects/labels/_label.html.haml b/app/views/projects/labels/_label.html.haml
index 82829452862..7fa1ee53f76 100644
--- a/app/views/projects/labels/_label.html.haml
+++ b/app/views/projects/labels/_label.html.haml
@@ -1,8 +1,8 @@
%li{id: dom_id(label)}
- = render_colored_label(label)
+ = link_to_label(label)
.pull-right
%strong.append-right-20
- = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do
+ = link_to_label(label) do
= pluralize label.open_issues_count, 'open issue'
- if can? current_user, :admin_label, @project
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index 9a2aa9c3de0..eb3dba6858d 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -27,5 +27,4 @@
%label Labels
.merge-request-show-labels
- @merge_request.labels.each do |label|
- = link_to namespace_project_merge_requests_path(@project.namespace, @project, label_name: label.name) do
- = render_colored_label(label)
+ = link_to_label(label)
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 5d5a23b5409..073476b0d27 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -4,8 +4,7 @@
= link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title"
.merge-request-labels
- merge_request.labels.each do |label|
- = link_to namespace_project_merge_requests_path(merge_request.project.namespace, merge_request.project, label_name: label.name) do
- = render_colored_label(label)
+ = link_to_label(label, project: merge_request.project)
.pull-right.light
- if merge_request.merged?
%span
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
index a5a821c1847..1d0e2e350b0 100644
--- a/app/views/projects/merge_requests/show/_context.html.haml
+++ b/app/views/projects/merge_requests/show/_context.html.haml
@@ -9,7 +9,7 @@
none
.issuable-context-selectbox
- if can?(current_user, :modify_merge_request, @merge_request)
- = users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id, null_user: true)
+ = users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id, project: @target_project, null_user: true)
%div.prepend-top-20.clearfix
.issuable-context-title
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index cb536214c69..882b219f6e2 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -6,7 +6,7 @@
.automerge_widget.cannot_be_merged.hide
%strong This request can't be merged automatically. Even if it could be merged, you don't have permission to do so.
.automerge_widget.work_in_progress.hide
- %strong This request can't be merged automatically because it is marked a Work In Progress. Even if it could be merged, you don't have permission to do so.
+ %strong This request can't be accepted because it is marked a Work In Progress. Even if it could be accepted, you don't have permission to do so.
.automerge_widget.can_be_merged.hide
%strong This request can be merged automatically, but you don't have permission to do so.
@@ -57,11 +57,11 @@
%i.fa.fa-warning
Accept Merge Request
&nbsp;
- This usually happens when git can not resolve conflicts between branches automatically.
+ This usually happens when Git can not resolve conflicts between branches automatically.
.automerge_widget.work_in_progress.hide
%h4
- This request can't be merged because it is marked a <strong>Work In Progress</strong>.
+ This request can't be accepted because it is marked a <strong>Work In Progress</strong>.
%p
%button.btn.disabled{:type => 'button'}
@@ -69,7 +69,7 @@
Accept Merge Request
&nbsp;
- When the merge request is ready, remove the "WIP" prefix from the title to allow it to be merged.
+ When the merge request is ready, remove the "WIP" prefix from the title to allow it to be accepted.
.automerge_widget.unchecked
%p
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index bba2b8764ac..5845fd744f4 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -61,11 +61,12 @@
Participants
%span.badge= @users.count
- - if @project.issues_enabled
- .pull-right
+ .pull-right
+ - if can?(current_user, :write_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
%i.fa.fa-plus
New Issue
+ - if can?(current_user, :read_issue, @project)
= link_to 'Browse Issues', namespace_project_issues_path(@milestone.project.namespace, @milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
.tab-content
diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder
index bb713dcafa5..242684e5c7c 100644
--- a/app/views/projects/show.atom.builder
+++ b/app/views/projects/show.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name} activity"
- xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.private_token), rel: "self", type: "application/atom+xml"
+ 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.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index 6834969de8b..b2c085f34b1 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -8,6 +8,8 @@
= label_tag :new_wiki_path do
%span Page slug
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project)
+ %p.hidden.text-danger{data: { error: "slug" }}
+ The page slug is invalid. Please don't use characters other then: a-z 0-9 _ - and /
%p.hint
Please don't use spaces.
.modal-footer
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index 8af393777f0..95099853918 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -13,16 +13,7 @@
.file-title
%i.fa.fa-file
%strong= snippet_blob[:snippet_object].file_name
- - if gitlab_markdown?(snippet_blob[:snippet_object].file_name)
- .file-content.wiki
- - snippet_blob[:snippet_chunks].each do |snippet|
- - unless snippet[:data].empty?
- = preserve do
- = markdown(snippet[:data])
- - else
- .file-content.code
- .nothing-here-block Empty file
- - elsif markup?(snippet_blob[:snippet_object].file_name)
+ - if markup?(snippet_blob[:snippet_object].file_name)
.file-content.wiki
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml
index b07c4d20f12..02416125a72 100644
--- a/app/views/shared/_visibility_radios.html.haml
+++ b/app/views/shared/_visibility_radios.html.haml
@@ -1,7 +1,7 @@
- Gitlab::VisibilityLevel.values.each do |level|
.radio
- restricted = restricted_visibility_levels.include?(level)
- = label model_method, level do
+ = form.label "#{model_method}_#{level}" do
= form.radio_button model_method, level, checked: (selected_level == level), disabled: restricted
= visibility_level_icon(level)
.option-title
diff --git a/app/views/shared/snippets/_blob.html.haml b/app/views/shared/snippets/_blob.html.haml
index 30458793fd1..d26a99bb14c 100644
--- a/app/views/shared/snippets/_blob.html.haml
+++ b/app/views/shared/snippets/_blob.html.haml
@@ -1,9 +1,5 @@
- unless @snippet.content.empty?
- - if gitlab_markdown?(@snippet.file_name)
- .file-content.wiki
- = preserve do
- = markdown(@snippet.data)
- - elsif markup?(@snippet.file_name)
+ - if markup?(@snippet.file_name)
.file-content.wiki
= render_markup(@snippet.file_name, @snippet.data)
- else
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index 6783587bda9..9610f9ce414 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -11,7 +11,7 @@
.col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
= render 'shared/visibility_level', f: f, visibility_level: visibility_level, can_change_visibility_level: true, form_model: @snippet
-
+
.form-group
.file-editor
= f.label :file_name, "File", class: 'control-label'
diff --git a/bin/rake b/bin/rake
index 8017a0271d2..0fb4e07e13a 100755
--- a/bin/rake
+++ b/bin/rake
@@ -3,6 +3,5 @@ begin
load File.expand_path("../spring", __FILE__)
rescue LoadError
end
-require_relative '../config/boot'
-require 'rake'
-Rake.application.run
+require 'bundler/setup'
+load Gem.bin_path('rake', 'rake')
diff --git a/bin/spring b/bin/spring
index 253ec37c345..7b45d374fcd 100755
--- a/bin/spring
+++ b/bin/spring
@@ -1,17 +1,14 @@
#!/usr/bin/env ruby
-# This file loads spring without using Bundler, in order to be fast
-# It gets overwritten when you run the `spring binstub` command
+# This file loads spring without using Bundler, in order to be fast.
+# It gets overwritten when you run the `spring binstub` command.
unless defined?(Spring)
require "rubygems"
require "bundler"
- if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m)
- ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
- ENV["GEM_HOME"] = ""
- Gem.paths = ENV
-
+ if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
+ Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
gem "spring", match[1]
require "spring/binstub"
end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index bd2081688d1..fbc7f515f34 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -245,6 +245,10 @@ production: &base
repos_path: /home/git/repositories/
hooks_path: /home/git/gitlab-shell/hooks/
+ # File that contains the secret key for verifying access for gitlab-shell.
+ # Default is '.gitlab_shell_secret' relative to Rails.root (i.e. root of the GitLab app).
+ # secret_file: /home/git/gitlab/.gitlab_shell_secret
+
# Git over HTTP
upload_pack: true
receive_pack: true
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index e5ac66a2323..2351ef7b0ce 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -148,6 +148,7 @@ Settings.gravatar['ssl_url'] ||= 'https://secure.gravatar.com/avatar/%{hash}?
Settings['gitlab_shell'] ||= Settingslogic.new({})
Settings.gitlab_shell['path'] ||= Settings.gitlab['user_home'] + '/gitlab-shell/'
Settings.gitlab_shell['hooks_path'] ||= Settings.gitlab['user_home'] + '/gitlab-shell/hooks/'
+Settings.gitlab_shell['secret_file'] ||= Rails.root.join('.gitlab_shell_secret')
Settings.gitlab_shell['receive_pack'] = true if Settings.gitlab_shell['receive_pack'].nil?
Settings.gitlab_shell['upload_pack'] = true if Settings.gitlab_shell['upload_pack'].nil?
Settings.gitlab_shell['repos_path'] ||= Settings.gitlab['user_home'] + '/repositories/'
diff --git a/config/initializers/gitlab_shell_secret_token.rb b/config/initializers/gitlab_shell_secret_token.rb
index e7c9f0ba7c2..751fccead07 100644
--- a/config/initializers/gitlab_shell_secret_token.rb
+++ b/config/initializers/gitlab_shell_secret_token.rb
@@ -5,8 +5,7 @@ require 'securerandom'
# Your secret key for verifying the gitlab_shell.
-secret_file = Rails.root.join('.gitlab_shell_secret')
-gitlab_shell_symlink = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')
+secret_file = Gitlab.config.gitlab_shell.secret_file
unless File.exist? secret_file
# Generate a new token of 16 random hexadecimal characters and store it in secret_file.
@@ -14,6 +13,7 @@ unless File.exist? secret_file
File.write(secret_file, token)
end
-if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(gitlab_shell_symlink)
- FileUtils.symlink(secret_file, gitlab_shell_symlink)
+link_path = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')
+if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(link_path)
+ FileUtils.symlink(secret_file, link_path)
end
diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb
index ae4c0550a4f..87839770924 100644
--- a/db/fixtures/development/04_project.rb
+++ b/db/fixtures/development/04_project.rb
@@ -23,7 +23,7 @@ Sidekiq::Testing.inline! do
name: group_path.titleize,
path: group_path
)
- group.description = Faker::Lorem.sentence
+ group.description = FFaker::Lorem.sentence
group.save
group.add_owner(User.first)
@@ -35,7 +35,7 @@ Sidekiq::Testing.inline! do
import_url: url,
namespace_id: group.id,
name: project_path.titleize,
- description: Faker::Lorem.sentence,
+ description: FFaker::Lorem.sentence,
visibility_level: Gitlab::VisibilityLevel.values.sample
}
diff --git a/db/fixtures/development/05_users.rb b/db/fixtures/development/05_users.rb
index 24952a1f661..378354efd5a 100644
--- a/db/fixtures/development/05_users.rb
+++ b/db/fixtures/development/05_users.rb
@@ -2,9 +2,9 @@ Gitlab::Seeder.quiet do
(2..20).each do |i|
begin
User.create!(
- username: Faker::Internet.user_name,
- name: Faker::Name.name,
- email: Faker::Internet.email,
+ username: FFaker::Internet.user_name,
+ name: FFaker::Name.name,
+ email: FFaker::Internet.email,
confirmed_at: DateTime.now,
password: '12345678'
)
diff --git a/db/fixtures/development/07_milestones.rb b/db/fixtures/development/07_milestones.rb
index 2296821e528..a43116829d9 100644
--- a/db/fixtures/development/07_milestones.rb
+++ b/db/fixtures/development/07_milestones.rb
@@ -3,7 +3,7 @@ Gitlab::Seeder.quiet do
(1..5).each do |i|
milestone_params = {
title: "v#{i}.0",
- description: Faker::Lorem.sentence,
+ description: FFaker::Lorem.sentence,
state: ['opened', 'closed'].sample,
}
diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb
index e8b01b46d22..c636e96381c 100644
--- a/db/fixtures/development/09_issues.rb
+++ b/db/fixtures/development/09_issues.rb
@@ -2,8 +2,8 @@ Gitlab::Seeder.quiet do
Project.all.each do |project|
(1..10).each do |i|
issue_params = {
- title: Faker::Lorem.sentence(6),
- description: Faker::Lorem.sentence,
+ title: FFaker::Lorem.sentence(6),
+ description: FFaker::Lorem.sentence,
state: ['opened', 'closed'].sample,
milestone: project.milestones.sample,
assignee: project.team.users.sample
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index f9b2fd8b05f..0825776ffaa 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -10,8 +10,8 @@ Gitlab::Seeder.quiet do
params = {
source_branch: source_branch,
target_branch: target_branch,
- title: Faker::Lorem.sentence(6),
- description: Faker::Lorem.sentences(3).join(" "),
+ title: FFaker::Lorem.sentence(6),
+ description: FFaker::Lorem.sentences(3).join(" "),
milestone: project.milestones.sample,
assignee: project.team.users.sample
}
diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb
index b3a6f39c7d5..3bd4b442ade 100644
--- a/db/fixtures/development/12_snippets.rb
+++ b/db/fixtures/development/12_snippets.rb
@@ -28,8 +28,8 @@ eos
PersonalSnippet.seed(:id, [{
id: i,
author_id: user.id,
- title: Faker::Lorem.sentence(3),
- file_name: Faker::Internet.domain_word + '.rb',
+ title: FFaker::Lorem.sentence(3),
+ file_name: FFaker::Internet.domain_word + '.rb',
visibility_level: Gitlab::VisibilityLevel.values.sample,
content: content,
}])
diff --git a/db/fixtures/development/13_comments.rb b/db/fixtures/development/13_comments.rb
index d37be53c7b9..566c0705638 100644
--- a/db/fixtures/development/13_comments.rb
+++ b/db/fixtures/development/13_comments.rb
@@ -6,7 +6,7 @@ Gitlab::Seeder.quiet do
note_params = {
noteable_type: 'Issue',
noteable_id: issue.id,
- note: Faker::Lorem.sentence,
+ note: FFaker::Lorem.sentence,
}
Notes::CreateService.new(project, user, note_params).execute
@@ -21,7 +21,7 @@ Gitlab::Seeder.quiet do
note_params = {
noteable_type: 'MergeRequest',
noteable_id: mr.id,
- note: Faker::Lorem.sentence,
+ note: FFaker::Lorem.sentence,
}
Notes::CreateService.new(project, user, note_params).execute
diff --git a/db/migrate/20150406133311_add_invite_data_to_member.rb b/db/migrate/20150406133311_add_invite_data_to_member.rb
index 3452fd45c4f..5d3e856ddce 100644
--- a/db/migrate/20150406133311_add_invite_data_to_member.rb
+++ b/db/migrate/20150406133311_add_invite_data_to_member.rb
@@ -1,5 +1,5 @@
class AddInviteDataToMember < ActiveRecord::Migration
- def change
+ def up
add_column :members, :created_by_id, :integer
add_column :members, :invite_email, :string
add_column :members, :invite_token, :string
@@ -9,4 +9,15 @@ class AddInviteDataToMember < ActiveRecord::Migration
add_index :members, :invite_token, unique: true
end
+
+ def down
+ remove_index :members, :invite_token
+
+ change_column :members, :user_id, :integer, null: false
+
+ remove_column :members, :invite_accepted_at
+ remove_column :members, :invite_token
+ remove_column :members, :invite_email
+ remove_column :members, :created_by_id
+ end
end
diff --git a/db/migrate/20150417122318_remove_import_data_from_project.rb b/db/migrate/20150417122318_remove_import_data_from_project.rb
index c275b49d228..46cf63593c9 100644
--- a/db/migrate/20150417122318_remove_import_data_from_project.rb
+++ b/db/migrate/20150417122318_remove_import_data_from_project.rb
@@ -1,5 +1,9 @@
class RemoveImportDataFromProject < ActiveRecord::Migration
- def change
+ def up
remove_column :projects, :import_data
end
+
+ def down
+ add_column :projects, :import_data, :text
+ end
end
diff --git a/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb b/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
index 51237354d9f..8f1b0cc8935 100644
--- a/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
+++ b/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
@@ -1,7 +1,11 @@
class AddDefaultSnippetVisibilityToAppSettings < ActiveRecord::Migration
- def change
+ def up
add_column :application_settings, :default_snippet_visibility, :integer
visibility = Settings.gitlab.default_projects_features['visibility_level']
execute("update application_settings set default_snippet_visibility = #{visibility}")
end
+
+ def down
+ remove_column :application_settings, :default_snippet_visibility
+ end
end
diff --git a/db/migrate/20150516060434_add_note_events_to_web_hooks.rb b/db/migrate/20150516060434_add_note_events_to_web_hooks.rb
new file mode 100644
index 00000000000..0097587b4f6
--- /dev/null
+++ b/db/migrate/20150516060434_add_note_events_to_web_hooks.rb
@@ -0,0 +1,9 @@
+class AddNoteEventsToWebHooks < ActiveRecord::Migration
+ def up
+ add_column :web_hooks, :note_events, :boolean, default: false, null: false
+ end
+
+ def down
+ remove_column :web_hooks, :note_events, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f7581eaf7fb..1ab91256406 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: 20150509180749) do
+ActiveRecord::Schema.define(version: 20150516060434) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -533,6 +533,7 @@ ActiveRecord::Schema.define(version: 20150509180749) do
t.boolean "issues_events", default: false, null: false
t.boolean "merge_requests_events", default: false, null: false
t.boolean "tag_push_events", default: false
+ t.boolean "note_events", default: false, null: false
end
add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree
diff --git a/doc/development/README.md b/doc/development/README.md
index 16df0b40c47..6bc8e1888db 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -7,3 +7,4 @@
- [Sidekiq debugging](sidekiq_debugging.md)
- [UI guide](ui_guide.md) for building GitLab with existing css styles and elements
- [Migration Style Guide](migration_style_guide.md) for creating safe migrations
+- [How to dump production data to staging](dump_db.md)
diff --git a/doc/development/db_dump.md b/doc/development/db_dump.md
new file mode 100644
index 00000000000..4ad3bd534e0
--- /dev/null
+++ b/doc/development/db_dump.md
@@ -0,0 +1,45 @@
+# Importing a database dump into a staging enviroment
+
+Sometimes it is useful to import the database from a production environment
+into a staging environment for testing. The procedure below assumes you have
+SSH+sudo access to both the production environment and the staging VM.
+
+On the staging VM, add the following line to `/etc/gitlab/gitlab.rb` to speed up
+large database imports.
+
+```
+# On STAGING
+echo "postgresql['checkpoint_segments'] = 64" | sudo tee -a /etc/gitlab/gitlab.rb
+sudo touch /etc/gitlab/skip-auto-migrations
+sudo gitlab-ctl reconfigure
+```
+
+Next, we let the production environment stream a compressed SQL dump to our
+local machine via SSH, and redirect this stream to a psql client on the staging
+VM.
+
+```
+# On LOCAL MACHINE
+ssh -C gitlab.example.com sudo -u gitlab-psql /opt/gitlab/embedded/bin/pg_dump -Cc gitlabhq_production |\
+ ssh -C staging-vm sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -d template1
+```
+
+## Recreating directory structure
+
+If you need to re-create some directory structure on the staging server you can
+use this procedure.
+
+First, on the production server, create a list of directories you want to
+re-create.
+
+```
+# On PRODUCTION
+(umask 077; sudo find /var/opt/gitlab/git-data/repositories -maxdepth 1 -type d -print0 > directories.txt)
+```
+
+Copy `directories.txt` to the staging server and create the directories there.
+
+```
+# On STAGING
+sudo -u git xargs -0 mkdir -p < directories.txt
+```
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 30c29084e34..9c7f723c06d 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -66,16 +66,26 @@ It is not reasonable to italicize just _part_ of a word, especially when you're
perform_complicated_task
do_this_and_do_that_and_another_thing
-perform_complicated_task
+perform_complicated_task
do_this_and_do_that_and_another_thing
## URL auto-linking
-GFM will autolink standard URLs you copy and paste into your text. So if you want to link to a URL (instead of a textural link), you can simply put the URL in verbatim and it will be turned into a link to that URL.
-
- http://www.google.com
-
-http://www.google.com
+GFM will autolink almost any URL you copy and paste into your text.
+
+ * http://www.google.com
+ * https://google.com/
+ * ftp://ftp.us.debian.org/debian/
+ * smb://foo/bar/baz
+ * irc://irc.freenode.net/gitlab
+ * http://localhost:3000
+
+* http://www.google.com
+* https://google.com/
+* ftp://ftp.us.debian.org/debian/
+* smb://foo/bar/baz
+* irc://irc.freenode.net/gitlab
+* http://localhost:3000
## Code and Syntax Highlighting
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index bca4fcfb404..ae2d465e0c1 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -299,3 +299,7 @@ Example: LVM snapshots + rsync
If you are running GitLab on a virtualized server you can possibly also create VM snapshots of the entire GitLab server.
It is not uncommon however for a VM snapshot to require you to power down the server, so this approach is probably of limited practical use.
+
+### Note
+This documentation is for GitLab CE.
+We backup GitLab.com and make sure your data is secure, but you can't use these methods to export / backup your data yourself from GitLab.com. \ No newline at end of file
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 5dd495718b0..eb97f3cd7f6 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -9,7 +9,8 @@ The new release manager should create overall issue to track the progress.
## Release Manager
-A release manager is selected that coordinates all releases the coming month, including the patch releases for previous releases.
+A release manager is selected that coordinates all releases the coming month,
+including the patch releases for previous releases.
The release manager has to make sure all the steps below are done and delegated where necessary.
This person should also make sure this document is kept up to date and issues are created and updated.
@@ -93,6 +94,8 @@ There are three changelogs that need to be updated: CE, EE and CI.
Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version, usually X.X.X.pre.
+On creating the stable branches, notify the core team and developers.
+
## QA
Create issue on dev.gitlab.org `gitlab` repository, named "GitLab X.X QA" in order to keep track of the progress.
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index d140f3a457a..73717ffc7d6 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -140,6 +140,285 @@ X-Gitlab-Event: Issue Hook
}
}
```
+## Comment events
+
+Triggered when a new comment is made on commits, merge requests, issues, and code snippets.
+The note data will be stored in `object_attributes` (e.g. `note`, `noteable_type`). The
+payload will also include information about the target of the comment. For example,
+a comment on a issue will include the specific issue information under the `issue` key.
+Valid target types:
+
+1. `commit`
+2. `merge_request`
+3. `issue`
+4. `snippet`
+
+### Comment on commit
+
+**Request header**:
+
+```
+X-Gitlab-Event: Note Hook
+```
+
+**Request body:**
+
+```json
+{
+ "object_kind": "note",
+ "user": {
+ "name": "Adminstrator",
+ "username": "root",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ },
+ "project_id": 5,
+ "repository": {
+ "name": "Gitlab Test",
+ "url": "http://localhost/gitlab-org/gitlab-test.git",
+ "description": "Aut reprehenderit ut est.",
+ "homepage": "http://example.com/gitlab-org/gitlab-test"
+ },
+ "object_attributes": {
+ "id": 1243,
+ "note": "This is a commit comment. How does this work?",
+ "noteable_type": "Commit",
+ "author_id": 1,
+ "created_at": "2015-05-17 18:08:09 UTC",
+ "updated_at": "2015-05-17 18:08:09 UTC",
+ "project_id": 5,
+ "attachment":null,
+ "line_code": "bec9703f7a456cd2b4ab5fb3220ae016e3e394e3_0_1",
+ "commit_id": "cfe32cf61b73a0d5e9f13e774abde7ff789b1660",
+ "noteable_id": null,
+ "system": false,
+ "st_diff": {
+ "diff": "--- /dev/null\n+++ b/six\n@@ -0,0 +1 @@\n+Subproject commit 409f37c4f05865e4fb208c771485f211a22c4c2d\n",
+ "new_path": "six",
+ "old_path": "six",
+ "a_mode": "0",
+ "b_mode": "160000",
+ "new_file": true,
+ "renamed_file": false,
+ "deleted_file": false
+ },
+ "url": "http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660#note_1243"
+ },
+ "commit": {
+ "id": "cfe32cf61b73a0d5e9f13e774abde7ff789b1660",
+ "message": "Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "timestamp": "2014-02-27T10:06:20+02:00",
+ "url": "http://example.com/gitlab-org/gitlab-test/commit/cfe32cf61b73a0d5e9f13e774abde7ff789b1660",
+ "author": {
+ "name": "Dmitriy Zaporozhets",
+ "email": "dmitriy.zaporozhets@gmail.com"
+ }
+ }
+}
+```
+
+### Comment on merge request
+
+**Request header**:
+
+```
+X-Gitlab-Event: Note Hook
+```
+
+**Request body:**
+
+```json
+{
+ "object_kind": "note",
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ },
+ "project_id": 5,
+ "repository": {
+ "name": "Gitlab Test",
+ "url": "http://example.com/gitlab-org/gitlab-test.git",
+ "description": "Aut reprehenderit ut est.",
+ "homepage": "http://example.com/gitlab-org/gitlab-test"
+ },
+ "object_attributes": {
+ "id": 1244,
+ "note": "This MR needs work.",
+ "noteable_type": "MergeRequest",
+ "author_id": 1,
+ "created_at": "2015-05-17 18:21:36 UTC",
+ "updated_at": "2015-05-17 18:21:36 UTC",
+ "project_id": 5,
+ "attachment": null,
+ "line_code": null,
+ "commit_id": "",
+ "noteable_id": 7,
+ "system": false,
+ "st_diff": null,
+ "url": "http://example.com/gitlab-org/gitlab-test/merge_requests/1#note_1244"
+ },
+ "merge_request": {
+ "id": 7,
+ "target_branch": "markdown",
+ "source_branch": "master",
+ "source_project_id": 5,
+ "author_id": 8,
+ "assignee_id": 28,
+ "title": "Tempora et eos debitis quae laborum et.",
+ "created_at": "2015-03-01 20:12:53 UTC",
+ "updated_at": "2015-03-21 18:27:27 UTC",
+ "milestone_id": 11,
+ "state": "opened",
+ "merge_status": "cannot_be_merged",
+ "target_project_id": 5,
+ "iid": 1,
+ "description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.",
+ "position": 0,
+ "locked_at": null,
+ "source": {
+ "name": "Gitlab Test",
+ "ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
+ "http_url": "http://example.com/gitlab-org/gitlab-test.git",
+ "namespace": "Gitlab Org",
+ "visibility_level": 10
+ },
+ "target": {
+ "name": "Gitlab Test",
+ "ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
+ "http_url": "http://example.com/gitlab-org/gitlab-test.git",
+ "namespace": "Gitlab Org",
+ "visibility_level": 10
+ },
+ "last_commit": {
+ "id": "562e173be03b8ff2efb05345d12df18815438a4b",
+ "message": "Merge branch 'another-branch' into 'master'\n\nCheck in this test\n",
+ "timestamp": "2015-04-08T21: 00:25-07:00",
+ "url": "http://example.com/gitlab-org/gitlab-test/commit/562e173be03b8ff2efb05345d12df18815438a4b",
+ "author": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ }
+ }
+ }
+}
+```
+
+### Comment on issue
+
+**Request header**:
+
+```
+X-Gitlab-Event: Note Hook
+```
+
+**Request body:**
+
+```json
+{
+ "object_kind": "note",
+ "user": {
+ "name": "Adminstrator",
+ "username": "root",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ },
+ "project_id": 5,
+ "repository": {
+ "name": "Gitlab Test",
+ "url": "http://example.com/gitlab-org/gitlab-test.git",
+ "description": "Aut reprehenderit ut est.",
+ "homepage": "http://example.com/gitlab-org/gitlab-test"
+ },
+ "object_attributes": {
+ "id": 1241,
+ "note": "Hello world",
+ "noteable_type": "Issue",
+ "author_id": 1,
+ "created_at": "2015-05-17 17:06:40 UTC",
+ "updated_at": "2015-05-17 17:06:40 UTC",
+ "project_id": 5,
+ "attachment": null,
+ "line_code": null,
+ "commit_id": "",
+ "noteable_id": 92,
+ "system": false,
+ "st_diff": null,
+ "url": "http://example.com/gitlab-org/gitlab-test/issues/17#note_1241"
+ },
+ "issue": {
+ "id": 92,
+ "title": "test",
+ "assignee_id": null,
+ "author_id": 1,
+ "project_id": 5,
+ "created_at": "2015-04-12 14:53:17 UTC",
+ "updated_at": "2015-04-26 08:28:42 UTC",
+ "position": 0,
+ "branch_name": null,
+ "description": "test",
+ "milestone_id": null,
+ "state": "closed",
+ "iid": 17
+ }
+}
+```
+
+### Comment on code snippet
+
+
+**Request header**:
+
+```
+X-Gitlab-Event: Note Hook
+```
+
+**Request body:**
+
+```
+{
+ "object_kind": "note",
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ },
+ "project_id": 5,
+ "repository": {
+ "name": "Gitlab Test",
+ "url": "http://example.com/gitlab-org/gitlab-test.git",
+ "description": "Aut reprehenderit ut est.",
+ "homepage": "http://example.com/gitlab-org/gitlab-test"
+ },
+ "object_attributes": {
+ "id": 1245,
+ "note": "Is this snippet doing what it's supposed to be doing?",
+ "noteable_type": "Snippet",
+ "author_id": 1,
+ "created_at": "2015-05-17 18:35:50 UTC",
+ "updated_at": "2015-05-17 18:35:50 UTC",
+ "project_id": 5,
+ "attachment": null,
+ "line_code": null,
+ "commit_id": "",
+ "noteable_id": 53,
+ "system": false,
+ "st_diff": null,
+ "url": "http://example.com/gitlab-org/gitlab-test/snippets/53#note_1245"
+ },
+ "snippet": {
+ "id": 53,
+ "title": "test",
+ "content": "puts 'Hello world'",
+ "author_id": 1,
+ "project_id": 5,
+ "created_at": "2015-04-09 02:40:38 UTC",
+ "updated_at": "2015-04-09 02:40:38 UTC",
+ "file_name": "test.rb",
+ "expires_at": null,
+ "type": "ProjectSnippet",
+ "visibility_level": 0
+ }
+}
+```
## Merge request events
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 7e996dc47d4..0fca68f364e 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -12,4 +12,6 @@
- [Project importing from GitHub to GitLab](import_projects_from_github.md)
- [Project importing from GitLab.com to your private GitLab instance](import_projects_from_gitlab_com.md)
- [Protected branches](protected_branches.md)
-- [Web Editor](web_editor.md)
+- [Change your time zone](timezone.md)
+- [Keyboard shortcuts](shortcuts.md)
+- [Web Editor](web_editor.md) \ No newline at end of file
diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md
new file mode 100644
index 00000000000..ffcb832cdd7
--- /dev/null
+++ b/doc/workflow/shortcuts.md
@@ -0,0 +1,5 @@
+# GitLab keyboard shortcuts
+
+You can see GitLab's keyboard shortcuts by using 'shift + ?'
+
+![Shortcuts](shortcuts.png) \ No newline at end of file
diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png
new file mode 100644
index 00000000000..68756ed1f98
--- /dev/null
+++ b/doc/workflow/shortcuts.png
Binary files differ
diff --git a/doc/workflow/timezone.md b/doc/workflow/timezone.md
new file mode 100644
index 00000000000..8540ccfcabb
--- /dev/null
+++ b/doc/workflow/timezone.md
@@ -0,0 +1,18 @@
+# Changing your time zone
+
+GitLab defaults its time zone to UTC. It has a global timezone configuration parameter in /etc/gitlab/gitlab.rb
+
+To update, add the time zone that best applies to your location. Here are two examples:
+```
+gitlab_rails['time_zone'] = 'America/New_York'
+```
+or
+```
+gitlab_rails['time_zone'] = 'Europe/Brussels'
+```
+
+After you added this field, reconfigure and restart:
+```
+gitlab-ctl reconfigure
+gitlab-ctl restart
+``` \ No newline at end of file
diff --git a/doc_styleguide.md b/doc_styleguide.md
new file mode 100644
index 00000000000..670af765f3a
--- /dev/null
+++ b/doc_styleguide.md
@@ -0,0 +1,22 @@
+# Documentation styleguide
+
+This styleguide recommends best practices to improve documentation and to keep it organized and easy to find.
+
+## Text
+
+* Make sure that the documentation is added in the correct directory and that there's a link to it somewhere useful.
+
+* Add only one H1 or title in each document, by adding '#' at the begining of it (when using markdown). For subtitles, use '##', '###' and so on.
+
+* Do not duplicate information.
+
+* Be brief and clear.
+
+
+## When adding images to a document
+
+* Create a directory to store the images with the specific name of the document where the images belong. It could be in the same directory where the .md document that you're working on is located.
+
+* Images should have a specific, non-generic name that will differentiate them.
+
+* Keep all file names in lower case. \ No newline at end of file
diff --git a/docker/single/Dockerfile b/docker/single/Dockerfile
index 89224572534..a6cbf131237 100644
--- a/docker/single/Dockerfile
+++ b/docker/single/Dockerfile
@@ -28,6 +28,7 @@ EXPOSE 80 22
# Copy assets
COPY assets/wrapper /usr/local/bin/
+COPY assets/gitlab.rb /etc/gitlab/
# Wrapper to handle signal, trigger runit and reconfigure GitLab
CMD ["/usr/local/bin/wrapper"]
diff --git a/docker/single/assets/gitlab.rb b/docker/single/assets/gitlab.rb
new file mode 100644
index 00000000000..ef84e7832d6
--- /dev/null
+++ b/docker/single/assets/gitlab.rb
@@ -0,0 +1,37 @@
+# External URL should be your Docker instance.
+# By default, GitLab will use the Docker container hostname.
+# Always use port 80 here to force the internal nginx to bind port 80,
+# even if you intend to use another port in Docker.
+# external_url "http://192.168.59.103/"
+
+# Prevent Postgres from trying to allocate 25% of total memory
+postgresql['shared_buffers'] = '1MB'
+
+# Configure GitLab to redirect PostgreSQL logs to the data volume
+postgresql['log_directory'] = '/var/log/gitlab/postgresql'
+
+# Some configuration of GitLab
+# You can find more at https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#configuration
+gitlab_rails['gitlab_email_from'] = 'gitlab@example.com'
+gitlab_rails['gitlab_support_email'] = 'support@example.com'
+gitlab_rails['time_zone'] = 'Europe/Paris'
+
+# SMTP settings
+# You must use an external server, the Docker container does not install an SMTP server
+gitlab_rails['smtp_enable'] = true
+gitlab_rails['smtp_address'] = "smtp.example.com"
+gitlab_rails['smtp_port'] = 587
+gitlab_rails['smtp_user_name'] = "user"
+gitlab_rails['smtp_password'] = "password"
+gitlab_rails['smtp_domain'] = "example.com"
+gitlab_rails['smtp_authentication'] = "plain"
+gitlab_rails['smtp_enable_starttls_auto'] = true
+
+# Enable LDAP authentication
+# gitlab_rails['ldap_enabled'] = true
+# gitlab_rails['ldap_host'] = 'ldap.example.com'
+# gitlab_rails['ldap_port'] = 389
+# gitlab_rails['ldap_method'] = 'plain' # 'ssl' or 'plain'
+# gitlab_rails['ldap_allow_username_or_email_login'] = false
+# gitlab_rails['ldap_uid'] = 'uid'
+# gitlab_rails['ldap_base'] = 'ou=users,dc=example,dc=com'
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index d9fbb875c28..ad1160e3343 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -38,3 +38,15 @@ Feature: Project Forked Merge Requests
Given I visit project "Forked Shop" merge requests page
And I click link "New Merge Request"
Then the target repository should be the original repository
+
+ @javascript
+ Scenario: I see the users in the target project for a new merge request
+ Given I logout
+ And I sign in as an admin
+ And I have a project forked off of "Shop" called "Forked Shop"
+ Then I visit project "Forked Shop" merge requests page
+ And I click link "New Merge Request"
+ And I fill out a "Merge Request On Forked Project" merge request
+ When I click "Assign to" dropdown"
+ Then I should see the target project ID in the input selector
+ And I should see the users from the target project ID
diff --git a/features/project/project.feature b/features/project/project.feature
index ae28312a69a..ef11bceed11 100644
--- a/features/project/project.feature
+++ b/features/project/project.feature
@@ -62,3 +62,9 @@ Feature: Project
And I add project tags
And I save project
Then I should see project tags
+
+ Scenario: I should not see "New Issue" or "New Merge Request" buttons
+ Given I disable issues and merge requests in project
+ When I visit project "Shop" page
+ Then I should not see "New Issue" button
+ And I should not see "New Merge Request" button
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 977cd609a11..7a70f348754 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -69,6 +69,11 @@ Feature: Project Wiki
And I click on the "Pages" button
Then I should see non-escaped link in the pages list
+ @javascript @focus
+ Scenario: Creating an invalid new page
+ Given I create a New page with an invalid name
+ Then I should see an error message
+
@javascript
Scenario: Edit Wiki page that has a path
Given I create a New page with paths
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index 94d21d28a0c..ebfa102cee5 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -128,6 +128,21 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
page.should have_select("merge_request_target_project_id", selected: @project.path_with_namespace)
end
+ step 'I click "Assign to" dropdown"' do
+ first('.ajax-users-select').click
+ end
+
+ step 'I should see the target project ID in the input selector' do
+ expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]")
+ end
+
+ step 'I should see the users from the target project ID' do
+ expect(page).to have_selector('.user-result', visible: true, count: 2)
+ users = page.all('.user-name')
+ users[0].text.should == 'Unassigned'
+ users[1].text.should == @project.users.first.name
+ end
+
# Verify a link is generated against the correct project
def verify_commit_link(container_div, container_project)
# This should force a wait for the javascript to execute
diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb
index 4b135202593..d06905285fe 100644
--- a/features/steps/project/hooks.rb
+++ b/features/steps/project/hooks.rb
@@ -23,7 +23,7 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps
end
step 'I submit new hook' do
- @url = Faker::Internet.uri("http")
+ @url = FFaker::Internet.uri("http")
fill_in "hook_url", with: @url
expect { click_button "Add Web Hook" }.to change(ProjectHook, :count).by(1)
end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 00706ab30e9..93fea693f89 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -102,4 +102,12 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should see project tags' do
expect(find_field('Tags').value).to eq 'tag1, tag2'
end
+
+ step 'I should not see "New Issue" button' do
+ page.should_not have_link 'New Issue'
+ end
+
+ step 'I should not see "New Merge Request" button' do
+ page.should_not have_link 'New Merge Request'
+ end
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index 717132da45d..58cb0ceb3f1 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -133,6 +133,16 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
current_path.should include 'one/two/three'
end
+ step 'I create a New page with an invalid name' do
+ click_on 'New Page'
+ fill_in 'Page slug', with: 'invalid name'
+ click_on 'Build'
+ end
+
+ step 'I should see an error message' do
+ expect(page).to have_content "The page slug is invalid"
+ end
+
step 'I should see non-escaped link in the pages list' do
page.should have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three']")
end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index b60ac5e3423..24136fe421c 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -14,6 +14,12 @@ module SharedProject
@project.team << [@user, :master]
end
+ step 'I disable issues and merge requests in project' do
+ @project.issues_enabled = false
+ @project.merge_requests_enabled = false
+ @project.save
+ end
+
# Add another user to project "Shop"
step 'I add a user to project "Shop"' do
@project = Project.find_by(name: "Shop")
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 85e9081680d..1ebf9a1f022 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -243,7 +243,7 @@ module API
end
def secret_token
- File.read(Rails.root.join('.gitlab_shell_secret')).chomp
+ File.read(Gitlab.config.gitlab_shell.secret_file).chomp
end
def handle_member_errors(errors)
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index be9850367b9..ad4d2e65dfd 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -43,7 +43,8 @@ module API
:push_events,
:issues_events,
:merge_requests_events,
- :tag_push_events
+ :tag_push_events,
+ :note_events
]
@hook = user_project.hooks.new(attrs)
@@ -73,7 +74,8 @@ module API
:push_events,
:issues_events,
:merge_requests_events,
- :tag_push_events
+ :tag_push_events,
+ :note_events
]
if @hook.update_attributes attrs
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
new file mode 100644
index 00000000000..bf33e5b1b1e
--- /dev/null
+++ b/lib/gitlab/asciidoc.rb
@@ -0,0 +1,60 @@
+require 'asciidoctor'
+require 'html/pipeline'
+
+module Gitlab
+ # Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
+ # the resulting HTML through HTML pipeline filters.
+ module Asciidoc
+
+ # Provide autoload paths for filters to prevent a circular dependency error
+ autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
+
+ DEFAULT_ADOC_ATTRS = [
+ 'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab',
+ 'env-gitlab', 'source-highlighter=html-pipeline'
+ ].freeze
+
+ # Public: Converts the provided Asciidoc markup into HTML.
+ #
+ # input - the source text in Asciidoc format
+ # context - a Hash with the template context:
+ # :commit
+ # :project
+ # :project_wiki
+ # :requested_path
+ # :ref
+ # asciidoc_opts - a Hash of options to pass to the Asciidoctor converter
+ # html_opts - a Hash of options for HTML output:
+ # :xhtml - output XHTML instead of HTML
+ #
+ def self.render(input, context, asciidoc_opts = {}, html_opts = {})
+ asciidoc_opts = asciidoc_opts.reverse_merge(
+ safe: :secure,
+ backend: html_opts[:xhtml] ? :xhtml5 : :html5,
+ attributes: []
+ )
+ asciidoc_opts[:attributes].unshift(*DEFAULT_ADOC_ATTRS)
+
+ html = ::Asciidoctor.convert(input, asciidoc_opts)
+
+ if context[:project]
+ result = HTML::Pipeline.new(filters).call(html, context)
+
+ save_opts = html_opts[:xhtml] ?
+ Nokogiri::XML::Node::SaveOptions::AS_XHTML : 0
+
+ html = result[:output].to_html(save_with: save_opts)
+ end
+
+ html.html_safe
+ end
+
+ private
+
+ def self.filters
+ [
+ Gitlab::Markdown::RelativeLinkFilter
+ ]
+ end
+ end
+end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 050b5ba29dd..03cef30c97d 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,4 +1,3 @@
-require_relative 'rack_attack_helpers'
require_relative 'shell_env'
module Grack
diff --git a/lib/gitlab/backend/rack_attack_helpers.rb b/lib/gitlab/backend/rack_attack_helpers.rb
deleted file mode 100644
index 8538f3f6eca..00000000000
--- a/lib/gitlab/backend/rack_attack_helpers.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# rack-attack v4.2.0 doesn't yet support clearing of keys.
-# Taken from https://github.com/kickstarter/rack-attack/issues/113
-class Rack::Attack::Allow2Ban
- def self.reset(discriminator, options)
- findtime = options[:findtime] or raise ArgumentError, "Must pass findtime option"
-
- cache.reset_count("#{key_prefix}:count:#{discriminator}", findtime)
- cache.delete("#{key_prefix}:ban:#{discriminator}")
- end
-end
-
-class Rack::Attack::Cache
- def reset_count(unprefixed_key, period)
- epoch_time = Time.now.to_i
- # Add 1 to expires_in to avoid timing error: http://git.io/i1PHXA
- expires_in = period - (epoch_time % period) + 1
- key = "#{(epoch_time / period).to_i}:#{unprefixed_key}"
- delete(key)
- end
-
- def delete(unprefixed_key)
- store.delete("#{prefix}:#{unprefixed_key}")
- end
-end
-
-class Rack::Attack::StoreProxy::RedisStoreProxy
- def delete(key, options={})
- self.del(key)
- rescue Redis::BaseError
- end
-end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 133010adcaf..c0fb22e7f36 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -1,5 +1,4 @@
require 'html/pipeline'
-require 'task_list/filter'
module Gitlab
# Custom parser for GitLab-flavored Markdown
@@ -19,6 +18,7 @@ module Gitlab
autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter'
autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter'
autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter'
+ autoload :TaskListFilter, 'gitlab/markdown/task_list_filter'
autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter'
# Public: Parse the provided text with GitLab-Flavored Markdown
@@ -113,7 +113,7 @@ module Gitlab
Gitlab::Markdown::CommitReferenceFilter,
Gitlab::Markdown::LabelReferenceFilter,
- TaskList::Filter
+ Gitlab::Markdown::TaskListFilter
]
end
end
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index a357f28458d..1a77becee89 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -84,11 +84,11 @@ module Gitlab
#
# Returns a Hash.
def label_params(id, name)
- if id > 0
- { id: id }
- else
+ if name
# TODO (rspeicher): Don't strip single quotes if we decide to only use double quotes for surrounding.
{ name: name.tr('\'"', '') }
+ else
+ { id: id }
end
end
end
diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb
index 6f33155badf..88781fea0c8 100644
--- a/lib/gitlab/markdown/sanitization_filter.rb
+++ b/lib/gitlab/markdown/sanitization_filter.rb
@@ -8,28 +8,33 @@ module Gitlab
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
class SanitizationFilter < HTML::Pipeline::SanitizationFilter
def whitelist
- whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST
+ whitelist = super
- # Allow code highlighting
- whitelist[:attributes]['pre'] = %w(class)
- whitelist[:attributes]['span'] = %w(class)
+ # Only push these customizations once
+ unless customized?(whitelist[:transformers])
+ # Allow code highlighting
+ whitelist[:attributes]['pre'] = %w(class)
+ whitelist[:attributes]['span'] = %w(class)
- # Allow table alignment
- whitelist[:attributes]['th'] = %w(style)
- whitelist[:attributes]['td'] = %w(style)
+ # Allow table alignment
+ whitelist[:attributes]['th'] = %w(style)
+ whitelist[:attributes]['td'] = %w(style)
- # Allow span elements
- whitelist[:elements].push('span')
+ # Allow span elements
+ whitelist[:elements].push('span')
- # Remove `rel` attribute from `a` elements
- whitelist[:transformers].push(remove_rel)
+ # Remove `rel` attribute from `a` elements
+ whitelist[:transformers].push(remove_rel)
- # Remove `class` attribute from non-highlight spans
- whitelist[:transformers].push(clean_spans)
+ # Remove `class` attribute from non-highlight spans
+ whitelist[:transformers].push(clean_spans)
+ end
whitelist
end
+ private
+
def remove_rel
lambda do |env|
if env[:node_name] == 'a'
@@ -48,6 +53,10 @@ module Gitlab
end
end
end
+
+ def customized?(transformers)
+ transformers.last.source_location[0] == __FILE__
+ end
end
end
end
diff --git a/lib/gitlab/markdown/task_list_filter.rb b/lib/gitlab/markdown/task_list_filter.rb
new file mode 100644
index 00000000000..c6eb2e2bf6d
--- /dev/null
+++ b/lib/gitlab/markdown/task_list_filter.rb
@@ -0,0 +1,23 @@
+require 'task_list/filter'
+
+module Gitlab
+ module Markdown
+ # Work around a bug in the default TaskList::Filter that adds a `task-list`
+ # class to every list element, regardless of whether or not it contains a
+ # task list.
+ #
+ # This is a (hopefully) temporary fix, pending a new release of the
+ # task_list gem.
+ #
+ # See https://github.com/github/task_list/pull/60
+ class TaskListFilter < TaskList::Filter
+ def add_css_class(node, *new_class_names)
+ if new_class_names.include?('task-list')
+ super if node.children.any? { |c| c['class'] == 'task-list-item' }
+ else
+ super
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown_helper.rb b/lib/gitlab/markup_helper.rb
index 5e3cfc0585b..f99be969d3e 100644
--- a/lib/gitlab/markdown_helper.rb
+++ b/lib/gitlab/markup_helper.rb
@@ -1,5 +1,5 @@
module Gitlab
- module MarkdownHelper
+ module MarkupHelper
module_function
# Public: Determines if a given filename is compatible with GitHub::Markup.
@@ -8,8 +8,10 @@ module Gitlab
#
# Returns boolean
def markup?(filename)
- filename.downcase.end_with?(*%w(.textile .rdoc .org .creole .wiki
- .mediawiki .rst .adoc .asciidoc .asc))
+ gitlab_markdown?(filename) ||
+ asciidoc?(filename) ||
+ filename.downcase.end_with?(*%w(.textile .rdoc .org .creole .wiki
+ .mediawiki .rst))
end
# Public: Determines if a given filename is compatible with
@@ -22,8 +24,17 @@ module Gitlab
filename.downcase.end_with?(*%w(.mdown .md .markdown))
end
+ # Public: Determines if the given filename has AsciiDoc extension.
+ #
+ # filename - Filename string to check
+ #
+ # Returns boolean
+ def asciidoc?(filename)
+ filename.downcase.end_with?(*%w(.adoc .ad .asciidoc))
+ end
+
def previewable?(filename)
- gitlab_markdown?(filename) || markup?(filename)
+ markup?(filename)
end
end
end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 75a3dfe37c3..06245374bc8 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -51,11 +51,23 @@ module Gitlab
end
def issues
- Issue.where(project_id: limit_project_ids).full_search(query).order('updated_at DESC')
+ issues = Issue.where(project_id: limit_project_ids)
+ if query =~ /#(\d+)\z/
+ issues = issues.where(iid: $1)
+ else
+ issues = issues.full_search(query)
+ end
+ issues.order('updated_at DESC')
end
def merge_requests
- MergeRequest.in_projects(limit_project_ids).full_search(query).order('updated_at DESC')
+ merge_requests = MergeRequest.in_projects(limit_project_ids)
+ if query =~ /[#!](\d+)\z/
+ merge_requests = merge_requests.where(iid: $1)
+ else
+ merge_requests = merge_requests.full_search(query)
+ end
+ merge_requests.order('updated_at DESC')
end
def default_scope
diff --git a/spec/factories.rb b/spec/factories.rb
index 26e8a795fa4..b7b2a1dac8e 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -2,23 +2,23 @@ include ActionDispatch::TestProcess
FactoryGirl.define do
sequence :sentence, aliases: [:title, :content] do
- Faker::Lorem.sentence
+ FFaker::Lorem.sentence
end
sequence :name do
- Faker::Name.name
+ FFaker::Name.name
end
sequence :file_name do
- Faker::Internet.user_name
+ FFaker::Internet.user_name
end
- sequence(:url) { Faker::Internet.uri('http') }
+ sequence(:url) { FFaker::Internet.uri('http') }
factory :user, aliases: [:author, :assignee, :owner, :creator] do
- email { Faker::Internet.email }
+ email { FFaker::Internet.email }
name
- sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" }
+ sequence(:username) { |n| "#{FFaker::Internet.user_name}#{n}" }
password "12345678"
confirmed_at { Time.now }
confirmation_token { nil }
@@ -122,12 +122,12 @@ FactoryGirl.define do
factory :email do
user
email do
- Faker::Internet.email('alias')
+ FFaker::Internet.email('alias')
end
factory :another_email do
email do
- Faker::Internet.email('another.alias')
+ FFaker::Internet.email('another.alias')
end
end
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index 25862614d28..00906e8087a 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -26,7 +26,7 @@ describe "Admin::Hooks", feature: true do
describe "New Hook" do
before do
- @url = Faker::Internet.uri("http")
+ @url = FFaker::Internet.uri("http")
visit admin_hooks_path
fill_in "hook_url", with: @url
expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1)
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index d4cf6540080..3307ac776fc 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -261,12 +261,26 @@ describe ApplicationHelper do
end
end
- describe 'markup_render' do
+ describe 'render_markup' do
let(:content) { 'Noël' }
it 'should preserve encoding' do
expect(content.encoding.name).to eq('UTF-8')
expect(render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
end
+
+ it "should delegate to #markdown when file name corresponds to Markdown" do
+ expect(self).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
+ expect(self).to receive(:markdown).and_return('NOEL')
+
+ expect(render_markup('foo.md', content)).to eq('NOEL')
+ end
+
+ it "should delegate to #asciidoc when file name corresponds to AsciiDoc" do
+ expect(self).to receive(:asciidoc?).with('foo.adoc').and_return(true)
+ expect(self).to receive(:asciidoc).and_return('NOEL')
+
+ expect(render_markup('foo.adoc', content)).to eq('NOEL')
+ end
end
end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index dd4c1d645e2..e0be2df0e5e 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -106,6 +106,16 @@ describe DiffHelper do
end
end
+ describe 'unfold_class' do
+ it 'returns empty on false' do
+ expect(unfold_class(false)).to eq('')
+ end
+
+ it 'returns a class on true' do
+ expect(unfold_class(true)).to eq('unfold js-unfold')
+ end
+ end
+
describe 'diff_line_content' do
it 'should return non breaking space when line is empty' do
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
new file mode 100644
index 00000000000..7a3e38d7e63
--- /dev/null
+++ b/spec/helpers/emails_helper_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe EmailsHelper do
+ describe 'password_reset_token_valid_time' do
+ def validate_time_string(time_limit, expected_string)
+ Devise.reset_password_within = time_limit
+ expect(password_reset_token_valid_time).to eq(expected_string)
+ end
+
+ context 'when time limit is less than 2 hours' do
+ it 'should display the time in hours using a singular unit' do
+ validate_time_string(1.hour, '1 hour')
+ end
+ end
+
+ context 'when time limit is 2 or more hours' do
+ it 'should display the time in hours using a plural unit' do
+ validate_time_string(2.hours, '2 hours')
+ end
+ end
+
+ context 'when time limit contains fractions of an hour' do
+ it 'should round down to the nearest hour' do
+ validate_time_string(96.minutes, '1 hour')
+ end
+ end
+
+ context 'when time limit is 24 or more hours' do
+ it 'should display the time in days using a singular unit' do
+ validate_time_string(24.hours, '1 day')
+ end
+ end
+
+ context 'when time limit is 2 or more days' do
+ it 'should display the time in days using a plural unit' do
+ validate_time_string(2.days, '2 days')
+ end
+ end
+
+ context 'when time limit contains fractions of a day' do
+ it 'should round down to the nearest day' do
+ validate_time_string(57.hours, '2 days')
+ end
+ end
+ end
+end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 9f3e8cf585e..0d0418f84a7 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -110,6 +110,14 @@ describe GitlabMarkdownHelper do
helper.render_wiki_content(@wiki)
end
+ it "should use Asciidoctor for asciidoc files" do
+ allow(@wiki).to receive(:format).and_return(:asciidoc)
+
+ expect(helper).to receive(:asciidoc).with('wiki content')
+
+ helper.render_wiki_content(@wiki)
+ end
+
it "should use the Gollum renderer for all other file types" do
allow(@wiki).to receive(:format).and_return(:rdoc)
formatted_content_stub = double('formatted_content')
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index 0b7e3b1d11f..0c8d06b7059 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -1,6 +1,70 @@
require 'spec_helper'
describe LabelsHelper do
- it { expect(text_color_for_bg('#EEEEEE')).to eq('#333333') }
- it { expect(text_color_for_bg('#222E2E')).to eq('#FFFFFF') }
+ describe 'link_to_label' do
+ let(:project) { create(:empty_project) }
+ let(:label) { create(:label, project: project) }
+
+ context 'with @project set' do
+ before do
+ @project = project
+ end
+
+ it 'uses the instance variable' do
+ expect(label).not_to receive(:project)
+ link_to_label(label)
+ end
+ end
+
+ context 'without @project set' do
+ it "uses the label's project" do
+ expect(label).to receive(:project).and_return(project)
+ link_to_label(label)
+ end
+ end
+
+ context 'with a named project argument' do
+ it 'uses the provided project' do
+ arg = double('project')
+ expect(arg).to receive(:namespace).and_return('foo')
+ expect(arg).to receive(:to_param).and_return('foo')
+
+ link_to_label(label, project: arg)
+ end
+
+ it 'takes precedence over other types' do
+ @project = project
+ expect(@project).not_to receive(:namespace)
+ expect(label).not_to receive(:project)
+
+ arg = double('project', namespace: 'foo', to_param: 'foo')
+ link_to_label(label, project: arg)
+ end
+ end
+
+ context 'with block' do
+ it 'passes the block to link_to' do
+ link = link_to_label(label) { 'Foo' }
+ expect(link).to match('Foo')
+ end
+ end
+
+ context 'without block' do
+ it 'uses render_colored_label as the link content' do
+ expect(self).to receive(:render_colored_label).
+ with(label).and_return('Foo')
+ expect(link_to_label(label)).to match('Foo')
+ end
+ end
+ end
+
+ describe 'text_color_for_bg' do
+ it 'uses light text on dark backgrounds' do
+ expect(text_color_for_bg('#222E2E')).to eq('#FFFFFF')
+ end
+
+ it 'uses dark text on light backgrounds' do
+ expect(text_color_for_bg('#EEEEEE')).to eq('#333333')
+ end
+ end
end
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
new file mode 100644
index 00000000000..23f83339ec5
--- /dev/null
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+require 'nokogiri'
+
+module Gitlab
+ describe Asciidoc do
+
+ let(:input) { '<b>ascii</b>' }
+ let(:context) { {} }
+ let(:html) { 'H<sub>2</sub>O' }
+
+ context "without project" do
+
+ it "should convert the input using Asciidoctor and default options" do
+ expected_asciidoc_opts = { safe: :secure, backend: :html5,
+ attributes: described_class::DEFAULT_ADOC_ATTRS }
+
+ expect(Asciidoctor).to receive(:convert)
+ .with(input, expected_asciidoc_opts).and_return(html)
+
+ expect( render(input, context) ).to eql html
+ end
+
+ context "with asciidoc_opts" do
+
+ let(:asciidoc_opts) { {safe: :safe, attributes: ['foo']} }
+
+ it "should merge the options with default ones" do
+ expected_asciidoc_opts = { safe: :safe, backend: :html5,
+ attributes: described_class::DEFAULT_ADOC_ATTRS + ['foo'] }
+
+ expect(Asciidoctor).to receive(:convert)
+ .with(input, expected_asciidoc_opts).and_return(html)
+
+ render(input, context, asciidoc_opts)
+ end
+ end
+ end
+
+ context "with project in context" do
+
+ let(:context) { {project: create(:project)} }
+
+ it "should filter converted input via HTML pipeline and return result" do
+ filtered_html = '<b>ASCII</b>'
+
+ allow(Asciidoctor).to receive(:convert).and_return(html)
+ expect_any_instance_of(HTML::Pipeline).to receive(:call)
+ .with(html, context)
+ .and_return(output: Nokogiri::HTML.fragment(filtered_html))
+
+ expect( render('foo', context) ).to eql filtered_html
+ end
+ end
+
+ def render(*args)
+ described_class.render(*args)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index d0aad54f677..42c9946d2a9 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -156,7 +156,7 @@ describe Grack::Auth do
end
expect(attempt_login(true)).to eq(200)
- expect(Rack::Attack::Allow2Ban.send(:banned?, ip)).to eq(nil)
+ expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey
for n in 0..maxretry do
expect(attempt_login(false)).to eq(401)
diff --git a/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb b/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb
deleted file mode 100644
index 2ac496fd669..00000000000
--- a/spec/lib/gitlab/backend/rack_attack_helpers_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require "spec_helper"
-
-describe 'RackAttackHelpers' do
- describe 'reset' do
- let(:discriminator) { 'test-key'}
- let(:maxretry) { 5 }
- let(:period) { 1.minute }
- let(:options) { { findtime: period, bantime: 60, maxretry: maxretry } }
-
- def do_filter
- for i in 1..maxretry - 1 do
- status = Rack::Attack::Allow2Ban.filter(discriminator, options) { true }
- expect(status).to eq(false)
- end
- end
-
- def do_reset
- Rack::Attack::Allow2Ban.reset(discriminator, options)
- end
-
- before do
- do_reset
- end
-
- after do
- do_reset
- end
-
- it 'user is not banned after n - 1 retries' do
- do_filter
- do_reset
- do_filter
- end
- end
-end
diff --git a/spec/lib/gitlab/gitlab_markdown_helper_spec.rb b/spec/lib/gitlab/gitlab_markdown_helper_spec.rb
deleted file mode 100644
index ab613193f41..00000000000
--- a/spec/lib/gitlab/gitlab_markdown_helper_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::MarkdownHelper do
- describe '#markup?' do
- %w(textile rdoc org creole wiki
- mediawiki rst adoc asciidoc asc).each do |type|
- it "returns true for #{type} files" do
- expect(Gitlab::MarkdownHelper.markup?("README.#{type}")).to be_truthy
- end
- end
-
- it 'returns false when given a non-markup filename' do
- expect(Gitlab::MarkdownHelper.markup?('README.rb')).not_to be_truthy
- end
- end
-
- describe '#gitlab_markdown?' do
- %w(mdown md markdown).each do |type|
- it "returns true for #{type} files" do
- expect(Gitlab::MarkdownHelper.gitlab_markdown?("README.#{type}")).to be_truthy
- end
- end
-
- it 'returns false when given a non-markdown filename' do
- expect(Gitlab::MarkdownHelper.gitlab_markdown?('README.rb')).not_to be_truthy
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
index 9f898837466..c4548e7431f 100644
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
@@ -149,5 +149,12 @@ module Gitlab::Markdown
end
end
end
+
+ describe 'edge cases' do
+ it 'gracefully handles non-references matching the pattern' do
+ exp = act = '(format nil "~0f" 3.0) ; 3.0'
+ expect(filter(act).to_html).to eq exp
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/markdown/task_list_filter_spec.rb b/spec/lib/gitlab/markdown/task_list_filter_spec.rb
new file mode 100644
index 00000000000..2a1e1cc5127
--- /dev/null
+++ b/spec/lib/gitlab/markdown/task_list_filter_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+module Gitlab::Markdown
+ describe TaskListFilter do
+ def filter(html, options = {})
+ described_class.call(html, options)
+ end
+
+ it 'does not apply `task-list` class to non-task lists' do
+ exp = act = %(<ul><li>Item</li></ul>)
+ expect(filter(act).to_html).to eq exp
+ end
+ end
+end
diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb
new file mode 100644
index 00000000000..7e716e866b1
--- /dev/null
+++ b/spec/lib/gitlab/markup_helper_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Gitlab::MarkupHelper do
+ describe '#markup?' do
+ %w(textile rdoc org creole wiki
+ mediawiki rst adoc ad asciidoc mdown md markdown).each do |type|
+ it "returns true for #{type} files" do
+ expect(Gitlab::MarkupHelper.markup?("README.#{type}")).to be_truthy
+ end
+ end
+
+ it 'returns false when given a non-markup filename' do
+ expect(Gitlab::MarkupHelper.markup?('README.rb')).not_to be_truthy
+ end
+ end
+
+ describe '#gitlab_markdown?' do
+ %w(mdown md markdown).each do |type|
+ it "returns true for #{type} files" do
+ expect(Gitlab::MarkupHelper.gitlab_markdown?("README.#{type}")).to be_truthy
+ end
+ end
+
+ it 'returns false when given a non-markdown filename' do
+ expect(Gitlab::MarkupHelper.gitlab_markdown?('README.rb')).not_to be_truthy
+ end
+ end
+
+ describe '#asciidoc?' do
+ %w(adoc ad asciidoc ADOC).each do |type|
+ it "returns true for #{type} files" do
+ expect(Gitlab::MarkupHelper.asciidoc?("README.#{type}")).to be_truthy
+ end
+ end
+
+ it 'returns false when given a non-asciidoc filename' do
+ expect(Gitlab::MarkupHelper.asciidoc?('README.rb')).not_to be_truthy
+ end
+ end
+end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index dbcf7286e45..c40ae7b5703 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -5,6 +5,8 @@ describe Notify do
include EmailSpec::Matchers
include RepoHelpers
+ new_user_address = 'newguy@example.com'
+
let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name }
let(:gitlab_sender) { Gitlab.config.gitlab.email_from }
let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
@@ -55,18 +57,9 @@ describe Notify do
end
end
- describe 'for new users, the email' do
- let(:example_site_path) { root_path }
- let(:new_user) { create(:user, email: 'newguy@example.com', created_by_id: 1) }
-
- token = 'kETLwRaayvigPq_x3SNM'
-
- subject { Notify.new_user_email(new_user.id, token) }
-
- it_behaves_like 'an email sent from GitLab'
-
+ shared_examples 'a new user email' do |user_email, site_path|
it 'is sent to the new user' do
- is_expected.to deliver_to new_user.email
+ is_expected.to deliver_to user_email
end
it 'has the correct subject' do
@@ -74,9 +67,25 @@ describe Notify do
end
it 'contains the new user\'s login name' do
- is_expected.to have_body_text /#{new_user.email}/
+ is_expected.to have_body_text /#{user_email}/
end
+ it 'includes a link to the site' do
+ is_expected.to have_body_text /#{site_path}/
+ end
+ end
+
+ describe 'for new users, the email' do
+ let(:example_site_path) { root_path }
+ let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
+
+ token = 'kETLwRaayvigPq_x3SNM'
+
+ subject { Notify.new_user_email(new_user.id, token) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'a new user email', new_user_address
+
it 'contains the password text' do
is_expected.to have_body_text /Click here to set your password/
end
@@ -88,39 +97,26 @@ describe Notify do
)
end
- it 'includes a link to the site' do
- is_expected.to have_body_text /#{example_site_path}/
+ it 'explains the reset link expiration' do
+ is_expected.to have_body_text(/This link is valid for \d+ (hours?|days?)/)
+ is_expected.to have_body_text(new_user_password_url)
+ is_expected.to have_body_text(/\?user_email=.*%40.*/)
end
end
describe 'for users that signed up, the email' do
let(:example_site_path) { root_path }
- let(:new_user) { create(:user, email: 'newguy@example.com', password: "securePassword") }
+ let(:new_user) { create(:user, email: new_user_address, password: "securePassword") }
subject { Notify.new_user_email(new_user.id) }
it_behaves_like 'an email sent from GitLab'
-
- it 'is sent to the new user' do
- is_expected.to deliver_to new_user.email
- end
-
- it 'has the correct subject' do
- is_expected.to have_subject /^Account was created for you$/i
- end
-
- it 'contains the new user\'s login name' do
- is_expected.to have_body_text /#{new_user.email}/
- end
+ it_behaves_like 'a new user email', new_user_address
it 'should not contain the new user\'s password' do
is_expected.not_to have_body_text /password/
end
-
- it 'includes a link to the site' do
- is_expected.to have_body_text /#{example_site_path}/
- end
end
describe 'user added ssh key' do
@@ -189,7 +185,7 @@ describe Notify do
context 'for issues' do
let(:issue) { create(:issue, author: current_user, assignee: assignee, project: project) }
- let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: Faker::Lorem.sentence) }
+ let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: FFaker::Lorem.sentence) }
describe 'that are new' do
subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
@@ -277,7 +273,7 @@ describe Notify do
context 'for merge requests' do
let(:merge_author) { create(:user) }
let(:merge_request) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project) }
- let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: Faker::Lorem.sentence) }
+ let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: FFaker::Lorem.sentence) }
describe 'that are new' do
subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index 4e0d50d7f3f..dae7e399cfb 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
require 'spec_helper'
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index d9714596f5d..fb5111dd9f5 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
require "spec_helper"
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index e4b6b886565..edb21fc2e47 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
require "spec_helper"
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 9f5ef3eff70..4c3f0cbcbbf 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -13,6 +13,7 @@
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
+# note_events :boolean default(FALSE), not null
#
require 'spec_helper'
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 45171e1bf64..eb73aa763fc 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -47,7 +47,7 @@ describe Milestone do
it "should recover from dividing by zero" do
expect(milestone.issues).to receive(:count).and_return(0)
- expect(milestone.percent_complete).to eq(100)
+ expect(milestone.percent_complete).to eq(0)
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 4c7d15d6594..8d0ae1475c2 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -5,7 +5,7 @@ describe API::API, api: true do
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
let(:project) { create(:project) }
- let(:secret_token) { File.read Rails.root.join('.gitlab_shell_secret') }
+ let(:secret_token) { File.read Gitlab.config.gitlab_shell.secret_file }
describe "GET /internal/check", no_db: true do
it do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index aada7febf6c..46cd26eb927 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -165,7 +165,7 @@ describe API::API, api: true do
it "should assign attributes to project" do
project = attributes_for(:project, {
path: 'camelCasePath',
- description: Faker::Lorem.sentence,
+ description: FFaker::Lorem.sentence,
issues_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false
@@ -274,7 +274,7 @@ describe API::API, api: true do
it 'should assign attributes to project' do
project = attributes_for(:project, {
- description: Faker::Lorem.sentence,
+ description: FFaker::Lorem.sentence,
issues_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index d15dff1b52b..0e5ae724bf7 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
describe Issues::CloseService do
- let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:issue) { create(:issue, assignee: user2) }
+ let(:project) { issue.project }
before do
project.team << [user, :master]
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 22b89bec96d..6fc69e93628 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe Issues::UpdateService do
- let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:issue) { create(:issue) }
let(:label) { create(:label) }
+ let(:project) { issue.project }
before do
project.team << [user, :master]
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 1a02299bf19..0dc3b412783 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -15,6 +15,8 @@ describe Notes::CreateService do
noteable_id: issue.id
}
+ expect(project).to receive(:execute_hooks)
+ expect(project).to receive(:execute_services)
@note = Notes::CreateService.new(project, user, opts).execute
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 2a54b2e920a..62a99d15952 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -31,7 +31,8 @@ describe NotificationService do
describe 'Notes' do
context 'issue note' do
- let(:issue) { create(:issue, assignee: create(:user)) }
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') }
@@ -101,7 +102,8 @@ describe NotificationService do
end
context 'issue note mention' do
- let(:issue) { create(:issue, assignee: create(:user)) }
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
@@ -145,7 +147,8 @@ describe NotificationService do
end
context 'commit note' do
- let(:note) { create(:note_on_commit) }
+ let(:project) { create(:project, :public) }
+ let(:note) { create(:note_on_commit, project: project) }
before do
build_team(note.project)
@@ -192,7 +195,8 @@ describe NotificationService do
end
describe 'Issues' do
- let(:issue) { create :issue, assignee: create(:user), description: 'cc @participant' }
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create :issue, project: project, assignee: create(:user), description: 'cc @participant' }
before do
build_team(issue.project)
@@ -295,7 +299,8 @@ describe NotificationService do
end
describe 'Merge Requests' do
- let(:merge_request) { create :merge_request, assignee: create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user) }
before do
build_team(merge_request.target_project)