mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-23 11:36:09 +10:00
Merge branch 'master' into improve-pipeline-design
This commit is contained in:
+118
-42
@@ -1,3 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.7.1
|
||||
0.7.3
|
||||
|
||||
@@ -293,9 +293,10 @@ 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 'coveralls', '~> 0.8.2', require: false
|
||||
gem 'simplecov', '~> 0.11.0', require: false
|
||||
gem 'flog', require: false
|
||||
gem 'flay', 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
|
||||
|
||||
+17
-12
@@ -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
|
||||
|
||||
@@ -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()
|
||||
date = new Date value.replace(new RegExp('-', 'g'), ',')
|
||||
mediumDate = $.datepicker.formatDate 'M d, yy', date
|
||||
|
||||
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()
|
||||
$dropdown.trigger('loading.gl.dropdown')
|
||||
$selectbox.hide()
|
||||
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) ->
|
||||
$dropdown.trigger('loaded.gl.dropdown')
|
||||
$dropdown.dropdown('toggle')
|
||||
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;
|
||||
}
|
||||
|
||||
.avatar, .identicon {
|
||||
margin: 0 auto;
|
||||
float: none;
|
||||
}
|
||||
.project-image-container {
|
||||
@include make-sm-column(1);
|
||||
max-width: 86px;
|
||||
min-width: 86px;
|
||||
padding-right: 0;
|
||||
margin: 11px 0;
|
||||
|
||||
.identicon {
|
||||
@include border-radius(50%);
|
||||
@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;
|
||||
|
||||
.count-buttons {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.clone-row {
|
||||
.split-repo-buttons,
|
||||
.project-clone-holder {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.split-repo-buttons {
|
||||
margin: 0 12px;
|
||||
}
|
||||
}
|
||||
font-size: 0;
|
||||
|
||||
.btn {
|
||||
@include btn-gray;
|
||||
padding: 3px 10px;
|
||||
text-transform: none;
|
||||
background-color: $background-color;
|
||||
|
||||
.fa {
|
||||
color: $layout-link-gray;
|
||||
}
|
||||
|
||||
.fa-caret-down {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group:not(:first-child):not(:last-child) > .btn {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%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
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
%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
|
||||
|
||||
@@ -1,63 +1,45 @@
|
||||
%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
|
||||
- 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
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: :deploy_keys) do
|
||||
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
|
||||
%span
|
||||
Deploy Keys
|
||||
= nav_link(controller: :hooks) do
|
||||
= link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do
|
||||
%span
|
||||
Webhooks
|
||||
= nav_link(controller: :services) do
|
||||
= link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
|
||||
%span
|
||||
Services
|
||||
= nav_link(controller: :protected_branches) do
|
||||
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
|
||||
%span
|
||||
Protected Branches
|
||||
|
||||
%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?
|
||||
= 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
|
||||
= 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
|
||||
= link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do
|
||||
= icon('link fw')
|
||||
%span
|
||||
Webhooks
|
||||
= 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
|
||||
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
|
||||
= icon('lock fw')
|
||||
%span
|
||||
Protected Branches
|
||||
|
||||
- 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
|
||||
- if @project.builds_enabled?
|
||||
= nav_link(controller: :runners) do
|
||||
= link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do
|
||||
%span
|
||||
Runners
|
||||
= nav_link(controller: :variables) do
|
||||
= link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do
|
||||
%span
|
||||
Variables
|
||||
= nav_link(controller: :triggers) do
|
||||
= link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
|
||||
%span
|
||||
Triggers
|
||||
= nav_link(controller: :badges) do
|
||||
= link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
|
||||
%span
|
||||
Badges
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- 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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Settings"
|
||||
- header_title project_title(@project, "Settings", edit_project_path(@project))
|
||||
- sidebar "project_settings"
|
||||
- nav "project"
|
||||
|
||||
= render template: "layouts/project"
|
||||
|
||||
@@ -1,59 +1,37 @@
|
||||
- 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')
|
||||
.cover-title.project-home-desc
|
||||
%h1
|
||||
= @project.name
|
||||
%span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
|
||||
= visibility_level_icon(@project.visibility_level, fw: false)
|
||||
.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
|
||||
%span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
|
||||
= visibility_level_icon(@project.visibility_level, fw: false)
|
||||
|
||||
- if @project.description.present?
|
||||
.cover-desc.project-home-desc
|
||||
= markdown(@project.description, pipeline: :description)
|
||||
- if @project.description.present?
|
||||
.cover-desc.project-home-desc
|
||||
= markdown(@project.description, pipeline: :description)
|
||||
|
||||
- if forked_from_project = @project.forked_from_project
|
||||
.cover-desc
|
||||
Forked from
|
||||
= link_to project_path(forked_from_project) do
|
||||
= forked_from_project.namespace.try(:name)
|
||||
- if forked_from_project = @project.forked_from_project
|
||||
.cover-desc
|
||||
Forked from
|
||||
= 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
|
||||
.count-buttons
|
||||
= render 'projects/buttons/star'
|
||||
= render 'projects/buttons/fork'
|
||||
|
||||
.project-repo-buttons
|
||||
.split-one.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
|
||||
= render "projects/buttons/download"
|
||||
= render 'projects/buttons/dropdown'
|
||||
.project-clone-holder
|
||||
= render "shared/clone_panel"
|
||||
|
||||
.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
|
||||
= @project.forks_count
|
||||
= link_to namespace_project_forks_path(@project.namespace, @project) do
|
||||
= @project.forks_count
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
- 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,18 +42,18 @@
|
||||
%td
|
||||
= build.name
|
||||
|
||||
.pull-right
|
||||
.label-container
|
||||
- if build.tags.any?
|
||||
- build.tags.each do |tag|
|
||||
%span.label.label-primary
|
||||
= tag
|
||||
- if build.try(:trigger_request)
|
||||
%span.label.label-info triggered
|
||||
- if build.try(:allow_failure)
|
||||
%span.label.label-danger allowed to fail
|
||||
- if defined?(retried) && retried
|
||||
%span.label.label-warning retried
|
||||
%td
|
||||
.label-container
|
||||
- if build.tags.any?
|
||||
- build.tags.each do |tag|
|
||||
%span.label.label-primary
|
||||
= tag
|
||||
- if build.try(:trigger_request)
|
||||
%span.label.label-info triggered
|
||||
- if build.try(:allow_failure)
|
||||
%span.label.label-danger allowed to fail
|
||||
- if defined?(retried) && retried
|
||||
%span.label.label-warning retried
|
||||
|
||||
%td.duration
|
||||
- if build.duration
|
||||
|
||||
@@ -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,50 +13,50 @@
|
||||
= render "home_panel"
|
||||
|
||||
.project-stats.row-content-block.second-block
|
||||
%ul.nav
|
||||
%li
|
||||
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
|
||||
= pluralize(number_with_delimiter(@project.commit_count), 'commit')
|
||||
%li
|
||||
= link_to namespace_project_branches_path(@project.namespace, @project) do
|
||||
= pluralize(number_with_delimiter(@repository.branch_names.count), 'branch')
|
||||
%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
|
||||
|
||||
- if default_project_view != 'readme' && @repository.readme
|
||||
.container-fluid.container-limited
|
||||
%ul.nav
|
||||
%li
|
||||
= link_to 'Readme', readme_path(@project)
|
||||
|
||||
- if @repository.changelog
|
||||
= link_to project_files_path(@project) do
|
||||
Files (#{repository_size})
|
||||
%li
|
||||
= link_to 'Changelog', changelog_path(@project)
|
||||
|
||||
- if @repository.license_blob
|
||||
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
|
||||
#{'Commit'.pluralize(@project.commit_count)} (#{number_with_delimiter(@project.commit_count)})
|
||||
%li
|
||||
= link_to license_short_name(@project), license_path(@project)
|
||||
|
||||
- if @repository.contribution_guide
|
||||
= link_to namespace_project_branches_path(@project.namespace, @project) do
|
||||
#{'Branch'.pluralize(@repository.branch_names.count)} (#{number_with_delimiter(@repository.branch_names.count)})
|
||||
%li
|
||||
= link_to 'Contribution guide', contribution_guide_path(@project)
|
||||
= link_to namespace_project_tags_path(@project.namespace, @project) do
|
||||
#{'Tag'.pluralize(@repository.tag_names.count)} (#{number_with_delimiter(@repository.tag_names.count)})
|
||||
|
||||
- if current_user && can_push_branch?(@project, @project.default_branch)
|
||||
- unless @repository.changelog
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'CHANGELOG') do
|
||||
Add Changelog
|
||||
- unless @repository.license_blob
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'LICENSE') do
|
||||
Add License
|
||||
- unless @repository.contribution_guide
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide') do
|
||||
Add Contribution guide
|
||||
- if default_project_view != 'readme' && @repository.readme
|
||||
%li
|
||||
= link_to 'Readme', readme_path(@project)
|
||||
|
||||
- if @repository.changelog
|
||||
%li
|
||||
= link_to 'Changelog', changelog_path(@project)
|
||||
|
||||
- if @repository.license_blob
|
||||
%li
|
||||
= link_to license_short_name(@project), license_path(@project)
|
||||
|
||||
- if @repository.contribution_guide
|
||||
%li
|
||||
= link_to 'Contribution guide', contribution_guide_path(@project)
|
||||
|
||||
- if current_user && can_push_branch?(@project, @project.default_branch)
|
||||
- unless @repository.changelog
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'CHANGELOG') do
|
||||
Add Changelog
|
||||
- unless @repository.license_blob
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'LICENSE') do
|
||||
Add License
|
||||
- unless @repository.contribution_guide
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide') do
|
||||
Add Contribution guide
|
||||
|
||||
- if @repository.commit
|
||||
.content-block.second-block.white
|
||||
|
||||
@@ -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,45 +44,53 @@
|
||||
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
|
||||
.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)
|
||||
|
||||
= 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
|
||||
- if milestone_options(issuable).present?
|
||||
.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
|
||||
= f.select(:milestone_id, milestone_options(issuable),
|
||||
{ include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No open milestones available.
|
||||
|
||||
- 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
|
||||
.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) }
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
= 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)
|
||||
%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),
|
||||
{ include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No open milestones available.
|
||||
- if can? current_user, :admin_milestone, issuable.project
|
||||
%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-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.
|
||||
- if can? current_user, :admin_label, issuable.project
|
||||
%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
|
||||
- if issuable.due_date
|
||||
= issuable.due_date.to_s(:medium)
|
||||
- else
|
||||
.light None
|
||||
%span.value-content
|
||||
- if issuable.due_date
|
||||
= issuable.due_date.to_s(:medium)
|
||||
- else
|
||||
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
|
||||
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
# GitLab Container Registry Administration
|
||||
|
||||
> **Note:**
|
||||
This feature was [introduced][ce-4040] in GitLab 8.8.
|
||||
|
||||
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/.
|
||||
|
||||
---
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||
|
||||
- [Enable the Container Registry](#enable-the-container-registry)
|
||||
- [Container Registry domain configuration](#container-registry-domain-configuration)
|
||||
- [Configure Container Registry under an existing GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain)
|
||||
- [Configure Container Registry under its own domain](#configure-container-registry-under-its-own-domain)
|
||||
- [Disable Container Registry site-wide](#disable-container-registry-site-wide)
|
||||
- [Disable Container Registry per project](#disable-container-registry-per-project)
|
||||
- [Disable Container Registry for new projects site-wide](#disable-container-registry-for-new-projects-site-wide)
|
||||
- [Container Registry storage path](#container-registry-storage-path)
|
||||
- [Storage limitations](#storage-limitations)
|
||||
- [Changelog](#changelog)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Enable the Container Registry
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
All you have to do is configure the domain name under which the Container
|
||||
Registry will listen to. Read [#container-registry-domain-configuration](#container-registry-domain-configuration)
|
||||
and pick one of the two options that fits your case.
|
||||
|
||||
>**Note:**
|
||||
The container Registry works under HTTPS by default. Using HTTP is possible
|
||||
but not recommended and out of the scope of this document.
|
||||
Read the [insecure Registry documentation][docker-insecure] if you want to
|
||||
implement this.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
If you have installed GitLab from source:
|
||||
|
||||
1. You will have to [install Docker Registry][registry-deploy] by yourself.
|
||||
1. After the installation is complete, you will have to configure the Registry's
|
||||
settings in `gitlab.yml` in order to enable it.
|
||||
1. Use the sample NGINX configuration file that is found under
|
||||
[`lib/support/nginx/registry-ssl`][registry-ssl] and edit it to match the
|
||||
`host`, `port` and TLS certs paths.
|
||||
|
||||
The contents of `gitlab.yml` are:
|
||||
|
||||
```
|
||||
registry:
|
||||
enabled: true
|
||||
host: registry.gitlab.example.com
|
||||
port: 5005
|
||||
api_url: http://localhost:5000/
|
||||
key_path: config/registry.key
|
||||
path: shared/registry
|
||||
issuer: gitlab-issuer
|
||||
```
|
||||
|
||||
where:
|
||||
|
||||
| Parameter | Description |
|
||||
| --------- | ----------- |
|
||||
| `enabled` | `true` or `false`. Enables the Registry in GitLab. By default this is `false`. |
|
||||
| `host` | The host URL under which the Registry will run and the users will be able to use. |
|
||||
| `port` | The port under which the external Registry domain will listen on. |
|
||||
| `api_url` | The internal API URL under which the Registry is exposed to. It defaults to `http://localhost:5000`. |
|
||||
| `key_path`| The private key location that is a pair of Registry's `rootcertbundle`. Read the [token auth configuration documentation][token-config]. |
|
||||
| `path` | This should be the same directory like specified in Registry's `rootdirectory`. Read the [storage configuration documentation][storage-config]. This path needs to be readable by the GitLab user, the web-server user and the Registry user. Read more in [#container-registry-storage-path](#container-registry-storage-path). |
|
||||
| `issuer` | This should be the same value as configured in Registry's `issuer`. Read the [token auth configuration documentation][token-config]. |
|
||||
|
||||
>**Note:**
|
||||
GitLab does not ship with a Registry init file. Hence, [restarting GitLab][restart gitlab]
|
||||
will not restart the Registry should you modify its settings. Read the upstream
|
||||
documentation on how to achieve that.
|
||||
|
||||
## Container Registry domain configuration
|
||||
|
||||
There are two ways you can configure the Registry's external domain.
|
||||
|
||||
- Either [use the existing GitLab domain][existing-domain] where in that case
|
||||
the Registry will have to listen on a port and reuse GitLab's TLS certificate,
|
||||
- or [use a completely separate domain][new-domain] with a new TLS certificate
|
||||
for that domain.
|
||||
|
||||
Since the container Registry requires a TLS certificate, in the end it all boils
|
||||
down to how easy or pricey is to get a new one.
|
||||
|
||||
Please take this into consideration before configuring the Container Registry
|
||||
for the first time.
|
||||
|
||||
### Configure Container Registry under an existing GitLab domain
|
||||
|
||||
If the Registry is configured to use the existing GitLab domain, you can
|
||||
expose the Registry on a port so that you can reuse the existing GitLab TLS
|
||||
certificate.
|
||||
|
||||
Assuming that the GitLab domain is `https://gitlab.example.com` and the port the
|
||||
Registry is exposed to the outside world is `4567`, here is what you need to set
|
||||
in `gitlab.rb` or `gitlab.yml` if you are using Omnibus GitLab or installed
|
||||
GitLab from source respectively.
|
||||
|
||||
---
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
1. Your `/etc/gitlab/gitlab.rb` should contain the Registry URL as well as the
|
||||
path to the existing TLS certificate and key used by GitLab:
|
||||
|
||||
```ruby
|
||||
registry_external_url 'https://gitlab.example.com:4567'
|
||||
```
|
||||
|
||||
Note how the `registry_external_url` is listening on HTTPS under the
|
||||
existing GitLab URL, but on a different port.
|
||||
|
||||
If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
|
||||
and key not in `/etc/gitlab/ssl/gitlab.example.com.key` uncomment the lines
|
||||
below:
|
||||
|
||||
```ruby
|
||||
registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
|
||||
registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
|
||||
configure it with the following settings:
|
||||
|
||||
```
|
||||
registry:
|
||||
enabled: true
|
||||
host: gitlab.example.com
|
||||
port: 4567
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
|
||||
|
||||
---
|
||||
|
||||
Users should now be able to login to the Container Registry with their GitLab
|
||||
credentials using:
|
||||
|
||||
```bash
|
||||
docker login gitlab.example.com:4567
|
||||
```
|
||||
|
||||
### Configure Container Registry under its own domain
|
||||
|
||||
If the Registry is configured to use its own domain, you will need a TLS
|
||||
certificate for that specific domain (e.g., `registry.example.com`) or maybe
|
||||
a wildcard certificate if hosted under a subdomain of your existing GitLab
|
||||
domain (e.g., `registry.gitlab.example.com`).
|
||||
|
||||
Let's assume that you want the container Registry to be accessible at
|
||||
`https://registry.gitlab.example.com`.
|
||||
|
||||
---
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
1. Place your TLS certificate and key in
|
||||
`/etc/gitlab/ssl/registry.gitlab.example.com.crt` and
|
||||
`/etc/gitlab/ssl/registry.gitlab.example.com.key` and make sure they have
|
||||
correct permissions:
|
||||
|
||||
```bash
|
||||
chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
|
||||
```
|
||||
|
||||
1. Once the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
|
||||
|
||||
```ruby
|
||||
registry_external_url 'https://registry.gitlab.example.com'
|
||||
```
|
||||
|
||||
Note how the `registry_external_url` is listening on HTTPS.
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
> **Note:**
|
||||
If you have a [wildcard certificate][], you need to specify the path to the
|
||||
certificate in addition to the URL, in this case `/etc/gitlab/gitlab.rb` will
|
||||
look like:
|
||||
>
|
||||
```ruby
|
||||
registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/certificate.pem"
|
||||
registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/certificate.key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
|
||||
configure it with the following settings:
|
||||
|
||||
```
|
||||
registry:
|
||||
enabled: true
|
||||
host: registry.gitlab.example.com
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
|
||||
|
||||
---
|
||||
|
||||
Users should now be able to login to the Container Registry using their GitLab
|
||||
credentials:
|
||||
|
||||
```bash
|
||||
docker login registry.gitlab.example.com
|
||||
```
|
||||
|
||||
## Disable Container Registry site-wide
|
||||
|
||||
>**Note:**
|
||||
Disabling the Registry in the Rails GitLab application as set by the following
|
||||
steps, will not remove any existing Docker images. This is handled by the
|
||||
Registry application itself.
|
||||
|
||||
**Omnibus GitLab**
|
||||
|
||||
1. Open `/etc/gitlab/gitlab.rb` and set `registry['enable']` to `false`:
|
||||
|
||||
```ruby
|
||||
registry['enable'] = false
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
|
||||
set `enabled` to `false`:
|
||||
|
||||
```
|
||||
registry:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
|
||||
## Disable Container Registry per project
|
||||
|
||||
If Registry is enabled in your GitLab instance, but you don't need it for your
|
||||
project, you can disable it from your project's settings. Read the user guide
|
||||
on how to achieve that.
|
||||
|
||||
## Disable Container Registry for new projects site-wide
|
||||
|
||||
If the Container Registry is enabled, then it will be available on all new
|
||||
projects. To disable this function and let the owners of a project to enable
|
||||
the Container Registry by themselves, follow the steps below.
|
||||
|
||||
---
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['gitlab_default_projects_features_container_registry'] = false
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `default_projects_features`
|
||||
entry and configure it so that `container_registry` is set to `false`:
|
||||
|
||||
```
|
||||
## Default project features settings
|
||||
default_projects_features:
|
||||
issues: true
|
||||
merge_requests: true
|
||||
wiki: true
|
||||
snippets: false
|
||||
builds: true
|
||||
container_registry: false
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
|
||||
## Container Registry storage path
|
||||
|
||||
To change the storage path where Docker images will be stored, follow the
|
||||
steps below.
|
||||
|
||||
This path is accessible to:
|
||||
|
||||
- the user running the Container Registry daemon,
|
||||
- the user running GitLab
|
||||
|
||||
> **Warning** You should confirm that all GitLab, Registry and web server users
|
||||
have access to this directory.
|
||||
|
||||
---
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
The default location where images are stored in Omnibus, is
|
||||
`/var/opt/gitlab/gitlab-rails/shared/registry`. To change it:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['registry_path'] = "/path/to/registry/storage"
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
The default location where images are stored in source installations, is
|
||||
`/home/git/gitlab/shared/registry`. To change it:
|
||||
|
||||
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
|
||||
change the `path` setting:
|
||||
|
||||
```
|
||||
registry:
|
||||
path: shared/registry
|
||||
```
|
||||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
|
||||
## Storage limitations
|
||||
|
||||
Currently, there is no storage limitation, which means a user can upload an
|
||||
infinite amount of Docker images with arbitrary sizes. This setting will be
|
||||
configurable in future releases.
|
||||
|
||||
## Changelog
|
||||
|
||||
**GitLab 8.8 ([source docs][8-8-docs])**
|
||||
|
||||
- GitLab Container Registry feature was introduced.
|
||||
|
||||
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
|
||||
[restart gitlab]: restart_gitlab.md#installations-from-source
|
||||
[wildcard certificate]: https://en.wikipedia.org/wiki/Wildcard_certificate
|
||||
[ce-4040]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4040
|
||||
[docker-insecure]: https://docs.docker.com/registry/insecure/
|
||||
[registry-deploy]: https://docs.docker.com/registry/deploying/
|
||||
[storage-config]: https://docs.docker.com/registry/configuration/#storage
|
||||
[token-config]: https://docs.docker.com/registry/configuration/#token
|
||||
[8-8-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/doc/administration/container_registry.md
|
||||
[registry-ssl]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/nginx/registry-ssl
|
||||
[existing-domain]: #configure-container-registry-under-an-existing-gitlab-domain
|
||||
[new-domain]: #configure-container-registry-under-its-own-domain
|
||||
@@ -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",
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# 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.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 346 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 384 KiB |
@@ -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
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# 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.
|
||||
|
||||

|
||||
|
||||
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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
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
|
||||
click_link('Snippets')
|
||||
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,7 +54,9 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
|
||||
end
|
||||
|
||||
step 'I click the "Branches" tab' do
|
||||
click_link('Branches')
|
||||
page.within '.content' do
|
||||
click_link('Branches')
|
||||
end
|
||||
end
|
||||
|
||||
step 'I click the "Tags" tab' do
|
||||
@@ -82,11 +82,15 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
|
||||
# Sub Tabs: Issues
|
||||
|
||||
step 'I click the "Milestones" tab' do
|
||||
click_link('Milestones')
|
||||
page.within('.layout-nav') do
|
||||
click_link('Milestones')
|
||||
end
|
||||
end
|
||||
|
||||
step 'I click the "Labels" tab' do
|
||||
click_link('Labels')
|
||||
page.within('.layout-nav') do
|
||||
click_link('Labels')
|
||||
end
|
||||
end
|
||||
|
||||
step 'the active sub tab should be Issues' do
|
||||
|
||||
@@ -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,7 +114,9 @@ class Spinach::Features::Project < Spinach::FeatureSteps
|
||||
end
|
||||
|
||||
step 'I should not see "Snippets" button' do
|
||||
expect(page).not_to have_link 'Snippets'
|
||||
page.within '.content' do
|
||||
expect(page).not_to have_link 'Snippets'
|
||||
end
|
||||
end
|
||||
|
||||
step 'project "Shop" belongs to group' do
|
||||
@@ -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,13 +337,15 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
|
||||
end
|
||||
|
||||
step 'I should see buttons for allowed commands' do
|
||||
expect(page).to have_content 'Raw'
|
||||
expect(page).to have_content 'History'
|
||||
expect(page).to have_content 'Permalink'
|
||||
expect(page).not_to have_content 'Edit'
|
||||
expect(page).not_to have_content 'Blame'
|
||||
expect(page).to have_content 'Delete'
|
||||
expect(page).to have_content 'Replace'
|
||||
page.within '.content' do
|
||||
expect(page).to have_content 'Raw'
|
||||
expect(page).to have_content 'History'
|
||||
expect(page).to have_content 'Permalink'
|
||||
expect(page).not_to have_content 'Edit'
|
||||
expect(page).not_to have_content 'Blame'
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module SharedActiveTab
|
||||
module SharedShortcuts
|
||||
include Spinach::DSL
|
||||
|
||||
step 'I press "g" and "p"' do
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
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
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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(([@-_])(.*?)?)?$/)
|
||||
|
||||
+2
-1
@@ -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}").
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
## 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
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')
|
||||
@@ -331,7 +389,7 @@ describe 'Issues', feature: true do
|
||||
page.within '.assignee' do
|
||||
click_link 'Edit'
|
||||
end
|
||||
|
||||
|
||||
page.within '.dropdown-menu-user' do
|
||||
click_link @user.name
|
||||
end
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
# .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
|
||||
```
|
||||
Reference in New Issue
Block a user