summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--README.md2
-rw-r--r--app/assets/stylesheets/framework.scss3
-rw-r--r--app/assets/stylesheets/framework/awards.scss (renamed from app/assets/stylesheets/pages/awards.scss)0
-rw-r--r--app/assets/stylesheets/framework/blocks.scss9
-rw-r--r--app/assets/stylesheets/framework/broadcast-messages.scss21
-rw-r--r--app/assets/stylesheets/framework/common.scss14
-rw-r--r--app/assets/stylesheets/framework/images.scss (renamed from app/assets/stylesheets/pages/appearances.scss)0
-rw-r--r--app/assets/stylesheets/framework/lists.scss39
-rw-r--r--app/assets/stylesheets/framework/nav.scss10
-rw-r--r--app/assets/stylesheets/framework/tables.scss17
-rw-r--r--app/assets/stylesheets/framework/variables.scss6
-rw-r--r--app/assets/stylesheets/framework/wells.scss13
-rw-r--r--app/assets/stylesheets/pages/admin.scss168
-rw-r--r--app/assets/stylesheets/pages/confirmation.scss32
-rw-r--r--app/assets/stylesheets/pages/dashboard.scss43
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss6
-rw-r--r--app/assets/stylesheets/pages/tags.scss7
-rw-r--r--app/models/ci/variable.rb4
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/environment.rb2
-rw-r--r--app/models/key.rb16
-rw-r--r--app/models/namespace.rb14
-rw-r--r--app/models/project.rb4
-rw-r--r--app/models/repository.rb14
-rw-r--r--app/models/snippet.rb8
-rw-r--r--app/views/admin/abuse_reports/index.html.haml10
-rw-r--r--app/views/admin/dashboard/index.html.haml12
-rw-r--r--app/views/admin/users/_user.html.haml8
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--app/views/devise/confirmations/almost_there.haml7
-rw-r--r--app/views/projects/buttons/_download.html.haml79
-rw-r--r--app/views/projects/pipelines_settings/show.html.haml3
-rw-r--r--app/views/projects/tags/show.html.haml21
-rw-r--r--changelogs/unreleased/move-admin-hooks-spinach-test-to-rspec.yml4
-rw-r--r--changelogs/unreleased/move-admin-logs-spinach-test-to-rspec.yml4
-rw-r--r--changelogs/unreleased/remove-has-visible-content-caching.yml4
-rw-r--r--changelogs/unreleased/update-git-version-in-doc.yml4
-rw-r--r--config/routes/group.rb22
-rw-r--r--doc/administration/custom_hooks.md20
-rw-r--r--doc/ci/examples/php.md2
-rw-r--r--doc/development/ux_guide/animation.md42
-rw-r--r--doc/development/ux_guide/basics.md15
-rw-r--r--doc/development/ux_guide/copy.md4
-rw-r--r--doc/development/ux_guide/img/animation-dropdown.gifbin0 -> 22483 bytes
-rw-r--r--doc/development/ux_guide/img/animation-hover.gifbin0 -> 247388 bytes
-rw-r--r--doc/development/ux_guide/img/animation-quickupdate.gifbin0 -> 6441 bytes
-rw-r--r--doc/development/ux_guide/index.md17
-rw-r--r--doc/install/installation.md8
-rw-r--r--features/admin/hooks.feature9
-rw-r--r--features/admin/logs.feature8
-rw-r--r--features/steps/admin/hooks.rb15
-rw-r--r--features/steps/admin/logs.rb11
-rw-r--r--lib/api/issues.rb15
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb15
-rw-r--r--spec/features/admin/admin_hooks_spec.rb15
-rw-r--r--spec/features/groups/labels/edit_spec.rb21
-rw-r--r--spec/lib/gitlab/github_import/importer_spec.rb2
-rw-r--r--spec/models/ci/variable_spec.rb7
-rw-r--r--spec/models/concerns/issuable_spec.rb2
-rw-r--r--spec/models/environment_spec.rb4
-rw-r--r--spec/models/key_spec.rb8
-rw-r--r--spec/models/namespace_spec.rb13
-rw-r--r--spec/models/project_spec.rb10
-rw-r--r--spec/models/repository_spec.rb31
-rw-r--r--spec/models/snippet_spec.rb24
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/requests/api/deploy_keys_spec.rb4
-rw-r--r--spec/support/matchers/is_within.rb9
69 files changed, 448 insertions, 521 deletions
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index fcdb2e109f6..c4e41f94594 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-4.0.0
+4.0.3
diff --git a/README.md b/README.md
index 61204630fd2..68b709b85d5 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.3
-- Git 2.7.4+
+- Git 2.8.4+
- Redis 2.8+
- MySQL or PostgreSQL
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 4aaff7d04f1..4d4835568ed 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -40,3 +40,6 @@
@import "framework/blank";
@import "framework/wells.scss";
@import "framework/page-header.scss";
+@import "framework/awards.scss";
+@import "framework/images.scss";
+@import "framework/broadcast-messages";
diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/framework/awards.scss
index c13cb4a02b2..c13cb4a02b2 100644
--- a/app/assets/stylesheets/pages/awards.scss
+++ b/app/assets/stylesheets/framework/awards.scss
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 57db5eaa2b3..95c02499271 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -1,8 +1,3 @@
-.light-well {
- background-color: $background-color;
- padding: 15px;
-}
-
.centered-light-block {
text-align: center;
color: $gl-gray;
@@ -274,6 +269,10 @@
}
}
+ .emoji-icon {
+ display: inline-block;
+ }
+
@media(max-width: $screen-xs-max) {
margin-top: 50px;
text-align: center;
diff --git a/app/assets/stylesheets/framework/broadcast-messages.scss b/app/assets/stylesheets/framework/broadcast-messages.scss
new file mode 100644
index 00000000000..9b54fb94cdc
--- /dev/null
+++ b/app/assets/stylesheets/framework/broadcast-messages.scss
@@ -0,0 +1,21 @@
+.broadcast-message {
+ @extend .alert-warning;
+ padding: 10px;
+ text-align: center;
+
+ div,
+ p {
+ display: inline;
+ margin: 0;
+
+ a {
+ color: inherit;
+ text-decoration: underline;
+ }
+ }
+}
+
+.broadcast-message-preview {
+ @extend .broadcast-message;
+ margin-bottom: 20px;
+}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 16646e33a4b..600bf17259b 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -379,7 +379,9 @@ table {
border-top: 1px solid $border-color;
}
-.hide-bottom-border { border-bottom: none !important; }
+.hide-bottom-border {
+ border-bottom: none !important;
+}
.gl-accessibility {
&:focus {
@@ -396,3 +398,13 @@ table {
z-index: 1;
}
}
+
+.str-truncated {
+ &-60 {
+ @include str-truncated(60%);
+ }
+
+ &-100 {
+ @include str-truncated(100%);
+ }
+}
diff --git a/app/assets/stylesheets/pages/appearances.scss b/app/assets/stylesheets/framework/images.scss
index 878f44116ba..878f44116ba 100644
--- a/app/assets/stylesheets/pages/appearances.scss
+++ b/app/assets/stylesheets/framework/images.scss
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index db8677433bb..ed4b60faf92 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -106,13 +106,13 @@ ul.task-list {
}
}
+// Generic content list
ul.content-list {
@include basic-list;
-
margin: 0;
padding: 0;
- > li {
+ li {
border-color: $table-border-color;
font-size: $list-font-size;
color: $list-text-color;
@@ -193,6 +193,41 @@ ul.content-list {
}
}
+// Content list using flexbox
+.flex-list {
+ .flex-row {
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ white-space: nowrap;
+ }
+
+ .row-main-content {
+ flex: 1 1 auto;
+ overflow: hidden;
+ padding-right: 8px;
+ }
+
+ .row-title {
+ font-weight: 600;
+ }
+
+ .row-second-line {
+ display: block;
+ }
+
+ .dropdown {
+ .btn-block {
+ margin-bottom: 0;
+ line-height: inherit;
+ }
+ }
+
+ .label-default {
+ color: $btn-transparent-color;
+ }
+}
+
.panel > .content-list > li {
padding: $gl-padding-top $gl-padding;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index c84a71a624d..69da520f21f 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -268,6 +268,16 @@
width: auto;
}
}
+
+ &.multi-line {
+ .nav-text {
+ line-height: 20px;
+ }
+
+ .nav-controls {
+ padding: 17px 0;
+ }
+ }
}
.layout-nav {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index a5f36c177fc..5d0ca63ea08 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -34,6 +34,10 @@ table {
background-color: $background-color;
font-weight: normal;
border-bottom: none;
+
+ &.wide {
+ width: 55%;
+ }
}
td {
@@ -42,3 +46,16 @@ table {
}
}
}
+
+.responsive-table {
+ @media (max-width: $screen-sm-max) {
+ th {
+ width: 100%;
+ }
+
+ td {
+ width: 100%;
+ float: left;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 647dcfc5187..18716813c48 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -427,12 +427,6 @@ $common-gray-dark: #444;
$common-red: $gl-text-red;
$common-green: $gl-text-green;
-
-/*
-* Dashboard
-*/
-$dashboard-project-access-icon-color: #888;
-
/*
* Editor
*/
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index 192939f4527..f2860dfe84d 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -43,3 +43,16 @@
background-color: $well-expand-item;
}
}
+
+.light-well {
+ background-color: $background-color;
+ padding: 15px;
+}
+
+.well-centered {
+ h1 {
+ font-weight: normal;
+ text-align: center;
+ font-size: 48px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/admin.scss b/app/assets/stylesheets/pages/admin.scss
deleted file mode 100644
index 44eac21b143..00000000000
--- a/app/assets/stylesheets/pages/admin.scss
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Admin area
- *
- */
-.admin-dashboard {
- .data {
- a {
- h1 {
- line-height: 48px;
- font-size: 48px;
- padding: 20px;
- text-align: center;
- font-weight: normal;
- }
- }
- }
-
- .str-truncated {
- max-width: 60%;
- }
-}
-
-.admin-filter form {
- .select2-container {
- width: 100%;
- }
-
- .controls {
- margin-left: 130px;
- }
-
- .form-actions {
- padding-left: 130px;
- background: $white-light;
- }
-
- .visibility-levels {
- .controls {
- margin-bottom: 9px;
- }
-
- i {
- color: inherit;
- }
- }
-}
-
-.broadcast-messages {
- .message {
- line-height: 2;
- }
-}
-
-.broadcast-message {
- @extend .alert-warning;
- padding: 10px;
- text-align: center;
-
- > div,
- p {
- display: inline;
- margin: 0;
-
- a {
- color: inherit;
- text-decoration: underline;
- }
- }
-}
-
-.broadcast-message-preview {
- @extend .broadcast-message;
- margin-bottom: 20px;
-}
-
-// Users List
-
-.users-list {
- .user-row {
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- white-space: nowrap;
- }
-
- .user-details {
- flex: 1 1 auto;
- overflow: hidden;
- padding-right: 8px;
- }
-
- .user-name {
- display: inline-block;
- font-weight: 600;
- }
-
- .user-name,
- .user-email {
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .dropdown {
- .btn-block {
- margin-bottom: 0;
- line-height: inherit;
- }
- }
-
- .label-default {
- color: $btn-transparent-color;
- }
-}
-
-.abuse-reports {
- .table {
- table-layout: fixed;
- }
-
- .subheading {
- padding-bottom: $gl-padding;
- }
-
- .message {
- word-wrap: break-word;
- }
-
- .btn {
- white-space: normal;
- padding: $gl-btn-padding;
- }
-
- th {
- width: 15%;
-
- &.wide {
- width: 55%;
- }
- }
-
- @media (max-width: $screen-sm-max) {
- th {
- width: 100%;
- }
-
- td {
- width: 100%;
- float: left;
- }
- }
-
- .no-reports {
- .emoji-icon {
- margin-left: $btn-side-margin;
- margin-top: 3px;
- }
-
- span {
- font-size: 18px;
- }
- }
-}
-
-.admin-builds-table {
- .ci-table td:last-child {
- min-width: 120px;
- }
-}
diff --git a/app/assets/stylesheets/pages/confirmation.scss b/app/assets/stylesheets/pages/confirmation.scss
deleted file mode 100644
index 8aab5e8231d..00000000000
--- a/app/assets/stylesheets/pages/confirmation.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-.well-confirmation {
- margin-bottom: 20px;
- border-bottom: 1px solid $gray-darker;
-
- > h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- font-weight: 400;
- }
-
- .lead {
- margin-bottom: 20px;
- }
-
- ul,
- ol {
- padding-left: 0;
- }
-
- li {
- list-style-type: none;
- }
-}
-
-.confirmation-content {
- a {
- color: $md-link-color;
- }
-}
diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
deleted file mode 100644
index 4421ed6a0b9..00000000000
--- a/app/assets/stylesheets/pages/dashboard.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-.dashboard {
- .side {
- .panel {
- .panel-heading {
- background: $background-color;
- border-top-left-radius: 0;
- }
-
- border-top-left-radius: 0;
- }
- }
-}
-
-.dashboard-search-filter {
- padding: 5px;
-
- .search-text-input {
- float: left;
- @extend .col-md-2;
- }
-
- .btn {
- margin-left: 5px;
- float: left;
- }
-}
-
-.project-access-icon {
- margin-left: 10px;
- float: left;
- margin-right: 15px;
- margin-bottom: 15px;
-
- i {
- color: $dashboard-project-access-icon-color;
- }
-}
-
-.dash-project-access-icon {
- float: left;
- margin-right: 5px;
- width: 16px;
-}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 0027d2caf22..08062b85504 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -280,6 +280,12 @@
}
}
+.admin-builds-table {
+ .ci-table td:last-child {
+ min-width: 120px;
+ }
+}
+
// Pipeline visualization
.toggle-pipeline-btn {
diff --git a/app/assets/stylesheets/pages/tags.scss b/app/assets/stylesheets/pages/tags.scss
deleted file mode 100644
index 24ebd3e7cfa..00000000000
--- a/app/assets/stylesheets/pages/tags.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.tag-buttons {
- line-height: 40px;
-
- .btn:not(.dropdown-toggle) {
- margin-left: 10px;
- }
-}
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index 94d9e2b3208..2c8698d8b5d 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -4,10 +4,10 @@ module Ci
belongs_to :project, foreign_key: :gl_project_id
- validates_uniqueness_of :key, scope: :gl_project_id
validates :key,
presence: true,
- length: { within: 0..255 },
+ uniqueness: { scope: :gl_project_id },
+ length: { maximum: 255 },
format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." }
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 69d8afc45da..0ea7b1b1098 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -41,7 +41,7 @@ module Issuable
has_one :metrics
validates :author, presence: true
- validates :title, presence: true, length: { within: 0..255 }
+ validates :title, presence: true, length: { maximum: 255 }
scope :authored, ->(user) { where(author_id: user) }
scope :assigned_to, ->(u) { where(assignee_id: u.id)}
diff --git a/app/models/environment.rb b/app/models/environment.rb
index a7f4156fc2e..96700143ddd 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -9,7 +9,7 @@ class Environment < ActiveRecord::Base
validates :name,
presence: true,
uniqueness: { scope: :project_id },
- length: { within: 0..255 },
+ length: { maximum: 255 },
format: { with: Gitlab::Regex.environment_name_regex,
message: Gitlab::Regex.environment_name_regex_message }
diff --git a/app/models/key.rb b/app/models/key.rb
index ff8dda2dc89..a5d25409730 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -8,10 +8,18 @@ class Key < ActiveRecord::Base
before_validation :generate_fingerprint
- validates :title, presence: true, length: { within: 0..255 }
- validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }
- validates :key, format: { without: /\n|\r/, message: 'should be a single line' }
- validates :fingerprint, uniqueness: true, presence: { message: 'cannot be generated' }
+ validates :title,
+ presence: true,
+ length: { maximum: 255 }
+ validates :key,
+ presence: true,
+ length: { maximum: 5000 },
+ format: { with: /\A(ssh|ecdsa)-.*\Z/ }
+ validates :key,
+ format: { without: /\n|\r/, message: 'should be a single line' }
+ validates :fingerprint,
+ uniqueness: true,
+ presence: { message: 'cannot be generated' }
delegate :name, :email, to: :user, prefix: true
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 891dffac648..7a545f752b6 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -12,17 +12,17 @@ class Namespace < ActiveRecord::Base
validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name,
- length: { within: 0..255 },
- namespace_name: true,
presence: true,
- uniqueness: true
+ uniqueness: true,
+ length: { maximum: 255 },
+ namespace_name: true
- validates :description, length: { within: 0..255 }
+ validates :description, length: { maximum: 255 }
validates :path,
- length: { within: 1..255 },
- namespace: true,
presence: true,
- uniqueness: { case_sensitive: false }
+ uniqueness: { case_sensitive: false },
+ length: { maximum: 255 },
+ namespace: true
delegate :name, to: :owner, allow_nil: true, prefix: true
diff --git a/app/models/project.rb b/app/models/project.rb
index 9d58aff4033..590885c0177 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -172,13 +172,13 @@ class Project < ActiveRecord::Base
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :name,
presence: true,
- length: { within: 0..255 },
+ length: { maximum: 255 },
format: { with: Gitlab::Regex.project_name_regex,
message: Gitlab::Regex.project_name_regex_message }
validates :path,
presence: true,
project_path: true,
- length: { within: 0..255 },
+ length: { maximum: 255 },
format: { with: Gitlab::Regex.project_path_regex,
message: Gitlab::Regex.project_path_regex_message }
validates :namespace, presence: true
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e2e7d08abac..3c4b0212af7 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -85,11 +85,7 @@ class Repository
# This method return true if repository contains some content visible in project page.
#
def has_visible_content?
- return @has_visible_content unless @has_visible_content.nil?
-
- @has_visible_content = cache.fetch(:has_visible_content?) do
- branch_count > 0
- end
+ branch_count > 0
end
def commit(ref = 'HEAD')
@@ -374,12 +370,6 @@ class Repository
return unless empty?
expire_method_caches(%i(empty?))
- expire_has_visible_content_cache
- end
-
- def expire_has_visible_content_cache
- cache.expire(:has_visible_content?)
- @has_visible_content = nil
end
def lookup_cache
@@ -467,7 +457,6 @@ class Repository
# Runs code after a new branch has been created.
def after_create_branch
expire_branches_cache
- expire_has_visible_content_cache
repository_event(:push_branch)
end
@@ -481,7 +470,6 @@ class Repository
# Runs code after an existing branch has been removed.
def after_remove_branch
- expire_has_visible_content_cache
expire_branches_cache
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index aa2e3a1ff18..98ccf5f331f 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -27,9 +27,9 @@ class Snippet < ActiveRecord::Base
delegate :name, :email, to: :author, prefix: true, allow_nil: true
validates :author, presence: true
- validates :title, presence: true, length: { within: 0..255 }
+ validates :title, presence: true, length: { maximum: 255 }
validates :file_name,
- length: { within: 0..255 },
+ length: { maximum: 255 },
format: { with: Gitlab::Regex.file_name_regex,
message: Gitlab::Regex.file_name_regex_message }
@@ -94,6 +94,10 @@ class Snippet < ActiveRecord::Base
0
end
+ def file_name
+ super.to_s
+ end
+
# alias for compatibility with blobs and highlighting
def path
file_name
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index 7bbc75db9ff..c4b748d0ab8 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -4,7 +4,7 @@
.abuse-reports
- if @abuse_reports.present?
.table-holder
- %table.table
+ %table.table.responsive-table
%thead.hidden-sm.hidden-xs
%tr
%th User
@@ -13,8 +13,6 @@
%th Action
= render @abuse_reports
- else
- .no-reports
- %span.pull-left
- There are no abuse reports!
- .pull-left
- = emoji_icon 'tada'
+ .empty-state
+ .text-center
+ %h4 There are no abuse reports! #{emoji_icon 'tada'}
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 1db2150f336..e51f4ac1d93 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -113,7 +113,7 @@
%hr
.row
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Projects
.data
= link_to admin_namespaces_projects_path do
@@ -121,7 +121,7 @@
%hr
= link_to('New Project', new_project_path, class: "btn btn-new")
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Users
.data
= link_to admin_users_path do
@@ -129,7 +129,7 @@
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Groups
.data
= link_to admin_groups_path do
@@ -143,7 +143,7 @@
%hr
- @projects.each do |project|
%p
- = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated'
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated-60'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
@@ -152,7 +152,7 @@
%hr
- @users.each do |user|
%p
- = link_to [:admin, user], class: 'str-truncated' do
+ = link_to [:admin, user], class: 'str-truncated-60' do
= user.name
%span.light.pull-right
#{time_ago_with_tooltip(user.created_at)}
@@ -162,7 +162,7 @@
%hr
- @groups.each do |group|
%p
- = link_to [:admin, group], class: 'str-truncated' do
+ = link_to [:admin, group], class: 'str-truncated-60' do
= group.name
%span.light.pull-right
#{time_ago_with_tooltip(group.created_at)}
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index 4bf1c9cde3c..2d9588f9d27 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -1,8 +1,8 @@
-%li.user-row
+%li.flex-row
.user-avatar
= image_tag avatar_icon(user), class: "avatar", alt: ''
- .user-details
- .user-name
+ .row-main-content
+ .user-name.row-title.str-truncated-100
= link_to user.name, [:admin, user]
- if user.blocked?
%span.label.label-danger blocked
@@ -12,7 +12,7 @@
%span.label.label-default External
- if user == current_user
%span It's you!
- .user-email
+ .row-second-line.str-truncated-100
= mail_to user.email, user.email
.controls
= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index d3038ae644f..4dc44225d49 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -68,7 +68,7 @@
%small.badge= number_with_delimiter(User.without_projects.count)
.fade-right
- %ul.users-list.content-list
+ %ul.flex-list.content-list
- if @users.empty?
%li
.nothing-here-block No users found.
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
index 20cd7b0179d..fb70d158096 100644
--- a/app/views/devise/confirmations/almost_there.haml
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -1,12 +1,13 @@
-.well-confirmation.text-center
+.well-confirmation.text-center.append-bottom-20
%h1.prepend-top-0
Almost there...
- %p.lead
+ %p.lead.append-bottom-20
Please check your email to confirm your account
+ %hr
- if current_application_settings.after_sign_up_text.present?
.well-confirmation.text-center
= markdown_field(current_application_settings, :after_sign_up_text)
-%p.confirmation-content.text-center
+%p.text-center
No confirmation email received? Please check your spam folder or
.append-bottom-20.prepend-top-20.text-center
%a.btn.btn-lg.btn-success{ href: new_user_confirmation_path }
diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml
index 7b995bd8735..40bfa01a45a 100644
--- a/app/views/projects/buttons/_download.html.haml
+++ b/app/views/projects/buttons/_download.html.haml
@@ -1,42 +1,41 @@
- if !project.empty_repo? && can?(current_user, :download_code, project)
- %span{class: 'download-button'}
- .dropdown.inline
- %button.btn{ 'data-toggle' => 'dropdown' }
- = icon('download')
- = icon("caret-down")
- %span.sr-only
- Select Archive Format
- %ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
- %li.dropdown-header Source code
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download zip
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar.gz
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar.bz2
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar
+ .dropdown.inline.download-button
+ %button.btn{ 'data-toggle' => 'dropdown' }
+ = icon('download')
+ = icon("caret-down")
+ %span.sr-only
+ Select Archive Format
+ %ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
+ %li.dropdown-header Source code
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download zip
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar.gz
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar.bz2
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar
- - pipeline = project.pipelines.latest_successful_for(ref)
- - if pipeline
- - artifacts = pipeline.builds.latest.with_artifacts
- - if artifacts.any?
- %li.dropdown-header Artifacts
- - unless pipeline.latest?
- - latest_pipeline = project.pipeline_for(ref)
- %li
- .unclickable= ci_status_for_statuseable(latest_pipeline)
- %li.dropdown-header Previous Artifacts
- - artifacts.each do |job|
- %li
- = link_to latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{ref}/download", job: job.name), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download '#{job.name}'
+ - pipeline = project.pipelines.latest_successful_for(ref)
+ - if pipeline
+ - artifacts = pipeline.builds.latest.with_artifacts
+ - if artifacts.any?
+ %li.dropdown-header Artifacts
+ - unless pipeline.latest?
+ - latest_pipeline = project.pipeline_for(ref)
+ %li
+ .unclickable= ci_status_for_statuseable(latest_pipeline)
+ %li.dropdown-header Previous Artifacts
+ - artifacts.each do |job|
+ %li
+ = link_to latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{ref}/download", job: job.name), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download '#{job.name}'
diff --git a/app/views/projects/pipelines_settings/show.html.haml b/app/views/projects/pipelines_settings/show.html.haml
index 96221a20502..1f698558bce 100644
--- a/app/views/projects/pipelines_settings/show.html.haml
+++ b/app/views/projects/pipelines_settings/show.html.haml
@@ -86,6 +86,9 @@
%li
tap --coverage-report=text-summary (NodeJS) -
%code ^Statements\s*:\s*([^%]+)
+ %li
+ excoveralls (Elixir) -
+ %code \[TOTAL\]\s+(\d+\.\d+)%
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 155af755759..12facb6eb73 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -3,8 +3,16 @@
= render "projects/commits/head"
%div{ class: container_class }
- .sub-header-block
- .pull-right.tag-buttons
+ .top-area.multi-line
+ .nav-text
+ .title
+ %span.item-title= @tag.name
+ - if @commit
+ = render 'projects/branches/commit', commit: @commit, project: @project
+ - else
+ Cant find HEAD commit for this tag
+
+ .nav-controls
- if can?(current_user, :push_code, @project)
= link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn has-tooltip', title: 'Edit release notes' do
= icon("pencil")
@@ -15,15 +23,8 @@
= render 'projects/buttons/download', project: @project, ref: @tag.name
- if can?(current_user, :admin_project, @project)
.pull-right
- = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
+ = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
%i.fa.fa-trash-o
- .tag-info.append-bottom-10
- .title
- %span.item-title= @tag.name
- - if @commit
- = render 'projects/branches/commit', commit: @commit, project: @project
- - else
- Cant find HEAD commit for this tag
- if @tag.message.present?
%pre.body
= strip_gpg_signature(@tag.message)
diff --git a/changelogs/unreleased/move-admin-hooks-spinach-test-to-rspec.yml b/changelogs/unreleased/move-admin-hooks-spinach-test-to-rspec.yml
new file mode 100644
index 00000000000..7dfd741985a
--- /dev/null
+++ b/changelogs/unreleased/move-admin-hooks-spinach-test-to-rspec.yml
@@ -0,0 +1,4 @@
+---
+title: Move admin hooks spinach to rspec
+merge_request: 7942
+author: Semyon Pupkov
diff --git a/changelogs/unreleased/move-admin-logs-spinach-test-to-rspec.yml b/changelogs/unreleased/move-admin-logs-spinach-test-to-rspec.yml
new file mode 100644
index 00000000000..696aa8510a0
--- /dev/null
+++ b/changelogs/unreleased/move-admin-logs-spinach-test-to-rspec.yml
@@ -0,0 +1,4 @@
+---
+title: Move admin logs spinach test to rspec
+merge_request: 7945
+author: Semyon Pupkov
diff --git a/changelogs/unreleased/remove-has-visible-content-caching.yml b/changelogs/unreleased/remove-has-visible-content-caching.yml
new file mode 100644
index 00000000000..e2940c60443
--- /dev/null
+++ b/changelogs/unreleased/remove-has-visible-content-caching.yml
@@ -0,0 +1,4 @@
+---
+title: Remove visible content caching
+merge_request:
+author:
diff --git a/changelogs/unreleased/update-git-version-in-doc.yml b/changelogs/unreleased/update-git-version-in-doc.yml
new file mode 100644
index 00000000000..cb3260f71cd
--- /dev/null
+++ b/changelogs/unreleased/update-git-version-in-doc.yml
@@ -0,0 +1,4 @@
+---
+title: Bump Git version requirement to 2.8.4
+merge_request:
+author:
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 9fe72990994..776c31c9dac 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -1,15 +1,5 @@
resources :groups, only: [:index, :new, :create]
-scope(path: 'groups/*id',
- controller: :groups,
- constraints: { id: Gitlab::Regex.namespace_route_regex }) do
- get :edit, as: :edit_group
- get :issues, as: :issues_group
- get :merge_requests, as: :merge_requests_group
- get :projects, as: :projects_group
- get :activity, as: :activity_group
-end
-
scope(path: 'groups/*group_id',
module: :groups,
as: :group,
@@ -22,10 +12,20 @@ scope(path: 'groups/*group_id',
resource :avatar, only: [:destroy]
resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :update, :new, :create]
- resources :labels, except: [:show], constraints: { id: /\d+/ } do
+ resources :labels, except: [:show] do
post :toggle_subscription, on: :member
end
end
+scope(path: 'groups/*id',
+ controller: :groups,
+ constraints: { id: Gitlab::Regex.namespace_route_regex }) do
+ get :edit, as: :edit_group
+ get :issues, as: :issues_group
+ get :merge_requests, as: :merge_requests_group
+ get :projects, as: :projects_group
+ get :activity, as: :activity_group
+end
+
# Must be last route in this file
get 'groups/*id' => 'groups#show', as: :group_canonical, constraints: { id: Gitlab::Regex.namespace_route_regex }
diff --git a/doc/administration/custom_hooks.md b/doc/administration/custom_hooks.md
index 0387d730489..06291705702 100644
--- a/doc/administration/custom_hooks.md
+++ b/doc/administration/custom_hooks.md
@@ -42,6 +42,25 @@ Follow the steps below to set up a custom hook:
That's it! Assuming the hook code is properly implemented the hook will fire
as appropriate.
+## Chained hooks support
+
+> [Introduced][93] in GitLab Shell 4.1.0.
+
+The hooks could be also placed in `hooks/<hook_name>.d` (global) or `custom_hooks/<hook_name>.d` (per project)
+directories supporting chained execution of the hooks.
+
+The hooks are searched and executed in this order:
+1. `<project>.git/hooks/` - symlink to `gitlab-shell/hooks` global dir
+1. `<project>.git/hooks/<hook_name>` - executed by `git` itself, this is `gitlab-shell/hooks/<hook_name>`
+1. `<project>.git/custom_hooks/<hook_name>` - per project hook (this is already existing behavior)
+1. `<project>.git/custom_hooks/<hook_name>.d/*` - per project hooks
+1. `<project>.git/hooks/<hook_name>.d/*` - global hooks: all executable files (minus editor backup files)
+
+Files in `.d` directories need to be executable and not match the backup file pattern (`*~`).
+
+The hooks of the same type are executed in order and execution stops on the first
+script exiting with non-zero value.
+
## Custom error messages
> [Introduced][5073] in GitLab 8.10.
@@ -54,3 +73,4 @@ STDERR takes precedence over STDOUT.
[hooks]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#Server-Side-Hooks
[5073]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5073
+[93]: https://gitlab.com/gitlab-org/gitlab-shell/merge_requests/93
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index 175e9d79904..82ffb841729 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -40,7 +40,7 @@ repository with the following content:
#!/bin/bash
# We need to install dependencies only for Docker
-[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0
+[[ ! -e /.dockerenv ]] && exit 0
set -xe
diff --git a/doc/development/ux_guide/animation.md b/doc/development/ux_guide/animation.md
new file mode 100644
index 00000000000..daeb15460c2
--- /dev/null
+++ b/doc/development/ux_guide/animation.md
@@ -0,0 +1,42 @@
+# Animation
+
+Motion is a tool to help convey important relationships, changes or transitions between elements. It should be used sparingly and intentionally, highlighting the right elements at the right moment.
+
+## Timings
+
+The longer distance an object travel, the timing should be longer for the animation. However, when in doubt, we should avoid large, full screen animations.
+
+Subtle animations, or objects leaving the screen should take **100-200 milliseconds**. Objects entering the screen, or motion we want to use to direct user attention can take between **200-400 milliseconds**. We should avoid animations of longer than 400 milliseconds as they will make the experience appear sluggish. If a specific animation feels like it will need more than 400 milliseconds, revisit the animation to see if there is a simpler, easier, shorter animation to implement.
+
+## Easing
+
+Easing specifies the rate of change of a parameter over time (see [easings.net](http://easings.net/)). Adding an easing curve will make the motion feel more natural. Being consistent with the easing curves will make the whole experience feel more cohesive and connected.
+
+* When an object is entering the screen, or transforming the scale, position, or shape, use the **easeOutQuint** curve (`cubic-bezier(0.23, 1, 0.32, 1)`)
+* When an object is leaving the screen, or transforming the opacity or color, no easing curve is needed. It shouldn't _slow down_ as it is exiting the screen, as that draws attention on the leaving object, where we don't want it. Adding easing to opacity and color transitions will make the motion appear less smooth. Therefore, for these cases, motion should just be **linear**.
+
+## Types of animations
+
+### Hover
+
+Interactive elements (links, buttons, etc.) should have a hover state. A subtle animation for this transition adds a polished feel. We should target a `200ms linear` transition for a color hover effect.
+
+View the [interactive example](http://codepen.io/awhildy/full/GNyEvM/) here.
+
+![Hover animation](img/animation-hover.gif)
+
+### Dropdowns
+
+The dropdown menu should feel like it is appearing from the triggering element. Combining a position shift `400ms cubic-bezier(0.23, 1, 0.32, 1)` with a opacity animation `200ms linear` on the second half of the motion achieves this affect.
+
+View the [interactive example](http://codepen.io/awhildy/full/jVLJpb/) here.
+
+![Dropdown animation](img/animation-dropdown.gif)
+
+### Quick update
+
+When information is updating in place, a quick, subtle animation is needed. The previous content should cut out, and the new content should have a quick, `200ms linear` fade in.
+
+![Quick update animation](img/animation-quickupdate.gif)
+
+> TODO: Add guidance for other kinds of animation \ No newline at end of file
diff --git a/doc/development/ux_guide/basics.md b/doc/development/ux_guide/basics.md
index a29cfa096b2..76b739386a5 100644
--- a/doc/development/ux_guide/basics.md
+++ b/doc/development/ux_guide/basics.md
@@ -5,8 +5,6 @@
* [Typography](#typography)
* [Icons](#icons)
* [Color](#color)
-* [Motion](#motion)
-* [Voice and tone](#voice-and-tone)
---
@@ -61,16 +59,3 @@ GitLab uses Font Awesome icons throughout our interface.
> TODO: Establish a perspective for color in terms of our personality and rationalize with Marketing usage.
----
-
-## Motion
-
-Motion is a tool to help convey important relationships, changes or transitions between elements. It should be used sparingly and intentionally, highlighting the right elements at the right moment.
-
-> TODO: Determine a more concrete perspective on motion, create consistent easing/timing curves to follow.
-
----
-
-## Voice and tone
-
-The copy for GitLab is clear and direct. We strike a clear balance between professional and friendly. We can empathesize with users (such as celebrating completing all Todos), and remain respectful of the importance of the work. We are that trusted, friendly coworker that is helpful and understanding.
diff --git a/doc/development/ux_guide/copy.md b/doc/development/ux_guide/copy.md
index b557fb47120..8896d450f14 100644
--- a/doc/development/ux_guide/copy.md
+++ b/doc/development/ux_guide/copy.md
@@ -1,6 +1,8 @@
# Copy
-The copy and messaging is a core part of the experience of GitLab and the conversation with our users. Follow the below conventions throughout GitLab.
+The copy for GitLab is clear and direct. We strike a clear balance between professional and friendly. We can empathesize with users (such as celebrating completing all Todos), and remain respectful of the importance of the work. We are that trusted, friendly coworker that is helpful and understanding.
+
+The copy and messaging is a core part of the experience of GitLab and the conversation with our users. Follow the below conventions throughout GitLab.
>**Note:**
We are currently inconsistent with this guidance. Images below are created to illustrate the point. As this guidance is refined, we will ensure that our experiences align.
diff --git a/doc/development/ux_guide/img/animation-dropdown.gif b/doc/development/ux_guide/img/animation-dropdown.gif
new file mode 100644
index 00000000000..c9b31d26165
--- /dev/null
+++ b/doc/development/ux_guide/img/animation-dropdown.gif
Binary files differ
diff --git a/doc/development/ux_guide/img/animation-hover.gif b/doc/development/ux_guide/img/animation-hover.gif
new file mode 100644
index 00000000000..37ad9c76828
--- /dev/null
+++ b/doc/development/ux_guide/img/animation-hover.gif
Binary files differ
diff --git a/doc/development/ux_guide/img/animation-quickupdate.gif b/doc/development/ux_guide/img/animation-quickupdate.gif
new file mode 100644
index 00000000000..8db70bc3d24
--- /dev/null
+++ b/doc/development/ux_guide/img/animation-quickupdate.gif
Binary files differ
diff --git a/doc/development/ux_guide/index.md b/doc/development/ux_guide/index.md
index 8aed11ebac3..8a849f239dc 100644
--- a/doc/development/ux_guide/index.md
+++ b/doc/development/ux_guide/index.md
@@ -12,7 +12,17 @@ These guiding principles set a solid foundation for our design system, and shoul
---
### [Basics](basics.md)
-The basic ingredients of our experience establish our personality and feel. This section includes details about typography, color, and motion.
+The basic ingredients of our experience establish our personality and feel. This section includes details about typography, iconography, and color.
+
+---
+
+### [Animation](animation.md)
+Guidance on the timing, curving and motion for GitLab.
+
+---
+
+### [Copy](copy.md)
+Conventions on text and messaging within labels, buttons, and other components.
---
@@ -26,11 +36,6 @@ The GitLab experience is broken apart into several surfaces. Each of these surfa
---
-### [Copy](copy.md)
-Conventions on text and messaging within labels, buttons, and other components.
-
----
-
### [Features](features.md)
The previous building blocks are combined into complete features in the GitLab UX. Examples include our navigation, filters, search results, and empty states.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 5099d639347..9c6a9656557 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -76,7 +76,7 @@ Make sure you have the right version of Git installed
# Install Git
sudo apt-get install -y git-core
- # Make sure Git is version 2.7.4 or higher
+ # Make sure Git is version 2.8.4 or higher
git --version
Is the system packaged Git too old? Remove it and compile from source.
@@ -89,9 +89,9 @@ Is the system packaged Git too old? Remove it and compile from source.
# Download and compile from source
cd /tmp
- curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.7.4.tar.gz
- echo '7104c4f5d948a75b499a954524cb281fe30c6649d8abe20982936f75ec1f275b git-2.7.4.tar.gz' | shasum -a256 -c - && tar -xzf git-2.7.4.tar.gz
- cd git-2.7.4/
+ curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.8.4.tar.gz
+ echo '626e319f8a24fc0866167ea5f6bf3e2f38f69d6cb2e59e150f13709ca3ebf301 git-2.8.4.tar.gz' | shasum -a256 -c - && tar -xzf git-2.8.4.tar.gz
+ cd git-2.8.4/
./configure
make prefix=/usr/local all
diff --git a/features/admin/hooks.feature b/features/admin/hooks.feature
deleted file mode 100644
index 5ca332d9f1c..00000000000
--- a/features/admin/hooks.feature
+++ /dev/null
@@ -1,9 +0,0 @@
-@admin
-Feature: Admin Hooks
- Background:
- Given I sign in as an admin
-
- Scenario: On Admin Hooks
- Given I visit admin hooks page
- Then I submit the form with enabled SSL verification
- And I see new hook with enabled SSL verification \ No newline at end of file
diff --git a/features/admin/logs.feature b/features/admin/logs.feature
deleted file mode 100644
index ceb3bc34927..00000000000
--- a/features/admin/logs.feature
+++ /dev/null
@@ -1,8 +0,0 @@
-@admin
-Feature: Admin Logs
- Background:
- Given I sign in as an admin
-
- Scenario: On Admin Logs
- Given I visit admin logs page
- Then I should see tabs with available logs
diff --git a/features/steps/admin/hooks.rb b/features/steps/admin/hooks.rb
deleted file mode 100644
index 541e25fcb70..00000000000
--- a/features/steps/admin/hooks.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class Spinach::Features::AdminHooks < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedAdmin
-
- step "I submit the form with enabled SSL verification" do
- fill_in 'hook_url', with: 'http://google.com'
- check "Enable SSL verification"
- click_on "Add System Hook"
- end
-
- step "I see new hook with enabled SSL verification" do
- expect(page).to have_content "SSL Verification: enabled"
- end
-end
diff --git a/features/steps/admin/logs.rb b/features/steps/admin/logs.rb
deleted file mode 100644
index 63881d69146..00000000000
--- a/features/steps/admin/logs.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class Spinach::Features::AdminLogs < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedAdmin
-
- step 'I should see tabs with available logs' do
- expect(page).to have_content 'test.log'
- expect(page).to have_content 'githost.log'
- expect(page).to have_content 'application.log'
- end
-end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index cfb7c45de8e..26c8f2fecd0 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -28,14 +28,6 @@ module API
new_params
end
-
- def merge_request_for_resolving_discussions
- return unless merge_request_iid = params[:merge_request_for_resolving_discussions]
-
- @merge_request_for_resolving_discussions ||= MergeRequestsFinder.new(current_user, project_id: user_project.id).
- execute.
- find_by(iid: merge_request_iid)
- end
end
resource :issues do
@@ -179,7 +171,12 @@ module API
attrs = attributes_for_keys(keys)
attrs[:labels] = params[:labels] if params[:labels]
- attrs[:merge_request_for_resolving_discussions] = merge_request_for_resolving_discussions if params[:merge_request_for_resolving_discussions]
+
+ if merge_request_iid = params[:merge_request_for_resolving_discussions]
+ attrs[:merge_request_for_resolving_discussions] = MergeRequestsFinder.new(current_user, project_id: user_project.id).
+ execute.
+ find_by(iid: merge_request_iid)
+ end
# Convert and filter out invalid confidential flags
attrs['confidential'] = to_boolean(attrs['confidential'])
diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb
new file mode 100644
index 00000000000..d880f3f07db
--- /dev/null
+++ b/spec/features/admin/admin_browses_logs_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe 'Admin browses logs' do
+ before do
+ login_as :admin
+ end
+
+ it 'shows available log files' do
+ visit admin_logs_path
+
+ expect(page).to have_content 'test.log'
+ expect(page).to have_content 'githost.log'
+ expect(page).to have_content 'application.log'
+ end
+end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index b3ce72b1452..f246997d5a2 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -26,16 +26,17 @@ describe "Admin::Hooks", feature: true do
end
describe "New Hook" do
- before do
- @url = FFaker::Internet.uri("http")
+ let(:url) { FFaker::Internet.uri('http') }
+
+ it 'adds new hook' do
visit admin_hooks_path
- fill_in "hook_url", with: @url
- expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1)
- end
+ fill_in 'hook_url', with: url
+ check 'Enable SSL verification'
- it "opens new hook popup" do
+ expect { click_button 'Add System Hook' }.to change(SystemHook, :count).by(1)
+ expect(page).to have_content 'SSL Verification: enabled'
expect(current_path).to eq(admin_hooks_path)
- expect(page).to have_content(@url)
+ expect(page).to have_content(url)
end
end
diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb
new file mode 100644
index 00000000000..69281cecb7b
--- /dev/null
+++ b/spec/features/groups/labels/edit_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+feature 'Edit group label', feature: true do
+ given(:user) { create(:user) }
+ given(:group) { create(:group) }
+ given(:label) { create(:group_label, group: group) }
+
+ background do
+ group.add_owner(user)
+ login_as(user)
+ visit edit_group_label_path(group, label)
+ end
+
+ scenario 'update label with new title' do
+ fill_in 'label_title', with: 'new label name'
+ click_button 'Save changes'
+
+ expect(current_path).to eq(root_path)
+ expect(label.reload.title).to eq('new label name')
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
index 000b9aa6f83..9e027839f59 100644
--- a/spec/lib/gitlab/github_import/importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -155,7 +155,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
message: 'The remote data could not be fully imported.',
errors: [
{ type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" },
- { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" },
+ { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" },
{ type: :wiki, errors: "Gitlab::Shell::Error" },
{ type: :release, url: 'https://api.github.com/repos/octocat/Hello-World/releases/2', errors: "Validation failed: Description can't be blank" }
]
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index 4e7833c3162..bee9f714849 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -5,6 +5,13 @@ describe Ci::Variable, models: true do
let(:secret_value) { 'secret' }
+ it { is_expected.to validate_presence_of(:key) }
+ it { is_expected.to validate_uniqueness_of(:key).scoped_to(:gl_project_id) }
+ it { is_expected.to validate_length_of(:key).is_at_most(255) }
+ it { is_expected.to allow_value('foo').for(:key) }
+ it { is_expected.not_to allow_value('foo bar').for(:key) }
+ it { is_expected.not_to allow_value('foo/bar').for(:key) }
+
before :each do
subject.value = secret_value
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 6f84bffe046..4fa06a8c60a 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -35,7 +35,7 @@ describe Issue, "Issuable" do
it { is_expected.to validate_presence_of(:iid) }
it { is_expected.to validate_presence_of(:author) }
it { is_expected.to validate_presence_of(:title) }
- it { is_expected.to validate_length_of(:title).is_at_least(0).is_at_most(255) }
+ it { is_expected.to validate_length_of(:title).is_at_most(255) }
end
describe "Scope" do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index d06665197db..c8170164898 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -13,9 +13,9 @@ describe Environment, models: true do
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:project_id) }
- it { is_expected.to validate_length_of(:name).is_within(0..255) }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
- it { is_expected.to validate_length_of(:external_url).is_within(0..255) }
+ it { is_expected.to validate_length_of(:external_url).is_at_most(255) }
# To circumvent a not null violation of the name column:
# https://github.com/thoughtbot/shoulda-matchers/issues/336
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 90731f55470..2a33d819138 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -7,9 +7,13 @@ describe Key, models: true do
describe "Validation" do
it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to validate_length_of(:title).is_at_most(255) }
+
it { is_expected.to validate_presence_of(:key) }
- it { is_expected.to validate_length_of(:title).is_within(0..255) }
- it { is_expected.to validate_length_of(:key).is_within(0..5000) }
+ it { is_expected.to validate_length_of(:key).is_at_most(5000) }
+ it { is_expected.to allow_value('ssh-foo').for(:key) }
+ it { is_expected.to allow_value('ecdsa-foo').for(:key) }
+ it { is_expected.not_to allow_value('foo-bar').for(:key) }
end
describe "Methods" do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 431b3e4435f..ba0ed4a3603 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -4,11 +4,18 @@ describe Namespace, models: true do
let!(:namespace) { create(:namespace) }
it { is_expected.to have_many :projects }
- it { is_expected.to validate_presence_of :name }
+
+ it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name) }
- it { is_expected.to validate_presence_of :path }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
+
+ it { is_expected.to validate_length_of(:description).is_at_most(255) }
+
+ it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
- it { is_expected.to validate_presence_of :owner }
+ it { is_expected.to validate_length_of(:path).is_at_most(255) }
+
+ it { is_expected.to validate_presence_of(:owner) }
describe "Mass assignment" do
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 587ca1936a3..4d57330ed1c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -131,14 +131,18 @@ describe Project, models: true do
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) }
- it { is_expected.to validate_length_of(:name).is_within(0..255) }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).scoped_to(:namespace_id) }
- it { is_expected.to validate_length_of(:path).is_within(0..255) }
- it { is_expected.to validate_length_of(:description).is_within(0..2000) }
+ it { is_expected.to validate_length_of(:path).is_at_most(255) }
+
+ it { is_expected.to validate_length_of(:description).is_at_most(2000) }
+
it { is_expected.to validate_presence_of(:creator) }
+
it { is_expected.to validate_presence_of(:namespace) }
+
it { is_expected.to validate_presence_of(:repository_storage) }
it 'does not allow new projects beyond user limits' do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b797d19161d..d9b0e63eeb6 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -768,7 +768,6 @@ describe Repository, models: true do
expect(repository).not_to receive(:expire_root_ref_cache)
expect(repository).not_to receive(:expire_emptiness_caches)
expect(repository).to receive(:expire_branches_cache)
- expect(repository).to receive(:expire_has_visible_content_cache)
repository.update_branch_with_hooks(user, 'new-feature') { new_rev }
end
@@ -786,7 +785,6 @@ describe Repository, models: true do
expect(empty_repository).to receive(:expire_root_ref_cache)
expect(empty_repository).to receive(:expire_emptiness_caches)
expect(empty_repository).to receive(:expire_branches_cache)
- expect(empty_repository).to receive(:expire_has_visible_content_cache)
empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!',
'Updates file content', 'master', false)
@@ -829,15 +827,6 @@ describe Repository, models: true do
expect(subject).to eq(true)
end
-
- it 'caches the output' do
- expect(repository).to receive(:branch_count).
- once.
- and_return(3)
-
- repository.has_visible_content?
- repository.has_visible_content?
- end
end
end
@@ -918,20 +907,6 @@ describe Repository, models: true do
end
end
- describe '#expire_has_visible_content_cache' do
- it 'expires the visible content cache' do
- repository.has_visible_content?
-
- expect(repository).to receive(:branch_count).
- once.
- and_return(0)
-
- repository.expire_has_visible_content_cache
-
- expect(repository.has_visible_content?).to eq(false)
- end
- end
-
describe '#expire_branch_cache' do
# This method is private but we need it for testing purposes. Sadly there's
# no other proper way of testing caching operations.
@@ -967,7 +942,6 @@ describe Repository, models: true do
allow(repository).to receive(:empty?).and_return(true)
expect(cache).to receive(:expire).with(:empty?)
- expect(repository).to receive(:expire_has_visible_content_cache)
repository.expire_emptiness_caches
end
@@ -976,7 +950,6 @@ describe Repository, models: true do
allow(repository).to receive(:empty?).and_return(false)
expect(cache).not_to receive(:expire).with(:empty?)
- expect(repository).not_to receive(:expire_has_visible_content_cache)
repository.expire_emptiness_caches
end
@@ -1204,7 +1177,7 @@ describe Repository, models: true do
describe '#after_create_branch' do
it 'flushes the visible content cache' do
- expect(repository).to receive(:expire_has_visible_content_cache)
+ expect(repository).to receive(:expire_branches_cache)
repository.after_create_branch
end
@@ -1212,7 +1185,7 @@ describe Repository, models: true do
describe '#after_remove_branch' do
it 'flushes the visible content cache' do
- expect(repository).to receive(:expire_has_visible_content_cache)
+ expect(repository).to receive(:expire_branches_cache)
repository.after_remove_branch
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 79d2843e122..7425a897769 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -23,9 +23,9 @@ describe Snippet, models: true do
it { is_expected.to validate_presence_of(:author) }
it { is_expected.to validate_presence_of(:title) }
- it { is_expected.to validate_length_of(:title).is_within(0..255) }
+ it { is_expected.to validate_length_of(:title).is_at_most(255) }
- it { is_expected.to validate_length_of(:file_name).is_within(0..255) }
+ it { is_expected.to validate_length_of(:file_name).is_at_most(255) }
it { is_expected.to validate_presence_of(:content) }
@@ -61,6 +61,26 @@ describe Snippet, models: true do
end
end
+ describe '#file_name' do
+ let(:project) { create(:empty_project) }
+
+ context 'file_name is nil' do
+ let(:snippet) { create(:snippet, project: project, file_name: nil) }
+
+ it 'returns an empty string' do
+ expect(snippet.file_name).to eq ''
+ end
+ end
+
+ context 'file_name is not nil' do
+ let(:snippet) { create(:snippet, project: project, file_name: 'foo.txt') }
+
+ it 'returns the file_name' do
+ expect(snippet.file_name).to eq 'foo.txt'
+ end
+ end
+ end
+
describe "#content_html_invalidated?" do
let(:snippet) { create(:snippet, content: "md", content_html: "html", file_name: "foo.md") }
it "invalidates the HTML cache of content when the filename changes" do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 2244803f90c..bad6ed9e146 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -79,7 +79,7 @@ describe User, models: true do
it { is_expected.to allow_value(0).for(:projects_limit) }
it { is_expected.not_to allow_value(-1).for(:projects_limit) }
- it { is_expected.to validate_length_of(:bio).is_within(0..255) }
+ it { is_expected.to validate_length_of(:bio).is_at_most(255) }
it_behaves_like 'an object with email-formated attributes', :email do
subject { build(:user) }
diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb
index 5fa7299044e..aabab8e6ae6 100644
--- a/spec/requests/api/deploy_keys_spec.rb
+++ b/spec/requests/api/deploy_keys_spec.rb
@@ -75,7 +75,6 @@ describe API::DeployKeys, api: true do
expect(response).to have_http_status(400)
expect(json_response['message']['key']).to eq([
'can\'t be blank',
- 'is too short (minimum is 0 characters)',
'is invalid'
])
end
@@ -85,8 +84,7 @@ describe API::DeployKeys, api: true do
expect(response).to have_http_status(400)
expect(json_response['message']['title']).to eq([
- 'can\'t be blank',
- 'is too short (minimum is 0 characters)'
+ 'can\'t be blank'
])
end
diff --git a/spec/support/matchers/is_within.rb b/spec/support/matchers/is_within.rb
deleted file mode 100644
index 0c35fc7e899..00000000000
--- a/spec/support/matchers/is_within.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# Extend shoulda-matchers
-module Shoulda::Matchers::ActiveModel
- class ValidateLengthOfMatcher
- # Shortcut for is_at_least and is_at_most
- def is_within(range)
- is_at_least(range.min) && is_at_most(range.max)
- end
- end
-end