Commit 2f252d8f authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge branch 'master' into improve-pipeline-design

parents 8d033236 16ca3ee6
require: rubocop-rspec
AllCops:
TargetRubyVersion: 2.1
# Cop names are not displayed in offense messages by default. Change behavior
......@@ -152,7 +154,7 @@ Style/ConstantName:
# Use def with parentheses when there are arguments.
Style/DefWithParentheses:
Enabled: false
Enabled: true
# Checks for use of deprecated Hash methods.
Style/DeprecatedHashMethods:
......@@ -299,7 +301,7 @@ Style/IndentHash:
# Use Kernel#loop for infinite loops.
Style/InfiniteLoop:
Enabled: false
Enabled: true
# Use the new lambda literal syntax for single-line blocks.
Style/Lambda:
......@@ -333,6 +335,12 @@ Style/MethodName:
Style/ModuleFunction:
Enabled: false
# Checks that the closing brace in an array literal is either on the same line
# as the last array element, or a new line.
Style/MultilineArrayBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Avoid multi-line chains of blocks.
Style/MultilineBlockChain:
Enabled: false
......@@ -341,10 +349,22 @@ Style/MultilineBlockChain:
Style/MultilineBlockLayout:
Enabled: true
# Checks that the closing brace in a hash literal is either on the same line as
# the last hash element, or a new line.
Style/MultilineHashBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Do not use then for multi-line if/unless.
Style/MultilineIfThen:
Enabled: false
# Checks that the closing brace in a method call is either on the same line as
# the last method argument, or a new line.
Style/MultilineMethodCallBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Checks indentation of method calls with the dot operator that span more than
# one line.
Style/MultilineMethodCallIndentation:
......@@ -525,10 +545,9 @@ Style/SpaceAfterSemicolon:
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
# TODO: Enable SpaceAroundKeyword Cop.
# Use a space around keywords if appropriate.
Style/SpaceAroundKeyword:
Enabled: false
Enabled: true
# Use a single space around operators.
Style/SpaceAroundOperators:
......@@ -755,19 +774,19 @@ Lint/BlockAlignment:
# Default values in optional keyword arguments and optional ordinal arguments
# should not refer back to the name of the argument.
Lint/CircularArgumentReference:
Enabled: false
Enabled: true
# Checks for condition placed in a confusing position relative to the keyword.
Lint/ConditionPosition:
Enabled: false
Enabled: true
# Check for debugger calls.
Lint/Debugger:
Enabled: false
Enabled: true
# Align ends corresponding to defs correctly.
Lint/DefEndAlignment:
Enabled: false
Enabled: true
# Check for deprecated class method calls.
Lint/DeprecatedClassMethods:
......@@ -783,15 +802,15 @@ Lint/DuplicatedKey:
# Check for immutable argument given to each_with_object.
Lint/EachWithObjectArgument:
Enabled: false
Enabled: true
# Check for odd code arrangement in an else block.
Lint/ElseLayout:
Enabled: false
Enabled: true
# Checks for empty ensure block.
Lint/EmptyEnsure:
Enabled: false
Enabled: true
# Checks for empty string interpolation.
Lint/EmptyInterpolation:
......@@ -799,37 +818,36 @@ Lint/EmptyInterpolation:
# Align ends correctly.
Lint/EndAlignment:
Enabled: false
Enabled: true
# END blocks should not be placed inside method definitions.
Lint/EndInMethod:
Enabled: false
Enabled: true
# Do not use return in an ensure block.
Lint/EnsureReturn:
Enabled: false
Enabled: true
# The use of eval represents a serious security risk.
Lint/Eval:
Enabled: false
Enabled: true
# Catches floating-point literals too large or small for Ruby to represent.
Lint/FloatOutOfRange:
Enabled: false
Enabled: true
# The number of parameters to format/sprint must match the fields.
Lint/FormatParameterMismatch:
Enabled: false
Enabled: true
# Don't suppress exception.
Lint/HandleExceptions:
Enabled: false
# TODO: Enable ImplicitStringConcatenation Cop.
# Checks for adjacent string literals on the same line, which could better be
# represented as a single string literal.
Lint/ImplicitStringConcatenation:
Enabled: false
Enabled: true
# TODO: Enable IneffectiveAccessModifier Cop.
# Checks for attempts to use `private` or `protected` to set the visibility
......@@ -840,7 +858,7 @@ Lint/IneffectiveAccessModifier:
# Checks for invalid character literals with a non-escaped whitespace
# character.
Lint/InvalidCharacterLiteral:
Enabled: false
Enabled: true
# Checks of literals used in conditions.
Lint/LiteralInCondition:
......@@ -848,7 +866,7 @@ Lint/LiteralInCondition:
# Checks for literals used in interpolation.
Lint/LiteralInInterpolation:
Enabled: false
Enabled: true
# Use Kernel#loop with break rather than begin/end/until or begin/end/while
# for post-loop tests.
......@@ -857,11 +875,11 @@ Lint/Loop:
# Do not use nested method definitions.
Lint/NestedMethodDefinition:
Enabled: false
Enabled: true
# Do not omit the accumulator when calling `next` in a `reduce`/`inject` block.
Lint/NextWithoutAccumulator:
Enabled: false
Enabled: true
# Checks for method calls with a space before the opening parenthesis.
Lint/ParenthesesAsGroupedExpression:
......@@ -870,11 +888,11 @@ Lint/ParenthesesAsGroupedExpression:
# Checks for `rand(1)` calls. Such calls always return `0` and most likely
# a mistake.
Lint/RandOne:
Enabled: false
Enabled: true
# Use parentheses in the method call to avoid confusion about precedence.
Lint/RequireParentheses:
Enabled: false
Enabled: true
# Avoid rescuing the Exception class.
Lint/RescueException:
......@@ -909,7 +927,7 @@ Lint/UnusedMethodArgument:
# Unreachable code.
Lint/UnreachableCode:
Enabled: false
Enabled: true
# Checks for useless access modifiers.
Lint/UselessAccessModifier:
......@@ -921,19 +939,19 @@ Lint/UselessAssignment:
# Checks for comparison of something with itself.
Lint/UselessComparison:
Enabled: false
Enabled: true
# Checks for useless `else` in `begin..end` without `rescue`.
Lint/UselessElseWithoutRescue:
Enabled: false
Enabled: true
# Checks for useless setter call to a local variable.
Lint/UselessSetterCall:
Enabled: false
Enabled: true
# Possible use of operator/literal/variable in void context.
Lint/Void:
Enabled: false
Enabled: true
##################### Performance ############################
......@@ -942,11 +960,10 @@ Lint/Void:
Performance/Casecmp:
Enabled: true
# TODO: Enable DoubleStartEndWith Cop.
# Use `str.{start,end}_with?(x, ..., y, ...)` instead of
# `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`.
Performance/DoubleStartEndWith:
Enabled: false
Enabled: true
# TODO: Enable EndWith Cop.
# Use `end_with?` instead of a regex match anchored to the end of a string.
......@@ -957,10 +974,9 @@ Performance/EndWith:
Performance/LstripRstrip:
Enabled: true
# TODO: Enable RangeInclude Cop.
# Use `Range#cover?` instead of `Range#include?`.
Performance/RangeInclude:
Enabled: false
Enabled: true
# TODO: Enable RedundantBlockCall Cop.
# Use `yield` instead of `block.call`.
......@@ -980,16 +996,14 @@ Performance/RedundantMerge:
MaxKeyValuePairs: 2
Enabled: false
# TODO: Enable RedundantSortBy Cop.
# Use `sort` instead of `sort_by { |x| x }`.
Performance/RedundantSortBy:
Enabled: false
Enabled: true
# TODO: Enable StartWith Cop.
# Use `start_with?` instead of a regex match anchored to the beginning of a
# string.
Performance/StartWith:
Enabled: false
Enabled: true
# Use `tr` instead of `gsub` when you are replacing the same number of
# characters. Use `delete` instead of `gsub` when you are deleting
......@@ -1025,11 +1039,11 @@ Rails/Delegate:
# Prefer `find_by` over `where.first`.
Rails/FindBy:
Enabled: false
Enabled: true
# Prefer `all.find_each` over `all.find`.
Rails/FindEach:
Enabled: false
Enabled: true
# Prefer has_many :through to has_and_belongs_to_many.
Rails/HasAndBelongsToMany:
......@@ -1041,7 +1055,7 @@ Rails/Output:
# Checks for incorrect grammar when using methods like `3.day.ago`.
Rails/PluralizationGrammar:
Enabled: false
Enabled: true
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute:
......@@ -1049,7 +1063,7 @@ Rails/ReadWriteAttribute:
# Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs:
Enabled: false
Enabled: true
# Checks the correct usage of time zone aware methods.
# http://danilenko.org/2012/7/6/rails_timezones
......@@ -1059,3 +1073,65 @@ Rails/TimeZone:
# Use validates :attribute, hash of validations.
Rails/Validation:
Enabled: false
##################### RSpec ##################################
# Check that instances are not being stubbed globally.
RSpec/AnyInstance:
Enabled: false
# Check that the first argument to the top level describe is the tested class or
# module.
RSpec/DescribeClass:
Enabled: false
# Use `described_class` for tested class / module.
RSpec/DescribeMethod:
Enabled: false
# Checks that the second argument to top level describe is the tested method
# name.
RSpec/DescribedClass:
Enabled: false
# Checks for long example.
RSpec/ExampleLength:
Enabled: false
Max: 5
# Do not use should when describing your tests.
RSpec/ExampleWording:
Enabled: false
CustomTransform:
be: is
have: has
not: does not
IgnoredWords: []
# Checks the file and folder naming of the spec file.
RSpec/FilePath:
Enabled: false
CustomTransform:
RuboCop: rubocop
RSpec: rspec
# Checks if there are focused specs.
RSpec/Focus:
Enabled: true
# Checks for the usage of instance variables.
RSpec/InstanceVariable:
Enabled: false
# Checks for multiple top-level describes.
RSpec/MultipleDescribes:
Enabled: false
# Enforces the usage of the same method on all negative message expectations.
RSpec/NotToNot:
EnforcedStyle: not_to
Enabled: false
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
Enabled: false
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.0 (unreleased)
v 8.9.0 (unreleased)
- Redesign navigation for project pages
v 8.8.2 (unreleased)
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
- Fix Error 500 in CI charts by gracefully handling commits with no durations
v 8.8.1
- Add documentation for the "Health Check" feature
- Allow anonymous users to access a public project's pipelines
- Fix MySQL compatibility in zero downtime migrations helpers
- Fix the CI login to Container Registry (the gitlab-ci-token user)
v 8.8.0
- Implement GFM references for milestones (Alejandro Rodríguez)
- Snippets tab under user profile. !4001 (Long Nguyen)
- Fix error when using link to uploads in global snippets
......@@ -14,6 +27,7 @@ v 8.8.0 (unreleased)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Improve design of Pipeline View
- Fix scope used when accessing container registry
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
......
......@@ -293,7 +293,8 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.38.0', require: false
gem 'rubocop', '~> 0.40.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.11.0', require: false
......@@ -325,7 +326,7 @@ gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'
## CI
gem 'activerecord-session_store', '~> 0.1.0'
gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2'
# OAuth
......
......@@ -33,10 +33,12 @@ GEM
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5)
activerecord-session_store (1.0.0)
actionpack (>= 4.0, < 5.1)
activerecord (>= 4.0, < 5.1)
multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
......@@ -549,7 +551,7 @@ GEM
orm_adapter (0.5.0)
paranoia (2.1.4)
activerecord (~> 4.0)
parser (2.3.0.6)
parser (2.3.1.0)
ast (~> 2.2)
pg (0.18.4)
poltergeist (1.9.0)
......@@ -684,15 +686,17 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.4.1)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
rubocop (0.40.0)
parser (>= 2.3.1.0, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.5.0)
rubocop (>= 0.40.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
ruby-progressbar (1.8.1)
ruby-saml (1.1.2)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
......@@ -839,7 +843,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.0.2)
unicode-display_width (1.0.5)
unicorn (4.9.0)
kgio (~> 2.6)
rack
......@@ -883,7 +887,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 4.0.2)
activerecord-session_store (~> 0.1.0)
activerecord-session_store (~> 1.0.0)
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
......@@ -1013,7 +1017,8 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0)
rspec-retry
rubocop (~> 0.38.0)
rubocop (~> 0.40.0)
rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
......@@ -1058,4 +1063,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.12.3
1.12.4
8.8.0-pre
8.9.0-pre
......@@ -119,7 +119,7 @@ class Dispatcher
new UsersSelect()
when 'projects'
new NamespaceSelect()
when 'dashboard'
when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles'
new Profile()
......
......@@ -11,6 +11,7 @@ class @DueDateSelect
$block = $dropdown.closest('.block')
$selectbox = $dropdown.closest('.selectbox')
$value = $block.find('.value')
$valueContent = $block.find('.value-content')
$sidebarValue = $('.js-due-date-sidebar-value', $block)
fieldName = $dropdown.data('field-name')
......@@ -23,11 +24,15 @@ class @DueDateSelect
$value.removeAttr('style')
)
addDueDate = ->
addDueDate = (isDropdown) ->
# Create the post date
value = $("input[name='#{fieldName}']").val()
if value isnt ''
date = new Date value.replace(new RegExp('-', 'g'), ',')
mediumDate = $.datepicker.formatDate 'M d, yy', date
else
mediumDate = 'None'
data = {}
data[abilityName] = {}
......@@ -39,23 +44,35 @@ class @DueDateSelect
data: data
beforeSend: ->
$loading.fadeIn()
if isDropdown
$dropdown.trigger('loading.gl.dropdown')
$selectbox.hide()
$value.removeAttr('style')
$value.html(mediumDate)
$valueContent.html(mediumDate)
$sidebarValue.html(mediumDate)
if value isnt ''
$('.js-remove-due-date-holder').removeClass 'hidden'
else
$('.js-remove-due-date-holder').addClass 'hidden'
).done (data) ->
if isDropdown
$dropdown.trigger('loaded.gl.dropdown')
$dropdown.dropdown('toggle')
$loading.fadeOut()
$block.on 'click', '.js-remove-due-date', (e) ->
e.preventDefault()
$("input[name='#{fieldName}']").val ''
addDueDate(false)
$datePicker.datepicker(
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='#{fieldName}']").val()
altField: "input[name='#{fieldName}']"
onSelect: ->
addDueDate()
addDueDate(true)
)
$(document)
......
......@@ -512,7 +512,7 @@ class GitLabDropdown
return false
if currentKeyCode is 13
@selectRowAtIndex currentIndex
@selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'
......
......@@ -20,6 +20,15 @@ class @IssuableForm
@initWip()
$issuableDueDate = $('#issuable-due-date')
if $issuableDueDate.length
$('.datepicker').datepicker(
dateFormat: 'yy-mm-dd',
onSelect: (dateText, inst) ->
$issuableDueDate.val dateText
).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,
......
......@@ -113,7 +113,7 @@ class @MergeRequestWidget
switch state
when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
when "running", "pending"
when "running"
@setMergeButtonClass('btn-warning')
when "success"
@setMergeButtonClass('btn-create')
......@@ -126,6 +126,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
$('.accept_merge_request')
$('.js-merge-button')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
......@@ -3,10 +3,10 @@
class @ShortcutsDashboardNavigation extends Shortcuts
constructor: ->
super()
Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-activity'))
Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-issues'))
Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-merge_requests'))
Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-projects'))
Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-activity'))
Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-issues'))
Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-merge_requests'))
Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-projects'))
@findAndFollowLink: (selector) ->
link = $(selector).attr('href')
......
......@@ -45,6 +45,7 @@
&.s32 { font-size: 20px; line-height: 32px; }
&.s40 { font-size: 16px; line-height: 40px; }
&.s60 { font-size: 32px; line-height: 60px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 90px; }
&.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 140px; }
......
......@@ -24,8 +24,8 @@
background-color: $background-color;
padding: $gl-padding;
margin-bottom: 0;
border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
color: $gl-gray;
&.oneline-block {
......@@ -110,9 +110,9 @@
.cover-title {
color: $gl-header-color;
margin: 0;
font-size: 23px;
font-size: 24px;
font-weight: normal;
margin: 16px 0 5px;
margin-bottom: 5px;
color: #4c4e54;
font-size: 23px;
line-height: 1.1;
......@@ -137,7 +137,6 @@
}
.cover-desc {
padding: 0 $gl-padding 3px;
color: $gl-text-color;
&.username:last-child {
......@@ -205,7 +204,7 @@
.content-block {
padding: $gl-padding 0;
border-bottom: 1px solid $border-color;
border-bottom: 1px solid $white-dark;
&.oneline-block {
line-height: 36px;
......
......@@ -28,10 +28,6 @@ input[type='text'].danger {
}
label {
&.control-label {
@extend .col-sm-2;
}
&.inline-label {
margin: 0;
}
......@@ -41,6 +37,10 @@ label {
}
}
.control-label {
@extend .col-sm-2;
}
.inline-input-group {
width: 250px;
}
......
......@@ -48,10 +48,6 @@
display: block;
}
.project-home-desc {
font-size: 21px;
}
.project-repo-buttons,
.git-clone-holder {
display: none;
......
......@@ -196,7 +196,7 @@
position: fixed;
top: $header-height;
width: 100%;
z-index: 1;
z-index: 3;
background: $background-color;
border-bottom: 1px solid $border-color;
transition-duration: .3s;
......@@ -238,6 +238,10 @@
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
li.active {
font-weight: bold;
}
}
}
......@@ -246,6 +250,11 @@
height: 51px;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
li {
......@@ -279,4 +288,8 @@
margin-top: 96px;
}
}
.right-sidebar {
top: ($header-height * 2) + 2;
}
}
......@@ -119,8 +119,8 @@ $border-white-light: #f1f2f4;
$border-white-normal: #d6dae2;
$border-white-dark: #c6cacf;
$border-gray-light: rgba(0, 0, 0, 0.06);
$border-gray-normal: rgba(0, 0, 0, 0.10);;
$border-gray-light: #dcdcdc;
$border-gray-normal: rgba(0, 0, 0, 0.10);
$border-gray-dark: #c6cacf;
$border-green-light: #2faa60;
......
......@@ -150,6 +150,10 @@
font-weight: 600;
}
.light {
font-weight: normal;
}
.sidebar-collapsed-icon {
display: none;
}
......
......@@ -26,8 +26,13 @@
}
.project-home-panel {
padding-bottom: 40px;
border-bottom: 1px solid $border-color;
background: $white-light;
text-align: left;
padding: 24px 0;
.container-fluid {
position: relative;
}
.cover-controls {
.project-settings-dropdown {
......@@ -43,21 +48,55 @@
}
}
.project-identicon-holder {
margin-bottom: 16px;
.cover-title {
margin-bottom: 0;
}
.project-image-container {
@include make-sm-column(1);
max-width: 86px;
min-width: 86px;
padding-right: 0;
margin: 11px 0;
.avatar, .identicon {
margin: 0 auto;
float: none;
@media (max-width: $screen-md-max) {
padding-left: 0;
margin: 0 0 10px;
max-width: none;
min-width: none;
.avatar.s70 {
margin: auto;
}
}
}
.project-info {
@include make-sm-column(10);
h1 {
font-size: 24px;
font-weight: normal;
margin: 0;
}
.project-home-desc {
p {
margin: 0;
}
}
}
.identicon {
float: left;
@include border-radius(50%);
}
.avatar {
float: none;
}
.notifications-btn {
margin-top: -28px;
.fa-bell {
margin-right: 6px;
......@@ -69,28 +108,45 @@
}
.project-repo-buttons {
margin-top: 20px;
margin-bottom: 0;
font-size: 0;
.count-buttons {
display: block;
margin-bottom: 20px;
.btn {
@include btn-gray;
padding: 3px 10px;
text-transform: none;
background-color: $background-color;
.fa {
color: $layout-link-gray;
}
.clone-row {
.split-repo-buttons,
.project-clone-holder {
display: inline-block;
.fa-caret-down {
margin-left: 3px;
}
}
.split-repo-buttons {
margin: 0 12px;
.btn-group:not(:first-child):not(:last-child) > .btn {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
form {
margin-left: 10px;
}
.btn {
@include btn-gray;
text-transform: none;
.count-buttons {
display: inline-block;
vertical-align: top;
margin-top: 16px;
}
.project-clone-holder {
display: inline-block;
margin-top: 16px;
input {
height: 29px;
}
}
.count-with-arrow {
......@@ -140,14 +196,18 @@
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
padding: 10px 14px;
padding: 7px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
white-space: nowrap;
margin: 0 11px 0 4px;
margin: 0 10px 0 4px;
a {
color: inherit;
}
&:hover {
background: #fff;
......@@ -155,13 +215,37 @@
}
}
}
.project-right-buttons {
position: absolute;
right: 16px;
bottom: 0;
.btn {
padding: 3px 10px;
background-color: $background-color;
}
@media (max-width: 1304px) {
top: 0;
}
}
@media (max-width: $screen-md-max) {
text-align: center;
.project-info,
.project-image-container {
width: 100%;
}
}
}
.split-one {
display: inline-table;
margin-right: 12px;
a {
> a {
margin: -1px;
}
}
......@@ -285,11 +369,11 @@ a.deploy-project-label {
}
.project-stats {
text-align: center;
margin-top: $gl-padding;
margin-bottom: 0;
padding-top: 10px;
padding-bottom: 4px;
padding: 16px 0;
background-color: $white-light;
font-size: 0;
ul.nav {
display: inline-block;
......@@ -300,12 +384,11 @@ a.deploy-project-label {
}
.nav > li > a {
@include btn-default;
@include btn-gray;
background-color: transparent;
border: 1px solid #f7f8fa;
margin-left: 12px;
margin-right: 12px;
padding: 0 10px;
font-size: 15px;
color: $notes-light-color;
}
li {
......@@ -325,6 +408,10 @@ a.deploy-project-label {
background-color: #f0f2f5;
}
}
&.row-content-block.second-block {
margin-top: 0;
}
}
pre.light-well {
......@@ -442,9 +529,14 @@ pre.light-well {
border-top: 0;
.edit-project-readme {
z-index: 100;
z-index: 2;
position: relative;
}
.wiki h1 {
border-bottom: none;
padding: 0;
}
}
.git-clone-holder {
......
......@@ -36,7 +36,7 @@ class JwtController < ApplicationController
end
def authenticate_project(login, password)
if login == 'gitlab_ci_token'
if login == 'gitlab-ci-token'
Project.find_by(builds_enabled: true, runners_token: password)
end
end
......
......@@ -110,8 +110,7 @@ module ApplicationHelper
]
# If reference is commit id - we should add it to branch/tag selectbox
if(@ref && !options.flatten.include?(@ref) &&
@ref =~ /\A[0-9a-zA-Z]{6,52}\z/)
if @ref && !options.flatten.include?(@ref) && @ref =~ /\A[0-9a-zA-Z]{6,52}\z/
options << ['Commit', [@ref]]
end
......
......@@ -13,7 +13,7 @@ module GitlabMarkdownHelper
def link_to_gfm(body, url, html_options = {})
return "" if body.blank?
escaped_body = if body =~ /\A\<img/
escaped_body = if body.start_with?('<img')
body
else
escape_once(body)
......
......@@ -144,6 +144,10 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
if can?(current_user, :read_pipeline, project)
nav_tabs << :pipelines
end
if can?(current_user, :read_build, project)
nav_tabs << :builds
end
......
......@@ -95,7 +95,9 @@ module TabHelper
end
def project_tab_class
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
if controller.controller_path.start_with?('projects')
return 'active'
end
if ['services', 'hooks', 'deploy_keys', 'protected_branches'].include? controller.controller_name
"active"
......@@ -112,7 +114,7 @@ module TabHelper
end
def profile_tab_class
if controller.controller_path =~ /\Aprofiles/
if controller.controller_path.start_with?('profiles')
return 'active'
end
......
......@@ -60,6 +60,7 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
:read_pipeline,
:read_commit_status,
:read_container_image,
:download_code
......
......@@ -7,7 +7,7 @@ class ApplicationSetting < ActiveRecord::Base
serialize :restricted_visibility_levels
serialize :import_sources
serialize :disabled_oauth_sign_in_sources
serialize :disabled_oauth_sign_in_sources, Array
serialize :restricted_signup_domains, Array
attr_accessor :restricted_signup_domains_raw
......
......@@ -253,7 +253,7 @@ module Network
leaves = []
leaves.push(commit) if commit.space.zero?
while true
loop do
return leaves if commit.parents(@map).count.zero?
commit = commit.parents(@map).first
......
......@@ -6,7 +6,7 @@ module Auth
return error('not found', 404) unless registry.enabled
if params[:offline_token]
return error('unauthorized', 401) unless current_user
return error('unauthorized', 401) unless current_user || project
else
return error('forbidden', 403) unless scope
end
......@@ -20,7 +20,7 @@ module Auth
token.issuer = registry.issuer
token.audience = AUDIENCE
token[:access] = names.map do |name|
{ type: 'repository', name: name, actions: %w(pull push) }
{ type: 'repository', name: name, actions: %w(*) }
end
token.encoded
end
......
%ul.nav.nav-sidebar
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do
= link_to dashboard_projects_path, title: 'Projects' do
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
= icon('bookmark fw')
%span
Projects
......@@ -11,7 +11,7 @@
Todos
%span.count.todos-pending-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'shortcuts-activity', title: 'Activity' do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
= icon('dashboard fw')
%span
Activity
......@@ -26,13 +26,13 @@
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
= icon('exclamation-circle fw')
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
......
%ul.nav.nav-sidebar
- if @project.group
= nav_link do
= link_to group_path(@project.group), title: 'Go to group', class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Go to group
- else
= nav_link do
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Go to dashboard
%li.separate-item
- if current_user
.controls
- access = user_max_access_in_project(current_user.id, @project)
- can_edit = can?(current_user, :admin_project, @project)
.dropdown.project-settings-dropdown
%a.dropdown-new.btn.btn-default#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
= icon('cog')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right
= render 'layouts/nav/project_settings'
%li.divider
- if can_edit
%li
= link_to edit_project_path(@project) do
Edit Project
- if access
%li
= link_to leave_namespace_project_project_members_path(@project.namespace, @project),
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
Leave Project
%ul.nav-links
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
= icon('bookmark fw')
......@@ -38,20 +44,21 @@
%span
Commits
- if project_nav_tab? :builds
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
= icon('ship fw')
%span
Pipelines
%span.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
= icon('cubes fw')
%span
Builds
%span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do
......@@ -81,7 +88,7 @@
%span
Issues
- if @project.default_issues_tracker?
%span.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
%span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
......@@ -89,14 +96,7 @@
= icon('tasks fw')
%span
Merge Requests
%span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :team
= nav_link(controller: [:project_members, :teams]) do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
= icon('users fw')
%span
Members
%span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
......@@ -112,13 +112,6 @@
%span
Wiki
- if project_nav_tab? :forks
= nav_link(controller: :forks, action: :index) do
= link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks' do
= icon('code-fork fw')
%span
Forks
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
......@@ -126,13 +119,6 @@
%span
Snippets
- if project_nav_tab? :settings
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
= link_to edit_project_path(@project), title: 'Settings' do
= icon('cogs fw')
%span
Settings
-# Global shortcut to network page for compatibility
- if project_nav_tab? :network
%li.hidden
......
%ul.nav.nav-sidebar
= nav_link do
= link_to project_path(@project), title: 'Go to project', class: 'back-link' do
= icon('caret-square-o-left fw')
- if project_nav_tab? :team
= nav_link(controller: [:project_members, :teams]) do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
%span
Go to project
Members
%li.separate-item
%ul.sidebar-subnav
= nav_link(path: 'projects#edit') do
= link_to edit_project_path(@project), title: 'Project Settings' do
= icon('pencil-square-o fw')
%span
Project Settings
- if @project.allowed_to_share_with_group?
- if @project.allowed_to_share_with_group?
= nav_link(controller: :group_links) do
= link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do
= icon('share-square-o fw')
%span
Groups
= nav_link(controller: :deploy_keys) do
= nav_link(controller: :deploy_keys) do
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
= icon('key fw')
%span
Deploy Keys
= nav_link(controller: :hooks) do
= nav_link(controller: :hooks) do
= link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do
= icon('link fw')
%span
Webhooks
= nav_link(controller: :services) do
= nav_link(controller: :services) do
= link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
= icon('cogs fw')
%span
Services
= nav_link(controller: :protected_branches) do
= nav_link(controller: :protected_branches) do
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
= icon('lock fw')
%span
Protected Branches
- if @project.builds_enabled?
- if @project.builds_enabled?
= nav_link(controller: :runners) do
= link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do
= icon('cog fw')
%span
Runners
= nav_link(controller: :variables) do
= link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do
= icon('code fw')
%span
Variables
= nav_link(controller: :triggers) do
= link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
= icon('retweet fw')
%span
Triggers
= nav_link(controller: :badges) do
= link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
= icon('star-half-empty fw')
%span
Badges
- page_title @project.name_with_namespace
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
- sidebar "project" unless sidebar
- nav "project"
- content_for :scripts_body_top do
- project = @target_project || @project
......
- page_title "Settings"
- header_title project_title(@project, "Settings", edit_project_path(@project))
- sidebar "project_settings"
- nav "project"
= render template: "layouts/project"
- empty_repo = @project.empty_repo?
.project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.container-fluid.container-limited
.row
.project-image-container
= project_icon(@project, alt: '', class: 'project-avatar avatar s70')
.project-info
.cover-title.project-home-desc
%h1
= @project.name
......@@ -18,42 +21,17 @@
= link_to project_path(forked_from_project) do
= forked_from_project.namespace.try(:name)
.cover-controls
- if current_user
= link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), class: 'btn btn-gray' do
= icon('rss')
- access = user_max_access_in_project(current_user.id, @project)
- can_edit = can?(current_user, :admin_project, @project)
- if access || can_edit
%span.dropdown.project-settings-dropdown
%a.dropdown-new.btn.btn-gray#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
= icon('cog')
= icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right
- if can_edit
%li
= link_to edit_project_path(@project) do
Edit Project
- if access
%li
= link_to leave_namespace_project_project_members_path(@project.namespace, @project),
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
Leave Project
.project-repo-buttons
.split-one.count-buttons
.count-buttons
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
.clone-row
.project-clone-holder
= render "shared/clone_panel"
.split-repo-buttons
.btn-group.pull-left
.project-repo-buttons.btn-group.project-right-buttons
= render "projects/buttons/download"
= render 'projects/buttons/dropdown'
= render 'projects/buttons/notifications'
:javascript
......
......@@ -2,7 +2,7 @@
.btn-group
%a.btn.dropdown-toggle{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
- can_create_issue = can?(current_user, :create_issue, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- can_create_snippet = can?(current_user, :create_snippet, @project)
......
......@@ -12,7 +12,8 @@
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do
= icon('code-fork fw')
Fork
= link_to namespace_project_forks_path(@project.namespace, @project), class: 'count-with-arrow' do
%div.count-with-arrow
%span.arrow
%span.count
= link_to namespace_project_forks_path(@project.namespace, @project) do
= @project.forks_count
- if @notification_setting
= form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
= f.hidden_field :level
%span.dropdown
.dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
= icon('bell')
= notification_title(@notification_setting.level)
= icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
- NotificationSetting.levels.each do |level|
= notification_list_item(level.first, @notification_setting)
......@@ -42,7 +42,7 @@
%td
= build.name
.pull-right
%td
.label-container
- if build.tags.any?
- build.tags.each do |tag|
......
......@@ -37,5 +37,16 @@
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Build ID
%th Name
%th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
%th Coverage
%th
- ci_commit.statuses.stages.each do |stage|
= render 'projects/commit/ci_stage', stage: stage, statuses: ci_commit.statuses.where(stage: stage)
......@@ -4,7 +4,7 @@
%hr
%ul.content-list
.light.prepend-top-default
%li.light.prepend-top-default
%p
A 'container image' is a snapshot of a container.
You can host your container images with GitLab.
......
......@@ -13,20 +13,20 @@
= render "home_panel"
.project-stats.row-content-block.second-block
.container-fluid.container-limited
%ul.nav
%li
= link_to project_files_path(@project) do
Files (#{repository_size})
%li
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
= pluralize(number_with_delimiter(@project.commit_count), 'commit')
#{'Commit'.pluralize(@project.commit_count)} (#{number_with_delimiter(@project.commit_count)})
%li
= link_to namespace_project_branches_path(@project.namespace, @project) do
= pluralize(number_with_delimiter(@repository.branch_names.count), 'branch')
#{'Branch'.pluralize(@repository.branch_names.count)} (#{number_with_delimiter(@repository.branch_names.count)})
%li
= link_to namespace_project_tags_path(@project.namespace, @project) do
= pluralize(number_with_delimiter(@repository.tag_names.count), 'tag')
%li
= link_to project_files_path(@project) do
= repository_size
#{'Tag'.pluralize(@repository.tag_names.count)} (#{number_with_delimiter(@repository.tag_names.count)})
- if default_project_view != 'readme' && @repository.readme
%li
......
......@@ -5,7 +5,7 @@
%a#clone-dropdown.clone-dropdown-btn.btn{href: '#', 'data-toggle' => 'dropdown'}
%span
= default_clone_protocol.upcase
= icon('angle-down')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-right.clone-options-dropdown
%li
= ssh_clone_button(project)
......
......@@ -3,4 +3,4 @@
- groups.each_with_index do |group, i|
= render "shared/groups/group", group: group
- else
%h3 No groups found
.nothing-here-block No groups found
......@@ -44,22 +44,23 @@
This issue is confidential and should only be visible to team members
- if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
- has_due_date = issuable.has_attribute?(:due_date)
%hr
.form-group
.issue-assignee
= f.label :assignee_id, "Assignee", class: 'control-label'
.col-sm-10
.row
%div{ class: (has_due_date ? "col-lg-6" : "col-sm-12") }
.form-group.issue-assignee
= f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
selected: issuable.assignee_id, project: @target_project || @project,
first_user: true, current_user: true, include_blank: true)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.issue-milestone
= f.label :milestone_id, "Milestone", class: 'control-label'
.col-sm-10
%div
= link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
.form-group.issue-milestone
= f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
- if milestone_options(issuable).present?
.issuable-form-select-holder
= f.select(:milestone_id, milestone_options(issuable),
......@@ -67,22 +68,29 @@
- else
.prepend-top-10
%span.light No open milestones available.
&nbsp;
- if can? current_user, :admin_milestone, issuable.project
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
%div
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
.form-group
- has_labels = issuable.project.labels.any?
= f.label :label_ids, "Labels", class: 'control-label'
.col-sm-10{ class: ('issuable-form-padding-top' if !has_labels) }
= f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
- if has_labels
.issuable-form-select-holder
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
- else
%span.light No labels yet.
&nbsp;
- if can? current_user, :admin_label, issuable.project
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
%div
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
- if has_due_date
.col-lg-6
.form-group
= f.label :due_date, "Due date", class: "control-label"
= f.hidden_field :due_date, id: "issuable-due-date"
.col-sm-10
.datepicker
- if issuable.can_move?(current_user)
%hr
......
......@@ -87,10 +87,16 @@
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.bold.hide-collapsed
%span.value-content
- if issuable.due_date
= issuable.due_date.to_s(:medium)
- else
.light None
None
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
%span.light.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) }
\-
%a.js-remove-due-date{ href: "#", role: "button" }
remove due date
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.selectbox.hide-collapsed
= f.hidden_field :due_date, value: issuable.due_date
......
......@@ -3,6 +3,6 @@
%li
= link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%strong= truncate(user.name, length: 40)
%br
%small.cgray= user.username
......@@ -179,11 +179,11 @@ production: &base
registry:
# enabled: true
# host: registry.example.com
# port: 5000
# api_url: http://localhost:5000/
# key: config/registry.key
# issuer: omnibus-certificate
# port: 5005
# api_url: http://localhost:5000/ # internal address to the registry, will be used by GitLab to directly communicate with API
# key_path: config/registry.key
# path: shared/registry
# issuer: gitlab-issuer
#
# 2. GitLab CI settings
......
......@@ -13,6 +13,7 @@
- [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
- [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
- [Container Registry](container_registry/README.md) Learn how to use GitLab Container Registry.
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
- [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
......@@ -41,8 +42,10 @@
- [Git LFS configuration](workflow/lfs/lfs_administration.md)
- [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
- [Monitoring uptime](monitoring/health_check.md) Check the server status using the health check endpoint
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab
## Contributor documentation
......
This diff is collapsed.
......@@ -265,7 +265,6 @@ GET /groups/:id/members
{
"id": 1,
"username": "raymond_smith",
"email": "ray@smith.org",
"name": "Raymond Smith",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
......@@ -274,7 +273,6 @@ GET /groups/:id/members
{
"id": 2,
"username": "john_doe",
"email": "joh@doe.org",
"name": "John Doe",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
......
# GitLab Container Registry
> **Note:**
This feature was [introduced][ce-4040] in GitLab 8.8.
> **Note:**
This document is about the user guide. To learn how to enable GitLab Container
Registry across your GitLab instance, visit the
[administrator documentation](../administration/container_registry.md).
With the Docker Container Registry integrated into GitLab, every project can
have its own space to store its Docker images.
You can read more about Docker Registry at https://docs.docker.com/registry/introduction/.
---
## Enable the Container Registry for your project
1. First, ask your system administrator to enable GitLab Container Registry
following the [administration documentation](../administration/container_registry.md).
If you are using GitLab.com, this is enabled by default so you can start using
the Registry immediately.
1. Go to your project's settings and enable the **Container Registry** feature
on your project. For new projects this might be enabled by default. For
existing projects you will have to explicitly enable it.
![Enable Container Registry](img/project_feature.png)
## Build and push images
After you save your project's settings, you should see a new link in the
sidebar called **Container Registry**. Following this link will get you to
your project's Registry panel where you can see how to login to the Container
Registry using your GitLab credentials.
For example if the Registry's URL is `registry.example.com`, the you should be
able to login with:
```
docker login registry.example.com
```
Building and publishing images should be a straightforward process. Just make
sure that you are using the Registry URL with the namespace and project name
that is hosted on GitLab:
```
docker build -t registry.example.com/group/project .
docker push registry.example.com/group/project
```
## Use images from GitLab Container Registry
To download and run a container from images hosted in GitLab Container Registry,
use `docker run`:
```
docker run [options] registry.example.com/group/project [arguments]
```
For more information on running Docker containers, visit the
[Docker documentation][docker-docs].
## Control Container Registry from within GitLab
GitLab offers a simple Container Registry management panel. Go to your project
and click **Container Registry** in the left sidebar.
This view will show you all tags in your project and will easily allow you to
delete them.
![Container Registry panel](img/container_registry.png)
## Build and push images using GitLab CI
> **Note:**
This feature requires GitLab 8.8 and GitLab Runner 1.2.
Make sure that your GitLab Runner is configured to allow building docker images.
You have to check the [Using Docker Build documentation](../../ci/docker/using_docker_build.md).
You can use [docker:dind](https://hub.docker.com/_/docker/) to build your images,
and this is how `.gitlab-ci.yml` should look like:
```
build_image:
image: docker:git
services:
- docker:dind
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.example.com
- docker build -t registry.example.com/group/project:latest .
- docker push registry.example.com/group/project:latest
```
You have to use the credentials of the special `gitlab-ci-token` user with its
password stored in `$CI_BUILD_TOKEN` in order to push to the Registry connected
to your project. This allows you to automated building and deployment of your
Docker images.
## Limitations
In order to use a container image from your private project as an `image:` in
your `.gitlab-ci.yml`, you have to follow the
[Using a private Docker Registry][private-docker]
documentation. This workflow will be simplified in the future.
[ce-4040]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4040
[docker-docs]: https://docs.docker.com/engine/userguide/intro/
[private-docker]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry
......@@ -394,7 +394,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse
sudo -u git -H git checkout v0.7.1
sudo -u git -H git checkout v0.7.3
sudo -u git -H make
### Initialize Database and Activate Advanced Features
......
# Health Check
>**Note:** This feature was [introduced][ce-3888] in GitLab 8.8.
GitLab provides a health check endpoint for uptime monitoring on the `health_check` web
endpoint. The health check reports on the overall system status based on the status of
the database connection, the state of the database migrations, and the ability to write
and access the cache. This endpoint can be provided to uptime monitoring services like
[Pingdom][pingdom], [Nagios][nagios-health], and [NewRelic][newrelic-health].
## Access Token
An access token needs to be provided while accessing the health check endpoint. The current
accepted token can be found on the `admin/heath_check` page of your GitLab instance.
![access token](img/health_check_token.png)
The access token can be passed as a URL parameter:
```
https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN
```
or as an HTTP header:
```bash
curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
```
## Using the Endpoint
Once you have the access token, health information can be retrieved as plain text, JSON,
or XML using the `health_check` endpoint:
- `https://gitlab.example.com/health_check?token=ACCESS_TOKEN`
- `https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN`
- `https://gitlab.example.com/health_check.xml?token=ACCESS_TOKEN`
You can also ask for the status of specific services:
- `https://gitlab.example.com/health_check/cache.json?token=ACCESS_TOKEN`
- `https://gitlab.example.com/health_check/database.json?token=ACCESS_TOKEN`
- `https://gitlab.example.com/health_check/migrations.json?token=ACCESS_TOKEN`
For example, the JSON output of the following health check:
```bash
curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
```
would be like:
```
{"healthy":true,"message":"success"}
```
## Status
On failure, the endpoint will return a `500` HTTP status code. On success, the endpoint
will return a valid successful HTTP status code, and a `success` message. Ideally your
uptime monitoring should look for the success message.
[ce-3888]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
[pingdom]: https://www.pingdom.com
[nagios-health]: https://nagios-plugins.org/doc/man/check_http.html
[newrelic-health]: https://docs.newrelic.com/docs/alerts/alert-policies/downtime-alerts/availability-monitoring
......@@ -30,11 +30,6 @@ Feature: Project Active Tab
Then the active main tab should be Merge Requests
And no other main tabs should be active
Scenario: On Project Members
Given I visit my project's members page
Then the active main tab should be Members
And no other main tabs should be active
Scenario: On Project Wiki
Given I visit my project's wiki page
Then the active main tab should be Wiki
......@@ -49,13 +44,6 @@ Feature: Project Active Tab
# Sub Tabs: Settings
Scenario: On Project Settings/Edit
Given I visit my project's settings page
And I click the "Edit" tab
Then the active sub nav should be Edit
And no other sub navs should be active
And the active main tab should be Settings
Scenario: On Project Settings/Hooks
Given I visit my project's settings page
And I click the "Hooks" tab
......@@ -70,6 +58,12 @@ Feature: Project Active Tab
And no other sub navs should be active
And the active main tab should be Settings
Scenario: On Project Members
Given I visit my project's members page
Then the active sub nav should be Members
And no other sub navs should be active
And the active main tab should be Settings
# Sub Tabs: Commits
Scenario: On Project Commits/Commits
......
......@@ -18,15 +18,6 @@ Feature: Project
Then I should see the default project avatar
And I should not see the "Remove avatar" button
Scenario: I should have back to group button
And project "Shop" belongs to group
And I visit project "Shop" page
Then I should see back to group button
Scenario: I should have back to group button
And I visit project "Shop" page
Then I should see back to dashboard button
Scenario: I should have readme on page
And I visit project "Shop" page
Then I should see project "Shop" README
......
class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
include SharedSidebarActiveTab
step 'the active main tab should be Home' do
ensure_active_main_tab('Overview')
......@@ -34,4 +34,12 @@ class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Messages' do
ensure_active_main_tab('Messages')
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
end
def ensure_active_main_tab(content)
expect(find('.nav-sidebar > li.active')).to have_content(content)
end
end
class Spinach::Features::DashboardActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
include SharedSidebarActiveTab
end
......@@ -2,5 +2,6 @@ class Spinach::Features::DashboardShortcuts < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedProject
include SharedActiveTab
include SharedSidebarActiveTab
include SharedShortcuts
end
......@@ -22,8 +22,4 @@ class Spinach::Features::ProfileActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Audit Log' do
ensure_active_main_tab('Audit Log')
end
def ensure_active_main_tab(content)
expect(find('.layout-nav li.active')).to have_content(content)
end
end
......@@ -16,12 +16,14 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
end
step 'I click the "Snippets" tab' do
page.within('.layout-nav') do
click_link('Snippets')
end
end
step 'I click the "Edit" tab' do
page.within '.sidebar-subnav' do
click_link('Project Settings')
step 'I click the "Edit Project"' do
page.within '.layout-nav .controls' do
click_link('Edit Project')
end
end
......@@ -33,14 +35,10 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
click_link('Deploy Keys')
end
step 'the active sub nav should be Team' do
step 'the active sub nav should be Members' do
ensure_active_sub_nav('Members')
end
step 'the active sub nav should be Edit' do
ensure_active_sub_nav('Project')
end
step 'the active sub nav should be Hooks' do
ensure_active_sub_nav('Webhooks')
end
......@@ -56,8 +54,10 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
end
step 'I click the "Branches" tab' do
page.within '.content' do
click_link('Branches')
end
end
step 'I click the "Tags" tab' do
click_link('Tags')
......@@ -82,12 +82,16 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
# Sub Tabs: Issues
step 'I click the "Milestones" tab' do
page.within('.layout-nav') do
click_link('Milestones')
end
end
step 'I click the "Labels" tab' do
page.within('.layout-nav') do
click_link('Labels')
end
end
step 'the active sub tab should be Issues' do
ensure_active_sub_tab('Issues')
......
......@@ -36,7 +36,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
end
step 'I goto the Merge Requests page' do
page.within '.page-sidebar-expanded' do
page.within '.layout-nav' do
click_link "Merge Requests"
end
end
......
......@@ -114,8 +114,10 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end
step 'I should not see "Snippets" button' do
page.within '.content' do
expect(page).not_to have_link 'Snippets'
end
end
step 'project "Shop" belongs to group' do
group = create(:group)
......@@ -123,14 +125,6 @@ class Spinach::Features::Project < Spinach::FeatureSteps
@project.save!
end
step 'I should see back to dashboard button' do
expect(page).to have_content 'Go to dashboard'
end
step 'I should see back to group button' do
expect(page).to have_content 'Go to group'
end
step 'I click notifications drop down button' do
click_link 'notifications-button'
end
......
......@@ -52,7 +52,7 @@ class Spinach::Features::ProjectMilestone < Spinach::FeatureSteps
end
step 'I click link "Labels"' do
page.within('.nav-links') do
page.within('.layout-nav .nav-links') do
page.find(:xpath, "//a[@href='#tab-labels']").click
end
end
......
......@@ -3,6 +3,7 @@ class Spinach::Features::ProjectShortcuts < Spinach::FeatureSteps
include SharedPaths
include SharedProject
include SharedProjectTab
include SharedShortcuts
step 'I press "g" and "f"' do
find('body').native.send_key('g')
......
......@@ -337,6 +337,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I should see buttons for allowed commands' do
page.within '.content' do
expect(page).to have_content 'Raw'
expect(page).to have_content 'History'
expect(page).to have_content 'Permalink'
......@@ -345,6 +346,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
expect(page).to have_content 'Delete'
expect(page).to have_content 'Replace'
end
end
step 'I should see a notice about a new fork having been created' do
expect(page).to have_content "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
......
......@@ -2,7 +2,7 @@ module SharedActiveTab
include Spinach::DSL
def ensure_active_main_tab(content)
expect(find('.nav-sidebar > li.active')).to have_content(content)
expect(find('.layout-nav li.active')).to have_content(content)
end
def ensure_active_sub_tab(content)
......@@ -10,11 +10,11 @@ module SharedActiveTab
end
def ensure_active_sub_nav(content)
expect(find('.sidebar-subnav > li.active')).to have_content(content)
expect(find('.layout-nav .controls li.active')).to have_content(content)
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
expect(page).to have_selector('.layout-nav .nav-links > li.active', count: 1)
end
step 'no other sub tabs should be active' do
......@@ -22,26 +22,6 @@ module SharedActiveTab
end
step 'no other sub navs should be active' do
expect(page).to have_selector('.sidebar-subnav > li.active', count: 1)
end
step 'the active main tab should be Home' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Projects' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
step 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
expect(page).to have_selector('.layout-nav .controls li.active', count: 1)
end
end
......@@ -111,7 +111,7 @@ module SharedIssuable
step 'I sort the list by "Oldest updated"' do
find('button.dropdown-toggle.btn').click
page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link "Oldest updated"
end
end
......@@ -119,7 +119,7 @@ module SharedIssuable
step 'I sort the list by "Least popular"' do
find('button.dropdown-toggle.btn').click
page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link 'Least popular'
end
end
......@@ -127,13 +127,13 @@ module SharedIssuable
step 'I sort the list by "Most popular"' do
find('button.dropdown-toggle.btn').click
page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link 'Most popular'
end
end
step 'The list should be sorted by "Oldest updated"' do
page.within('div.dropdown.inline.prepend-left-10') do
page.within('.content div.dropdown.inline.prepend-left-10') do
expect(page.find('button.dropdown-toggle.btn')).to have_content('Oldest updated')
end
end
......
......@@ -41,9 +41,7 @@ module SharedProjectTab
end
step 'the active main tab should be Settings' do
page.within '.nav-sidebar' do
expect(page).to have_content('Go to project')
end
expect(page).to have_selector('.layout-nav .nav-links > li.active', count: 0)
end
step 'the active main tab should be Activity' do
......
module SharedActiveTab
module SharedShortcuts
include Spinach::DSL
step 'I press "g" and "p"' do
......
module SharedSidebarActiveTab
include Spinach::DSL
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
end
def ensure_active_main_tab(content)
expect(find('.nav-sidebar li.active')).to have_content(content)
end
step 'the active main tab should be Home' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Projects' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
step 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
end
......@@ -29,7 +29,7 @@ module API
@current_user
end
def sudo_identifier()
def sudo_identifier
identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER]
# Regex for integers
......
......@@ -98,7 +98,7 @@ module Ci
open_new_tag
s = StringScanner.new(ansi)
while(!s.eos?)
until s.eos?
if s.scan(/\e([@-_])(.*?)([@-~])/)
handle_sequence(s)
elsif s.scan(/\e(([@-_])(.*?)?)?$/)
......
......@@ -64,7 +64,8 @@ module Ci
commits.each do |commit|
@labels << commit.short_sha
@build_times << (commit.duration / 60)
duration = commit.duration || 0
@build_times << (duration / 60)
end
end
end
......
......@@ -121,7 +121,7 @@ module Gitlab
def get(url)
response = api.get(url)
raise Unauthorized if (400..499).include?(response.code.to_i)
raise Unauthorized if (400..499).cover?(response.code.to_i)
response
end
......
......@@ -39,7 +39,15 @@ module Gitlab
def update_column_in_batches(table, column, value)
quoted_table = quote_table_name(table)
quoted_column = quote_column_name(column)
quoted_value = quote(value)
##
# Workaround for #17711
#
# It looks like for MySQL `ActiveRecord::Base.conntection.quote(true)`
# returns correct value (1), but `ActiveRecord::Migration.new.quote`
# returns incorrect value ('true'), which causes migrations to fail.
#
quoted_value = connection.quote(value)
processed = 0
total = exec_query("SELECT COUNT(*) AS count FROM #{quoted_table}").
......
## Lines starting with two hashes (##) are comments with information.
## Lines starting with one hash (#) are configuration parameters that can be uncommented.
##
###################################
## configuration ##
###################################
## Redirects all HTTP traffic to the HTTPS host
server {
listen *:80;
server_name registry.gitlab.example.com;
server_tokens off; ## Don't show the nginx version number, a security best practice
return 301 https://$http_host:$request_uri;
access_log /var/log/nginx/gitlab_registry_access.log gitlab_access;
error_log /var/log/nginx/gitlab_registry_error.log;
}
server {
# If a different port is specified in https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/config/gitlab.yml.example#L182,
# it should be declared here as well
listen *:443 ssl http2;
server_name registry.gitlab.example.com;
server_tokens off; ## Don't show the nginx version number, a security best practice
client_max_body_size 0;
chunked_transfer_encoding on;
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on;
ssl_certificate /etc/gitlab/ssl/registry.gitlab.example.com.crt
ssl_certificate_key /etc/gitlab/ssl/registry.gitlab.example.com.key
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_session_timeout 5m;
access_log /var/log/gitlab/nginx/gitlab_registry_access.log gitlab_access;
error_log /var/log/gitlab/nginx/gitlab_registry_error.log;
location / {
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
proxy_pass http://localhost:5000;
}
}
unless Rails.env.production?
require 'rubocop/rake_task'
RuboCop::RakeTask.new
end
......@@ -28,7 +28,7 @@ describe Projects::GroupLinksController do
expect(group.shared_projects).to include project
end
it 'redirects to project group links page'do
it 'redirects to project group links page' do
expect(response).to redirect_to(
namespace_project_group_links_path(project.namespace, project)
)
......
......@@ -5,7 +5,7 @@ describe 'factories' do
describe "#{factory.name} factory" do
let(:entity) { build(factory.name) }
it 'does not raise error when created 'do
it 'does not raise error when created' do
expect { entity }.to_not raise_error
end
......
......@@ -64,6 +64,64 @@ describe 'Issues', feature: true do
end
end
describe 'due date', js: true do
context 'on new form' do
before do
visit new_namespace_project_issue_path(project.namespace, project)
end
it 'should save with due date' do
date = Date.today.at_beginning_of_month
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
page.within '.datepicker' do
click_link date.day
end
expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
click_button 'Submit issue'
page.within '.issuable-sidebar' do
expect(page).to have_content date.to_s(:medium)
end
end
end
context 'on edit form' do
let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) }
before do
visit edit_namespace_project_issue_path(project.namespace, project, issue)
end
it 'should save with due date' do
date = Date.today.at_beginning_of_month
expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
date = date.tomorrow
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
page.within '.datepicker' do
click_link date.day
end
expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
click_button 'Save changes'
page.within '.issuable-sidebar' do
expect(page).to have_content date.to_s(:medium)
end
end
end
end
describe 'Issue info' do
it 'excludes award_emoji from comment count' do
issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
......@@ -431,6 +489,43 @@ describe 'Issues', feature: true do
end
end
describe 'due date' do
context 'update due on issue#show', js: true do
let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
before do
visit namespace_project_issue_path(project.namespace, project, issue)
end
it 'should add due date to issue' do
page.within '.due_date' do
click_link 'Edit'
page.within '.ui-datepicker-calendar' do
first('.ui-state-default').click
end
expect(page).to have_no_content 'None'
end
end
it 'should remove due date from issue' do
page.within '.due_date' do
click_link 'Edit'
page.within '.ui-datepicker-calendar' do
first('.ui-state-default').click
end
expect(page).to have_no_content 'None'
click_link 'remove due date'
expect(page).to have_content 'None'
end
end
end
end
def first_issue
page.all('ul.issues-list > li').first.text
end
......
......@@ -24,6 +24,12 @@ describe "Pipelines" do
end
end
context 'anonymous access' do
before { visit namespace_project_pipelines_path(project.namespace, project) }
it { expect(page).to have_http_status(:success) }
end
context 'cancelable pipeline' do
let!(:running) { create(:ci_build, :running, commit: pipeline, stage: 'test', commands: 'test') }
......
......@@ -8,12 +8,10 @@ feature 'list of badges' do
project = create(:project)
project.team << [user, :master]
login_as(user)
visit edit_namespace_project_path(project.namespace, project)
visit namespace_project_badges_path(project.namespace, project)
end
scenario 'user displays list of badges' do
click_link 'Badges'
expect(page).to have_content 'build status'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
......@@ -26,7 +24,6 @@ feature 'list of badges' do
end
scenario 'user changes current ref on badges list page', js: true do
click_link 'Badges'
select2('improve/awesome', from: '#ref')
expect(page).to have_content 'badges/improve/awesome/build.svg'
......
......@@ -25,7 +25,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
......@@ -33,7 +33,7 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
scenario 'project master creates a license file from the "Add license" link' do
......@@ -48,7 +48,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
......@@ -56,6 +56,6 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
......@@ -24,7 +24,7 @@ feature 'project owner sees a link to create a license file in empty project', f
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
# Remove pre-receive hook so we can push without auth
......@@ -34,6 +34,6 @@ feature 'project owner sees a link to create a license file in empty project', f
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
......@@ -12,7 +12,7 @@ feature 'Master updates tag', feature: true do
context 'from the tags list page' do
scenario 'updates the release notes' do
page.within(first('.controls')) do
page.within(first('.content-list .controls')) do
click_link 'Edit release notes'
end
......
......@@ -12,5 +12,12 @@ describe Ci::Charts, lib: true do
chart = Ci::Charts::BuildTime.new(@commit.project)
expect(chart.build_times).to eq([2])
end
it 'should handle nil build times' do
create(:ci_commit, duration: nil, project: @commit.project)
chart = Ci::Charts::BuildTime.new(@commit.project)
expect(chart.build_times).to eq([2, 0])
end
end
end
......@@ -2,15 +2,13 @@ require 'spec_helper'
describe Gitlab::Database::MigrationHelpers, lib: true do
let(:model) do
Class.new do
include Gitlab::Database::MigrationHelpers
def method_missing(name, *args, &block)
ActiveRecord::Base.connection.send(name, *args, &block)
end
end.new
ActiveRecord::Migration.new.extend(
Gitlab::Database::MigrationHelpers
)
end
before { allow(model).to receive(:puts) }
describe '#add_concurrent_index' do
context 'outside a transaction' do
before do
......@@ -60,6 +58,12 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
expect(Project.where(import_error: 'foo').count).to eq(5)
end
it 'updates boolean values correctly' do
model.update_column_in_batches(:projects, :archived, true)
expect(Project.where(archived: true).count).to eq(5)
end
end
describe '#add_column_with_default' do
......
......@@ -49,7 +49,7 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
context 'token is generated' do
before { subject.send("reset_#{token_field}!") }
it 'persists a new token 'do
it 'persists a new token' do
expect(subject.send(:read_attribute, token_field)).to be_a String
end
end
......
......@@ -57,7 +57,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('Copyright (c) 2016 Anton')
expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton")
end
end
......@@ -70,7 +70,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
......@@ -83,7 +83,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
......@@ -96,7 +96,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
......@@ -108,7 +108,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('Copyright 2016 Anton')
expect(json_response['content']).to include("Copyright #{Time.now.year} Anton")
end
end
......@@ -128,7 +128,7 @@ describe API::Licenses, api: true do
it 'replaces the copyright owner placeholder with the name of the current user' do
get api('/licenses/mit', user)
expect(json_response['content']).to include("Copyright (c) 2016 #{user.name}")
expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}")
end
end
end
......
......@@ -23,7 +23,7 @@ describe JwtController do
context 'when using authorized request' do
context 'using CI token' do
let(:project) { create(:empty_project, runners_token: 'token', builds_enabled: builds_enabled) }
let(:headers) { { authorization: credentials('gitlab_ci_token', project.runners_token) } }
let(:headers) { { authorization: credentials('gitlab-ci-token', project.runners_token) } }
subject! { get '/jwt/auth', parameters, headers }
......
......@@ -10,7 +10,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
subject { described_class.new(current_project, current_user, current_params).execute }
before do
stub_container_registry_config(enabled: true, issuer: 'rspec', key: nil)
allow(Gitlab.config.registry).to receive_messages(enabled: true, issuer: 'rspec', key: nil)
allow_any_instance_of(JSONWebToken::RSAToken).to receive(:key).and_return(rsa_key)
end
......@@ -60,6 +60,17 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
it { is_expected.to_not include(:token) }
end
describe '#full_access_token' do
let(:project) { create(:empty_project) }
let(:token) { described_class.full_access_token(project.path_with_namespace) }
subject { { token: token } }
it_behaves_like 'a accessible' do
let(:actions) { ['*'] }
end
end
context 'user authorization' do
let(:project) { create(:project) }
let(:current_user) { create(:user) }
......@@ -116,12 +127,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'project authorization' do
let(:current_project) { create(:empty_project) }
context 'disallow to use offline_token' do
context 'allow to use offline_token' do
let(:current_params) do
{ offline_token: true }
end
it_behaves_like 'an unauthorized'
it_behaves_like 'an authenticated'
end
context 'allow to pull and push images' do
......
......@@ -54,7 +54,7 @@ describe Issues::CreateService, services: true do
label_ids: [label.id] }
end
it 'does not assign label'do
it 'does not assign label' do
expect(issue.labels).to_not include label
end
end
......
# .gitignore templates
This directory contains language-specific .gitignore templates that are used by GitLab.
These files were automatically pulled from [this repository](https://github.com/github/gitignore).
Please submit pull requests to that repository. There is no need to edit the files in this directory.
## Bulk Update
To update this directory with the latest changes in the repository, run:
```sh
bundle exec rake gitlab:update_gitignore
```
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment