summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfredo Sumaran <alfredo@gitlab.com>2016-03-01 13:37:03 -0500
committerAlfredo Sumaran <alfredo@gitlab.com>2016-03-01 13:37:03 -0500
commit9f1c3bb7659365d09f2482d57621a3ff0510d9bf (patch)
tree1bdde66b08c960e8447d9400f129477095fac2e2
parentfefa6a6f9e8f484300a808f1db6254a502cef73a (diff)
parent90ced487f2e8a6252864f9ac8821c2de06be9ced (diff)
downloadgitlab-ce-9f1c3bb7659365d09f2482d57621a3ff0510d9bf.tar.gz
Merge branch 'master' into improve-user-tabs
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml8
-rw-r--r--CHANGELOG5
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock62
-rw-r--r--PROCESS.md19
-rwxr-xr-xRakefile3
-rw-r--r--app/assets/javascripts/application.js.coffee2
-rw-r--r--app/assets/javascripts/logo.js.coffee2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee1
-rw-r--r--app/assets/stylesheets/application.scss6
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/progress.scss5
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss15
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/login.scss4
-rw-r--r--app/assets/stylesheets/pages/notes.scss13
-rw-r--r--app/assets/stylesheets/pages/todos.scss35
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb12
-rw-r--r--app/controllers/projects/avatars_controller.rb4
-rw-r--r--app/controllers/projects/forks_controller.rb22
-rw-r--r--app/controllers/projects/raw_controller.rb13
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/helpers/blob_helper.rb18
-rw-r--r--app/helpers/events_helper.rb4
-rw-r--r--app/models/user.rb16
-rw-r--r--app/views/dashboard/todos/_todo.html.haml6
-rw-r--r--app/views/events/event/_common.html.haml2
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/ci/_page.html.haml2
-rw-r--r--app/views/projects/diffs/_warning.html.haml11
-rw-r--r--app/views/projects/forks/index.html.haml14
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml2
-rw-r--r--app/views/projects/notes/_note.html.haml2
-rw-r--r--config/application.rb8
-rw-r--r--config/initializers/relative_url.rb.sample10
-rw-r--r--db/migrate/20160222153918_create_appearances_ce.rb2
-rw-r--r--doc/ci/variables/README.md4
-rw-r--r--doc/install/relative_url.md20
-rw-r--r--lib/api/commit_statuses.rb10
-rw-r--r--lib/api/internal.rb13
-rw-r--r--lib/banzai/filter/gollum_tags_filter.rb35
-rw-r--r--lib/banzai/pipeline/wiki_pipeline.rb6
-rw-r--r--lib/tasks/cache.rake2
-rw-r--r--spec/controllers/users_controller_spec.rb18
-rw-r--r--spec/factories.rb1
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb52
-rw-r--r--spec/models/user_spec.rb18
-rw-r--r--spec/requests/api/commit_status_spec.rb164
-rw-r--r--spec/requests/api/internal_spec.rb12
52 files changed, 466 insertions, 232 deletions
diff --git a/.gitignore b/.gitignore
index 91ea81bfc4e..1eb785451f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ config/gitlab.yml
config/gitlab_ci.yml
config/initializers/rack_attack.rb
config/initializers/smtp_settings.rb
+config/initializers/relative_url.rb
config/resque.yml
config/unicorn.rb
config/secrets.yml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e98b7a68ee..c477721f9da 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -89,6 +89,7 @@ spec:other:
spinach:project:half:
stage: test
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
tags:
- ruby
@@ -97,6 +98,7 @@ spinach:project:half:
spinach:project:rest:
stage: test
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
tags:
- ruby
@@ -105,6 +107,7 @@ spinach:project:rest:
spinach:other:
stage: test
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
tags:
- ruby
@@ -275,6 +278,7 @@ spinach:project:half:ruby22:
only:
- master
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
cache:
key: "ruby22"
@@ -290,6 +294,7 @@ spinach:project:rest:ruby22:
only:
- master
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
cache:
key: "ruby22"
@@ -305,6 +310,7 @@ spinach:other:ruby22:
only:
- master
script:
+ - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
cache:
key: "ruby22"
@@ -318,7 +324,7 @@ spinach:other:ruby22:
notify:slack:
stage: notifications
script:
- - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Check <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>"
+ - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>"
when: on_failure
only:
- master@gitlab-org/gitlab-ce
diff --git a/CHANGELOG b/CHANGELOG
index 9e897644af0..4dc38117eb7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,14 +1,18 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.6.0 (unreleased)
+ - Contributions to forked projects are included in calendar
- Improve the formatting for the user page bio (Connor Shea)
+ - Fix issue when pushing to projects ending in .wiki
- Fix avatar stretching by providing a cropping feature (Johann Pardanaud)
- Strip leading and trailing spaces in URL validator (evuez)
+ - Return empty array instead of 404 when commit has no statuses in commit status API
- Update documentation to reflect Guest role not being enforced on internal projects
v 8.5.2
- Fix sidebar overlapping content when screen width was below 1200px
- Fix error 500 when commenting on a commit
+ - Fix broken icons on installations with relative URL (Artem Sidorenko)
v 8.5.1
- Fix group projects styles
@@ -28,6 +32,7 @@ v 8.5.1
- Re-add the newrelic_rpm gem which was removed without any deprecation or warning (Stan Hu)
- Update sentry-raven gem to 0.15.6
- Add build coverage in project's builds page (Steffen Köhler)
+ - Changed # to ! for merge requests in activity view
v 8.5.0
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
diff --git a/Gemfile b/Gemfile
index e37651f6fb3..76357d2b674 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source "https://rubygems.org"
-gem 'rails', '4.2.5.1'
+gem 'rails', '4.2.5.2'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with
@@ -213,7 +213,6 @@ gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 5.0.0'
-gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9'
diff --git a/Gemfile.lock b/Gemfile.lock
index d0f780e9519..29563b18db1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -4,41 +4,41 @@ GEM
CFPropertyList (2.3.2)
RedCloth (4.2.9)
ace-rails-ap (2.0.1)
- actionmailer (4.2.5.1)
- actionpack (= 4.2.5.1)
- actionview (= 4.2.5.1)
- activejob (= 4.2.5.1)
+ actionmailer (4.2.5.2)
+ actionpack (= 4.2.5.2)
+ actionview (= 4.2.5.2)
+ activejob (= 4.2.5.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
- actionpack (4.2.5.1)
- actionview (= 4.2.5.1)
- activesupport (= 4.2.5.1)
+ actionpack (4.2.5.2)
+ actionview (= 4.2.5.2)
+ activesupport (= 4.2.5.2)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (4.2.5.1)
- activesupport (= 4.2.5.1)
+ actionview (4.2.5.2)
+ activesupport (= 4.2.5.2)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- activejob (4.2.5.1)
- activesupport (= 4.2.5.1)
+ activejob (4.2.5.2)
+ activesupport (= 4.2.5.2)
globalid (>= 0.3.0)
- activemodel (4.2.5.1)
- activesupport (= 4.2.5.1)
+ activemodel (4.2.5.2)
+ activesupport (= 4.2.5.2)
builder (~> 3.1)
- activerecord (4.2.5.1)
- activemodel (= 4.2.5.1)
- activesupport (= 4.2.5.1)
+ activerecord (4.2.5.2)
+ activemodel (= 4.2.5.2)
+ activesupport (= 4.2.5.2)
arel (~> 6.0)
activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5)
- activesupport (4.2.5.1)
+ activesupport (4.2.5.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
@@ -483,7 +483,6 @@ GEM
newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
- nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
@@ -587,16 +586,16 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
- rails (4.2.5.1)
- actionmailer (= 4.2.5.1)
- actionpack (= 4.2.5.1)
- actionview (= 4.2.5.1)
- activejob (= 4.2.5.1)
- activemodel (= 4.2.5.1)
- activerecord (= 4.2.5.1)
- activesupport (= 4.2.5.1)
+ rails (4.2.5.2)
+ actionmailer (= 4.2.5.2)
+ actionpack (= 4.2.5.2)
+ actionview (= 4.2.5.2)
+ activejob (= 4.2.5.2)
+ activemodel (= 4.2.5.2)
+ activerecord (= 4.2.5.2)
+ activesupport (= 4.2.5.2)
bundler (>= 1.3.0, < 2.0)
- railties (= 4.2.5.1)
+ railties (= 4.2.5.2)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
@@ -606,9 +605,9 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
- railties (4.2.5.1)
- actionpack (= 4.2.5.1)
- activesupport (= 4.2.5.1)
+ railties (4.2.5.2)
+ actionpack (= 4.2.5.2)
+ activesupport (= 4.2.5.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.0.0)
@@ -964,7 +963,6 @@ DEPENDENCIES
net-ssh (~> 3.0.1)
newrelic_rpm (~> 3.14)
nokogiri (~> 1.6.7, >= 1.6.7.2)
- nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.8.0)
omniauth (~> 1.3.1)
@@ -989,7 +987,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
- rails (= 4.2.5.1)
+ rails (= 4.2.5.2)
rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2)
rblineprof
diff --git a/PROCESS.md b/PROCESS.md
index 5f4d67bc10e..54ebe11d5a0 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -36,18 +36,15 @@ The most important thing is making sure valid issues receive feedback from the d
Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
-- *Awaiting feedback*: Feedback pending from the reporter
-- *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
-- *Attached MR*: There is a MR attached and the discussion should happen there
- - We need to let issues stay in sync with the MR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the MR. We can't close the issue when there is a merge request because sometimes a MR is not good and we just close the MR, then the issue must stay.
-- *Developer*: needs help from a developer
-- *UX* needs needs help from a UX designer
-- *Frontend* needs help from a Front-end engineer
-- *Graphics* needs help from a Graphics designer
-- *up-for-grabs* is an issue suitable for first-time contributors, of reasonable difficulty and size. Not exclusive with other labels.
-- *feature proposal* is a proposal for a new feature for GitLab. People are encouraged to vote
+- ~"Awaiting Feedback" Feedback pending from the reporter
+- ~UX needs help from a UX designer
+- ~Frontend needs help from a Front-end engineer
+- ~up-for-grabs is an issue suitable for first-time contributors, of reasonable difficulty and size. Not exclusive with other labels.
+- ~"feature proposal" is a proposal for a new feature for GitLab. People are encouraged to vote
in support or comment for further detail. Do not use `feature request`.
-
+- ~bug is an issue reporting undesirable or incorrect behavior.
+- ~customer is an issue reported by enterprise subscribers. This label should
+be accompanied by *bug* or *feature proposal* labels.
Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label.
## Functional labels
diff --git a/Rakefile b/Rakefile
index 35b2f05cbb4..5dd389d5678 100755
--- a/Rakefile
+++ b/Rakefile
@@ -4,4 +4,7 @@
require File.expand_path('../config/application', __FILE__)
+relative_url_conf = File.expand_path('../config/initializers/relative_url', __FILE__)
+require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
+
Gitlab::Application.load_tasks
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 5463397f475..c17d2186e29 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -31,8 +31,6 @@
#= require ace/ace
#= require ace/ext-searchbox
#= require underscore
-#= require nprogress
-#= require nprogress-turbolinks
#= require dropzone
#= require mousetrap
#= require mousetrap/pause
diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee
index 35b2fbbba07..d14b7139237 100644
--- a/app/assets/javascripts/logo.js.coffee
+++ b/app/assets/javascripts/logo.js.coffee
@@ -1,4 +1,4 @@
-NProgress.configure(showSpinner: false)
+Turbolinks.enableProgressBar();
defaultClass = 'tanuki-shape'
pieces = [
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 40cfa59a229..23a218b4c7d 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -146,6 +146,7 @@ class @MergeRequestTabs
url: "#{source}.json" + @_location.search
success: (data) =>
document.querySelector("div#diffs").innerHTML = data.html
+ $('.js-timeago').timeago()
$('div#diffs .js-syntax-highlight').syntaxHighlight()
@expandViewContainer() if @diffViewType() is 'parallel'
@diffsLoaded = true
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index f51054f13dc..e2d590f4df4 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -26,12 +26,6 @@
@import "framework";
/*
- * NProgress load bar css
- */
-@import 'nprogress';
-@import 'nprogress-bootstrap';
-
-/*
* Font icons
*/
@import "font-awesome";
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index fa7641b1676..e2a30f5ed34 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -26,6 +26,7 @@
@import "framework/mobile.scss";
@import "framework/nav.scss";
@import "framework/pagination.scss";
+@import "framework/progress.scss";
@import "framework/panels.scss";
@import "framework/selects.scss";
@import "framework/sidebar.scss";
diff --git a/app/assets/stylesheets/framework/progress.scss b/app/assets/stylesheets/framework/progress.scss
new file mode 100644
index 00000000000..e9800bd24b5
--- /dev/null
+++ b/app/assets/stylesheets/framework/progress.scss
@@ -0,0 +1,5 @@
+html.turbolinks-progress-bar::before {
+ background-color: $progress-color!important;
+ height: 2px!important;
+ box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color;
+}
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index e0ccd6f100f..de947c89c19 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -13,6 +13,19 @@
transition-duration: .3s;
}
+ .gitlab-text-container-link {
+ z-index: 1;
+ position: absolute;
+ left: 0px;
+ }
+
+ #logo {
+ z-index: 2;
+ position: absolute;
+ width: 58px;
+ cursor: pointer;
+ }
+
&.right-sidebar-expanded {
padding-right: $gutter_width;
}
@@ -74,7 +87,7 @@
width: 158px;
float: left;
margin: 0;
- margin-left: 14px;
+ margin-left: 50px;
font-size: 19px;
line-height: 41px;
font-weight: normal;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 2706d031d7b..7834cb0bfa5 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -7,7 +7,7 @@ $gl-header-color: #323232;
$gl-link-color: #333c48;
$md-text-color: #444;
$md-link-color: #3084bb;
-$nprogress-color: #c0392b;
+$progress-color: #c0392b;
$gl-font-size: 15px;
$list-font-size: 15px;
$sidebar_collapsed_width: 62px;
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index f9c6f1b39f9..61bec02f6c5 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -8,6 +8,10 @@
max-width: none;
}
+ .flash-container {
+ margin-bottom: $gl-padding;
+ }
+
.brand-holder {
font-size: 18px;
line-height: 1.5;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 19ead07c06a..d5f9852ebed 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -14,6 +14,18 @@ ul.notes {
margin: 0px;
padding: 0px;
+ .timeline-icon {
+ float: left;
+ }
+
+ .timeline-content {
+ margin-left: 55px;
+ }
+
+ .note_created_ago, .note-updated-at {
+ white-space: nowrap;
+ }
+
.system-note {
font-size: 14px;
padding-top: 10px;
@@ -151,6 +163,7 @@ ul.notes {
border-left: none;
&.notes_line {
+ vertical-align: middle;
text-align: center;
padding: 10px 0;
background: #FFF;
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 2f57f21963d..0dc5a905f99 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -12,29 +12,10 @@
}
}
-.todos {
- .panel {
- border-top: none;
- margin-bottom: 0;
- }
-}
-
.todo-item {
font-size: $gl-font-size;
- padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
- border-bottom: 1px solid $table-border-color;
- color: #7f8fa4;
-
- &.todo-inline {
- .avatar {
- position: relative;
- top: -2px;
- }
-
- .todo-title {
- line-height: 40px;
- }
- }
+ padding-left: $gl-avatar-size + $gl-padding-top;
+ color: $secondary-text;
a {
color: #4c4e54;
@@ -48,7 +29,7 @@
@include str-truncated(calc(100% - 174px));
font-weight: 600;
- .author_name {
+ .author-name {
color: #333;
}
}
@@ -88,17 +69,7 @@
margin-bottom: 0;
}
}
-
- .todo-note-icon {
- color: #777;
- float: left;
- font-size: $gl-font-size;
- line-height: 16px;
- margin-right: 5px;
- }
}
-
- &:last-child { border:none }
}
@media (max-width: $screen-xs-max) {
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index f3bfede4354..8f83fdd02bc 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -12,11 +12,13 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
current_user.save! if current_user.changed?
- if two_factor_grace_period_expired?
- flash.now[:alert] = 'You must enable Two-factor Authentication for your account.'
- else
- grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
- flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}."
+ if two_factor_authentication_required?
+ if two_factor_grace_period_expired?
+ flash.now[:alert] = 'You must enable Two-factor Authentication for your account.'
+ else
+ grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
+ flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}."
+ end
end
@qr_code = build_qr_code
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index f7e6bb34443..b64dbbd89ce 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -1,4 +1,6 @@
class Projects::AvatarsController < Projects::ApplicationController
+ include BlobHelper
+
before_action :project
def show
@@ -7,7 +9,7 @@ class Projects::AvatarsController < Projects::ApplicationController
headers['X-Content-Type-Options'] = 'nosniff'
headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob))
headers['Content-Disposition'] = 'inline'
- headers['Content-Type'] = @blob.content_type
+ headers['Content-Type'] = safe_content_type(@blob)
head :ok # 'render nothing: true' messes up the Content-Type
else
render_404
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index 0c551501ca4..a0835c9aad0 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -4,12 +4,22 @@ class Projects::ForksController < Projects::ApplicationController
before_action :authorize_download_code!
def index
- @sort = params[:sort] || 'id_desc'
- @all_forks = project.forks.includes(:creator).order_by(@sort)
-
- @public_forks, @protected_forks = @all_forks.partition do |project|
- can?(current_user, :read_project, project)
- end
+ base_query = project.forks.includes(:creator)
+
+ @forks = if current_user
+ base_query.where('projects.visibility_level IN (?) OR projects.id IN (?)',
+ Project.public_and_internal_levels,
+ current_user.authorized_projects.pluck(:id))
+ else
+ base_query.where('projects.visibility_level = ?', Project::PUBLIC)
+ end
+
+ @total_forks_count = base_query.size
+ @private_forks_count = @total_forks_count - @forks.size
+ @public_forks_count = @total_forks_count - @private_forks_count
+
+ @sort = params[:sort] || 'id_desc'
+ @forks = @forks.order_by(@sort).page(params[:page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 87b4d08da0e..d9723acb1d9 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -1,6 +1,7 @@
# Controller for viewing a file's raw
class Projects::RawController < Projects::ApplicationController
include ExtractsPath
+ include BlobHelper
before_action :require_non_empty_project
before_action :assign_ref_vars
@@ -17,7 +18,7 @@ class Projects::RawController < Projects::ApplicationController
else
headers.store(*Gitlab::Workhorse.send_git_blob(@repository, @blob))
headers['Content-Disposition'] = 'inline'
- headers['Content-Type'] = get_blob_type
+ headers['Content-Type'] = safe_content_type(@blob)
head :ok # 'render nothing: true' messes up the Content-Type
end
else
@@ -27,16 +28,6 @@ class Projects::RawController < Projects::ApplicationController
private
- def get_blob_type
- if @blob.text?
- 'text/plain; charset=utf-8'
- elsif @blob.image?
- @blob.content_type
- else
- 'application/octet-stream'
- end
- end
-
def send_lfs_object
lfs_object = find_lfs_object
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index eae19214bf5..4b1cf242885 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -89,7 +89,7 @@ class UsersController < ApplicationController
def contributions_calendar
@contributions_calendar ||= Gitlab::ContributionsCalendar.
- new(contributed_projects.reject(&:forked?), @user)
+ new(contributed_projects, @user)
end
def load_events
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 7143a744869..7f63a2e2cb4 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -134,4 +134,22 @@ module BlobHelper
blob.data = Loofah.scrub_fragment(blob.data, :strip).to_xml
blob
end
+
+ # If we blindly set the 'real' content type when serving a Git blob we
+ # are enabling XSS attacks. An attacker could upload e.g. a Javascript
+ # file to a Git repository, trick the browser of a victim into
+ # downloading the blob, and then the 'application/javascript' content
+ # type would tell the browser to execute the attacker's Javascript. By
+ # overriding the content type and setting it to 'text/plain' (in the
+ # example of Javascript) we tell the browser of the victim not to
+ # execute untrusted data.
+ def safe_content_type(blob)
+ if blob.text?
+ 'text/plain; charset=utf-8'
+ elsif blob.image?
+ blob.content_type
+ else
+ 'application/octet-stream'
+ end
+ end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 31bf45baeb7..e5fcaab9551 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -168,11 +168,11 @@ module EventsHelper
link_to(namespace_project_snippet_path(event.project.namespace,
event.project,
event.note_target)) do
- "#{event.note_target_type} ##{truncate event.note_target_id}"
+ "#{event.note_target_type} #{truncate event.note_target.to_reference}"
end
else
link_to event_note_target_path(event) do
- "#{event.note_target_type} ##{truncate event.note_target_iid}"
+ "#{event.note_target_type} #{truncate event.note_target.to_reference}"
end
end
else
diff --git a/app/models/user.rb b/app/models/user.rb
index 6baf2468ade..3098d49d58a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -169,7 +169,7 @@ class User < ActiveRecord::Base
validates :avatar_crop_x, :avatar_crop_y, :avatar_crop_size,
numericality: { only_integer: true },
presence: true,
- if: ->(user) { user.avatar? }
+ if: ->(user) { user.avatar? && user.avatar_changed? }
before_validation :generate_password, on: :create
before_validation :restricted_signup_domains, on: :create
@@ -362,17 +362,19 @@ class User < ActiveRecord::Base
def disable_two_factor!
update_attributes(
- two_factor_enabled: false,
- encrypted_otp_secret: nil,
- encrypted_otp_secret_iv: nil,
- encrypted_otp_secret_salt: nil,
- otp_backup_codes: nil
+ two_factor_enabled: false,
+ encrypted_otp_secret: nil,
+ encrypted_otp_secret_iv: nil,
+ encrypted_otp_secret_salt: nil,
+ otp_grace_period_started_at: nil,
+ otp_backup_codes: nil
)
end
def namespace_uniq
# Return early if username already failed the first uniqueness validation
- return if self.errors[:username].include?('has already been taken')
+ return if self.errors.key?(:username) &&
+ self.errors[:username].include?('has already been taken')
namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name)
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 6975f6ed0db..f878d36e739 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -1,11 +1,11 @@
%li{class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo) }
- .todo-item{class: 'todo-block'}
+ .todo-item.todo-block
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title
- %span.author_name
+ %span.author-name
= link_to_author todo
- %span.todo_label
+ %span.todo-label
= todo_action_name(todo)
= todo_target_link(todo)
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index 4ecf1c33d2a..e9e16a7646f 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -4,7 +4,7 @@
= event_action_name(event)
- if event.target
- %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
+ %strong= link_to event.target.to_reference, [event.project.namespace.becomes(Namespace), event.project, event.target]
= event_preposition(event)
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index e53d5b07801..c799e9c588d 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -4,7 +4,7 @@
.header-logo
%a#logo
= brand_header_logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
+ = link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
diff --git a/app/views/layouts/ci/_page.html.haml b/app/views/layouts/ci/_page.html.haml
index 3cfd36720f0..a13241bebee 100644
--- a/app/views/layouts/ci/_page.html.haml
+++ b/app/views/layouts/ci/_page.html.haml
@@ -4,7 +4,7 @@
.header-logo
%a#logo
= brand_header_logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home' do
+ = link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index f99bc9a85eb..63ede71e6f1 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -3,17 +3,16 @@
Too many changes to show.
.pull-right
- unless diff_hard_limit_enabled?
- = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm btn-warning"
+ = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm"
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
- = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-sm"
- = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-sm"
+ = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm"
+ = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-sm"
- elsif @merge_request && @merge_request.persisted?
- = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-sm"
- = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-sm"
+ = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm"
+ = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm"
%p
To preserve performance only
%strong #{shown_files_count} of #{diffs.size}
files are displayed.
-
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index 42fa6fdb782..ace22625d1d 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -1,9 +1,7 @@
.top-area
.nav-text
- - public_count = @public_forks.size
- - protected_count = @protected_forks.size
- - full_count_title = "#{public_count} public and #{protected_count} private"
- == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title}
+ - full_count_title = "#{@public_forks_count} public and #{@private_forks_count} private"
+ == #{pluralize(@total_forks_count, 'fork')}: #{full_count_title}
.nav-controls
= search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short',
@@ -41,17 +39,17 @@
.projects-list-holder
- - if @public_forks.blank?
+ - if @forks.blank?
%ul.content-list
%li
.nothing-here-block No forks to show
- else
- = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true,
+ = render 'shared/projects/list', projects: @forks, use_creator_avatar: true,
forks: true, show_last_commit_as_description: true
- - if protected_count > 0
+ - if @private_forks_count > 0
%ul.projects-list.private-forks-notice
%li.project-row
= icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon')
- %strong= pluralize(protected_count, 'private fork')
+ %strong= pluralize(@private_forks_count, 'private fork')
%span you have no access to.
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index b9d5982a56f..18cf3f14f0b 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -48,7 +48,7 @@
= note_count
.merge-request-info
- \##{merge_request.iid} &middot;
+ #{merge_request.to_reference} &middot;
opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')}
by #{link_to_member(@project, merge_request.author, avatar: false)}
- if merge_request.target_project.default_branch != merge_request.target_branch
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 648512e5379..d7bc26e24b9 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -1,4 +1,4 @@
-- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
+- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 14ea7b17786..b634a4af8d2 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -2,7 +2,7 @@
.status-box{ class: status_box_class(@merge_request) }
= @merge_request.state_human_name
%span.identifier
- Merge Request ##{@merge_request.iid}
+ Merge Request #{@merge_request.to_reference}
%span.creator
&middot;
by #{link_to_member(@project, @merge_request.author, size: 24)}
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index e858c412836..52972576aff 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -28,7 +28,7 @@
%a{name: dom_id(note), href: "##{dom_id(note)}", title: 'Link here'}
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
- if note.updated_at != note.created_at
- %span
+ %span.note-updated-at
&middot;
= icon('edit', title: 'edited')
= time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
diff --git a/config/application.rb b/config/application.rb
index b905f1a3e90..28684a3e578 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -54,14 +54,6 @@ module Gitlab
config.action_view.sanitized_allowed_protocols = %w(smb)
- # Relative URL support
- # WARNING: We recommend using an FQDN to host GitLab in a root path instead
- # of using a relative URL.
- # Documentation: http://doc.gitlab.com/ce/install/relative_url.html
- # Uncomment and customize the following line to run in a non-root path
- #
- # config.relative_url_root = "/gitlab"
-
config.middleware.use Rack::Attack
# Allow access to GitLab API from other domains
diff --git a/config/initializers/relative_url.rb.sample b/config/initializers/relative_url.rb.sample
new file mode 100644
index 00000000000..125297d5385
--- /dev/null
+++ b/config/initializers/relative_url.rb.sample
@@ -0,0 +1,10 @@
+# Relative URL support
+# WARNING: We recommend using an FQDN to host GitLab in a root path instead
+# of using a relative URL.
+# Documentation: http://doc.gitlab.com/ce/install/relative_url.html
+# Copy this file to relative_url.rb and customize it to run in a non-root path
+#
+
+Rails.application.configure do
+ config.relative_url_root = "/gitlab"
+end
diff --git a/db/migrate/20160222153918_create_appearances_ce.rb b/db/migrate/20160222153918_create_appearances_ce.rb
index 5e66d5094bd..bec66bcc71e 100644
--- a/db/migrate/20160222153918_create_appearances_ce.rb
+++ b/db/migrate/20160222153918_create_appearances_ce.rb
@@ -1,4 +1,4 @@
-class CreateAppearancesCE < ActiveRecord::Migration
+class CreateAppearancesCe < ActiveRecord::Migration
def change
unless table_exists?(:appearances)
create_table :appearances do |t|
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 9e89e6e395e..b0e53cbc261 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -30,7 +30,7 @@ The API_TOKEN will take the Secure Variable value: `SECURE`.
| **CI_BUILD_REF_NAME** | all | The branch or tag name for which project is built |
| **CI_BUILD_ID** | all | The unique id of the current build that GitLab CI uses internally |
| **CI_BUILD_REPO** | all | The URL to clone the Git repository |
-| **CI_BUILD_TRIGGERED** | 0.5 | The flag to indicate that build was triggered |
+| **CI_BUILD_TRIGGERED** | 0.5 | The flag to indicate that build was [triggered] |
| **CI_PROJECT_ID** | all | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_DIR** | all | The full path where the repository is cloned and where the build is ran |
@@ -104,3 +104,5 @@ job_name:
script:
- export
```
+
+[triggered]: ../triggers/README.md
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
index b341b6311c6..0245febfcd8 100644
--- a/doc/install/relative_url.md
+++ b/doc/install/relative_url.md
@@ -25,7 +25,7 @@ that points to your GitLab instance.
The TL;DR list of configuration files that you need to change in order to
serve GitLab under a relative URL is:
-- `/home/git/gitlab/config/application.rb`
+- `/home/git/gitlab/config/initializers/relative_url.rb`
- `/home/git/gitlab/config/gitlab.yml`
- `/home/git/gitlab/config/unicorn.rb`
- `/home/git/gitlab-shell/config.yml`
@@ -66,8 +66,14 @@ Make sure to follow all steps below:
sudo service gitlab stop
```
-1. Edit `/home/git/gitlab/config/application.rb` and uncomment/change the
- following line:
+1. Create `/home/git/gitlab/config/initializers/relative_url.rb`
+
+ ```shell
+ cp /home/git/gitlab/config/initializers/relative_url.rb.sample \
+ /home/git/gitlab/config/initializers/relative_url.rb
+ ```
+
+ and change the following line:
```ruby
config.relative_url_root = "/gitlab"
@@ -119,8 +125,12 @@ Make sure to follow all steps below:
### Disable relative URL in GitLab
-To disable the relative URL, follow the same steps as above and set up the
-GitLab URL to one that doesn't contain a relative path.
+To disable the relative URL:
+
+1. Remove `/home/git/gitlab/config/initializers/relative_url.rb`
+
+1. Follow the same as above starting from 2. and set up the
+ GitLab URL to one that doesn't contain a relative path.
[omnibus-rel]: http://doc.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab "How to setup relative URL in Omnibus GitLab"
[restart gitlab]: ../administration/restart_gitlab.md#installations-from-source "How to restart GitLab"
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 9422d438d21..8e74e177ea0 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -18,10 +18,12 @@ module API
# Examples:
# GET /projects/:id/repository/commits/:sha/statuses
get ':id/repository/commits/:sha/statuses' do
- authorize! :read_commit_status, user_project
- sha = params[:sha]
- ci_commit = user_project.ci_commit(sha)
- not_found! 'Commit' unless ci_commit
+ authorize!(:read_commit_status, user_project)
+
+ not_found!('Commit') unless user_project.commit(params[:sha])
+ ci_commit = user_project.ci_commit(params[:sha])
+ return [] unless ci_commit
+
statuses = ci_commit.statuses
statuses = statuses.latest unless parse_boolean(params[:all])
statuses = statuses.where(ref: params[:ref]) if params[:ref].present?
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index e38736fc28b..2200208b946 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -14,6 +14,14 @@ module API
# ref - branch name
# forced_push - forced_push
#
+
+ helpers do
+ def wiki?
+ @wiki ||= params[:project].end_with?('.wiki') &&
+ !Project.find_with_namespace(params[:project])
+ end
+ end
+
post "/allowed" do
status 200
@@ -30,13 +38,12 @@ module API
# Strip out the .wiki from the pathname before finding the
# project. This applies the correct project permissions to
# the wiki repository as well.
- wiki = project_path.end_with?('.wiki')
- project_path.chomp!('.wiki') if wiki
+ project_path.chomp!('.wiki') if wiki?
project = Project.find_with_namespace(project_path)
access =
- if wiki
+ if wiki?
Gitlab::GitAccessWiki.new(actor, project)
else
Gitlab::GitAccess.new(actor, project)
diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb
index fe01dae4850..bcf5297e382 100644
--- a/lib/banzai/filter/gollum_tags_filter.rb
+++ b/lib/banzai/filter/gollum_tags_filter.rb
@@ -50,21 +50,30 @@ module Banzai
# See https://github.com/gollum/gollum/wiki
#
# Rubular: http://rubular.com/r/7dQnE5CUCH
- TAGS_PATTERN = %r{\[\[(.+?)\]\]}
+ TAGS_PATTERN = %r{\[\[(.+?)\]\]}.freeze
# Pattern to match allowed image extensions
- ALLOWED_IMAGE_EXTENSIONS = %r{.+(jpg|png|gif|svg|bmp)\z}i
+ ALLOWED_IMAGE_EXTENSIONS = %r{.+(jpg|png|gif|svg|bmp)\z}i.freeze
def call
search_text_nodes(doc).each do |node|
- content = node.content
+ # A Gollum ToC tag is `[[_TOC_]]`, but due to MarkdownFilter running
+ # before this one, it will be converted into `[[<em>TOC</em>]]`, so it
+ # needs special-case handling
+ if toc_tag?(node)
+ next unless result[:toc].present?
- next unless content.match(TAGS_PATTERN)
+ process_toc_tag(node)
+ else
+ content = node.content
- html = process_tag($1)
+ next unless content =~ TAGS_PATTERN
- if html && html != node.content
- node.replace(html)
+ html = process_tag($1)
+
+ if html && html != node.content
+ node.replace(html)
+ end
end
end
@@ -73,6 +82,12 @@ module Banzai
private
+ # Replace an entire `[[<em>TOC</em>]]` node with the result generated by
+ # TableOfContentsFilter
+ def process_toc_tag(node)
+ node.parent.parent.replace(result[:toc])
+ end
+
# Process a single tag into its final HTML form.
#
# tag - The String tag contents (the stuff inside the double brackets).
@@ -108,6 +123,12 @@ module Banzai
end
end
+ def toc_tag?(node)
+ node.content == 'TOC' &&
+ node.parent.name == 'em' &&
+ node.parent.parent.text == '[[TOC]]'
+ end
+
def image?(path)
path =~ ALLOWED_IMAGE_EXTENSIONS
end
diff --git a/lib/banzai/pipeline/wiki_pipeline.rb b/lib/banzai/pipeline/wiki_pipeline.rb
index 50b5450e70b..bc2bf111971 100644
--- a/lib/banzai/pipeline/wiki_pipeline.rb
+++ b/lib/banzai/pipeline/wiki_pipeline.rb
@@ -4,7 +4,11 @@ module Banzai
module Pipeline
class WikiPipeline < FullPipeline
def self.filters
- super.insert(1, Filter::GollumTagsFilter)
+ @filters ||= begin
+ filters = super
+ toc = filters.index(Filter::TableOfContentsFilter)
+ filters.insert(toc + 1, Filter::GollumTagsFilter)
+ end
end
end
end
diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake
index 9e2fb429d57..f221afcf73a 100644
--- a/lib/tasks/cache.rake
+++ b/lib/tasks/cache.rake
@@ -1,5 +1,5 @@
namespace :cache do
- CLEAR_BATCH_SIZE = 1000 # The more the faster, but having too many can crash Ruby
+ CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000
REDIS_SCAN_START_STOP = '0' # Magic value, see http://redis.io/commands/scan
desc "GitLab | Clear redis cache"
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 104a5f50143..7337ff58be1 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -41,6 +41,7 @@ describe UsersController do
end
describe 'GET #calendar' do
+
it 'renders calendar' do
sign_in(user)
@@ -48,6 +49,23 @@ describe UsersController do
expect(response).to render_template('calendar')
end
+
+ context 'forked project' do
+ let!(:project) { create(:project) }
+ let!(:forked_project) { Projects::ForkService.new(project, user).execute }
+
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ EventCreateService.new.push(project, user, [])
+ EventCreateService.new.push(forked_project, user, [])
+ end
+
+ it 'includes forked projects' do
+ get :calendar, username: user.username
+ expect(assigns(:contributions_calendar).projects.count).to eq(2)
+ end
+ end
end
describe 'GET #calendar_activities' do
diff --git a/spec/factories.rb b/spec/factories.rb
index 264e3ed2c8d..cd57661c1cd 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -32,6 +32,7 @@ FactoryGirl.define do
before(:create) do |user|
user.two_factor_enabled = true
user.otp_secret = User.generate_otp_secret(32)
+ user.otp_grace_period_started_at = Time.now
user.generate_otp_backup_codes!
end
end
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index 38baa819957..11cc290d6d0 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -86,4 +86,56 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do
expect(doc.at_css('a')['href']).to eq 'wiki-slug'
end
end
+
+ context 'table of contents' do
+ let(:pipeline) { Banzai::Pipeline[:wiki] }
+
+ it 'replaces the tag with the TableOfContentsFilter result' do
+ markdown = <<-MD.strip_heredoc
+ [[_TOC_]]
+
+ ## Header
+
+ Foo
+ MD
+
+ result = pipeline.call(markdown, project_wiki: project_wiki, project: project)
+
+ aggregate_failures do
+ expect(result[:output].text).not_to include '[[_TOC_]]'
+ expect(result[:output].text).not_to include '[['
+ expect(result[:output].to_html).to include(result[:toc])
+ end
+ end
+
+ it 'is case-sensitive' do
+ markdown = <<-MD.strip_heredoc
+ [[_toc_]]
+
+ # Header 1
+
+ Foo
+ MD
+
+ output = pipeline.to_html(markdown, project_wiki: project_wiki, project: project)
+
+ expect(output).to include('[[<em>toc</em>]]')
+ end
+
+ it 'handles an empty pipeline result' do
+ # No Markdown headers in this doc, so `result[:toc]` will be empty
+ markdown = <<-MD.strip_heredoc
+ [[_TOC_]]
+
+ Foo
+ MD
+
+ output = pipeline.to_html(markdown, project_wiki: project_wiki, project: project)
+
+ aggregate_failures do
+ expect(output).not_to include('<ul>')
+ expect(output).to include('[[<em>TOC</em>]]')
+ end
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 88821dd0dad..412101ac9f9 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -176,7 +176,7 @@ describe User, models: true do
end
describe 'avatar' do
- it 'only validates when avatar is present' do
+ it 'only validates when avatar is present and changed' do
user = build(:user, :with_avatar)
user.avatar_crop_x = nil
@@ -184,6 +184,20 @@ describe User, models: true do
user.avatar_crop_size = nil
expect(user).not_to be_valid
+ expect(user.errors.keys).
+ to match_array %i(avatar_crop_x avatar_crop_y avatar_crop_size)
+ end
+
+ it 'does not validate when avatar has not changed' do
+ user = create(:user, :with_avatar)
+
+ expect { user.avatar_crop_x = nil }.not_to change(user, :valid?)
+ end
+
+ it 'does not validate when avatar is not present' do
+ user = create(:user)
+
+ expect { user.avatar_crop_y = nil }.not_to change(user, :valid?)
end
end
end
@@ -268,6 +282,7 @@ describe User, models: true do
expect(user).to be_two_factor_enabled
expect(user.encrypted_otp_secret).not_to be_nil
expect(user.otp_backup_codes).not_to be_nil
+ expect(user.otp_grace_period_started_at).not_to be_nil
user.disable_two_factor!
@@ -276,6 +291,7 @@ describe User, models: true do
expect(user.encrypted_otp_secret_iv).to be_nil
expect(user.encrypted_otp_secret_salt).to be_nil
expect(user.otp_backup_codes).to be_nil
+ expect(user.otp_grace_period_started_at).to be_nil
end
end
diff --git a/spec/requests/api/commit_status_spec.rb b/spec/requests/api/commit_status_spec.rb
index 89b554622ef..8017ed97d88 100644
--- a/spec/requests/api/commit_status_spec.rb
+++ b/spec/requests/api/commit_status_spec.rb
@@ -2,88 +2,125 @@ require 'spec_helper'
describe API::CommitStatus, api: true do
include ApiHelpers
+
let!(:project) { create(:project) }
let(:commit) { project.repository.commit }
- let!(:ci_commit) { project.ensure_ci_commit(commit.id) }
let(:commit_status) { create(:commit_status, commit: ci_commit) }
let(:guest) { create_user(ProjectMember::GUEST) }
let(:reporter) { create_user(ProjectMember::REPORTER) }
let(:developer) { create_user(ProjectMember::DEVELOPER) }
+ let(:sha) { commit.id }
+
describe "GET /projects/:id/repository/commits/:sha/statuses" do
- it_behaves_like 'a paginated resources' do
- let(:request) { get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", reporter) }
- end
+ let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" }
- context "reporter user" do
- let(:statuses_id) { json_response.map { |status| status['id'] } }
+ context 'ci commit exists' do
+ let!(:ci_commit) { project.ensure_ci_commit(commit.id) }
- before do
- @status1 = create(:commit_status, commit: ci_commit, status: 'running')
- @status2 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'pending')
- @status3 = create(:commit_status, commit: ci_commit, name: 'coverage', ref: 'develop', status: 'running', allow_failure: true)
- @status4 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'success')
- @status5 = create(:commit_status, commit: ci_commit, ref: 'develop', status: 'success')
- @status6 = create(:commit_status, commit: ci_commit, status: 'success')
+ it_behaves_like 'a paginated resources' do
+ let(:request) { get api(get_url, reporter) }
end
- it "should return latest commit statuses" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", reporter)
- expect(response.status).to eq(200)
+ context "reporter user" do
+ let(:statuses_id) { json_response.map { |status| status['id'] } }
- expect(json_response).to be_an Array
- expect(statuses_id).to contain_exactly(@status3.id, @status4.id, @status5.id, @status6.id)
- json_response.sort_by!{ |status| status['id'] }
- expect(json_response.map{ |status| status['allow_failure'] }).to eq([true, false, false, false])
- end
+ def create_status(opts = {})
+ create(:commit_status, { commit: ci_commit }.merge(opts))
+ end
- it "should return all commit statuses" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?all=1", reporter)
- expect(response.status).to eq(200)
+ let!(:status1) { create_status(status: 'running') }
+ let!(:status2) { create_status(name: 'coverage', status: 'pending') }
+ let!(:status3) { create_status(ref: 'develop', status: 'running', allow_failure: true) }
+ let!(:status4) { create_status(name: 'coverage', status: 'success') }
+ let!(:status5) { create_status(name: 'coverage', ref: 'develop', status: 'success') }
+ let!(:status6) { create_status(status: 'success') }
- expect(json_response).to be_an Array
- expect(statuses_id).to contain_exactly(@status1.id, @status2.id, @status3.id, @status4.id, @status5.id, @status6.id)
- end
+ context 'latest commit statuses' do
+ before { get api(get_url, reporter) }
- it "should return latest commit statuses for specific ref" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?ref=develop", reporter)
- expect(response.status).to eq(200)
+ it 'returns latest commit statuses' do
+ expect(response.status).to eq(200)
- expect(json_response).to be_an Array
- expect(statuses_id).to contain_exactly(@status3.id, @status5.id)
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(status3.id, status4.id, status5.id, status6.id)
+ json_response.sort_by!{ |status| status['id'] }
+ expect(json_response.map{ |status| status['allow_failure'] }).to eq([true, false, false, false])
+ end
+ end
+
+ context 'all commit statuses' do
+ before { get api(get_url, reporter), all: 1 }
+
+ it 'returns all commit statuses' do
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(status1.id, status2.id,
+ status3.id, status4.id,
+ status5.id, status6.id)
+ end
+ end
+
+ context 'latest commit statuses for specific ref' do
+ before { get api(get_url, reporter), ref: 'develop' }
+
+ it 'returns latest commit statuses for specific ref' do
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(status3.id, status5.id)
+ end
+ end
+
+ context 'latest commit statues for specific name' do
+ before { get api(get_url, reporter), name: 'coverage' }
+
+ it 'return latest commit statuses for specific name' do
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(status4.id, status5.id)
+ end
+ end
end
+ end
- it "should return latest commit statuses for specific name" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?name=coverage", reporter)
- expect(response.status).to eq(200)
+ context 'ci commit does not exist' do
+ before { get api(get_url, reporter) }
+ it 'returns empty array' do
+ expect(response.status).to eq 200
expect(json_response).to be_an Array
- expect(statuses_id).to contain_exactly(@status3.id, @status4.id)
+ expect(json_response).to be_empty
end
end
context "guest user" do
+ before { get api(get_url, guest) }
+
it "should not return project commits" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", guest)
expect(response.status).to eq(403)
end
end
context "unauthorized user" do
+ before { get api(get_url) }
+
it "should not return project commits" do
- get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses")
expect(response.status).to eq(401)
end
end
end
describe 'POST /projects/:id/statuses/:sha' do
- let(:post_url) { "/projects/#{project.id}/statuses/#{commit.id}" }
+ let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" }
context 'developer user' do
- context 'should create commit status' do
- it 'with only required parameters' do
- post api(post_url, developer), state: 'success'
+ context 'only required parameters' do
+ before { post api(post_url, developer), state: 'success' }
+
+ it 'creates commit status' do
expect(response.status).to eq(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
@@ -92,9 +129,17 @@ describe API::CommitStatus, api: true do
expect(json_response['target_url']).to be_nil
expect(json_response['description']).to be_nil
end
+ end
- it 'with all optional parameters' do
- post api(post_url, developer), state: 'success', context: 'coverage', ref: 'develop', target_url: 'url', description: 'test'
+ context 'with all optional parameters' do
+ before do
+ optional_params = { state: 'success', context: 'coverage',
+ ref: 'develop', target_url: 'url', description: 'test' }
+
+ post api(post_url, developer), optional_params
+ end
+
+ it 'creates commit status' do
expect(response.status).to eq(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
@@ -105,41 +150,52 @@ describe API::CommitStatus, api: true do
end
end
- context 'should not create commit status' do
- it 'with invalid state' do
- post api(post_url, developer), state: 'invalid'
+ context 'invalid status' do
+ before { post api(post_url, developer), state: 'invalid' }
+
+ it 'does not create commit status' do
expect(response.status).to eq(400)
end
+ end
- it 'without state' do
- post api(post_url, developer)
+ context 'request without state' do
+ before { post api(post_url, developer) }
+
+ it 'does not create commit status' do
expect(response.status).to eq(400)
end
+ end
- it 'invalid commit' do
- post api("/projects/#{project.id}/statuses/invalid_sha", developer), state: 'running'
+ context 'invalid commit' do
+ let(:sha) { 'invalid_sha' }
+ before { post api(post_url, developer), state: 'running' }
+
+ it 'returns not found error' do
expect(response.status).to eq(404)
end
end
end
context 'reporter user' do
+ before { post api(post_url, reporter) }
+
it 'should not create commit status' do
- post api(post_url, reporter)
expect(response.status).to eq(403)
end
end
context 'guest user' do
+ before { post api(post_url, guest) }
+
it 'should not create commit status' do
- post api(post_url, guest)
expect(response.status).to eq(403)
end
end
context 'unauthorized user' do
+ before { post api(post_url) }
+
it 'should not create commit status' do
- post api(post_url)
expect(response.status).to eq(401)
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 8d0ae1475c2..22802dd0e05 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -54,6 +54,18 @@ describe API::API, api: true do
project.team << [user, :developer]
end
+ context "git push with project.wiki" do
+ it 'responds with success' do
+ project_wiki = create(:project, name: 'my.wiki', path: 'my.wiki')
+ project_wiki.team << [user, :developer]
+
+ push(key, project_wiki)
+
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_truthy
+ end
+ end
+
context "git pull" do
it do
pull(key, project)