Commit 0378c5b8 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into sidebar-expand-collapse

parents aa2a7dad 380966e8
require: rubocop-rspec
AllCops:
TargetRubyVersion: 2.1
# Cop names are not displayed in offense messages by default. Change behavior
......@@ -57,7 +59,7 @@ Style/AndOr:
# Use `Array#join` instead of `Array#*`.
Style/ArrayJoin:
Enabled: false
Enabled: true
# Use only ascii symbols in comments.
Style/AsciiComments:
......@@ -69,7 +71,7 @@ Style/AsciiIdentifiers:
# Checks for uses of Module#attr.
Style/Attr:
Enabled: false
Enabled: true
# Avoid the use of BEGIN blocks.
Style/BeginBlock:
......@@ -81,7 +83,7 @@ Style/BarePercentLiterals:
# Do not use block comments.
Style/BlockComments:
Enabled: false
Enabled: true
# Put end statement of multiline block on its own line.
Style/BlockEndNewline:
......@@ -122,7 +124,7 @@ Style/ClassCheck:
# Use self when defining module/class methods.
Style/ClassMethods:
Enabled: false
Enabled: true
# Avoid the use of class variables.
Style/ClassVars:
......@@ -216,7 +218,7 @@ Style/EmptyLiteral:
# Avoid the use of END blocks.
Style/EndBlock:
Enabled: false
Enabled: true
# Use Unix-style line endings.
Style/EndOfLine:
......@@ -224,7 +226,7 @@ Style/EndOfLine:
# Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd:
Enabled: false
Enabled: true
# Do not use unnecessary spacing.
Style/ExtraSpacing:
......@@ -232,11 +234,16 @@ Style/ExtraSpacing:
# Use snake_case for source file names.
Style/FileName:
Enabled: false
Enabled: true
# Checks for a line break before the first parameter in a multi-line method
# parameter definition.
Style/FirstMethodParameterLineBreak:
Enabled: true
# Checks for flip flops.
Style/FlipFlop:
Enabled: false
Enabled: true
# Checks use of for or each in multiline loops.
Style/For:
......@@ -248,7 +255,7 @@ Style/FormatString:
# Do not introduce global variables.
Style/GlobalVars:
Enabled: false
Enabled: true
# Check for conditionals that can be replaced with guard clauses.
Style/GuardClause:
......@@ -269,7 +276,7 @@ Style/IfUnlessModifier:
# Do not use if x; .... Use the ternary operator instead.
Style/IfWithSemicolon:
Enabled: false
Enabled: true
# Checks that conditional statements do not have an identical line at the
# end of each branch, which can validly be moved out of the conditional.
......@@ -307,7 +314,7 @@ Style/Lambda:
# Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall:
Enabled: false
Enabled: true
# Comments should start with a space.
Style/LeadingCommentSpace:
......@@ -327,7 +334,7 @@ Style/MethodDefParentheses:
# Use the configured style when naming methods.
Style/MethodName:
Enabled: false
Enabled: true
# Checks for usage of `extend self` in modules.
Style/ModuleFunction:
......@@ -368,6 +375,11 @@ Style/MultilineMethodCallBraceLayout:
Style/MultilineMethodCallIndentation:
Enabled: false
# Checks that the closing brace in a method definition is symmetrical with
# respect to the opening brace and the method parameters.
Style/MultilineMethodDefinitionBraceLayout:
Enabled: false
# Checks indentation of binary operations that span more than one line.
Style/MultilineOperationIndentation:
Enabled: false
......@@ -390,7 +402,7 @@ Style/NegatedWhile:
# Avoid using nested modifiers.
Style/NestedModifier:
Enabled: false
Enabled: true
# Parenthesize method calls which are nested inside the argument list of
# another parenthesized method call.
......@@ -427,7 +439,7 @@ Style/OneLineConditional:
# When defining binary operators, name the argument other.
Style/OpMethod:
Enabled: false
Enabled: true
# Check for simple usages of parallel assignment. It will only warn when
# the number of variables matches on both sides of the assignment.
......@@ -507,7 +519,8 @@ Style/Semicolon:
# Checks for proper usage of fail and raise.
Style/SignalException:
Enabled: false
EnforcedStyle: only_raise
Enabled: true
# Enforces the names of some block params.
Style/SingleLineBlockParams:
......@@ -532,11 +545,11 @@ Style/SpaceAfterMethodName:
# Tracks redundant space after the ! operator.
Style/SpaceAfterNot:
Enabled: false
Enabled: true
# Use spaces after semicolons.
Style/SpaceAfterSemicolon:
Enabled: false
Enabled: true
# Checks that the equals signs in parameter default assignments have or don't
# have surrounding space depending on configuration.
......@@ -570,7 +583,7 @@ Style/SpaceBeforeFirstArg:
# No spaces before semicolons.
Style/SpaceBeforeSemicolon:
Enabled: false
Enabled: true
# Checks that block braces have or don't have surrounding space.
# For blocks taking parameters, checks that the left brace has or doesn't
......@@ -592,11 +605,12 @@ Style/SpaceInsideParens:
# No spaces inside range literals.
Style/SpaceInsideRangeLiteral:
Enabled: false
Enabled: true
# Checks for padding/surrounding spaces inside string interpolation.
Style/SpaceInsideStringInterpolation:
Enabled: false
EnforcedStyle: no_space
Enabled: true
# Avoid Perl-style global variables.
Style/SpecialGlobalVars:
......@@ -604,7 +618,8 @@ Style/SpecialGlobalVars:
# Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses:
Enabled: false
EnforcedStyle: require_parentheses
Enabled: true
# Checks if uses of quotes match the configured preference.
Style/StringLiterals:
......@@ -617,7 +632,9 @@ Style/StringLiteralsInInterpolation:
# Checks if configured preferred methods are used over non-preferred.
Style/StringMethods:
Enabled: false
PreferredMethods:
intern: to_sym
Enabled: true
# Use %i or %I for arrays of symbols.
Style/SymbolArray:
......@@ -675,15 +692,16 @@ Style/UnneededPercentQ:
# Don't interpolate global, instance and class variables directly in strings.
Style/VariableInterpolation:
Enabled: false
Enabled: true
# Use the configured style when naming variables.
Style/VariableName:
Enabled: false
EnforcedStyle: snake_case
Enabled: true
# Use when x then ... for one-line cases.
Style/WhenThen:
Enabled: false
Enabled: true
# Checks for redundant do after while or until.
Style/WhileUntilDo:
......@@ -691,7 +709,7 @@ Style/WhileUntilDo:
# Favor modifier while/until usage when you have a single-line body.
Style/WhileUntilModifier:
Enabled: false
Enabled: true
# Use %w or %W for arrays of words.
Style/WordArray:
......@@ -1071,3 +1089,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: true
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
Enabled: false
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.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.9.0 (unreleased)
- Redesign navigation for project pages
- Use gitlab-shell v3.0.0
- Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
- Changed the Slack build message to use the singular duration if necessary (Aran Koning)
- Fix issues filter when ordering by milestone
- Todos will display target state if issuable target is 'Closed' or 'Merged'
v 8.8.2
- Added remove due date button. !4209
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources. !4242
- Fix Error 500 in CI charts by gracefully handling commits with no durations. !4245
- Fix table UI on CI builds page. !4249
- Fix backups if registry is disabled. !4263
- Fixed issue with merge button color. !4211
- Fixed issue with enter key selecting wrong option in dropdown. !4210
- When creating a .gitignore file a dropdown with templates will be provided. !4075
- Fix concurrent request when updating build log in browser. !4183
v 8.8.1
- Add documentation for the "Health Check" feature
- Allow anonymous users to access a public project's pipelines
- Allow anonymous users to access a public project's pipelines !4233
- Fix MySQL compatibility in zero downtime migrations helpers
- Fix the CI login to Container Registry (the gitlab-ci-token user)
......
......@@ -294,6 +294,7 @@ group :development, :test do
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.40.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.11.0', require: false
......
......@@ -692,6 +692,8 @@ GEM
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.8.1)
......@@ -1016,6 +1018,7 @@ DEPENDENCIES
rspec-rails (~> 3.4.0)
rspec-retry
rubocop (~> 0.40.0)
rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
......
8.8.0-pre
8.9.0-pre
......@@ -28,12 +28,15 @@ class CiBuild
#
CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is build_url
last_state = @state
$.ajax
url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
dataType: "json"
success: (log) =>
@state = log.state
if log.status is "running"
return unless last_state is @state
if log.state and log.status is "running"
@state = log.state
if log.append
$('.fa-refresh').before log.html
else
......
......@@ -16,7 +16,6 @@ class Dispatcher
shortcut_handler = null
switch page
when 'projects:issues:index'
Issues.init()
Issuable.init()
shortcut_handler = new ShortcutsNavigation()
when 'projects:issues:show'
......@@ -119,7 +118,7 @@ class Dispatcher
new UsersSelect()
when 'projects'
new NamespaceSelect()
when 'dashboard'
when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles'
new Profile()
......
issuable_created = false
@Issuable =
init: ->
Issuable.initTemplates()
Issuable.initSearch()
unless issuable_created
issuable_created = true
Issuable.initTemplates()
Issuable.initSearch()
Issuable.initChecks()
initTemplates: ->
Issuable.labelRow = _.template(
......@@ -19,7 +23,16 @@
.on 'keyup', ->
clearTimeout(@timer)
@timer = setTimeout( ->
Issuable.filterResults $('#issue_search_form')
$search = $('#issue_search')
$form = $('.js-filter-form')
$input = $("input[name='#{$search.attr('name')}']", $form)
if $input.length is 0
$form.append "<input type='hidden' name='#{$search.attr('name')}' value='#{_.escape($search.val())}'/>"
else
$input.val $search.val()
Issuable.filterResults $form
, 500)
toggleLabelFilters: ->
......@@ -59,15 +72,22 @@
dataType: "json"
reload: ->
if Issues.created
Issues.initChecks()
if Issuable.created
Issuable.initChecks()
$('#filter_issue_search').val($('#issue_search').val())
initChecks: ->
$('.check_all_issues').on 'click', ->
$('.selected_issue').prop('checked', @checked)
Issuable.checkChanged()
$('.selected_issue').on 'change', Issuable.checkChanged
updateStateFilters: ->
stateFilters = $('.issues-state-filters')
stateFilters = $('.issues-state-filters, .dropdown-menu-sort')
newParams = {}
paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search']
paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search', 'issue_search']
for paramKey in paramKeys
newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
......@@ -82,3 +102,17 @@
else
newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
$(this).attr 'href', newUrl
checkChanged: ->
checked_issues = $('.selected_issue:checked')
if checked_issues.length > 0
ids = $.map checked_issues, (value) ->
$(value).data('id')
$('#update_issues_ids').val ids
$('.issues-other-filters').hide()
$('.issues_bulk_update').show()
else
$('#update_issues_ids').val []
$('.issues_bulk_update').hide()
$('.issues-other-filters').show()
@Issues =
init: ->
Issues.created = true
Issues.initChecks()
$("body").on "ajax:success", ".close_issue, .reopen_issue", ->
t = $(this)
totalIssues = undefined
reopen = t.hasClass("reopen_issue")
$(".issue_counter").each ->
issue = $(this)
totalIssues = parseInt($(this).html(), 10)
if reopen and issue.closest(".main_menu").length
$(this).html totalIssues + 1
else
$(this).html totalIssues - 1
initChecks: ->
$(".check_all_issues").click ->
$(".selected_issue").prop("checked", @checked)
Issues.checkChanged()
$(".selected_issue").bind "change", Issues.checkChanged
checkChanged: ->
checked_issues = $(".selected_issue:checked")
if checked_issues.length > 0
ids = []
$.each checked_issues, (index, value) ->
ids.push $(value).attr("data-id")
$("#update_issues_ids").val ids
$(".issues-other-filters").hide()
$(".issues_bulk_update").show()
else
$("#update_issues_ids").val []
$(".issues_bulk_update").hide()
$(".issues-other-filters").show()
......@@ -26,10 +26,19 @@
newUrl = decodeURIComponent(url)
for paramName, paramValue of params
pattern = new RegExp "\\b(#{paramName}=).*?(&|$)"
if url.search(pattern) >= 0
if not paramValue?
newUrl = newUrl.replace pattern, ''
else if url.search(pattern) isnt -1
newUrl = newUrl.replace pattern, "$1#{paramValue}$2"
else
newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}"
# Remove a trailing ampersand
lastChar = newUrl[newUrl.length - 1]
if lastChar is '&'
newUrl = newUrl.slice 0, -1
newUrl
# removes parameter query string from url. returns the modified url
......
......@@ -75,6 +75,9 @@ class @MergeRequestTabs
@loadDiff($target.attr('href'))
if bp? and bp.getBreakpointSize() isnt 'lg'
@shrinkView()
navBarHeight = $('.navbar-gitlab').outerHeight()
$.scrollTo(".merge-request-details .merge-request-tabs", offset: -navBarHeight)
else if action == 'builds'
@loadBuilds($target.attr('href'))
@expandView()
......
......@@ -106,6 +106,7 @@ class @MergeRequestWidget
@firstCICheck = false
showCIStatus: (state) ->
return if not state?
$('.ci_widget').hide()
allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
if state in allowed_states
......@@ -126,6 +127,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
$('.js-merge-button')
$('.js-merge-button,.accept-action .dropdown-toggle')
.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;
......
......@@ -162,6 +162,10 @@
}
}
.dropdown-menu-full-width {
width: 100%;
}
.dropdown-menu-paging {
.dropdown-page-two,
.dropdown-menu-back {
......
......@@ -5,6 +5,10 @@
.file-holder {
border: 1px solid $border-color;
&.file-holder-no-border {
border: 0;
}
&.readme-holder {
margin: $gl-padding-top 0;
}
......@@ -23,8 +27,17 @@
word-wrap: break-word;
border-radius: 3px 3px 0 0;
&.file-title-clear {
padding-left: 0;
padding-right: 0;
background-color: transparent;
.file-actions {
right: 0;
}
}
.file-actions {
float: right;
position: absolute;
top: 5px;
right: 15px;
......
......@@ -48,10 +48,6 @@
display: block;
}
.project-home-desc {
font-size: 21px;
}
.project-repo-buttons,
.git-clone-holder {
display: none;
......
......@@ -119,7 +119,7 @@
}
input {
height: 34px;
height: 35px;
display: inline-block;
position: relative;
top: 2px;
......@@ -196,7 +196,7 @@
position: fixed;
top: $header-height;
width: 100%;
z-index: 1;
z-index: 11;
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;
......
......@@ -40,11 +40,6 @@
}
}
.issue-search-form {
margin: 0;
height: 24px;
}
form.edit-issue {
margin: 0;
}
......@@ -96,8 +91,3 @@ form.edit-issue {
.issue-form .select2-container {
width: 250px !important;
}
.issue-closed-by-widget {
color: $gl-text-color;
margin-left: 52px;
}
......@@ -134,14 +134,6 @@
}
}
.change-username-title {
color: $gl-warning;
}
.remove-account-title {
color: $gl-danger;
}
.provider-btn-group {
display: inline-block;
margin-right: 10px;
......
......@@ -10,7 +10,7 @@
margin-bottom: 0;
}
.new_project,
.edit_project {
.edit-project {
fieldset.features {
.control-label {
font-weight: normal;
......@@ -26,8 +26,13 @@
}
.project-home-panel {
padding-bottom: 40px;
border-bottom: 1px solid $border-color;
background: $white-light;
text-align: left;
padding: 24px 0;
.container-fluid {
position: relative;
}
.cover-controls {
.project-settings-dropdown {
......@@ -43,21 +48,55 @@
}
}
.project-identicon-holder {
margin-bottom: 16px;
.cover-title {
margin-bottom: 0;
}
.project-image-container {
@include make-sm-column(1);
max-width: 86px;
min-width: 86px;
padding-right: 0;
margin: 11px 0;
.avatar, .identicon {
margin: 0 auto;
float: none;
@media (max-width: $screen-md-max) {
padding-left: 0;
margin: 0 0 10px;
max-width: none;
min-width: none;
.avatar.s70 {
margin: auto;
}
}
}
.identicon {
@include border-radius(50%);
.project-info {
@include make-sm-column(10);
h1 {
font-size: 24px;
font-weight: normal;
margin: 0;
}
.project-home-desc {
p {
margin: 0;
}
}
}
.identicon {
float: left;
@include border-radius(50%);
}
.avatar {
float: none;
}
.notifications-btn {
margin-top: -28px;
.fa-bell {
margin-right: 6px;
......@@ -69,28 +108,45 @@
}
.project-repo-buttons {
margin-top: 20px;
margin-bottom: 0;
font-size: 0;
.count-buttons {
display: block;
margin-bottom: 20px;
}
.btn {
@include btn-gray;
padding: 3px 10px;
text-transform: none;
background-color: $background-color;
.clone-row {
.split-repo-buttons,
.project-clone-holder {
display: inline-block;
.fa {
color: $layout-link-gray;
}
.split-repo-buttons {
margin: 0 12px;
.fa-caret-down {
margin-left: 3px;
}
}
.btn {
@include btn-gray;
text-transform: none;
.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,14 @@
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;
......@@ -159,6 +215,30 @@
}
}
}
.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 {
......@@ -289,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;
......@@ -304,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 {
......@@ -329,6 +408,10 @@ a.deploy-project-label {
background-color: #f0f2f5;
}
}
&.row-content-block.second-block {
margin-top: 0;
}
}
pre.light-well {
......@@ -446,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 {
......
......@@ -12,3 +12,11 @@
border: 1px solid $warning-message-border;
border-radius: $border-radius-base;
}
.warning-title {
color: $gl-warning;
}
.danger-title {
color: $gl-danger;
}
......@@ -16,19 +16,6 @@
}
}
.snippet-box {
@include border-radius(2px);
display: block;
float: left;
padding: 0 $gl-padding;
font-weight: normal;
margin-right: 10px;
font-size: $gl-font-size;
border: 1px solid;
line-height: 32px;
}
.markdown-snippet-copy {
position: fixed;
top: -10px;
......@@ -36,3 +23,34 @@
max-height: 0;
max-width: 0;
}
.file-holder.snippet-file-content {
padding-bottom: $gl-padding;
border-bottom: 1px solid $border-color;
.file-title {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
}
.file-actions {
top: 12px;
}
.file-content {
border-left: 1px solid $border-color;
border-right: 1px solid $border-color;
border-bottom: 1px solid $border-color;
}
}
.snippet-title {
font-size: 24px;
font-weight: normal;
}
.snippet-actions {
@media (min-width: $screen-sm-min) {
float: right;
}
}
......@@ -29,6 +29,17 @@
.todo-item {
.todo-title {
@include str-truncated(calc(100% - 174px));
overflow: visible;
}
.status-box {
margin: 0;
float: none;
display: inline-block;
font-weight: normal;
padding: 0 5px;
line-height: inherit;
font-size: 14px;
}
.todo-body {
......@@ -76,12 +87,11 @@
@media (max-width: $screen-xs-max) {
.todo-item {
padding-left: $gl-padding;
.todo-title {
white-space: normal;
overflow: visible;
max-width: 100%;
margin-bottom: 10px;
}
.avatar {
......
......@@ -229,6 +229,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if ci_commit
status = ci_commit.status
coverage = ci_commit.try(:coverage)
status ||= "preparing"
else
ci_service = @merge_request.source_project.ci_service
status = ci_service.commit_status(merge_request.last_commit.sha, merge_request.source_branch) if ci_service
......@@ -238,8 +240,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
status = "preparing" if status.nil?
response = {
title: merge_request.title,
sha: merge_request.last_commit_short_sha,
......
......@@ -250,12 +250,12 @@ class IssuableFinder
def by_milestone(items)
if milestones?
if filter_by_no_milestone?
items = items.where(milestone_id: [-1, nil])
items = items.left_joins_milestones.where(milestone_id: [-1, nil])
elsif filter_by_upcoming_milestone?
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
items = items.joins(:milestone).where(milestone_id: upcoming_ids)
items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
else
items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
items = items.with_milestone(params[:milestone_title])
if projects
items = items.where(milestones: { project_id: projects })
......
......@@ -262,6 +262,8 @@ module ApplicationHelper
assignee_id: params[:assignee_id],
author_id: params[:author_id],
sort: params[:sort],
issue_search: params[:issue_search],
label_name: params[:label_name]
}
options = exist_opts.merge(options)
......@@ -272,16 +274,11 @@ module ApplicationHelper
end
end
path = request.path
path << "?#{options.to_param}"
if add_label
if params[:label_name].present? and params[:label_name].respond_to?('any?')
params[:label_name].each do |label|
path << "&label_name[]=#{label}"
end
end
end
path
params = options.compact
params.delete(:label_name) unless add_label
"#{request.path}?#{params.to_param}"
end
def outdated_browser?
......
......@@ -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"
......
......@@ -37,6 +37,16 @@ module TodosHelper
end
end
def todo_target_state_pill(todo)
return unless show_todo_state?(todo)
content_tag(:span, nil, class: 'target-status') do
content_tag(:span, nil, class: "status-box status-box-#{todo.target.state.dasherize}") do
todo.target.state.capitalize
end
end
end
def todos_filter_params
{
state: params[:state],
......@@ -95,4 +105,10 @@ module TodosHelper
options_from_collection_for_select(types, 'name', 'title', params[:type])
end
private
def show_todo_state?(todo)
(todo.target.is_a?(MergeRequest) || todo.target.is_a?(Issue)) && ['closed', 'merged'].include?(todo.target.state)
end
end
......@@ -31,18 +31,21 @@ module Issuable
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) }
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
scope :opened, -> { with_state(:opened, :reopened) }
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) }
scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :left_joins_milestones, -> { joins("LEFT OUTER JOIN milestones ON #{table_name}.milestone_id = milestones.id") }
scope :order_milestone_due_desc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date DESC') }
scope :order_milestone_due_asc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date ASC') }
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
scope :outer_join_milestone, -> { joins("LEFT OUTER JOIN milestones ON milestones.id = #{table_name}.milestone_id") }
delegate :name,
:email,
......
......@@ -431,7 +431,13 @@ class Project < ActiveRecord::Base
def check_limit
unless creator.can_create_project? or namespace.kind == 'group'
self.errors.add(:limit_reached, "Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
projects_limit = creator.projects_limit
if projects_limit == 0
self.errors.add(:limit_reached, "Personal project creation is not allowed. Please contact your administrator with questions")
else
self.errors.add(:limit_reached, "Your project limit is #{projects_limit} projects! Please contact your administrator to increase it")
end
end
rescue
self.errors.add(:base, "Can't check your ability to create project")
......
......@@ -35,8 +35,8 @@ class SlackService
private
def message
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} second(s)"
end
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} #{'second'.pluralize(duration)}"
end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
......
......@@ -3,6 +3,8 @@
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title.title
- unless todo.build_failed?
= todo_target_state_pill(todo)
%span.author-name
- if todo.author
= link_to_author(todo)
......
%h3.page-title Authorize required
%h3.page-title Authorization required
%main{:role => "main"}
%p.h4
Authorize
......
......@@ -47,7 +47,7 @@
%td.import-target
= repo["path_with_namespace"]
%td.import-actions.job-status
= button_tag class: "btn js-add-to-import" do
= button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
......
%ul.nav.nav-sidebar
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do
= link_to dashboard_projects_path, title: 'Projects' do
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
= icon('bookmark fw')
%span
Projects
......@@ -11,7 +11,7 @@
Todos
%span.count.todos-pending-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'shortcuts-activity', title: 'Activity' do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
= icon('dashboard fw')
%span
Activity
......@@ -26,13 +26,13 @@
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
= icon('exclamation-circle fw')
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
......
%ul.nav.nav-sidebar
- if @project.group
= nav_link do
= link_to group_path(@project.group), title: 'Go to group', class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Go to group
- else
= nav_link do
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Go to dashboard
%li.separate-item
- if current_user
.controls
- access = user_max_access_in_project(current_user.id, @project)
- can_edit = can?(current_user, :admin_project, @project)
.dropdown.project-settings-dropdown
%a.dropdown-new.btn.btn-default#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
= icon('cog')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right
= render 'layouts/nav/project_settings'
%li.divider
- if can_edit
%li
= link_to edit_project_path(@project) do
Edit Project
- if access
%li
= link_to leave_namespace_project_project_members_path(@project.namespace, @project),
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
Leave Project
%ul.nav-links
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
= icon('bookmark fw')
......@@ -44,7 +50,7 @@
= 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
......@@ -52,7 +58,7 @@
= 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
......@@ -82,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
......@@ -90,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
......@@ -113,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
......@@ -127,13 +119,6 @@
%span
Snippets
- if project_nav_tab? :settings
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
= link_to edit_project_path(@project), title: 'Settings' do
= icon('cogs fw')
%span
Settings
-# Global shortcut to network page for compatibility
- if project_nav_tab? :network
%li.hidden
......
%ul.nav.nav-sidebar
= nav_link do
= link_to project_path(@project), title: 'Go to project', class: 'back-link' do
= icon('caret-square-o-left fw')
- if project_nav_tab? :team
= nav_link(controller: [:project_members, :teams]) do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
%span
Go to project
Members
%li.separate-item
%ul.sidebar-subnav
= nav_link(path: 'projects#edit') do
= link_to edit_project_path(@project), title: 'Project Settings' do
= icon('pencil-square-o fw')
%span
Project Settings
- if @project.allowed_to_share_with_group?
= 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.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
- 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
- page_title @project.name_with_namespace
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
- sidebar "project" unless sidebar
- nav "project"
- content_for :scripts_body_top do
- project = @target_project || @project
......
- page_title "Settings"
- header_title project_title(@project, "Settings", edit_project_path(@project))
- sidebar "project_settings"
- nav "project"
= render template: "layouts/project"
......@@ -70,7 +70,7 @@
- if current_user.can_change_username?
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0.change-username-title
%h4.prepend-top-0.warning-title
Change username
%p
Changing your username will change path to all personal projects!
......@@ -94,7 +94,7 @@
- if signup_enabled?
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0.remove-account-title
%h4.prepend-top-0.danger-title
Remove account
.col-lg-9
- if @user.can_be_removed?
......
......@@ -5,7 +5,7 @@
%h4.prepend-top-0
Application theme
%p
This setting allows you to customize the appearance of the site, ex. sidebar.
This setting allows you to customize the appearance of the site, e.g. the sidebar.
.col-lg-9.application-theme
- Gitlab::Themes.each do |theme|
= label_tag do
......
%fieldset.builds-feature
%legend
Builds:
%h5.prepend-top-0
Builds
- unless @repository.gitlab_ci_yml
.form-group
.col-sm-offset-2.col-sm-10
%p Builds need to be configured before you can begin using Continuous Integration.
= link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
%hr
%p Builds need to be configured before you can begin using Continuous Integration.
= link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
.form-group
.col-sm-offset-2.col-sm-10
%p Get recent application code using the following command:
.radio
= f.label :build_allow_git_fetch_false do
= f.radio_button :build_allow_git_fetch, 'false'
%strong git clone
%br
%span.descr Slower but makes sure you have a clean dir before every build
.radio
= f.label :build_allow_git_fetch_true do
= f.radio_button :build_allow_git_fetch, 'true'
%strong git fetch
%br
%span.descr Faster
%p Get recent application code using the following command:
.radio
= f.label :build_allow_git_fetch_false do
= f.radio_button :build_allow_git_fetch, 'false'
%strong git clone
%br
%span.descr Slower but makes sure you have a clean dir before every build
.radio
= f.label :build_allow_git_fetch_true do
= f.radio_button :build_allow_git_fetch, 'true'
%strong git fetch
%br
%span.descr Faster
.form-group
= f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
.col-sm-10
= f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
%p.help-block per build in minutes
= f.label :build_timeout_in_minutes, 'Timeout', class: 'label-light'
= f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
%p.help-block per build in minutes
.form-group
= f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
.col-sm-10
.input-group
%span.input-group-addon /
= f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
%span.input-group-addon /
%p.help-block
We will use this regular expression to find test coverage output in build trace.
Leave blank if you want to disable this feature
.bs-callout.bs-callout-info
%p Below are examples of regex for existing tools:
%ul
%li
Simplecov (Ruby) -
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
%code \d+\%\s*$
%li
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
%li
gcovr (C/C++) -
%code ^TOTAL.*\s+(\d+\%)$
%li
tap --coverage-report=text-summary (Node.js) -
%code ^Statements\s*:\s*([^%]+)
= f.label :build_coverage_regex, "Test coverage parsing", class: 'label-light'
.input-group
%span.input-group-addon /
= f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
%span.input-group-addon /
%p.help-block
We will use this regular expression to find test coverage output in build trace.
Leave blank if you want to disable this feature
.bs-callout.bs-callout-info
%p Below are examples of regex for existing tools:
%ul
%li
Simplecov (Ruby) -
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
%code \d+\%\s*$
%li
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
%li
gcovr (C/C++) -
%code ^TOTAL.*\s+(\d+\%)$
%li
tap --coverage-report=text-summary (Node.js) -
%code ^Statements\s*:\s*([^%]+)
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :public_builds do
= f.check_box :public_builds
%strong Public builds
.help-block Allow everyone to access builds for Public and Internal projects
.checkbox
= f.label :public_builds do
= f.check_box :public_builds
%strong Public builds
.help-block Allow everyone to access builds for Public and Internal projects
.form-group
= f.label :runners_token, "Runners token", class: 'control-label'
.col-sm-10
= f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
%p.help-block The secure token used to checkout project.
.form-group.append-bottom-0
= f.label :runners_token, "Runners token", class: 'label-light'
= f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
%p.help-block The secure token used to checkout project.
- empty_repo = @project.empty_repo?
.project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.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 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
.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'
.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 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)
.project-repo-buttons
.count-buttons
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
.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)
......
- 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)
.project-edit-container.prepend-top-default
.project-edit-errors
.project-edit-content
.panel.panel-default
.panel-heading
.project-edit-container
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
Project settings
.panel-body
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit_project form-horizontal fieldset-form" }, authenticity_token: true do |f|
%fieldset
.form-group.project_name_holder
= f.label :name, class: 'control-label' do
Project name
.col-sm-10
= f.text_field :name, class: "form-control", id: "project_name_edit"
.form-group
= f.label :description, class: 'control-label' do
Project description
%span.light (optional)
.col-sm-10
= f.text_area :description, class: "form-control", rows: 3, maxlength: 250
- unless @project.empty_repo?
.form-group
= f.label :default_branch, "Default Branch", class: 'control-label'
.col-sm-10= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
= render 'shared/visibility_level', f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can_change_visibility_level?(@project, current_user), form_model: @project
.col-lg-9
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset.append-bottom-0
.form-group
= f.label :tag_list, "Tags", class: 'control-label'
.col-sm-10
= f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control"
%p.help-block Separate tags with commas.
%fieldset.features
%legend
Features:
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :issues_enabled do
= f.check_box :issues_enabled
%strong Issues
%br
%span.descr Lightweight issue tracking system for this project
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :merge_requests_enabled do
= f.check_box :merge_requests_enabled
%strong Merge Requests
%br
%span.descr Submit changes to be merged upstream
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :builds_enabled do
= f.check_box :builds_enabled
%strong Builds
%br
%span.descr Test and deploy your changes before merge
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :wiki_enabled do
= f.check_box :wiki_enabled
%strong Wiki
%br
%span.descr Pages for project documentation
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :snippets_enabled do
= f.check_box :snippets_enabled
%strong Snippets
%br
%span.descr Share code pastes with others out of git repository
- if Gitlab.config.registry.enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :container_registry_enabled do
= f.check_box :container_registry_enabled
%strong Container Registry
%br
%span.descr Enable Container Registry for this repository
= render 'builds_settings', f: f
= f.label :name, class: 'label-light' do
Project name
= f.text_field :name, class: "form-control", id: "project_name_edit"
.form-group
= f.label :description, class: 'label-light' do
Project description
%span.light (optional)
= f.text_area :description, class: "form-control", rows: 3, maxlength: 250
%fieldset.features
%legend
Project avatar:
- unless @project.empty_repo?
.form-group
.col-sm-offset-2.col-sm-10
- if @project.avatar?
= project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
%p.light
- if @project.avatar_in_git
Project avatar in repository: #{ @project.avatar_in_git }
%p.light
- if @project.avatar?
You can change your project avatar here
- else
You can upload a project avatar here
%a.choose-btn.btn.btn-sm.js-choose-project-avatar-button
%i.icon-paper-clip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-project-avatar-input hidden"
.light The maximum file size allowed is 200KB.
- if @project.avatar?
%hr
= link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
.danger-settings
.panel.panel-default
.panel-heading Housekeeping
.errors-holder
.panel-body
%p
Runs a number of housekeeping tasks within the current repository,
such as compressing file revisions and removing unreachable objects.
%br
.form-actions
= link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
method: :post, class: "btn btn-default"
- if can? current_user, :archive_project, @project
- if @project.archived?
.panel.panel-success
.panel-heading
Unarchive project
.panel-body
%p
Unarchiving the project will mark its repository as active.
= f.label :default_branch, "Default Branch", class: 'label-light'
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
.form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'label-light' do
Visibility Level
= link_to "(?)", help_page_path("public_access", "public_access")
- if can_change_visibility_level?(@project, current_user)
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project)
- else
.info
= visibility_level_icon(@project.visibility_level)
%strong
= visibility_level_label(@project.visibility_level)
.light= visibility_level_description(@project.visibility_level, @project)
.form-group
= f.label :tag_list, "Tags", class: 'label-light'
= f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control"
%p.help-block Separate tags with commas.
%hr
%fieldset.features.append-bottom-0
%h5.prepend-top-0
Features
.form-group
.checkbox
= f.label :issues_enabled do
= f.check_box :issues_enabled
%strong Issues
%br
The project can be committed to.
%span.descr Lightweight issue tracking system for this project
.form-group
.checkbox
= f.label :merge_requests_enabled do
= f.check_box :merge_requests_enabled
%strong Merge Requests
%br
%strong Once active this project shows up in the search and on the dashboard.
.form-actions
= link_to 'Unarchive project', unarchive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
method: :post, class: "btn btn-success"
- else
.panel.panel-warning
.panel-heading
Archive project
.panel-body
%p
Archiving the project will mark its repository as read-only.
%span.descr Submit changes to be merged upstream
.form-group
.checkbox
= f.label :builds_enabled do
= f.check_box :builds_enabled
%strong Builds
%br
%span.descr Test and deploy your changes before merge
.form-group
.checkbox
= f.label :wiki_enabled do
= f.check_box :wiki_enabled
%strong Wiki
%br
It is hidden from the dashboard and doesn't show up in searches.
%span.descr Pages for project documentation
.form-group
.checkbox
= f.label :snippets_enabled do
= f.check_box :snippets_enabled
%strong Snippets
%br
%strong Archived projects cannot be committed to!
.form-actions
= link_to 'Archive project', archive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
method: :post, class: "btn btn-warning"
- else
.nothing-here-block Only the project owner can archive a project
.panel.panel-default.panel.panel-warning
.panel-heading Rename repository
.errors-holder
.panel-body
= form_for([@project.namespace.becomes(Namespace), @project], html: { class: 'form-horizontal' }) do |f|
.form-group.project_name_holder
= f.label :name, class: 'control-label' do
Project name
.col-sm-9
.form-group
= f.text_field :name, class: "form-control"
%span.descr Share code pastes with others out of git repository
- if Gitlab.config.registry.enabled
.form-group
= f.label :path, class: 'control-label' do
%span Path
.col-sm-9
.form-group
.input-group
.input-group-addon
#{URI.join(root_url, @project.namespace.path)}/
= f.text_field :path, class: 'form-control'
%ul
%li Be careful. Renaming a project's repository can have unintended side effects.
%li You will need to update your local repositories to point to the new location.
.form-actions
= f.submit 'Rename project', class: "btn btn-warning"
- if can?(current_user, :change_namespace, @project)
.panel.panel-default.panel.panel-danger
.panel-heading Transfer project
.errors-holder
.panel-body
= form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.form-group
= label_tag :new_namespace_id, nil, class: 'control-label' do
%span Namespace
.col-sm-9
.form-group
= select_tag :new_namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace', class: 'select2' }
%ul
%li Be careful. Changing the project's namespace can have unintended side effects.
%li You can only transfer the project to namespaces you manage.
%li You will need to update your local repositories to point to the new location.
%li Project visibility level will be changed to match namespace rules when transfering to a group.
.form-actions
= f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
- else
.nothing-here-block Only the project owner can transfer a project
- if @project.forked?
- if can?(current_user, :remove_fork_project, @project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.panel.panel-default.panel.panel-danger
.panel-heading Remove fork relationship
.panel-body
%p
This will remove the fork relationship to source project
#{link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)}.
.checkbox
= f.label :container_registry_enabled do
= f.check_box :container_registry_enabled
%strong Container Registry
%br
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
.form-actions
= button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
%span.descr Enable Container Registry for this repository
%hr
= render 'builds_settings', f: f
%hr
%fieldset.features.append-bottom-default
%h5.prepend-top-0
Project avatar
.form-group
- if @project.avatar?
= project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
%p.light
- if @project.avatar_in_git
Project avatar in repository: #{ @project.avatar_in_git }
%a.choose-btn.btn.js-choose-project-avatar-button
Browse file...
%span.file_name.prepend-left-default.js-avatar-filename No file chosen
= f.file_field :avatar, class: "js-project-avatar-input hidden"
.help-block The maximum file size allowed is 200KB.
- if @project.avatar?
%hr
= link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
= f.submit 'Save changes', class: "btn btn-save"
.row.prepend-top-default
%hr
.row.prepend-top-default
.col-lg-3
%h4.prepend-top-0
Housekeeping
%p.append-bottom-0
%p
Runs a number of housekeeping tasks within the current repository,
such as compressing file revisions and removing unreachable objects.
.col-lg-9
= link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
method: :post, class: "btn btn-save"
%hr
- if can? current_user, :archive_project, @project
.row.prepend-top-default
.col-lg-3
%h4.warning-title.prepend-top-0
- if @project.archived?
Unarchive project
- else
Archive project
%p.append-bottom-0
- if @project.archived?
Unarchiving the project will mark its repository as active. The project can be committed to.
- else
Archiving the project will mark its repository as read-only. It is hidden from the dashboard and doesn't show up in searches.
.col-lg-9
- if @project.archived?
%p
%strong Once active this project shows up in the search and on the dashboard.
= link_to 'Unarchive project', unarchive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
method: :post, class: "btn btn-success"
- else
.nothing-here-block Only the project owner can remove the fork relationship.
- if can?(current_user, :remove_project, @project)
.panel.panel-default.panel.panel-danger
.panel-heading Remove project
.panel-body
= form_tag(namespace_project_path(@project.namespace, @project), method: :delete, class: 'form-horizontal') do
%p
Removing the project will delete its repository and all related resources including issues, merge requests etc.
%br
%strong Removed projects cannot be restored!
.form-actions
= button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
- else
.nothing-here-block Only the project owner can remove a project.
%p
%strong Archived projects cannot be committed to!
= link_to 'Archive project', archive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
method: :post, class: "btn btn-warning"
%hr
.row.prepend-top-default
.col-lg-3
%h4.prepend-top-0.warning-title
Rename repository
.col-lg-9
= form_for([@project.namespace.becomes(Namespace), @project]) do |f|
.form-group.project_name_holder
= f.label :name, class: 'label-light' do
Project name
.form-group
= f.text_field :name, class: "form-control"
.form-group
= f.label :path, class: 'label-light' do
%span Path
.form-group
.input-group
.input-group-addon
#{URI.join(root_url, @project.namespace.path)}/
= f.text_field :path, class: 'form-control'
%ul
%li Be careful. Renaming a project's repository can have unintended side effects.
%li You will need to update your local repositories to point to the new location.
= f.submit 'Rename project', class: "btn btn-warning"
- if can?(current_user, :change_namespace, @project)
%hr
.row.prepend-top-default
.col-lg-3
%h4.prepend-top-0.danger-title
Transfer project
.col-lg-9
= form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true) do |f|
.form-group
= label_tag :new_namespace_id, nil, class: 'label-light' do
%span Namespace
.form-group
= select_tag :new_namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace', class: 'select2' }
%ul
%li Be careful. Changing the project's namespace can have unintended side effects.
%li You can only transfer the project to namespaces you manage.
%li You will need to update your local repositories to point to the new location.
%li Project visibility level will be changed to match namespace rules when transfering to a group.
= f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
- if @project.forked? && can?(current_user, :remove_fork_project, @project)
%hr
.row.prepend-top-default.append-bottom-default
.col-lg-3
%h4.prepend-top-0.danger-title
Remove fork relationship
%p.append-bottom-0
%p
This will remove the fork relationship to source project
= succeed "." do
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
.col-lg-9
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
%p
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
= button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
- if can?(current_user, :remove_project, @project)
%hr
.row.prepend-top-default.append-bottom-default
.col-lg-3
%h4.prepend-top-0.danger-title
Remove project
%p.append-bottom-0
Removing the project will delete its repository and all related resources including issues, merge requests etc.
.col-lg-9
= form_tag(namespace_project_path(@project.namespace, @project), method: :delete) do
%p
%strong Removed projects cannot be restored!
= button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
.save-project-loader.hide
.center
......@@ -264,5 +224,4 @@
Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
= render 'shared/confirm_modal', phrase: @project.path
......@@ -40,13 +40,13 @@
%td
= generic_commit_status.name
.pull-right
- if generic_commit_status.tags.any?
- generic_commit_status.tags.each do |tag|
%span.label.label-primary
= tag
- if defined?(retried) && retried
%span.label.label-warning retried
%td
- if generic_commit_status.tags.any?
- generic_commit_status.tags.each do |tag|
%span.label.label-primary
= tag
- if defined?(retried) && retried
%span.label.label-warning retried
%td.duration
- if generic_commit_status.duration
......
......@@ -19,7 +19,7 @@
.header.clearfix
%h3#date_header.page-title
%p.light
Commits to #{@ref}, excluding merge commits. Limited by 6,000 commits
Commits to #{@ref}, excluding merge commits. Limited to 6,000 commits.
%input#brush_change{:type => "hidden"}
.graphs
#contributors-master
......
......@@ -24,5 +24,8 @@
MERGED
- elsif merge_request.closed?
CLOSED
- if @closed_by_merge_requests.present?
%li
= render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
- if @closed_by_merge_requests.present?
%li
= render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
......@@ -18,6 +18,6 @@
- else
.nothing-here-block
- if can? current_user, :admin_label, @project
Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}.
- else
No labels created
......@@ -8,7 +8,7 @@
Install GitLab Runner software.
Checkout the #{link_to 'GitLab Runner section', 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'} to install it
%li
Specify following URL during runner setup:
Specify the following URL during runner setup:
%code #{ci_root_url(only_path: false)}
%li
Use the following registration token during setup:
......
......@@ -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 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 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
......
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :admin_project_snippet, @snippet)
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
- if can?(current_user, :update_project_snippet, @snippet)
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
= icon('pencil-square-o')
Edit
.hidden-xs
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
Delete
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
......@@ -4,15 +4,13 @@
.snippet-holder
= render 'shared/snippets/header'
%article.file-holder
.file-title
%article.file-holder.file-holder-no-border.snippet-file-content
.file-title.file-title-clear
= blob_icon 0, @snippet.file_name
%strong
= @snippet.file_name
= @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
= render 'shared/snippets/blob'
%div#notes= render "projects/notes/notes_with_form"
......@@ -5,7 +5,7 @@
%h4.prepend-top-0
= page_title
%p
Triggers can be used to force a rebuild of a specific branch or tag with an API call.
Triggers can force a specific branch or tag to rebuild with an API call.
.col-lg-9
%h5.prepend-top-0
Your triggers
......@@ -19,7 +19,7 @@
= render partial: 'trigger', collection: @triggers, as: :trigger
- else
%p.settings-message.text-center.append-bottom-default
There are no triggers to use, add one by the button below.
No triggers have been created yet. Add one using the button below.
= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create') do |f|
= f.submit "Add Trigger", class: 'btn btn-success'
......@@ -28,8 +28,7 @@
Use CURL
%p.light
Copy the token above and set your branch or tag name. This is the reference that will be rebuild.
Copy the token above, set your branch or tag name, and that reference will be rebuilt.
%pre
:plain
......@@ -41,10 +40,10 @@
Use .gitlab-ci.yml
%p.light
Copy the snippet to
%i .gitlab-ci.yml
of dependent project.
At the end of your build it will trigger this project to rebuilt.
In the
%code .gitlab-ci.yml
of the dependent project, include the following snippet.
The project will rebuild at the end of the build.
%pre
:plain
......@@ -57,9 +56,8 @@
%p.light
Add
%strong variables[VARIABLE]=VALUE
to API request.
The value of variable could then be used to distinguish triggered build from normal one.
%code variables[VARIABLE]=VALUE
to an API request. Variable values can be used to distinguish between triggered builds and normal builds.
%pre.append-bottom-0
:plain
......
......@@ -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)
......
......@@ -6,7 +6,7 @@
- else
= sort_title_recently_created
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li
= link_to page_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
......
.issues-filters
.issues-details-filters.row-content-block.second-block
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :issue_search]), method: :get, class: 'filter-form js-filter-form' do
- if params[:issue_search].present?
= hidden_field_tag :issue_search, params[:issue_search]
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.check-all-holder
= check_box_tag "check_all_issues", nil, false,
......
= form_tag(path, method: :get, id: "issue_search_form", class: 'issue-search-form') do
= search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input input-short', spellcheck: false }
= hidden_field_tag :state, params['state']
= hidden_field_tag :scope, params['scope']
= hidden_field_tag :assignee_id, params['assignee_id']
= hidden_field_tag :author_id, params['author_id']
= hidden_field_tag :milestone_id, params['milestone_id']
= hidden_field_tag :label_id, params['label_id']
.detail-page-header
.snippet-box.has-tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }}
.detail-page-header.clearfix
.snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
%span.sr-only
= visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
= visibility_level_label(@snippet.visibility_level)
%span.identifier
%strong.item-title
Snippet ##{@snippet.id}
%span.creator
&middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
&middot;
created by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title")}
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
- if @snippet.updated_at != @snippet.created_at
%span
&middot;
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
.pull-right
.snippet-actions
- if @snippet.project_id?
= render "projects/snippets/actions"
- else
= render "snippets/actions"
.detail-page-description.row-content-block.second-block
%h2.title
.content-block.second-block
%h2.snippet-title.prepend-top-0.append-bottom-0
= markdown escape_once(@snippet.title), pipeline: :single_line
= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
= icon('pencil-square-o')
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
.hidden-xs
= link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
Delete
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
%li
= link_to new_snippet_path, title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
%li
= link_to edit_snippet_path(@snippet) do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
%li
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
......@@ -3,11 +3,10 @@
.snippet-holder
= render 'shared/snippets/header'
%article.file-holder
.file-title
%article.file-holder.file-holder-no-border.snippet-file-content
.file-title.file-title-clear
= blob_icon 0, @snippet.file_name
%strong
= @snippet.file_name
= @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
......
......@@ -26,7 +26,7 @@ that runs Redis.
```ruby
external_url 'https://gitlab.example.com'
# Disable all components except PostgreSQL
# Disable all components except Redis
redis['enable'] = true
bootstrap['enable'] = false
nginx['enable'] = false
......
......@@ -65,7 +65,7 @@ the command line via `bundle exec teaspoon`, or via a web browser at
- Use `context` to test branching logic.
- Don't `describe` symbols (see [Gotchas](gotchas.md#dont-describe-symbols)).
- Don't supply the `:each` argument to hooks since it's the default.
- Prefer `not_to` to `to_not`.
- Prefer `not_to` to `to_not` (_this is enforced by Rubocop_).
- Try to match the ordering of tests to the ordering within the class.
- Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines
to separate phases.
......
......@@ -6,3 +6,31 @@ We created a page inside GitLab where you can check commonly used html and css e
When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples
you can use during GitLab development.
## Design repository
All design files are stored in the [gitlab-design](https://gitlab.com/gitlab-org/gitlab-design)
repository and maintained by GitLab UX designers.
## Navigation
GitLab's layout contains 2 sections: the left sidebar and the content. The left sidebar contains a static navigation menu.
This menu will be visible regardless of what page you visit. The left sidebar also contains the GitLab logo
and the current user's profile picture. The content section contains a header and the content itself.
The header describes the current GitLab page and what navigation is
available to user in this area. Depending on the area (project, group, profile setting) the header name and navigation may change. For example when user visits one of the
project pages the header will contain a project name and navigation for that project. When the user visits a group page it will contain a group name and navigation related to this group.
### Adding new tab to header navigation
We try to keep the amount of tabs in the header navigation between 5 and 10 so that it fits on a typical laptop screen. We also try not to confuse the user with too many options. Ideally each
tab should represent separate functionality. Everything related to the issue
tracker should be under the 'Issues' tab while everything related to the wiki should
be under 'Wiki' tab and so on and so forth.
## Mobile screen size
We want GitLab to work well on small mobile screens as well. Size limitations make it is impossible to fit everything on a mobile screen. In this case it is OK to hide
part of the UI for smaller resolutions in favor of a better user experience.
However core functionality like browsing files, creating issues, writing comments, should
be available on all resolutions.
\ No newline at end of file
......@@ -271,7 +271,7 @@ sudo usermod -aG redis git
# Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-8-stable gitlab
**Note:** You can change `8-7-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
**Note:** You can change `8-8-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
......
......@@ -11,9 +11,9 @@ To enable the Google OAuth2 OmniAuth provider you must register your application
- Project ID: Must be unique to all Google Developer registered applications. Google provides a randomly generated Project ID by default. You can use the randomly generated ID or choose a new one.
1. Refresh the page. You should now see your new project in the list. Click on the project.
1. Select "APIs & auth" in the left menu.
1. Select the "Google APIs" tab in the Overview.
1. Select "APIs" in the submenu.
1. Select and enable the following Google APIs - listed under "Popular APIs"
- Enable `Contacts API`
- Enable `Google+ API`
......
......@@ -11,7 +11,7 @@ and access the cache. This endpoint can be provided to uptime monitoring service
## 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.
accepted token can be found on the `admin/health_check` page of your GitLab instance.
![access token](img/health_check_token.png)
......
......@@ -30,11 +30,6 @@ Feature: Project Active Tab
Then the active main tab should be Merge Requests
And no other main tabs should be active
Scenario: On Project Members
Given I visit my project's members page
Then the active main tab should be Members
And no other main tabs should be active
Scenario: On Project Wiki
Given I visit my project's wiki page
Then the active main tab should be Wiki
......@@ -49,13 +44,6 @@ Feature: Project Active Tab
# Sub Tabs: Settings
Scenario: On Project Settings/Edit
Given I visit my project's settings page
And I click the "Edit" tab
Then the active sub nav should be Edit
And no other sub navs should be active
And the active main tab should be Settings
Scenario: On Project Settings/Hooks
Given I visit my project's settings page
And I click the "Hooks" tab
......@@ -70,6 +58,12 @@ Feature: Project Active Tab
And no other sub navs should be active
And the active main tab should be Settings
Scenario: On Project Members
Given I visit my project's members page
Then the active sub nav should be Members
And no other sub navs should be active
And the active main tab should be Settings
# Sub Tabs: Commits
Scenario: On Project Commits/Commits
......
......@@ -18,15 +18,6 @@ Feature: Project
Then I should see the default project avatar
And I should not see the "Remove avatar" button
Scenario: I should have back to group button
And project "Shop" belongs to group
And I visit project "Shop" page
Then I should see back to group button
Scenario: I should have back to group button
And I visit project "Shop" page
Then I should see back to dashboard button
Scenario: I should have readme on page
And I visit project "Shop" page
Then I should see project "Shop" README
......
class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedActiveTab
include SharedSidebarActiveTab
step 'the active main tab should be Home' do
ensure_active_main_tab('Overview')
......@@ -34,4 +34,12 @@ class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Messages' do
ensure_active_main_tab('Messages')
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
end
def ensure_active_main_tab(content)
expect(find('.nav-sidebar > li.active')).to have_content(content)
end
end
......@@ -158,7 +158,7 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
step 'I should not see twitter details' do
expect(page).to have_content 'Pete'
expect(page).to_not have_content 'twitter'
expect(page).not_to have_content 'twitter'
end
step 'click on ssh keys tab' do
......
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
......@@ -106,7 +106,7 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
if pending
expect(page).to have_link 'Done'
else
expect(page).to_not have_link 'Done'
expect(page).not_to have_link 'Done'
end
end
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
......
......@@ -105,7 +105,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I should not see button to create a new merge request' do
expect(page).to_not have_link 'Create Merge Request'
expect(page).not_to have_link 'Create Merge Request'
end
step 'I should see button to the merge request' 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
......
......@@ -39,8 +39,8 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
step 'I can see the activity and food categories' do
page.within '.emoji-menu' do
expect(page).to_not have_selector 'Activity'
expect(page).to_not have_selector 'Food'
expect(page).not_to have_selector 'Activity'
expect(page).not_to have_selector 'Food'
end
end
......
......@@ -216,7 +216,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
page.within 'li.issue:nth-child(3)' do
expect(page).to have_content 'Bugfix'
expect(page).to_not have_content '0 0'
expect(page).not_to have_content '0 0'
end
end
end
......@@ -235,7 +235,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
page.within 'li.issue:nth-child(3)' do
expect(page).to have_content 'Bugfix'
expect(page).to_not have_content '0 0'
expect(page).not_to have_content '0 0'
end
end
end
......
......@@ -24,8 +24,8 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
step 'I should see labels help message' do
page.within '.labels' do
expect(page).to have_content 'Create first label or generate default set of '\
'labels'
expect(page).to have_content 'Create a label or generate a default set '\
'of labels'
end
end
......
......@@ -203,7 +203,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within 'li.merge-request:nth-child(3)' do
expect(page).to have_content 'Bug NS-05'
expect(page).to_not have_content '0 0'
expect(page).not_to have_content '0 0'
end
end
end
......@@ -222,7 +222,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within 'li.merge-request:nth-child(3)' do
expect(page).to have_content 'Bug NS-05'
expect(page).to_not have_content '0 0'
expect(page).not_to have_content '0 0'
end
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')
......
......@@ -43,12 +43,12 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
step 'I click link "Edit"' do
page.within ".detail-page-header" do
click_link "Edit"
first(:link, "Edit").click
end
end
step 'I click link "Delete"' do
click_link "Delete"
first(:link, "Delete").click
end
step 'I submit new snippet "Snippet three"' do
......
......@@ -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
......
......@@ -107,7 +107,7 @@ module SharedNote
end
step 'I should see no notes at all' do
expect(page).to_not have_css('.note')
expect(page).not_to have_css('.note')
end
# Markdown
......
......@@ -95,7 +95,7 @@ module SharedProject
step 'I should see project settings' do
expect(current_path).to eq edit_namespace_project_path(@project.namespace, @project)
expect(page).to have_content("Project name")
expect(page).to have_content("Features:")
expect(page).to have_content("Features")
end
def current_project
......
......@@ -41,9 +41,7 @@ module SharedProjectTab
end
step 'the active main tab should be Settings' do
page.within '.nav-sidebar' do
expect(page).to have_content('Go to project')
end
expect(page).to have_selector('.layout-nav .nav-links > li.active', count: 0)
end
step 'the active main tab should be Activity' do
......
module SharedActiveTab
module SharedShortcuts
include Spinach::DSL
step 'I press "g" and "p"' do
......
module SharedSidebarActiveTab
include Spinach::DSL
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
end
def ensure_active_main_tab(content)
expect(find('.nav-sidebar li.active')).to have_content(content)
end
step 'the active main tab should be Home' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Projects' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
step 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
step 'the active main tab should be Help' do
ensure_active_main_tab('Help')
end
end
......@@ -14,12 +14,12 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
step 'I click link "Edit"' do
page.within ".detail-page-header" do
click_link "Edit"
first(:link, "Edit").click
end
end
step 'I click link "Delete"' do
click_link "Delete"
first(:link, "Delete").click
end
step 'I submit new snippet "Personal snippet three"' do
......
module Backup
class Manager
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts lfs registry]
FOLDERS_TO_BACKUP = %w[repositories db]
def pack
# Make sure there is a connection
ActiveRecord::Base.connection.reconnect!
......@@ -147,7 +150,7 @@ module Backup
end
def skipped?(item)
settings[:skipped] && settings[:skipped].include?(item)
settings[:skipped] && settings[:skipped].include?(item) || disabled_features.include?(item)
end
private
......@@ -157,11 +160,17 @@ module Backup
end
def archives_to_backup
%w{uploads builds artifacts lfs registry}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
ARCHIVES_TO_BACKUP.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
end
def folders_to_backup
%w{repositories db}.reject{ |name| skipped?(name) }
FOLDERS_TO_BACKUP.reject{ |name| skipped?(name) }
end
def disabled_features
features = []
features << 'registry' unless Gitlab.config.registry.enabled
features
end
def settings
......
......@@ -90,7 +90,7 @@ module Ci
def convert(raw, new_state)
reset_state
restore_state(raw, new_state) if new_state
restore_state(raw, new_state) if new_state.present?
start = @offset
ansi = raw[@offset..-1]
......@@ -105,6 +105,8 @@ module Ci
break
elsif s.scan(/</)
@out << '&lt;'
elsif s.scan(/\n/)
@out << '<br>'
else
@out << s.scan(/./m)
end
......
module Ci
class GitlabCiYamlProcessor
class ValidationError < StandardError;end
class ValidationError < StandardError; end
DEFAULT_STAGES = %w(build test deploy)
DEFAULT_STAGE = 'test'
......
......@@ -179,18 +179,26 @@ namespace :gitlab do
task create: :environment do
$progress.puts "Dumping container registry images ... ".blue
if ENV["SKIP"] && ENV["SKIP"].include?("registry")
$progress.puts "[SKIPPED]".cyan
if Gitlab.config.registry.enabled
if ENV["SKIP"] && ENV["SKIP"].include?("registry")
$progress.puts "[SKIPPED]".cyan
else
Backup::Registry.new.dump
$progress.puts "done".green
end
else
Backup::Registry.new.dump
$progress.puts "done".green
$progress.puts "[DISABLED]".cyan
end
end
task restore: :environment do
$progress.puts "Restoring container registry images ... ".blue
Backup::Registry.new.restore
$progress.puts "done".green
if Gitlab.config.registry.enabled
Backup::Registry.new.restore
$progress.puts "done".green
else
$progress.puts "[DISABLED]".cyan
end
end
end
......
......@@ -36,5 +36,15 @@ namespace :gitlab do
# Add `IF EXISTS` because cascade could have already deleted a table.
tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{t} CASCADE") }
end
desc 'Configures the database by running migrate, or by loading the schema and seeding if needed'
task configure: :environment do
if ActiveRecord::Base.connection.tables.any?
Rake::Task['db:migrate'].invoke
else
Rake::Task['db:schema:load'].invoke
Rake::Task['db:seed_fu'].invoke
end
end
end
end
unless Rails.env.production?
require 'rubocop/rake_task'
RuboCop::RakeTask.new
end
......@@ -17,7 +17,7 @@ describe Admin::ProjectsController do
it 'does not retrieve the project' do
get :index, visibility_levels: [Gitlab::VisibilityLevel::INTERNAL]
expect(response.body).to_not match(project.name)
expect(response.body).not_to match(project.name)
end
end
end
......@@ -19,7 +19,7 @@ describe Projects::CompareController do
to: ref_to)
expect(response).to be_success
expect(assigns(:diffs).first).to_not be_nil
expect(assigns(:diffs).first).not_to be_nil
expect(assigns(:commits).length).to be >= 1
end
......@@ -32,7 +32,7 @@ describe Projects::CompareController do
w: 1)
expect(response).to be_success
expect(assigns(:diffs).first).to_not be_nil
expect(assigns(:diffs).first).not_to be_nil
expect(assigns(:commits).length).to be >= 1
# without whitespace option, there are more than 2 diff_splits
diff_splits = assigns(:diffs).first.diff.split("\n")
......
......@@ -43,7 +43,7 @@ describe Projects::GroupLinksController do
end
it 'does not share project with that group' do
expect(group.shared_projects).to_not include project
expect(group.shared_projects).not_to include project
end
end
end
......
......@@ -56,7 +56,7 @@ describe Projects::IssuesController do
move_issue
expect(response).to have_http_status :found
expect(another_project.issues).to_not be_empty
expect(another_project.issues).not_to be_empty
end
end
......
......@@ -38,7 +38,7 @@ describe Projects::ProjectMembersController do
include_context 'import applied'
it 'does not import team members' do
expect(project.team_members).to_not include member
expect(project.team_members).not_to include member
end
it 'responds with not found' do
......
......@@ -16,7 +16,7 @@ describe RegistrationsController do
it 'logs user in directly' do
post(:create, user_params)
expect(ActionMailer::Base.deliveries.last).to be_nil
expect(subject.current_user).to_not be_nil
expect(subject.current_user).not_to be_nil
end
end
......
......@@ -47,7 +47,7 @@ describe SessionsController do
authenticate_2fa(login: another_user.username,
otp_attempt: another_user.current_otp)
expect(subject.current_user).to_not eq another_user
expect(subject.current_user).not_to eq another_user
end
end
......@@ -56,7 +56,7 @@ describe SessionsController do
authenticate_2fa(login: another_user.username,
otp_attempt: 'invalid')
expect(subject.current_user).to_not eq another_user
expect(subject.current_user).not_to eq another_user
end
end
......@@ -73,7 +73,7 @@ describe SessionsController do
before { authenticate_2fa(otp_attempt: 'invalid') }
it 'does not authenticate' do
expect(subject.current_user).to_not eq user
expect(subject.current_user).not_to eq user
end
it 'warns about invalid OTP code' do
......
......@@ -6,7 +6,7 @@ describe 'factories' do
let(:entity) { build(factory.name) }
it 'does not raise error when created' do
expect { entity }.to_not raise_error
expect { entity }.not_to raise_error
end
it 'should be valid', if: factory.build_class < ActiveRecord::Base do
......
......@@ -79,7 +79,7 @@ describe "Admin Runners" do
end
it 'changes registration token' do
expect(page_token).to_not eq token
expect(page_token).not_to eq token
end
end
end
......
......@@ -152,7 +152,7 @@ describe "Admin::Users", feature: true do
it 'sees impersonation log out icon' do
icon = first('.fa.fa-user-secret')
expect(icon).to_not eql nil
expect(icon).not_to eql nil
end
it 'can log out of impersonated user back to original user' do
......
......@@ -47,7 +47,7 @@ describe "Builds" do
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
it { expect(page).to_not have_link 'Cancel running' }
it { expect(page).not_to have_link 'Cancel running' }
end
end
......@@ -63,7 +63,7 @@ describe "Builds" do
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
it { expect(page).to_not have_link 'Cancel running' }
it { expect(page).not_to have_link 'Cancel running' }
end
describe "GET /:project/builds/:id" do
......
......@@ -137,8 +137,8 @@ describe 'Commits' do
expect(page).to have_content commit.git_commit_message
expect(page).to have_content commit.git_author_name
expect(page).to have_link('Download artifacts')
expect(page).to_not have_link('Cancel running')
expect(page).to_not have_link('Retry failed')
expect(page).not_to have_link('Cancel running')
expect(page).not_to have_link('Retry failed')
end
end
......@@ -155,9 +155,9 @@ describe 'Commits' do
expect(page).to have_content commit.sha[0..7]
expect(page).to have_content commit.git_commit_message
expect(page).to have_content commit.git_author_name
expect(page).to_not have_link('Download artifacts')
expect(page).to_not have_link('Cancel running')
expect(page).to_not have_link('Retry failed')
expect(page).not_to have_link('Download artifacts')
expect(page).not_to have_link('Cancel running')
expect(page).not_to have_link('Retry failed')
end
end
end
......
......@@ -154,4 +154,144 @@ describe 'Filter issues', feature: true do
end
end
end
describe 'filter issues by text' do
before do
create(:issue, title: "Bug", project: project)
bug_label = create(:label, project: project, title: 'bug')
milestone = create(:milestone, title: "8", project: project)
issue = create(:issue,
title: "Bug 2",
project: project,
milestone: milestone,
author: user,
assignee: user)
issue.labels << bug_label
visit namespace_project_issues_path(project.namespace, project)
end
context 'only text', js: true do
it 'should filter issues by searched text' do
fill_in 'issue_search', with: 'Bug'
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
end
it 'should not show any issues' do
fill_in 'issue_search', with: 'testing'
page.within '.issues-list' do
expect(page).to_not have_selector('.issue')
end
end
end
context 'text and dropdown options', js: true do
it 'should filter by text and label' do
fill_in 'issue_search', with: 'Bug'
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
click_button 'Label'
page.within '.labels-filter' do
click_link 'bug'
end
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 1)
end
end
it 'should filter by text and milestone' do
fill_in 'issue_search', with: 'Bug'
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
click_button 'Milestone'
page.within '.milestone-filter' do
click_link '8'
end
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 1)
end
end
it 'should filter by text and assignee' do
fill_in 'issue_search', with: 'Bug'
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
click_button 'Assignee'
page.within '.dropdown-menu-assignee' do
click_link user.name
end
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 1)
end
end
it 'should filter by text and author' do
fill_in 'issue_search', with: 'Bug'
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
click_button 'Author'
page.within '.dropdown-menu-author' do
click_link user.name
end
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 1)
end
end
end
end
describe 'filter issues and sort', js: true do
before do
bug_label = create(:label, project: project, title: 'bug')
bug_one = create(:issue, title: "Frontend", project: project)
bug_two = create(:issue, title: "Bug 2", project: project)
bug_one.labels << bug_label
bug_two.labels << bug_label
visit namespace_project_issues_path(project.namespace, project)
end
it 'should be able to filter and sort issues' do
click_button 'Label'
page.within '.labels-filter' do
click_link 'bug'
end
page.within '.issues-list' do
expect(page).to have_selector('.issue', count: 2)
end
click_button 'Last created'
page.within '.dropdown-menu-sort' do
click_link 'Oldest created'
end
page.within '.issues-list' do
expect(first('.issue')).to have_content('Frontend')
end
end
end
end
......@@ -95,7 +95,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
find('.dropdown-menu-milestone a', text: "No Milestone").click
click_update_issues_button
expect(first('.issue')).to_not have_content milestone.title
expect(first('.issue')).not_to have_content milestone.title
end
end
......
......@@ -41,7 +41,7 @@ describe "Pipelines" do
context 'when canceling' do
before { click_link('Cancel') }
it { expect(page).to_not have_link('Cancel') }
it { expect(page).not_to have_link('Cancel') }
it { expect(page).to have_selector('.ci-canceled') }
end
end
......@@ -57,7 +57,7 @@ describe "Pipelines" do
context 'when retrying' do
before { click_link('Retry') }
it { expect(page).to_not have_link('Retry') }
it { expect(page).not_to have_link('Retry') }
it { expect(page).to have_selector('.ci-pending') }
end
end
......@@ -75,7 +75,7 @@ describe "Pipelines" do
context 'without artifacts' do
let!(:without_artifacts) { create(:ci_build, :success, commit: pipeline, name: 'rspec', stage: 'test') }
it { expect(page).to_not have_selector('.build-artifacts') }
it { expect(page).not_to have_selector('.build-artifacts') }
end
end
end
......@@ -104,23 +104,23 @@ describe "Pipelines" do
end
context 'retrying builds' do
it { expect(page).to_not have_content('retried') }
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
before { click_on 'Retry failed' }
it { expect(page).to_not have_content('Retry failed') }
it { expect(page).not_to have_content('Retry failed') }
it { expect(page).to have_content('retried') }
end
end
context 'canceling builds' do
it { expect(page).to_not have_selector('.ci-canceled') }
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
before { click_on 'Cancel running' }
it { expect(page).to_not have_content('Cancel running') }
it { expect(page).not_to have_content('Cancel running') }
it { expect(page).to have_selector('.ci-canceled') }
end
end
......
......@@ -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'
......
......@@ -29,8 +29,8 @@ describe "Runners" do
end
before do
expect(page).to_not have_content(@specific_runner3.display_name)
expect(page).to_not have_content(@specific_runner3.display_name)
expect(page).not_to have_content(@specific_runner3.display_name)
expect(page).not_to have_content(@specific_runner3.display_name)
end
it "places runners in right places" do
......
......@@ -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
......
require 'rails_helper'
feature 'Todo target states', feature: true do
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:project) { create(:project) }
before do
login_as user
end
scenario 'on a closed issue todo has closed label' do
issue_closed = create(:issue, state: 'closed')
create_todo issue_closed
visit dashboard_todos_path
page.within '.todos-list' do
expect(page).to have_content('Closed')
end
end
scenario 'on an open issue todo does not have an open label' do
issue_open = create(:issue)
create_todo issue_open
visit dashboard_todos_path
page.within '.todos-list' do
expect(page).not_to have_content('Open')
end
end
scenario 'on a merged merge request todo has merged label' do
mr_merged = create(:merge_request, :simple, author: user, state: 'merged')
create_todo mr_merged
visit dashboard_todos_path
page.within '.todos-list' do
expect(page).to have_content('Merged')
end
end
scenario 'on a closed merge request todo has closed label' do
mr_closed = create(:merge_request, :simple, author: user, state: 'closed')
create_todo mr_closed
visit dashboard_todos_path
page.within '.todos-list' do
expect(page).to have_content('Closed')
end
end
scenario 'on an open merge request todo does not have an open label' do
mr_open = create(:merge_request, :simple, author: user)
create_todo mr_open
visit dashboard_todos_path
page.within '.todos-list' do
expect(page).not_to have_content('Open')
end
end
def create_todo(target)
create(:todo, :mentioned, user: user, project: project, target: target, author: author)
end
end
......@@ -34,7 +34,7 @@ describe 'Project variables', js: true do
find('.btn-variable-delete').click
end
expect(page).to_not have_selector('variables-table')
expect(page).not_to have_selector('variables-table')
end
it 'should edit variable' do
......
......@@ -36,7 +36,7 @@ describe AuthHelper do
)
expect(helper.enabled_button_based_providers).to include('twitter')
expect(helper.enabled_button_based_providers).to_not include('github')
expect(helper.enabled_button_based_providers).not_to include('github')
end
end
end
......
......@@ -17,7 +17,7 @@ describe MergeRequestsHelper do
it 'does not include api credentials in a link' do
allow(ci_service).
to receive(:build_page).and_return("http://secretuser:secretpass@jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c")
expect(helper.ci_build_details_path(merge_request)).to_not match("secret")
expect(helper.ci_build_details_path(merge_request)).not_to match("secret")
end
end
......
......@@ -5,7 +5,7 @@ describe AwardEmoji do
subject { AwardEmoji.urls }
it { is_expected.to be_an_instance_of(Array) }
it { is_expected.to_not be_empty }
it { is_expected.not_to be_empty }
context 'every Hash in the Array' do
it 'has the correct keys and values' do
......
......@@ -175,5 +175,14 @@ describe Ci::Ansi2html, lib: true do
it_behaves_like 'stateable converter'
end
context 'with new line' do
let(:pre_text) { "Hello\r" }
let(:pre_html) { "Hello\r" }
let(:text) { "\nWorld" }
let(:html) { "<br>World" }
it_behaves_like 'stateable converter'
end
end
end
......@@ -619,19 +619,19 @@ module Ci
context 'no dependencies' do
let(:dependencies) { }
it { expect { subject }.to_not raise_error }
it { expect { subject }.not_to raise_error }
end
context 'dependencies to builds' do
let(:dependencies) { ['build1', 'build2'] }
it { expect { subject }.to_not raise_error }
it { expect { subject }.not_to raise_error }
end
context 'dependencies to builds defined as symbols' do
let(:dependencies) { [:build1, :build2] }
it { expect { subject }.to_not raise_error }
it { expect { subject }.not_to raise_error }
end
context 'undefined dependency' do
......
......@@ -10,7 +10,7 @@ describe ContainerRegistry::Registry do
it { is_expected.to respond_to(:uri) }
it { is_expected.to respond_to(:path) }
it { expect(subject.repository('test')).to_not be_nil }
it { expect(subject.repository('test')).not_to be_nil }
context '#path' do
subject { registry.path }
......
......@@ -6,7 +6,7 @@ describe ContainerRegistry::Repository do
it { expect(repository).to respond_to(:registry) }
it { expect(repository).to delegate_method(:client).to(:registry) }
it { expect(repository.tag('test')).to_not be_nil }
it { expect(repository.tag('test')).not_to be_nil }
context '#path' do
subject { repository.path }
......@@ -27,7 +27,7 @@ describe ContainerRegistry::Repository do
context '#manifest' do
subject { repository.manifest }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
context '#valid?' do
......@@ -39,7 +39,7 @@ describe ContainerRegistry::Repository do
context '#tags' do
subject { repository.tags }
it { is_expected.to_not be_empty }
it { is_expected.not_to be_empty }
end
end
......
......@@ -50,13 +50,13 @@ describe ContainerRegistry::Tag do
context '#config' do
subject { tag.config }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
context '#created_at' do
subject { tag.created_at }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
end
end
......
......@@ -59,7 +59,7 @@ describe Gitlab::BitbucketImport::Client, lib: true do
bitbucket_access_token_secret: "test" } })
project.import_url = "ssh://git@bitbucket.org/test/test.git"
expect { described_class.from_project(project) }.to_not raise_error
expect { described_class.from_project(project) }.not_to raise_error
end
end
end
......@@ -122,7 +122,7 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
describe 'empty path', path: '' do
subject { |example| path(example) }
it { is_expected.to_not have_parent }
it { is_expected.not_to have_parent }
describe '#children' do
subject { |example| path(example).children }
......
......@@ -33,8 +33,8 @@ describe Gitlab::Gfm::ReferenceRewriter do
end
it { is_expected.to include issue_first.to_reference(new_project) }
it { is_expected.to_not include issue_second.to_reference(new_project) }
it { is_expected.to_not include merge_request.to_reference(new_project) }
it { is_expected.not_to include issue_second.to_reference(new_project) }
it { is_expected.not_to include merge_request.to_reference(new_project) }
end
context 'description ambigous elements' do
......
......@@ -32,13 +32,13 @@ describe Gitlab::Gfm::UploadsRewriter do
let(:new_paths) { new_files.map(&:path) }
it 'rewrites content' do
expect(new_text).to_not eq text
expect(new_text).not_to eq text
expect(new_text.length).to eq text.length
end
it 'copies files' do
expect(new_files).to all(exist)
expect(old_paths).to_not match_array new_paths
expect(old_paths).not_to match_array new_paths
expect(old_paths).to all(include(old_project.path_with_namespace))
expect(new_paths).to all(include(new_project.path_with_namespace))
end
......@@ -48,8 +48,8 @@ describe Gitlab::Gfm::UploadsRewriter do
end
it 'generates a new secret for each file' do
expect(new_paths).to_not include image_uploader.secret
expect(new_paths).to_not include zip_uploader.secret
expect(new_paths).not_to include image_uploader.secret
expect(new_paths).not_to include zip_uploader.secret
end
end
......
......@@ -368,7 +368,7 @@ describe Gitlab::Lfs::Router, lib: true do
expect(response['objects']).to be_kind_of(Array)
expect(response['objects'].first['oid']).to eq(sample_oid)
expect(response['objects'].first['size']).to eq(sample_size)
expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
......@@ -430,7 +430,7 @@ describe Gitlab::Lfs::Router, lib: true do
expect(response_body['objects'].last['oid']).to eq(sample_oid)
expect(response_body['objects'].last['size']).to eq(sample_size)
expect(response_body['objects'].last).to_not have_key('actions')
expect(response_body['objects'].last).not_to have_key('actions')
end
end
end
......
......@@ -67,7 +67,7 @@ describe Gitlab::Metrics::Instrumentation do
allow(Gitlab::Metrics).to receive(:method_call_threshold).
and_return(100)
expect(transaction).to_not receive(:add_metric)
expect(transaction).not_to receive(:add_metric)
@dummy.foo
end
......@@ -147,7 +147,7 @@ describe Gitlab::Metrics::Instrumentation do
allow(Gitlab::Metrics).to receive(:method_call_threshold).
and_return(100)
expect(transaction).to_not receive(:add_metric)
expect(transaction).not_to receive(:add_metric)
@dummy.new.bar
end
......@@ -220,7 +220,7 @@ describe Gitlab::Metrics::Instrumentation do
described_class.instrument_methods(@dummy)
expect(@dummy).to_not respond_to(:_original_kittens)
expect(@dummy).not_to respond_to(:_original_kittens)
end
it 'can take a block to determine if a method should be instrumented' do
......@@ -228,7 +228,7 @@ describe Gitlab::Metrics::Instrumentation do
false
end
expect(@dummy).to_not respond_to(:_original_foo)
expect(@dummy).not_to respond_to(:_original_foo)
end
end
......
......@@ -130,7 +130,7 @@ describe Gitlab::Metrics::Sampler do
100.times do
interval = sampler.sleep_interval
expect(interval).to_not eq(last)
expect(interval).not_to eq(last)
last = interval
end
......
......@@ -13,7 +13,7 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do
describe 'without a current transaction' do
it 'simply returns' do
expect_any_instance_of(Gitlab::Metrics::Transaction).
to_not receive(:increment)
not_to receive(:increment)
subscriber.sql(event)
end
......
......@@ -11,13 +11,13 @@ describe Gitlab::Sherlock::Collection, lib: true do
it 'adds a new transaction' do
collection.add(transaction)
expect(collection).to_not be_empty
expect(collection).not_to be_empty
end
it 'is aliased as <<' do
collection << transaction
expect(collection).to_not be_empty
expect(collection).not_to be_empty
end
end
......@@ -47,7 +47,7 @@ describe Gitlab::Sherlock::Collection, lib: true do
it 'returns false for a collection with a transaction' do
collection.add(transaction)
expect(collection).to_not be_empty
expect(collection).not_to be_empty
end
end
......
......@@ -85,7 +85,7 @@ FROM users;
frames = query.application_backtrace
expect(frames).to be_an_instance_of(Array)
expect(frames).to_not be_empty
expect(frames).not_to be_empty
frames.each do |frame|
expect(frame.path).to start_with(Rails.root.to_s)
......
......@@ -203,7 +203,7 @@ describe Gitlab::Sherlock::Transaction, lib: true do
end
it 'only tracks queries triggered from the transaction thread' do
expect(transaction).to_not receive(:track_query)
expect(transaction).not_to receive(:track_query)
Thread.new { subscription.publish('test', time, time, nil, query_data) }.
join
......@@ -226,7 +226,7 @@ describe Gitlab::Sherlock::Transaction, lib: true do
end
it 'only tracks views rendered from the transaction thread' do
expect(transaction).to_not receive(:track_view)
expect(transaction).not_to receive(:track_view)
Thread.new { subscription.publish('test', time, time, nil, view_data) }.
join
......
......@@ -23,7 +23,7 @@ describe JSONWebToken::RSAToken do
subject { JWT.decode(rsa_encoded, rsa_key) }
it { expect{subject}.to_not raise_error }
it { expect{subject}.not_to raise_error }
it { expect(subject.first).to include('key' => 'value') }
it do
expect(subject.second).to eq(
......
......@@ -146,8 +146,8 @@ shared_examples 'it should have Gmail Actions links' do
end
shared_examples 'it should not have Gmail Actions links' do
it { is_expected.to_not have_body_text '<script type="application/ld+json">' }
it { is_expected.to_not have_body_text /ViewAction/ }
it { is_expected.not_to have_body_text '<script type="application/ld+json">' }
it { is_expected.not_to have_body_text /ViewAction/ }
end
shared_examples 'it should show Gmail Actions View Issue link' do
......
......@@ -90,7 +90,7 @@ describe Ci::Build, models: true do
build.update_attributes(trace: token)
end
it { is_expected.to_not include(token) }
it { is_expected.not_to include(token) }
end
end
......@@ -317,7 +317,7 @@ describe Ci::Build, models: true do
context 'when build does not have tags' do
subject { create(:ci_build, tag_list: []) }
it { is_expected.to_not have_tags }
it { is_expected.not_to have_tags }
end
end
......@@ -534,7 +534,7 @@ describe Ci::Build, models: true do
end
it 'should set erase date' do
expect(build.erased_at).to_not be_falsy
expect(build.erased_at).not_to be_falsy
end
end
......@@ -606,7 +606,7 @@ describe Ci::Build, models: true do
describe '#erase' do
it 'should not raise error' do
expect { build.erase }.to_not raise_error
expect { build.erase }.not_to raise_error
end
end
end
......
......@@ -247,7 +247,7 @@ describe Ci::Commit, models: true do
expect(commit.builds.pluck(:status)).to contain_exactly('pending')
commit.builds.running_or_pending.each(&:success)
expect(commit.builds.running_or_pending).to_not be_empty
expect(commit.builds.running_or_pending).not_to be_empty
expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
......
......@@ -140,7 +140,7 @@ describe Ci::Runner, models: true do
context 'when runner does not have tags' do
subject { create(:ci_runner, tag_list: []) }
it { is_expected.to_not have_tags }
it { is_expected.not_to have_tags }
end
end
......
......@@ -114,6 +114,35 @@ describe Issue, "Issuable" do
end
end
describe "#sort" do
let(:project) { build_stubbed(:empty_project) }
context "by milestone due date" do
#Correct order is:
#Issues/MRs with milestones ordered by date
#Issues/MRs with milestones without dates
#Issues/MRs without milestones
let!(:issue) { create(:issue, project: project) }
let!(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
let!(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
let!(:issue1) { create(:issue, project: project, milestone: early_milestone) }
let!(:issue2) { create(:issue, project: project, milestone: late_milestone) }
let!(:issue3) { create(:issue, project: project) }
it "sorts desc" do
issues = project.issues.sort('milestone_due_desc')
expect(issues).to match_array([issue2, issue1, issue, issue3])
end
it "sorts asc" do
issues = project.issues.sort('milestone_due_asc')
expect(issues).to match_array([issue1, issue2, issue, issue3])
end
end
end
describe '#subscribed?' do
context 'user is not a participant in the issue' do
before { allow(issue).to receive(:participants).with(user).and_return([]) }
......@@ -165,7 +194,7 @@ describe Issue, "Issuable" do
expect(data[:object_kind]).to eq("issue")
expect(data[:user]).to eq(user.hook_attrs)
expect(data[:object_attributes]).to eq(issue.hook_attrs)
expect(data).to_not have_key(:assignee)
expect(data).not_to have_key(:assignee)
end
context "issue is assigned" do
......
......@@ -28,14 +28,14 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
context 'token is not generated yet' do
describe 'token field accessor' do
subject { described_class.new.send(token_field) }
it { is_expected.to_not be_blank }
it { is_expected.not_to be_blank }
end
describe 'ensured token' do
subject { described_class.new.send("ensure_#{token_field}") }
it { is_expected.to be_a String }
it { is_expected.to_not be_blank }
it { is_expected.not_to be_blank }
end
describe 'ensured! token' do
......
......@@ -27,13 +27,13 @@ describe GenericCommitStatus, models: true do
describe :context do
subject { generic_commit_status.context }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
describe :stage do
subject { generic_commit_status.stage }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
end
end
......@@ -192,7 +192,7 @@ describe Issue, models: true do
source_project: subject.project,
source_branch: "#{subject.iid}-branch" })
merge_request.create_cross_references!(user)
expect(subject.referenced_merge_requests).to_not be_empty
expect(subject.referenced_merge_requests).not_to be_empty
expect(subject.related_branches(user)).to eq([subject.to_branch_name])
end
......
......@@ -303,7 +303,7 @@ describe HipchatService, models: true do
it "should notify only broken" do
hipchat.notify_only_broken_builds = true
hipchat.execute(data)
expect(WebMock).to_not have_requested(:post, api_url).once
expect(WebMock).not_to have_requested(:post, api_url).once
end
end
end
......
......@@ -15,7 +15,7 @@ describe SlackService::BuildMessage do
commit: {
status: status,
author_name: 'hacker',
duration: 10,
duration: duration,
},
}
end
......@@ -23,9 +23,10 @@ describe SlackService::BuildMessage do
context 'succeeded' do
let(:status) { 'success' }
let(:color) { 'good' }
let(:duration) { 10 }
it 'returns a message with information about succeeded build' do
message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 second(s)'
message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 seconds'
expect(subject.pretext).to be_empty
expect(subject.fallback).to eq(message)
expect(subject.attachments).to eq([text: message, color: color])
......@@ -35,9 +36,23 @@ describe SlackService::BuildMessage do
context 'failed' do
let(:status) { 'failed' }
let(:color) { 'danger' }
let(:duration) { 10 }
it 'returns a message with information about failed build' do
message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 second(s)'
message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 seconds'
expect(subject.pretext).to be_empty
expect(subject.fallback).to eq(message)
expect(subject.attachments).to eq([text: message, color: color])
end
end
describe '#seconds_name' do
let(:status) { 'failed' }
let(:color) { 'danger' }
let(:duration) { 1 }
it 'returns seconds as singular when there is only one' do
message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 1 second'
expect(subject.pretext).to be_empty
expect(subject.fallback).to eq(message)
expect(subject.attachments).to eq([text: message, color: color])
......
......@@ -60,7 +60,7 @@ describe Project, models: true do
project2 = build(:project)
allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
expect(project2).not_to be_valid
expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
expect(project2.errors[:limit_reached].first).to match(/Personal project creation is not allowed/)
end
end
......@@ -791,7 +791,7 @@ describe Project, models: true do
subject { project.container_registry_repository }
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
describe '#container_registry_repository_url' do
......@@ -809,7 +809,7 @@ describe Project, models: true do
}
end
it { is_expected.to_not be_nil }
it { is_expected.not_to be_nil }
end
context 'for disabled registry' do
......
......@@ -443,7 +443,7 @@ describe Repository, models: true do
end
it 'does nothing' do
expect(repository.raw_repository).to_not receive(:autocrlf=).
expect(repository.raw_repository).not_to receive(:autocrlf=).
with(:input)
repository.update_autocrlf_option
......@@ -511,7 +511,7 @@ describe Repository, models: true do
it 'does not expire the emptiness caches for a non-empty repository' do
expect(repository).to receive(:empty?).and_return(false)
expect(repository).to_not receive(:expire_emptiness_caches)
expect(repository).not_to receive(:expire_emptiness_caches)
repository.expire_cache
end
......@@ -674,7 +674,7 @@ describe Repository, models: true do
end
it 'does not flush caches that depend on repository data' do
expect(repository).to_not receive(:expire_cache)
expect(repository).not_to receive(:expire_cache)
repository.before_delete
end
......@@ -951,7 +951,7 @@ describe Repository, models: true do
expect(repository.avatar).to eq('logo.png')
expect(repository).to_not receive(:blob_at_branch)
expect(repository).not_to receive(:blob_at_branch)
expect(repository.avatar).to eq('logo.png')
end
end
......@@ -1045,7 +1045,7 @@ describe Repository, models: true do
and_return(true)
repository.cache_keys.each do |key|
expect(repository).to_not receive(key)
expect(repository).not_to receive(key)
end
repository.build_cache
......
......@@ -133,7 +133,7 @@ describe API::API, api: true do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
expect do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
end.to_not change { ProjectMember.count }
end.not_to change { ProjectMember.count }
expect(response.status).to eq(200)
end
......
......@@ -49,7 +49,7 @@ describe API::API, api: true do
it "should not create new hook without url" do
expect do
post api("/hooks", admin)
end.to_not change { SystemHook.count }
end.not_to change { SystemHook.count }
end
end
......
......@@ -253,13 +253,13 @@ describe Ci::API::API do
it "using token as parameter" do
post authorize_url, { token: build.token }, headers
expect(response.status).to eq(200)
expect(json_response["TempPath"]).to_not be_nil
expect(json_response["TempPath"]).not_to be_nil
end
it "using token as header" do
post authorize_url, {}, headers_with_token
expect(response.status).to eq(200)
expect(json_response["TempPath"]).to_not be_nil
expect(json_response["TempPath"]).not_to be_nil
end
end
......
......@@ -52,12 +52,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
shared_examples 'an unauthorized' do
it { is_expected.to include(http_status: 401) }
it { is_expected.to_not include(:token) }
it { is_expected.not_to include(:token) }
end
shared_examples 'a forbidden' do
it { is_expected.to include(http_status: 403) }
it { is_expected.to_not include(:token) }
it { is_expected.not_to include(:token) }
end
describe '#full_access_token' do
......
......@@ -78,7 +78,7 @@ describe CreateCommitBuildsService, services: true do
expect(commit).to be_persisted
expect(commit.builds.any?).to be false
expect(commit.status).to eq('failed')
expect(commit.yaml_errors).to_not be_nil
expect(commit.yaml_errors).not_to be_nil
end
describe :ci_skip? do
......
......@@ -14,7 +14,7 @@ describe Groups::CreateService, services: true do
context "cannot create group with restricted visibility level" do
before { allow(current_application_settings).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
it { is_expected.to_not be_persisted }
it { is_expected.not_to be_persisted }
end
end
end
......@@ -55,7 +55,7 @@ describe Issues::CreateService, services: true do
end
it 'does not assign label' do
expect(issue.labels).to_not include label
expect(issue.labels).not_to include label
end
end
......@@ -69,7 +69,7 @@ describe Issues::CreateService, services: true do
end
it 'does not assign milestone' do
expect(issue.milestone).to_not eq milestone
expect(issue.milestone).not_to eq milestone
end
end
end
......
......@@ -194,10 +194,10 @@ describe Issues::MoveService, services: true do
include_context 'issue move executed'
it 'rewrites uploads in description' do
expect(new_issue.description).to_not eq description
expect(new_issue.description).not_to eq description
expect(new_issue.description)
.to match(/Text and #{FileUploader::MARKDOWN_PATTERN}/)
expect(new_issue.description).to_not include uploader.secret
expect(new_issue.description).not_to include uploader.secret
end
end
end
......@@ -231,7 +231,7 @@ describe Issues::MoveService, services: true do
context 'user is reporter in both projects' do
include_context 'user can move issue'
it { expect { move }.to_not raise_error }
it { expect { move }.not_to raise_error }
end
context 'user is reporter only in new project' do
......
......@@ -75,7 +75,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
allow(ci_commit).to receive(:success?).and_return(true)
allow(old_build).to receive(:sha).and_return('1234abcdef')
expect(MergeWorker).to_not receive(:perform_async)
expect(MergeWorker).not_to receive(:perform_async)
service.trigger(old_build)
end
end
......@@ -88,7 +88,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
it "doesn't merge a requests for status on other branch" do
allow(project.repository).to receive(:branch_names_contains).with(commit_status.sha).and_return([])
expect(MergeWorker).to_not receive(:perform_async)
expect(MergeWorker).not_to receive(:perform_async)
service.trigger(commit_status)
end
......@@ -122,7 +122,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
end
it "doesn't merge if some stages failed" do
expect(MergeWorker).to_not receive(:perform_async)
expect(MergeWorker).not_to receive(:perform_async)
build.success
test.drop
end
......
......@@ -2,6 +2,8 @@ require 'spec_helper'
require 'rake'
describe 'gitlab:app namespace rake task' do
let(:enable_registry) { true }
before :all do
Rake.application.rake_require 'tasks/gitlab/task_helpers'
Rake.application.rake_require 'tasks/gitlab/backup'
......@@ -15,6 +17,10 @@ describe 'gitlab:app namespace rake task' do
FileUtils.mkdir_p('public/uploads')
end
before do
stub_container_registry_config(enabled: enable_registry)
end
def run_rake_task(task_name)
Rake::Task[task_name].reenable
Rake.application.invoke_task task_name
......@@ -143,6 +149,18 @@ describe 'gitlab:app namespace rake task' do
expect(temp_dirs).to be_empty
end
context 'registry disabled' do
let(:enable_registry) { false }
it 'should not create registry.tar.gz' do
tar_contents, exit_status = Gitlab::Popen.popen(
%W{tar -tvf #{@backup_tar}}
)
expect(exit_status).to eq(0)
expect(tar_contents).not_to match('registry.tar.gz')
end
end
end # backup_create task
describe "Skipping items" do
......
require 'spec_helper'
require 'rake'
describe 'gitlab:db namespace rake task' do
before :all do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db'
# empty task as env is already loaded
Rake::Task.define_task :environment
end
before do
# Stub out db tasks
allow(Rake::Task['db:migrate']).to receive(:invoke).and_return(true)
allow(Rake::Task['db:schema:load']).to receive(:invoke).and_return(true)
allow(Rake::Task['db:seed_fu']).to receive(:invoke).and_return(true)
end
describe 'configure' do
it 'should invoke db:migrate when schema has already been loaded' do
allow(ActiveRecord::Base.connection).to receive(:tables).and_return(['default'])
expect(Rake::Task['db:migrate']).to receive(:invoke)
expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
end
it 'should invoke db:shema:load and db:seed_fu when schema is not loaded' do
allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
expect(Rake::Task['db:schema:load']).to receive(:invoke)
expect(Rake::Task['db:seed_fu']).to receive(:invoke)
expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
end
it 'should not invoke any other rake tasks during an error' do
allow(ActiveRecord::Base).to receive(:connection).and_raise(RuntimeError, 'error')
expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
# unstub connection so that the database cleaner still works
allow(ActiveRecord::Base).to receive(:connection).and_call_original
end
it 'should not invoke seed after a failed schema_load' do
allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
allow(Rake::Task['db:schema:load']).to receive(:invoke).and_raise(RuntimeError, 'error')
expect(Rake::Task['db:schema:load']).to receive(:invoke)
expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
end
end
def run_rake_task(task_name)
Rake::Task[task_name].reenable
Rake.application.invoke_task task_name
end
end
......@@ -61,7 +61,7 @@ describe PostReceive do
context "does not create a Ci::Commit" do
before { stub_ci_commit_yaml_file(nil) }
it { expect{ subject }.to_not change{ Ci::Commit.count } }
it { expect{ subject }.not_to change{ Ci::Commit.count } }
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment