diff options
262 files changed, 2155 insertions, 1776 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 05b8ecc3b00..11e4502849a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -932,7 +932,7 @@ Lint/UselessAccessModifier: Lint/UselessAssignment: Description: 'Checks for useless assignment to a local variable.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars' - Enabled: false + Enabled: true Lint/UselessComparison: Description: 'Checks for comparison of something with itself.' diff --git a/CHANGELOG b/CHANGELOG index 8308b693219..ec23d0f1172 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,11 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.1.0 (unreleased) - - Fix bug where projects would appear to be stuck in the forked import state (Stan Hu) - - Fix Error 500 in creating merge requests with > 1000 diffs (Stan Hu) + - Fix bug where transferring a project would result in stale commit links (Stan Hu) + - Include full path of source and target branch names in New Merge Request page (Stan Hu) + - Fix Message-ID header to be RFC 2111-compliant to prevent e-mails being dropped (Stan Hu) + - Add user preference to view activities as default dashboard (Stan Hu) + - Add option to admin area to sign in as a specific user (Pavel Forkert) - Show CI status on all pages where commits list is rendered - Automatically enable CI when push .gitlab-ci.yml file to repository - Move CI charts to project graphs area @@ -13,8 +16,24 @@ v 8.1.0 (unreleased) - Remove "Continuous Integration" page from dashboard - Add notes and SSL verification entries to hook APIs (Ben Boeckel) - Fix grammar in admin area "labels" .nothing-here-block when no labels exist. - -v 8.0.3 (unreleased) + - Move CI runners page to project settings area + - Move CI variables page to project settings area + - Move CI triggers page to project settings area + - Move CI project settings page to CE project settings area + - Fix bug when removed file was not appearing in merge request diff + - Note the original location of a moved project when notifying users of the move + - Improve error message when merging fails + - Add support of multibyte characters in LDAP UID (Roman Petrov) + - Show additions/deletions stats on merge request diff + - Remove footer text in emails (Zeger-Jan van de Weg) + - Ensure code blocks are properly highlighted after a note is updated + - Fix wrong access level badge on MR comments + - Hide password in the service settings form + +v 8.0.3 + - Fix URL shown in Slack notifications + - Fix bug where projects would appear to be stuck in the forked import state (Stan Hu) + - Fix Error 500 in creating merge requests with > 1000 diffs (Stan Hu) v 8.0.2 - Fix default avatar not rendering in network graph (Stan Hu) @@ -28,6 +47,7 @@ v 8.0.2 - Use standard Markdown font in Markdown preview instead of fixed-width font (Stan Hu) - Fix Reply by email for non-UTF-8 messages. - Add option to use StartTLS with Reply by email IMAP server. + - Allow AWS S3 Server-Side Encryption with Amazon S3-Managed Keys for backups (Paul Beattie) v 8.0.1 - Remove git refs used internally by GitLab from network graph (Stan Hu) @@ -94,6 +114,8 @@ v 8.0.0 - Webhook for issue now contains repository field (Jungkook Park) - Add ability to add custom text to the help page (Jeroen van Baarsen) - Add pg_schema to backup config + - Fix references to target project issues in Merge Requests markdown preview and textareas (Francesco Levorato) + - Redirect from incorrectly cased group or project path to correct one (Francesco Levorato) - Removed API calls from CE to CI v 7.14.3 @@ -47,7 +47,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.15' +gem "gitlab_git", '~> 7.2.17' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes @@ -270,6 +270,8 @@ group :development, :test do gem 'rubocop', '~> 0.28.0', require: false gem 'coveralls', '~> 0.8.2', require: false gem 'simplecov', '~> 0.10.0', require: false + + gem 'benchmark-ips', require: false end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 4386c6b9abb..1dd56cd9c8c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,6 +66,7 @@ GEM ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) bcrypt (3.1.10) + benchmark-ips (2.3.0) better_errors (1.0.1) coderay (>= 1.0.0) erubis (>= 2.6.6) @@ -278,7 +279,7 @@ GEM mime-types (~> 1.19) gitlab_emoji (0.1.1) gemojione (~> 2.0) - gitlab_git (7.2.15) + gitlab_git (7.2.17) activesupport (~> 4.0) charlock_holmes (~> 0.6) gitlab-linguist (~> 3.0) @@ -795,6 +796,7 @@ DEPENDENCIES asciidoctor (~> 1.5.2) attr_encrypted (~> 1.3.4) awesome_print (~> 1.2.0) + benchmark-ips better_errors (~> 1.0.1) binding_of_caller (~> 0.7.2) bootstrap-sass (~> 3.0) @@ -834,7 +836,7 @@ DEPENDENCIES gitlab-flowdock-git-hook (~> 1.0.1) gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.1) - gitlab_git (~> 7.2.15) + gitlab_git (~> 7.2.17) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.0.2) @@ -937,3 +939,6 @@ DEPENDENCIES webmock (~> 1.21.0) whenever (~> 0.8.4) wikicloth (= 0.8.1) + +BUNDLED WITH + 1.10.6 diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf Binary files differindex 50d81bdad58..5d65c93242f 100755 --- a/app/assets/fonts/SourceSansPro-Bold.ttf +++ b/app/assets/fonts/SourceSansPro-Bold.ttf diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf Binary files differindex 5f64679f6b9..83a0a336661 100755 --- a/app/assets/fonts/SourceSansPro-Light.ttf +++ b/app/assets/fonts/SourceSansPro-Light.ttf diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf Binary files differindex 91e9ea5757f..44486cdc670 100755 --- a/app/assets/fonts/SourceSansPro-Regular.ttf +++ b/app/assets/fonts/SourceSansPro-Regular.ttf diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf Binary files differindex 5020594826b..86b00c067e0 100755 --- a/app/assets/fonts/SourceSansPro-Semibold.ttf +++ b/app/assets/fonts/SourceSansPro-Semibold.ttf diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 995a2f24093..3176e5a8965 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -15,11 +15,12 @@ class @MergeRequestWidget type: 'GET' url: $('.merge-request').data('url') success: (data) => - switch data.state - when 'merged' - location.reload() - else - setTimeout(merge_request_widget.mergeInProgress, 2000) + if data.state == "merged" + location.reload() + else if data.merge_error + $('.mr-widget-body').html("<h4>" + data.merge_error + "</h4>") + else + setTimeout(merge_request_widget.mergeInProgress, 2000) dataType: 'json' getMergeStatus: -> diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index ce638c2641b..4b9f0d68912 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -277,13 +277,15 @@ class @Notes Updates the current note field. ### - updateNote: (xhr, note, status) => - note_li = $(".note-row-" + note.id) - note_li.replaceWith(note.html) - note_li.find('.note-edit-form').hide() - note_li.find('.note-body > .note-text').show() - note_li.find('js-task-list-container').taskList('enable') - @enableTaskList() + updateNote: (_xhr, note, _status) => + # Convert returned HTML to a jQuery object so we can modify it further + $html = $(note.html) + $html.syntaxHighlight() + $html.find('.js-task-list-container').taskList('enable') + + # Find the note's `li` element by ID and replace it with the updated HTML + $note_li = $("#note_#{note.id}") + $note_li.replaceWith($html) ### Called in response to clicking the edit note link diff --git a/app/assets/stylesheets/base/layout.scss b/app/assets/stylesheets/base/layout.scss index b91c15d8910..f0569a5e673 100644 --- a/app/assets/stylesheets/base/layout.scss +++ b/app/assets/stylesheets/base/layout.scss @@ -1,18 +1,34 @@ html { overflow-y: scroll; + height: 100%; + margin: 0; &.touch .tooltip { display: none !important; } body { padding-top: $header-height; + height: 100%; + margin: 0; } } .container { padding-top: 0; + height: 100%; + width: 100%; z-index: 5; } +.content { + height: 100%; + width: 100%; +} + +.content section { + height: 100%; + display: table-row; +} + .container .content { margin: 0 0; } @@ -24,3 +40,9 @@ html { .container-limited { max-width: $fixed-layout-width; } + +.max-height { + height: 100%; + display: table; + width: 100%; +}
\ No newline at end of file diff --git a/app/assets/stylesheets/base/mixins.scss b/app/assets/stylesheets/base/mixins.scss index 421588f64d8..c74a6d39824 100644 --- a/app/assets/stylesheets/base/mixins.scss +++ b/app/assets/stylesheets/base/mixins.scss @@ -117,12 +117,12 @@ margin: 24px 0 12px 0; font-size: 1.1em; } - + h5 { margin: 24px 0 12px 0; font-size: 1em; } - + h6 { margin: 24px 0 12px 0; font-size: 0.90em; @@ -133,18 +133,18 @@ margin: 12px 0 12px; border-left: 3px solid #e7e9ed; } - + blockquote p { color: #7f8fa4 !important; font-size: 15px; line-height: 1.5; } - + p { color:#5c5d5e; margin:6px 0 0 0; } - + table { @extend .table; @extend .table-bordered; @@ -152,15 +152,16 @@ color: #5c5d5e; th { background: #f8fafc; - } + } } - + pre { margin: 12px 0 12px 0 !important; background-color: #f8fafc !important; font-size: 13px !important; color: #5b6169 !important; line-height: 1.6em !important; + @include border-radius(2px); } p > code { @@ -171,7 +172,7 @@ ul { color: #5c5d5e; } - + li { line-height: 1.6em; } @@ -293,3 +294,8 @@ } } } + +.fa-align { + top: 20px; + position: relative; +} diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss index 2fc7bf1720a..befd63832d5 100644 --- a/app/assets/stylesheets/base/variables.scss +++ b/app/assets/stylesheets/base/variables.scss @@ -1,5 +1,8 @@ $hover: #FFFAF1; -$gl-text-color: #54565b; +$gl-text-color: #54565B; +$gl-text-green: #4A2; +$gl-text-red: #D12F19; +$gl-text-orange: #D90; $gl-header-color: #4c4e54; $gl-link-color: #333c48; $md-text-color: #444; @@ -12,8 +15,8 @@ $sidebar_width: 230px; $avatar_radius: 50%; $code_font_size: 13px; $code_line_height: 1.5; -$border-color: #E7E9ED; -$background-color: #F8FAFC; +$border-color: #dce0e6; +$background-color: #F7F8FA; $header-height: 58px; $fixed-layout-width: 1200px; $gl-gray: #7f8fa4; diff --git a/app/assets/stylesheets/generic/avatar.scss b/app/assets/stylesheets/generic/avatar.scss index 221cb6a04a5..36e582d4854 100644 --- a/app/assets/stylesheets/generic/avatar.scss +++ b/app/assets/stylesheets/generic/avatar.scss @@ -28,6 +28,7 @@ &.s48 { width: 48px; height: 48px; margin-right: 10px; } &.s60 { width: 60px; height: 60px; margin-right: 12px; } &.s90 { width: 90px; height: 90px; margin-right: 15px; } + &.s110 { width: 110px; height: 110px; margin-right: 15px; } &.s140 { width: 140px; height: 140px; margin-right: 20px; } &.s160 { width: 160px; height: 160px; margin-right: 20px; } } @@ -42,6 +43,7 @@ &.s32 { font-size: 22px; line-height: 32px; } &.s60 { font-size: 32px; line-height: 60px; } &.s90 { font-size: 36px; line-height: 90px; } + &.s110 { font-size: 40px; line-height: 112px; font-weight: 300; } &.s140 { font-size: 72px; line-height: 140px; } &.s160 { font-size: 96px; line-height: 160px; } } diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss index 46ef595ddf0..a5fe5890447 100644 --- a/app/assets/stylesheets/generic/buttons.scss +++ b/app/assets/stylesheets/generic/buttons.scss @@ -1,3 +1,6 @@ +body { + text-rendering: geometricPrecision; +} .btn { @extend .btn-default; @@ -88,3 +91,142 @@ } } } + +@mixin btn-info { + @include border-radius(2px); + @include transition (all 0.2s ease 0s); + + border-width: 1px; + border-style: solid; + text-transform: uppercase; + font-size: 13px; + font-weight: 600; + line-height: 18px; + padding: 11px 16px; + letter-spacing: .4px; + + &:hover { + border-width: 1px; + border-style: solid; + } + + &:focus { + border-width: 1px; + border-style: solid; + } + + &:active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + border-width: 1px; + border-style: solid; + } +} + +@mixin btn-middle { + @include border-radius(2px); + @include transition (all 0.2s ease 0s); + + border-width: 1px; + border-style: solid; + text-transform: uppercase; + font-size: 13px; + font-weight: 600; + line-height: 18px; + padding: 11px 24px; + letter-spacing: .4px; + + &:hover { + border-width: 1px; + border-style: solid; + } + + &:focus { + border-width: 1px; + border-style: solid; + } + + &:active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + border-width: 1px; + border-style: solid; + } +} + + +@mixin btn-green { + background-color: #28b061; + border: 1px solid #26a65c; + color: #fff; + + &:hover { + background-color: #26ab5d; + border: 1px solid #229954; + color: #fff; + } + + &:focus { + background-color: #26ab5d; + border: 1px solid #229954; + color: #fff; + } + + &:active { + @include box-shadow (inset 0 0 4px rgba(0, 0, 0, 0.12)); + + background-color: #23a158 !important; + border: 1px solid #229954 !important; + color: #fff !important; + } +} + +/*Butons*/ + +@mixin bnt-project { + background-color: #f0f2f5; + border-color: #dce0e5; + color: #313236; + + &:hover { + border-color:#dce0e5; + background-color: #ebeef2; + color: #313236; + } + + &:focus { + border-color: #dce0e5; + background-color: #ebeef2; + color: #313236; + } + + &:active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + color: #313236 !important; + border-color: #c6cacf !important; + background-color: #e4e7ed !important; + } +} + +@mixin btn-remove { + background-color: #f72e60; + border-color: #ee295a; + + &:hover { + background-color: #e82757; + border-color: #e32555; + } + + &:focus { + background-color: #e82757; + border-color: #e32555; + } + + &:active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + background-color: #d42450 !important; + border-color: #e12554 !important; + } + +}
\ No newline at end of file diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index b659717b4e1..016cc015e9c 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -1,8 +1,8 @@ /** COLORS **/ .cgray { color: $gl-gray; } .clgray { color: #BBB } -.cred { color: #D12F19 } -.cgreen { color: #4a2 } +.cred { color: $gl-text-red; } +.cgreen { color: $gl-text-green; } .cdark { color: #444 } /** COMMON CLASSES **/ @@ -313,7 +313,7 @@ table { } .wiki .highlight, .note-body .highlight { - margin-bottom: 9px; + margin: 12px 0 12px 0; } .wiki .code { diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss index b758a526fbb..543ce41ab52 100644 --- a/app/assets/stylesheets/generic/header.scss +++ b/app/assets/stylesheets/generic/header.scss @@ -26,7 +26,6 @@ header { min-height: $header-height; background-color: #fff; border: none; - border-bottom: 1px solid #EEE; .container-fluid { width: 100% !important; diff --git a/app/assets/stylesheets/generic/sidebar.scss b/app/assets/stylesheets/generic/sidebar.scss index 3d055f0e66f..d30fc6e189d 100644 --- a/app/assets/stylesheets/generic/sidebar.scss +++ b/app/assets/stylesheets/generic/sidebar.scss @@ -1,4 +1,7 @@ .page-with-sidebar { + min-height: 100%; + height: 100%; + .sidebar-wrapper { position: fixed; top: 0; @@ -18,16 +21,19 @@ } .content-wrapper { - min-height: 100vh; + min-height: 900px; + display: table; width: 100%; padding: 20px; - background: #f1f4f8; + background: #EAEBEC; + height: 100%; + width: 100%; .container-fluid { background: #FFF; padding: $gl-padding; - border: 1px solid #e7e9ed; - min-height: 90vh; + height: 100%; + min-height: 100%; &.container-blank { background: none; diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss index 551db31db12..6a3cb49baae 100644 --- a/app/assets/stylesheets/generic/typography.scss +++ b/app/assets/stylesheets/generic/typography.scss @@ -2,11 +2,24 @@ * Headers * */ +body { + text-rendering:optimizeLegibility; + -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px; +} + .page-title { margin-top: 0px; - line-height: 1.5; - font-weight: normal; - margin-bottom: 5px; + line-height: 1.3; + font-size: 1.25em; + font-weight: 600; +} + +.page-title-empty { + margin-top: 0px; + line-height: 1.3; + font-size: 1.25em; + font-weight: 600; + margin: 12px 7px 12px 7px; } h1, h2, h3, h4, h5, h6 { @@ -114,4 +127,4 @@ textarea.js-gfm-input { .strikethrough { text-decoration: line-through; -} +}
\ No newline at end of file diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 5de589109bd..20a144ef952 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -1,9 +1,10 @@ /* https://github.com/aahan/pygments-github-style */ pre.code.highlight.white, .code.white { - - background-color: #fff; - color: #333; + background-color: #f8fafc; + font-size: 13px; + color: #5b6169; + line-height: 1.6em; .line-numbers, .line-numbers a { diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss index 051ca3792c3..741ff9051a2 100644 --- a/app/assets/stylesheets/pages/commit.scss +++ b/app/assets/stylesheets/pages/commit.scss @@ -49,30 +49,33 @@ } .file-stats { + ul { + list-style: none; + margin: 0; + padding: 10px 0; + + li { + padding: 3px 0px; + } + } .new-file { a { - color: #090; - } - i { - color: #1BCF00; + color: $gl-text-green; } } .renamed-file { - i { - color: #FE9300; + a { + color: $gl-text-orange; } } .deleted-file { a { - color: #B00; - } - i { - color: #EE0000; + color: $gl-text-red; } } .edit-file{ - i{ - color: #555; + a { + color: $gl-text-color; } } } diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 2b1b747139a..07a38a19fad 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -10,3 +10,9 @@ .milestone-row { @include str-truncated(90%); } + +.dashboard .side .panel .panel-heading .input-group { + .form-control { + height: 42px; + } +}
\ No newline at end of file diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 8d75f3aad49..b7d046e891a 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -1,3 +1,14 @@ +.alert_holder { + margin: -16px; + + .alert-link { + font-weight: normal; + } +} +.no-ssh-key-message { + background-color: #f28d35; + margin-bottom: 16px; +} .new_project, .edit_project { fieldset.features { @@ -19,10 +30,10 @@ background: #f7f8fa; margin: -$gl-padding; padding: $gl-padding; - padding-top: 40px; + padding: 44px 0 17px 0; .project-identicon-holder { - margin-bottom: 15px; + margin-bottom: 16px; .avatar, .identicon { margin: 0 auto; @@ -40,23 +51,26 @@ .project-home-desc { h1 { + color: #313236; margin: 0; - margin-bottom: 10px; + margin-bottom: 6px; font-size: 23px; font-weight: normal; } p { - color: #7f8fa4; + color: #5c5d5e; } } .git-clone-holder { - max-width: 600px; - margin: 20px auto; + max-width: 498px; .form-control { background: #FFF; + font-size: 14px; + height: 42px; + margin-left: -1px; } } @@ -66,30 +80,37 @@ color: inherit; } } + .input-group { + display: inline-table; + position: relative; + top: 17px; + margin-bottom: 44px; + } .project-repo-buttons { - margin-top: $gl-padding; - margin-bottom: 25px; + margin-top: 12px; + margin-bottom: 0px; .btn { - @extend .btn-info; - - text-transform: uppercase; - font-size: 15px; - line-height: 20px; - padding: 8px 14px; - border-radius: 3px; - margin-left: 10px; + @include bnt-project; + @include btn-info; .count { - padding-left: 7px; display: inline-block; - margin-left: 7px; } } } } +.split-one { + display: inline-table; + margin-right: 12px; + + a { + margin: -1px !important; + } +} + .git-clone-holder { .project-home-dropdown + & { margin-right: 45px; @@ -99,11 +120,11 @@ cursor: auto; @extend .monospace; background: #FAFAFA; - width: 100%; + width: 101%; } .input-group-addon { - background: #FAFAFA; + background: #f7f8fa; &.git-protocols { padding: 0; @@ -111,11 +132,120 @@ .input-group-btn:last-child > .btn { @include border-radius-right(0); + + border-left: 1px solid #c6cacf; + margin-left: -2px !important; } } } } +.projects-search-form { + + .input-group .form-control { + height: 42px; + } +} + +.input-group-btn { + .btn { + @include bnt-project; + @include btn-middle; + + &:hover { + outline: none; + } + + &:focus { + outline: none; + } + + &:active { + outline: none; + } + } + + .active { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + border: 1px solid #c6cacf !important; + background-color: #e4e7ed !important; + } + + .btn-green { + @include btn-green + } + +} + +.split-repo-buttons { + display: inline-table; + margin: 0 12px 0 12px; + + .btn{ + @include bnt-project; + @include btn-info; + } + + .dropdown-toggle { + margin: -5px; + } +} + +#notification-form { + margin-left: 5px; +} + +.dropdown-new { + margin-left: -5px; +} + +.open > .dropdown-new.btn { + @include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12)); + + border: 1px solid #c6cacf !important; + background-color: #e4e7ed !important; + text-transform: uppercase; + color: #313236 !important; + font-size: 13px; + font-weight: 600; +} + +.dropdown-menu { + @include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px); + @include border-radius (0px); + + border: none; + padding: 16px 0; + font-size: 14px; + font-weight: 100; + + li a { + color: #5f697a; + line-height: 30px; + + &:hover { + background-color: #3084bb !important; + } + } + + .fa-fw { + margin-right: 8px; + } +} + +.fa-bell { + margin-right: 6px; +} + +.fa-angle-down { + margin-left: 6px; +} + +.project-home-panel .project-home-dropdown { + margin: 13px 0px 0; +} + .project-visibility-level-holder { .radio { margin-bottom: 10px; @@ -232,15 +362,28 @@ table.table.protected-branches-list tr.no-border { .project-stats { text-align: center; - margin-top: 0; + margin-top: 15px; margin-bottom: 0; - padding-top: 5px; - padding-bottom: 0; + padding-top: 10px; + padding-bottom: 4px; ul.nav-pills { display:inline-block; } + .nav-pills li { + display:inline; + } + + .nav > li > a { + @include btn-info; + @include bnt-project; + + background-color: transparent; + border: 1px solid #f7f8fa; + margin-left: 12px; + } + li { display:inline; } @@ -251,11 +394,11 @@ table.table.protected-branches-list tr.no-border { } li.missing a { - color: #bbb; - border: 1px dashed #ccc; + color: #5a6069; + border: 1px dashed #dce0e5; &:hover { - background-color: #FAFAFA; + background-color: #f0f2f5; } } } @@ -273,9 +416,37 @@ pre.light-well { border-bottom: 1px solid #e7e9ed; } +.git-empty { + margin: 0 7px 0 7px; + + h5 { + color: #5c5d5e; + } + + .light-well { + @include border-radius (2px); + + color: #5b6169; + font-size: 13px; + line-height: 1.6em; + } +} + +.project-footer { + margin-top: 20px; + + .btn-remove { + @include btn-middle; + @include btn-remove; + + float: left !important; + } +} + /* * Projects list rendered on dashboard and user page */ + .projects-list { @include basic-list; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index a19b1abee27..00f41a10dd1 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -63,6 +63,12 @@ class Admin::UsersController < Admin::ApplicationController end end + def login_as + sign_in(user) + flash[:alert] = "Logged in as #{user.username}" + redirect_to root_path + end + def disable_two_factor user.disable_two_factor! redirect_to admin_user_path(user), diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9b6472a7b13..527c9da0faa 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -117,9 +117,14 @@ class ApplicationController < ActionController::Base redirect_to request.original_url.gsub(/\.git\Z/, '') and return end - @project = Project.find_with_namespace("#{namespace}/#{id}") + project_path = "#{namespace}/#{id}" + @project = Project.find_with_namespace(project_path) + if @project and can?(current_user, :read_project, @project) + if @project.path_with_namespace != project_path + redirect_to request.original_url.gsub(project_path, @project.path_with_namespace) and return + end @project elsif current_user.nil? @project = nil diff --git a/app/controllers/ci/admin/runners_controller.rb b/app/controllers/ci/admin/runners_controller.rb index dc3508b49dd..9a68add9083 100644 --- a/app/controllers/ci/admin/runners_controller.rb +++ b/app/controllers/ci/admin/runners_controller.rb @@ -12,7 +12,10 @@ module Ci def show @builds = @runner.builds.order('id DESC').first(30) @projects = Ci::Project.all - @projects = @projects.search(params[:search]) if params[:search].present? + if params[:search].present? + @gl_projects = ::Project.search(params[:search]) + @projects = @projects.where(gitlab_id: @gl_projects.select(:id)) + end @projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any? @projects = @projects.page(params[:page]).per(30) end diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb index a81e4e319ff..24dd1b5c93a 100644 --- a/app/controllers/ci/lints_controller.rb +++ b/app/controllers/ci/lints_controller.rb @@ -18,7 +18,7 @@ module Ci rescue Ci::GitlabCiYamlProcessor::ValidationError => e @error = e.message @status = false - rescue Exception => e + rescue Exception @error = "Undefined error" @status = false end diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 6111753a7fb..e8788955eba 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -2,9 +2,9 @@ module Ci class ProjectsController < Ci::ApplicationController before_action :authenticate_user!, except: [:build, :badge, :show] before_action :authenticate_public_page!, only: :show - before_action :project, only: [:build, :show, :badge, :edit, :update, :destroy, :toggle_shared_runners, :dumped_yaml] + before_action :project, only: [:build, :show, :badge, :toggle_shared_runners, :dumped_yaml] before_action :authorize_access_project!, except: [:build, :badge, :show, :new, :disabled] - before_action :authorize_manage_project!, only: [:edit, :update, :destroy, :toggle_shared_runners, :dumped_yaml] + before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml] before_action :authenticate_token!, only: [:build] before_action :no_cache, only: [:badge] skip_before_action :check_enable_flag!, only: [:disabled] @@ -23,28 +23,6 @@ module Ci @commits = @commits.page(params[:page]).per(20) end - def edit - end - - def update - if project.update_attributes(project_params) - Ci::EventService.new.change_project_settings(current_user, project) - - redirect_to :back, notice: 'Project was successfully updated.' - else - render action: "edit" - end - end - - def destroy - project.gl_project.gitlab_ci_service.update_attributes(active: false) - project.destroy - - Ci::EventService.new.remove_project(current_user, project) - - redirect_to ci_projects_url - end - # Project status badge # Image with build status for sha or ref def badge @@ -55,7 +33,8 @@ module Ci def toggle_shared_runners project.toggle!(:shared_runners_enabled) - redirect_to :back + + redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project) end def dumped_yaml @@ -73,12 +52,5 @@ module Ci response.headers["Pragma"] = "no-cache" response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" end - - def project_params - params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build, - :polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients, - :email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token, - { variables_attributes: [:id, :key, :value, :_destroy] }) - end end end diff --git a/app/controllers/ci/runner_projects_controller.rb b/app/controllers/ci/runner_projects_controller.rb index a8bdd5bb362..97f01d40af5 100644 --- a/app/controllers/ci/runner_projects_controller.rb +++ b/app/controllers/ci/runner_projects_controller.rb @@ -11,10 +11,12 @@ module Ci return head(403) unless current_user.ci_authorized_runners.include?(@runner) + path = runners_path(@project.gl_project) + if @runner.assign_to(project, current_user) - redirect_to ci_project_runners_path(project) + redirect_to path else - redirect_to ci_project_runners_path(project), alert: 'Failed adding runner to project' + redirect_to path, alert: 'Failed adding runner to project' end end @@ -22,7 +24,7 @@ module Ci runner_project = project.runner_projects.find(params[:id]) runner_project.destroy - redirect_to ci_project_runners_path(project) + redirect_to runners_path(@project.gl_project) end private diff --git a/app/controllers/ci/runners_controller.rb b/app/controllers/ci/runners_controller.rb deleted file mode 100644 index a672370302b..00000000000 --- a/app/controllers/ci/runners_controller.rb +++ /dev/null @@ -1,73 +0,0 @@ -module Ci - class RunnersController < Ci::ApplicationController - before_action :authenticate_user! - before_action :project - before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show] - before_action :authorize_access_project! - before_action :authorize_manage_project! - - layout 'ci/project' - - def index - @runners = @project.runners.order('id DESC') - @specific_runners = - Ci::Runner.specific.includes(:runner_projects). - where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ). - where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20) - @shared_runners = Ci::Runner.shared.active - @shared_runners_count = @shared_runners.count(:all) - end - - def edit - end - - def update - if @runner.update_attributes(runner_params) - redirect_to edit_ci_project_runner_path(@project, @runner), notice: 'Runner was successfully updated.' - else - redirect_to edit_ci_project_runner_path(@project, @runner), alert: 'Runner was not updated.' - end - end - - def destroy - if @runner.only_for?(@project) - @runner.destroy - end - - redirect_to ci_project_runners_path(@project) - end - - def resume - if @runner.update_attributes(active: true) - redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.' - else - redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.' - end - end - - def pause - if @runner.update_attributes(active: false) - redirect_to ci_project_runners_path(@project, @runner), notice: 'Runner was successfully updated.' - else - redirect_to ci_project_runners_path(@project, @runner), alert: 'Runner was not updated.' - end - end - - def show - end - - protected - - def project - @project = Ci::Project.find(params[:project_id]) - end - - def set_runner - @runner ||= @project.runners.find(params[:id]) - end - - def runner_params - params.require(:runner).permit(:description, :tag_list, :contacted_at, :active) - end - end -end diff --git a/app/controllers/ci/triggers_controller.rb b/app/controllers/ci/triggers_controller.rb deleted file mode 100644 index a39cc5d3a56..00000000000 --- a/app/controllers/ci/triggers_controller.rb +++ /dev/null @@ -1,43 +0,0 @@ -module Ci - class TriggersController < Ci::ApplicationController - before_action :authenticate_user! - before_action :project - before_action :authorize_access_project! - before_action :authorize_manage_project! - - layout 'ci/project' - - def index - @triggers = @project.triggers - @trigger = Ci::Trigger.new - end - - def create - @trigger = @project.triggers.new - @trigger.save - - if @trigger.valid? - redirect_to ci_project_triggers_path(@project) - else - @triggers = @project.triggers.select(&:persisted?) - render :index - end - end - - def destroy - trigger.destroy - - redirect_to ci_project_triggers_path(@project) - end - - private - - def trigger - @trigger ||= @project.triggers.find(params[:id]) - end - - def project - @project = Ci::Project.find(params[:project_id]) - end - end -end diff --git a/app/controllers/ci/variables_controller.rb b/app/controllers/ci/variables_controller.rb deleted file mode 100644 index 9c6c775fde8..00000000000 --- a/app/controllers/ci/variables_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Ci - class VariablesController < Ci::ApplicationController - before_action :authenticate_user! - before_action :project - before_action :authorize_access_project! - before_action :authorize_manage_project! - - layout 'ci/project' - - def show - end - - def update - if project.update_attributes(project_params) - Ci::EventService.new.change_project_settings(current_user, project) - - redirect_to ci_project_variables_path(project), notice: 'Variables were successfully updated.' - else - render action: 'show' - end - end - - private - - def project - @project ||= Ci::Project.find(params[:project_id]) - end - - def project_params - params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] }) - end - end -end diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 467d0f81aca..58e9049f158 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -20,6 +20,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController @projects = current_user.starred_projects @projects = @projects.includes(:namespace, :forked_from_project, :tags) @projects = @projects.sort(@sort = params[:sort]) + @last_push = current_user.recent_push @groups = [] respond_to do |format| diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 523264b8ea9..f809fa7500a 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -71,7 +71,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return end end - rescue Gitlab::OAuth::SignupDisabledError => e + rescue Gitlab::OAuth::SignupDisabledError label = Gitlab::OAuth::Provider.label_for(oauth['provider']) message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed." @@ -80,7 +80,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController end flash[:notice] = message - + redirect_to new_user_session_path end diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index 8450ba31021..2025158d065 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -1,41 +1,7 @@ class PasswordsController < Devise::PasswordsController - - def create - email = resource_params[:email] - resource_found = resource_class.find_by_email(email) - if resource_found && resource_found.ldap_user? - flash[:alert] = "Cannot reset password for LDAP user." - respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) and return - end - - self.resource = resource_class.send_reset_password_instructions(resource_params) - if successfully_sent?(resource) - respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) - else - respond_with(resource) - end - end - - # After a user resets their password, prompt for 2FA code if enabled instead - # of signing in automatically - # - # See http://git.io/vURrI - def update - super do |resource| - # TODO (rspeicher): In Devise master (> 3.4.1), we can set - # `Devise.sign_in_after_reset_password = false` and avoid this mess. - if resource.errors.empty? && resource.try(:two_factor_enabled?) - resource.unlock_access! if unlockable?(resource) - - # Since we are not signing this user in, we use the :updated_not_active - # message which only contains "Your password was changed successfully." - set_flash_message(:notice, :updated_not_active) if is_flashing_format? - - # Redirect to sign in so they can enter 2FA code - respond_with(resource, location: new_session_path(resource)) and return - end - end - end + before_action :resource_from_email, only: [:create] + before_action :prevent_ldap_reset, only: [:create] + before_action :throttle_reset, only: [:create] def edit super @@ -56,4 +22,25 @@ class PasswordsController < Devise::PasswordsController end end end + + protected + + def resource_from_email + email = resource_params[:email] + self.resource = resource_class.find_by_email(email) + end + + def prevent_ldap_reset + return unless resource && resource.ldap_user? + + redirect_to after_sending_reset_password_instructions_path_for(resource_name), + alert: "Cannot reset password for LDAP user." + end + + def throttle_reset + return unless resource && resource.recently_sent_password_reset? + + redirect_to new_password_path(resource_name), + alert: I18n.t('devise.passwords.recently_reset') + end end diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index 48c922f450c..519d6d6127e 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -31,4 +31,8 @@ class Projects::ApplicationController < ApplicationController def ci_enabled return render_404 unless @project.gitlab_ci? end + + def ci_project + @ci_project ||= @project.ensure_gitlab_ci_project + end end diff --git a/app/controllers/projects/ci_settings_controller.rb b/app/controllers/projects/ci_settings_controller.rb new file mode 100644 index 00000000000..a263242a850 --- /dev/null +++ b/app/controllers/projects/ci_settings_controller.rb @@ -0,0 +1,36 @@ +class Projects::CiSettingsController < Projects::ApplicationController + before_action :ci_project + before_action :authorize_admin_project! + + layout "project_settings" + + def edit + end + + def update + if ci_project.update_attributes(project_params) + Ci::EventService.new.change_project_settings(current_user, ci_project) + + redirect_to edit_namespace_project_ci_settings_path(project.namespace, project), notice: 'Project was successfully updated.' + else + render action: "edit" + end + end + + def destroy + ci_project.destroy + Ci::EventService.new.remove_project(current_user, ci_project) + project.gitlab_ci_service.update_attributes(active: false) + + redirect_to project_path(project), notice: "CI was disabled for this project" + end + + protected + + def project_params + params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build, + :polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients, + :email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token, + { variables_attributes: [:id, :key, :value, :_destroy] }) + end +end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 7574842cd43..7570934e727 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -150,6 +150,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController return access_denied! unless @merge_request.can_be_merged_by?(current_user) if @merge_request.mergeable? + @merge_request.update(merge_error: nil) MergeWorker.perform_async(@merge_request.id, current_user.id, params) @status = true else diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb new file mode 100644 index 00000000000..6cb6e3ef6d4 --- /dev/null +++ b/app/controllers/projects/runners_controller.rb @@ -0,0 +1,65 @@ +class Projects::RunnersController < Projects::ApplicationController + before_action :ci_project + before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show] + before_action :authorize_admin_project! + + layout 'project_settings' + + def index + @runners = @ci_project.runners.order('id DESC') + @specific_runners = + Ci::Runner.specific.includes(:runner_projects). + where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ). + where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20) + @shared_runners = Ci::Runner.shared.active + @shared_runners_count = @shared_runners.count(:all) + end + + def edit + end + + def update + if @runner.update_attributes(runner_params) + redirect_to runner_path(@runner), notice: 'Runner was successfully updated.' + else + redirect_to runner_path(@runner), alert: 'Runner was not updated.' + end + end + + def destroy + if @runner.only_for?(@ci_project) + @runner.destroy + end + + redirect_to runners_path(@project) + end + + def resume + if @runner.update_attributes(active: true) + redirect_to runner_path(@runner), notice: 'Runner was successfully updated.' + else + redirect_to runner_path(@runner), alert: 'Runner was not updated.' + end + end + + def pause + if @runner.update_attributes(active: false) + redirect_to runner_path(@runner), notice: 'Runner was successfully updated.' + else + redirect_to runner_path(@runner), alert: 'Runner was not updated.' + end + end + + def show + end + + protected + + def set_runner + @runner ||= @ci_project.runners.find(params[:id]) + end + + def runner_params + params.require(:runner).permit(:description, :tag_list, :contacted_at, :active) + end +end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 3a22ed832ac..3047ee8a1ff 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -58,6 +58,8 @@ class Projects::ServicesController < Projects::ApplicationController end def service_params - params.require(:service).permit(ALLOWED_PARAMS) + service_params = params.require(:service).permit(ALLOWED_PARAMS) + service_params.delete("password") if service_params["password"].blank? + service_params end end diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb new file mode 100644 index 00000000000..782ebd01b05 --- /dev/null +++ b/app/controllers/projects/triggers_controller.rb @@ -0,0 +1,35 @@ +class Projects::TriggersController < Projects::ApplicationController + before_action :ci_project + before_action :authorize_admin_project! + + layout 'project_settings' + + def index + @triggers = @ci_project.triggers + @trigger = Ci::Trigger.new + end + + def create + @trigger = @ci_project.triggers.new + @trigger.save + + if @trigger.valid? + redirect_to namespace_project_triggers_path(@project.namespace, @project) + else + @triggers = @ci_project.triggers.select(&:persisted?) + render :index + end + end + + def destroy + trigger.destroy + + redirect_to namespace_project_triggers_path(@project.namespace, @project) + end + + private + + def trigger + @trigger ||= @ci_project.triggers.find(params[:id]) + end +end diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb new file mode 100644 index 00000000000..d6561a45a70 --- /dev/null +++ b/app/controllers/projects/variables_controller.rb @@ -0,0 +1,25 @@ +class Projects::VariablesController < Projects::ApplicationController + before_action :ci_project + before_action :authorize_admin_project! + + layout 'project_settings' + + def show + end + + def update + if ci_project.update_attributes(project_params) + Ci::EventService.new.change_project_settings(current_user, ci_project) + + redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.' + else + render action: 'show' + end + end + + private + + def project_params + params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] }) + end +end diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 51c26a6a465..88fccfed509 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -98,7 +98,7 @@ class Projects::WikisController < Projects::ApplicationController # Call #wiki to make sure the Wiki Repo is initialized @project_wiki.wiki - rescue ProjectWiki::CouldNotCreateWikiError => ex + rescue ProjectWiki::CouldNotCreateWikiError flash[:notice] = "Could not create Wiki Repository at this time. Please try again later." redirect_to project_path(@project) return false diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb index 54171ff67c5..ad04c646e1b 100644 --- a/app/controllers/root_controller.rb +++ b/app/controllers/root_controller.rb @@ -22,6 +22,10 @@ class RootController < Dashboard::ProjectsController when 'stars' flash.keep redirect_to starred_dashboard_projects_path + when 'project_activity' + redirect_to activity_dashboard_path + when 'starred_project_activity' + redirect_to activity_dashboard_path(filter: 'starred') else return end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index ab89aa2c53a..6aa16673d63 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -39,7 +39,7 @@ class IssuableFinder items = by_assignee(items) items = by_author(items) items = by_label(items) - items = sort(items) + sort(items) end def group diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 39ab83ccf12..3ab44719d9f 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -35,7 +35,7 @@ module ApplicationHelper def project_icon(project_id, options = {}) project = if project_id.is_a?(Project) - project = project_id + project_id else Project.find_with_namespace(project_id) end diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index ce7e9b1db87..cd99a232403 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,6 +1,6 @@ module AuthHelper PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze - FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze + FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze def ldap_enabled? Gitlab.config.ldap.enabled diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb new file mode 100644 index 00000000000..b6658e52d09 --- /dev/null +++ b/app/helpers/builds_helper.rb @@ -0,0 +1,17 @@ +module BuildsHelper + def build_ref_link build + gitlab_ref_link build.project, build.ref + end + + def build_compare_link build + gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha + end + + def build_commit_link build + gitlab_commit_link build.project, build.short_sha + end + + def build_url(build) + ci_project_build_url(build.project, build) + end +end diff --git a/app/helpers/ci/application_helper.rb b/app/helpers/ci/application_helper.rb deleted file mode 100644 index 9fe6282bb81..00000000000 --- a/app/helpers/ci/application_helper.rb +++ /dev/null @@ -1,54 +0,0 @@ -module Ci - module ApplicationHelper - def loader_html - image_tag 'ci/loader.gif', alt: 'Loading' - end - - def date_from_to(from, to) - "#{from.to_s(:short)} - #{to.to_s(:short)}" - end - - def duration_in_words(finished_at, started_at) - if finished_at && started_at - interval_in_seconds = finished_at.to_i - started_at.to_i - elsif started_at - interval_in_seconds = Time.now.to_i - started_at.to_i - end - - time_interval_in_words(interval_in_seconds) - end - - def time_interval_in_words(interval_in_seconds) - minutes = interval_in_seconds / 60 - seconds = interval_in_seconds - minutes * 60 - - if minutes >= 1 - "#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}" - else - "#{pluralize(seconds, "second")}" - end - end - - def ci_icon_for_status(status) - icon_name = - case status - when 'success' - 'check-square' - when 'failed' - 'close' - when 'running', 'pending' - 'clock-o' - else - 'circle' - end - - icon(icon_name) - end - - def ci_status_with_icon(status) - content_tag :span, class: "ci-status ci-#{status}" do - ci_icon_for_status(status) + ' '.html_safe + status - end - end - end -end diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb deleted file mode 100644 index 5d6e785d951..00000000000 --- a/app/helpers/ci/builds_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Ci - module BuildsHelper - def build_ref_link build - gitlab_ref_link build.project, build.ref - end - - def build_compare_link build - gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha - end - - def build_commit_link build - gitlab_commit_link build.project, build.short_sha - end - - def build_url(build) - ci_project_build_url(build.project, build) - end - end -end diff --git a/app/helpers/ci/gitlab_helper.rb b/app/helpers/ci/gitlab_helper.rb index 2b89a0ce93e..13e4d0fd9c3 100644 --- a/app/helpers/ci/gitlab_helper.rb +++ b/app/helpers/ci/gitlab_helper.rb @@ -27,9 +27,9 @@ module Ci commits = project.commits if commits.any? && commits.last.push_data[:ci_yaml_file] - "#{@project.gitlab_url}/edit/master/.gitlab-ci.yml" + "#{project.gitlab_url}/edit/master/.gitlab-ci.yml" else - "#{@project.gitlab_url}/new/master" + "#{project.gitlab_url}/new/master" end end end diff --git a/app/helpers/ci/icons_helper.rb b/app/helpers/ci/icons_helper.rb deleted file mode 100644 index be40f79e880..00000000000 --- a/app/helpers/ci/icons_helper.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Ci - module IconsHelper - def boolean_to_icon(value) - if value.to_s == "true" - content_tag :i, nil, class: 'fa fa-circle cgreen' - else - content_tag :i, nil, class: 'fa fa-power-off clgray' - end - end - end -end diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb deleted file mode 100644 index 03c9914641e..00000000000 --- a/app/helpers/ci/runners_helper.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Ci - module RunnersHelper - def runner_status_icon(runner) - unless runner.contacted_at - return content_tag :i, nil, - class: "fa fa-warning-sign", - title: "New runner. Has not connected yet" - end - - status = - if runner.active? - runner.contacted_at > 3.hour.ago ? :online : :offline - else - :paused - end - - content_tag :i, nil, - class: "fa fa-circle runner-status-#{status}", - title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago" - end - end -end diff --git a/app/helpers/ci/triggers_helper.rb b/app/helpers/ci/triggers_helper.rb deleted file mode 100644 index 0d2438928ce..00000000000 --- a/app/helpers/ci/triggers_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ci - module TriggersHelper - def ci_build_trigger_url(project_id, ref_name) - "#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger" - end - end -end diff --git a/app/helpers/ci/user_helper.rb b/app/helpers/ci/user_helper.rb deleted file mode 100644 index c332d6ed9cf..00000000000 --- a/app/helpers/ci/user_helper.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Ci - module UserHelper - def user_avatar_url(user = nil, size = nil, default = 'identicon') - size = 40 if size.nil? || size <= 0 - - if user.blank? || user.avatar_url.blank? - 'ci/no_avatar.png' - elsif /^(http(s?):\/\/(www|secure)\.gravatar\.com\/avatar\/(\w*))/ =~ user.avatar_url - Regexp.last_match[0] + "?s=#{size}&d=#{default}" - else - user.avatar_url - end - end - end -end diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 18c30ddb281..3a88ed7107e 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -4,19 +4,7 @@ module CiStatusHelper end def ci_status_icon(ci_commit) - icon_name = - case ci_commit.status - when 'success' - 'check' - when 'failed' - 'close' - when 'running', 'pending' - 'clock-o' - else - 'circle' - end - - icon(icon_name) + ci_icon_for_status(ci_commit.status) end def ci_status_color(ci_commit) @@ -31,4 +19,26 @@ module CiStatusHelper 'gray' end end + + def ci_status_with_icon(status) + content_tag :span, class: "ci-status ci-#{status}" do + ci_icon_for_status(status) + ' '.html_safe + status + end + end + + def ci_icon_for_status(status) + icon_name = + case status + when 'success' + 'check' + when 'failed' + 'close' + when 'running', 'pending' + 'clock-o' + else + 'circle' + end + + icon(icon_name) + end end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 6ffa1a7121d..b896fba3704 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -167,4 +167,23 @@ module DiffHelper content_tag(:span, commit_id, class: 'monospace'), ].join(' ').html_safe end + + def commit_for_diff(diff) + if diff.deleted_file + @merge_request ? @merge_request.commits.last : @commit.parents.first + else + @commit + end + end + + def diff_file_html_data(project, diff_commit, diff_file) + { + blob_diff_path: namespace_project_blob_diff_path(project.namespace, project, + tree_join(diff_commit.id, diff_file.file_path)) + } + end + + def editable_diff?(diff) + !diff.deleted_file && @merge_request && @merge_request.source_project + end end diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 153a44870f6..12b87dca798 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -21,7 +21,7 @@ module GitlabMarkdownHelper gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: current_user) - fragment = Nokogiri::XML::DocumentFragment.parse(gfm_body) + fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body) if fragment.children.size == 1 && fragment.children[0].name == 'a' # Fragment has only one node, and it's a link generated by `gfm`. # Replace it with our requested link. diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index e0816f4e714..4d9da6ff837 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -33,6 +33,14 @@ module GitlabRoutingHelper edit_namespace_project_path(project.namespace, project, *args) end + def runners_path(project, *args) + namespace_project_runners_path(project.namespace, project, *args) + end + + def runner_path(runner, *args) + namespace_project_runner_path(@project.namespace, @project, runner, *args) + end + def issue_path(entity, *args) namespace_project_issue_path(entity.project.namespace, entity.project, entity, *args) end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index f8169b4f288..81773e7afcf 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -71,4 +71,17 @@ module MergeRequestsHelper merge_request.source_branch end end + + def format_mr_branch_names(merge_request) + source_path = merge_request.source_project_path + target_path = merge_request.target_project_path + source_branch = merge_request.source_branch + target_branch = merge_request.target_branch + + if source_path == target_path + [source_branch, target_branch] + else + ["#{source_path}:#{source_branch}", "#{target_path}:#{target_branch}"] + end + end end diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index 7f1b6a69926..1b1f4162df4 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -3,7 +3,9 @@ module PreferencesHelper # Maps `dashboard` values to more user-friendly option text DASHBOARD_CHOICES = { projects: 'Your Projects (default)', - stars: 'Starred Projects' + stars: 'Starred Projects', + project_activity: "Your Projects' Activity", + starred_project_activity: "Starred Projects' Activity" }.with_indifferent_access.freeze # Returns an Array usable by a select field for more user-friendly option text diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 7b4747ce3d7..a0220af4c30 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -296,7 +296,7 @@ module ProjectsHelper def readme_cache_key sha = @project.commit.try(:sha) || 'nil' - [@project.id, sha, "readme"].join('-') + [@project.path_with_namespace, sha, "readme"].join('-') end def round_commit_count(project) diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb new file mode 100644 index 00000000000..5d7d06c8490 --- /dev/null +++ b/app/helpers/runners_helper.rb @@ -0,0 +1,20 @@ +module RunnersHelper + def runner_status_icon(runner) + unless runner.contacted_at + return content_tag :i, nil, + class: "fa fa-warning-sign", + title: "New runner. Has not connected yet" + end + + status = + if runner.active? + runner.contacted_at > 3.hour.ago ? :online : :offline + else + :paused + end + + content_tag :i, nil, + class: "fa fa-circle runner-status-#{status}", + title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago" + end +end diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb new file mode 100644 index 00000000000..8142f733e76 --- /dev/null +++ b/app/helpers/time_helper.rb @@ -0,0 +1,27 @@ +module TimeHelper + def duration_in_words(finished_at, started_at) + if finished_at && started_at + interval_in_seconds = finished_at.to_i - started_at.to_i + elsif started_at + interval_in_seconds = Time.now.to_i - started_at.to_i + end + + time_interval_in_words(interval_in_seconds) + end + + def time_interval_in_words(interval_in_seconds) + minutes = interval_in_seconds / 60 + seconds = interval_in_seconds - minutes * 60 + + if minutes >= 1 + "#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}" + else + "#{pluralize(seconds, "second")}" + end + end + + + def date_from_to(from, to) + "#{from.to_s(:short)} - #{to.to_s(:short)}" + end +end diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb new file mode 100644 index 00000000000..2a3a7e80fca --- /dev/null +++ b/app/helpers/triggers_helper.rb @@ -0,0 +1,5 @@ +module TriggersHelper + def ci_build_trigger_url(project_id, ref_name) + "#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger" + end +end diff --git a/app/mailers/ci/notify.rb b/app/mailers/ci/notify.rb index 4462da0d7d2..404842cf213 100644 --- a/app/mailers/ci/notify.rb +++ b/app/mailers/ci/notify.rb @@ -2,7 +2,6 @@ module Ci class Notify < ActionMailer::Base include Ci::Emails::Builds - add_template_helper Ci::ApplicationHelper add_template_helper Ci::GitlabHelper default_url_options[:host] = Gitlab.config.gitlab.host diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 4a6e18e6a74..caba63006da 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -50,10 +50,11 @@ module Emails subject: subject("Invitation declined")) end - def project_was_moved_email(project_id, user_id) + def project_was_moved_email(project_id, user_id, old_path_with_namespace) @current_user = @user = User.find user_id @project = Project.find project_id @target_url = namespace_project_url(@project.namespace, @project) + @old_path_with_namespace = old_path_with_namespace mail(to: @user.notification_email, subject: subject("Project was moved")) end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index db2f9654e14..50a409c3754 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -140,7 +140,7 @@ class Notify < BaseMailer # * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID' # def mail_answer_thread(model, headers = {}) - headers['Message-ID'] = SecureRandom.hex + headers['Message-ID'] = "<#{SecureRandom.hex}@#{Gitlab.config.gitlab.host}>" headers['In-Reply-To'] = message_id(model) headers['References'] = message_id(model) diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb index 07c87a7fe87..89b3116b9f2 100644 --- a/app/models/abuse_report.rb +++ b/app/models/abuse_report.rb @@ -11,11 +11,11 @@ # class AbuseReport < ActiveRecord::Base - belongs_to :reporter, class_name: "User" + belongs_to :reporter, class_name: 'User' belongs_to :user validates :reporter, presence: true validates :user, presence: true validates :message, presence: true - validates :user_id, uniqueness: { scope: :reporter_id } + validates :user_id, uniqueness: true end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 8096d4fa5ae..645ad68e1b3 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -26,11 +26,10 @@ module Ci class Build < ActiveRecord::Base extend Ci::Model - + LAZY_ATTRIBUTES = ['trace'] belongs_to :commit, class_name: 'Ci::Commit' - belongs_to :project, class_name: 'Ci::Project' belongs_to :runner, class_name: 'Ci::Runner' belongs_to :trigger_request, class_name: 'Ci::TriggerRequest' @@ -80,7 +79,6 @@ module Ci new_build.commands = build.commands new_build.tag_list = build.tag_list new_build.commit_id = build.commit_id - new_build.project_id = build.project_id new_build.name = build.name new_build.allow_failure = build.allow_failure new_build.stage = build.stage @@ -137,18 +135,12 @@ module Ci state :canceled, value: 'canceled' end - delegate :sha, :short_sha, :before_sha, :ref, + delegate :sha, :short_sha, :before_sha, :ref, :project, to: :commit, prefix: false def trace_html html = Ci::Ansi2html::convert(trace) if trace.present? - html ||= '' - end - - def trace - if project && read_attribute(:trace).present? - read_attribute(:trace).gsub(project.token, 'xxxxxx') - end + html || '' end def started? @@ -188,7 +180,7 @@ module Ci end def project_id - commit.project_id + commit.project.id end def project_name @@ -219,13 +211,13 @@ module Ci if coverage.present? coverage.to_f end - rescue => ex + rescue # if bad regex or something goes wrong we dont want to interrupt transition # so we just silentrly ignore error for now end end - def trace + def raw_trace if File.exist?(path_to_trace) File.read(path_to_trace) else @@ -234,6 +226,15 @@ module Ci end end + def trace + trace = raw_trace + if project && trace.present? + trace.gsub(project.token, 'xxxxxx') + else + trace + end + end + def trace=(trace) unless Dir.exists? dir_to_trace FileUtils.mkdir_p dir_to_trace diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index f102d0a7679..6d048779cde 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -18,8 +18,8 @@ module Ci class Commit < ActiveRecord::Base extend Ci::Model - - belongs_to :project, class_name: 'Ci::Project' + + belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id has_many :builds, dependent: :destroy, class_name: 'Ci::Build' has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest' @@ -36,6 +36,14 @@ module Ci sha end + def project + @project ||= gl_project.ensure_gitlab_ci_project + end + + def project_id + project.id + end + def last_build builds.order(:id).last end @@ -111,15 +119,14 @@ module Ci builds_attrs = config_processor.builds_for_stage_and_ref(stage, ref, tag) builds_attrs.map do |build_attrs| builds.create!({ - project: project, - name: build_attrs[:name], - commands: build_attrs[:script], - tag_list: build_attrs[:tags], - options: build_attrs[:options], - allow_failure: build_attrs[:allow_failure], - stage: build_attrs[:stage], - trigger_request: trigger_request, - }) + name: build_attrs[:name], + commands: build_attrs[:script], + tag_list: build_attrs[:tags], + options: build_attrs[:options], + allow_failure: build_attrs[:allow_failure], + stage: build_attrs[:stage], + trigger_request: trigger_request, + }) end end diff --git a/app/models/ci/project.rb b/app/models/ci/project.rb index a52e28615f7..88ba933a434 100644 --- a/app/models/ci/project.rb +++ b/app/models/ci/project.rb @@ -33,15 +33,12 @@ module Ci belongs_to :gl_project, class_name: '::Project', foreign_key: :gitlab_id - has_many :commits, ->() { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }, dependent: :destroy, class_name: 'Ci::Commit' - has_many :builds, through: :commits, dependent: :destroy, class_name: 'Ci::Build' has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject' has_many :runners, through: :runner_projects, class_name: 'Ci::Runner' has_many :web_hooks, dependent: :destroy, class_name: 'Ci::WebHook' has_many :events, dependent: :destroy, class_name: 'Ci::Event' has_many :variables, dependent: :destroy, class_name: 'Ci::Variable' has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger' - has_one :last_commit, -> { order 'ci_commits.created_at DESC' }, class_name: 'Ci::Commit' # Project services has_many :services, dependent: :destroy, class_name: 'Ci::Service' @@ -51,19 +48,18 @@ module Ci accepts_nested_attributes_for :variables, allow_destroy: true + delegate :name_with_namespace, :path_with_namespace, :web_url, :http_url_to_repo, :ssh_url_to_repo, to: :gl_project + # # Validations # - validates_presence_of :name, :timeout, :token, :default_ref, - :path, :ssh_url_to_repo, :gitlab_id + validates_presence_of :timeout, :token, :default_ref, :gitlab_id validates_uniqueness_of :gitlab_id validates :polling_interval, - presence: true, - if: ->(project) { project.always_build.present? } - - scope :public_only, ->() { where(public: true) } + presence: true, + if: ->(project) { project.always_build.present? } before_validation :set_default_values @@ -79,11 +75,8 @@ module Ci def parse(project) params = { - name: project.name_with_namespace, gitlab_id: project.id, - path: project.path_with_namespace, default_ref: project.default_branch || 'master', - ssh_url_to_repo: project.ssh_url_to_repo, email_add_pusher: current_application_settings.add_pusher, email_only_broken_builds: current_application_settings.all_broken_builds, } @@ -100,19 +93,26 @@ module Ci def unassigned(runner) joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \ "AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}"). - where('#{Ci::RunnerProject.table_name}.project_id' => nil) + where("#{Ci::RunnerProject.table_name}.project_id" => nil) end def ordered_by_last_commit_date - last_commit_subquery = "(SELECT project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY project_id)" - joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.id = last_commit.project_id"). + last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)" + joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id"). order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC") end + end - def search(query) - where("LOWER(#{Ci::Project.table_name}.name) LIKE :query", - query: "%#{query.try(:downcase)}%") - end + def name + name_with_namespace + end + + def path + path_with_namespace + end + + def gitlab_url + web_url end def any_runners? @@ -125,10 +125,11 @@ module Ci def set_default_values self.token = SecureRandom.hex(15) if self.token.blank? + self.default_ref ||= 'master' end def tracked_refs - @tracked_refs ||= default_ref.split(",").map{|ref| ref.strip} + @tracked_refs ||= default_ref.split(",").map { |ref| ref.strip } end def valid_token? token @@ -168,8 +169,7 @@ module Ci # using http and basic auth def repo_url_with_auth auth = "gitlab-ci-token:#{token}@" - url = gitlab_url + ".git" - url.sub(/^https?:\/\//) do |prefix| + http_url_to_repo.sub(/^https?:\/\//) do |prefix| prefix + auth end end @@ -184,7 +184,7 @@ module Ci # If service is available but missing in db # we should create an instance. Ex `create_gitlab_ci_service` - service = self.send :"create_#{service_name}_service" if service.nil? + self.send :"create_#{service_name}_service" if service.nil? end end @@ -200,12 +200,16 @@ module Ci end end - def gitlab_url - File.join(Gitlab.config.gitlab.url, path) - end - def setup_finished? commits.any? end + + def commits + gl_project.ci_commits + end + + def builds + gl_project.ci_builds + end end end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 1e9f78a3748..6838ccfaaab 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -41,6 +41,10 @@ module Ci query: "%#{query.try(:downcase)}%") end + def gl_projects_ids + projects.select(:gitlab_id) + end + def set_default_values self.token = SecureRandom.hex(15) if self.token.blank? end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index f75f999b0d0..c9ef8023aea 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -144,12 +144,10 @@ class MergeRequestDiff < ActiveRecord::Base # Collect array of Git::Diff objects # between target and source branches def unmerged_diffs - diffs = compare_result.diffs - diffs ||= [] - diffs - rescue Gitlab::Git::Diff::TimeoutError => ex + compare_result.diffs || [] + rescue Gitlab::Git::Diff::TimeoutError self.state = :timeout - diffs = [] + [] end def repository diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 161a16ca61c..bc8525df5a5 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -137,7 +137,9 @@ class Namespace < ActiveRecord::Base end def send_update_instructions - projects.each(&:send_move_instructions) + projects.each do |project| + project.send_move_instructions("#{path_was}/#{project.path}") + end end def kind diff --git a/app/models/note.rb b/app/models/note.rb index 89d81ab1de2..de3b6df88f7 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -366,6 +366,6 @@ class Note < ActiveRecord::Base end def editable? - !read_attribute(:system) + !system? end end diff --git a/app/models/project.rb b/app/models/project.rb index e912c48467d..b90a82da9f2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -118,6 +118,8 @@ class Project < ActiveRecord::Base has_many :deploy_keys, through: :deploy_keys_projects has_many :users_star_projects, dependent: :destroy has_many :starrers, through: :users_star_projects, source: :user + has_many :ci_commits, ->() { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id + has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build' has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id @@ -236,10 +238,10 @@ class Project < ActiveRecord::Base return nil unless id.include?('/') id = id.split('/') - namespace = Namespace.find_by(path: id.first) + namespace = Namespace.by_path(id.first) return nil unless namespace - where(namespace_id: namespace.id).find_by(path: id.second) + where(namespace_id: namespace.id).where("LOWER(projects.path) = :path", path: id.second.downcase).first end def visibility_levels @@ -411,7 +413,7 @@ class Project < ActiveRecord::Base if template.nil? # If no template, we should create an instance. Ex `create_gitlab_ci_service` - service = self.send :"create_#{service_name}_service" + self.send :"create_#{service_name}_service" else Service.create_from_template(self.id, template) end @@ -479,8 +481,8 @@ class Project < ActiveRecord::Base end end - def send_move_instructions - NotificationService.new.project_was_moved(self) + def send_move_instructions(old_path_with_namespace) + NotificationService.new.project_was_moved(self, old_path_with_namespace) end def owner @@ -622,7 +624,7 @@ class Project < ActiveRecord::Base # So we basically we mute exceptions in next actions begin gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") - send_move_instructions + send_move_instructions(old_path_with_namespace) reset_events_cache rescue # Returning false does not rollback after_* transaction but gives @@ -736,7 +738,7 @@ class Project < ActiveRecord::Base def create_wiki ProjectWiki.new(self, self.owner).wiki true - rescue ProjectWiki::CouldNotCreateWikiError => ex + rescue ProjectWiki::CouldNotCreateWikiError errors.add(:base, 'Failed create wiki') false end @@ -745,13 +747,13 @@ class Project < ActiveRecord::Base gitlab_ci_project.commits.find_by(sha: sha) if gitlab_ci? end - def enable_ci(user) - # Enable service + def ensure_gitlab_ci_project + gitlab_ci_project || create_gitlab_ci_project + end + + def enable_ci service = gitlab_ci_service || create_gitlab_ci_service service.active = true service.save - - # Create Ci::Project - Ci::CreateProjectService.new.execute(user, self) end end diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 23ab206efba..6d2cf79b691 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -22,12 +22,17 @@ class GitlabCiService < CiService include Gitlab::Application.routes.url_helpers after_save :compose_service_hook, if: :activated? + after_save :ensure_gitlab_ci_project, if: :activated? def compose_service_hook hook = service_hook || build_service_hook hook.save end + def ensure_gitlab_ci_project + project.ensure_gitlab_ci_project + end + def supported_events %w(push tag_push) end @@ -67,25 +72,6 @@ class GitlabCiService < CiService :error end - def fork_registration(new_project, current_user) - params = OpenStruct.new({ - id: new_project.id, - name_with_namespace: new_project.name_with_namespace, - path_with_namespace: new_project.path_with_namespace, - web_url: new_project.web_url, - default_branch: new_project.default_branch, - ssh_url_to_repo: new_project.ssh_url_to_repo - }) - - ci_project = Ci::Project.find_by!(gitlab_id: project.id) - - Ci::CreateProjectService.new.execute( - current_user, - params, - ci_project - ) - end - def commit_coverage(sha, ref) get_ci_commit(sha, ref).coverage rescue ActiveRecord::RecordNotFound diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 7a15a861abc..af2840a57f0 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -85,17 +85,16 @@ class HipchatService < Service def create_message(data) object_kind = data[:object_kind] - message = \ - case object_kind - when "push", "tag_push" - create_push_message(data) - when "issue" - create_issue_message(data) unless is_update?(data) - when "merge_request" - create_merge_request_message(data) unless is_update?(data) - when "note" - create_note_message(data) - end + case object_kind + when "push", "tag_push" + create_push_message(data) + when "issue" + create_issue_message(data) unless is_update?(data) + when "merge_request" + create_merge_request_message(data) unless is_update?(data) + when "note" + create_note_message(data) + end end def create_push_message(push) @@ -167,8 +166,6 @@ class HipchatService < Service obj_attr = data[:object_attributes] obj_attr = HashWithIndifferentAccess.new(obj_attr) merge_request_id = obj_attr[:iid] - source_branch = obj_attr[:source_branch] - target_branch = obj_attr[:target_branch] state = obj_attr[:state] description = obj_attr[:description] title = obj_attr[:title] @@ -194,8 +191,6 @@ class HipchatService < Service data = HashWithIndifferentAccess.new(data) user_name = data[:user][:name] - repo_attr = HashWithIndifferentAccess.new(data[:repository]) - obj_attr = HashWithIndifferentAccess.new(data[:object_attributes]) note = obj_attr[:note] note_url = obj_attr[:url] diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 56e49af2324..f602a965364 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -135,6 +135,10 @@ class ProjectTeam !!find_member(user_id) end + def human_max_access(user_id) + Gitlab::Access.options.key max_member_access(user_id) + end + def max_member_access(user_id) access = [] access << project.project_members.find_by(user_id: user_id).try(:access_field) diff --git a/app/models/repository.rb b/app/models/repository.rb index 79b48ebfedf..2c5ab62d22c 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -549,7 +549,7 @@ class Repository # Run GitLab post receive hook post_receive_hook = Gitlab::Git::Hook.new('post-receive', path_to_repo) - status = post_receive_hook.trigger(gl_id, oldrev, newrev, ref) + post_receive_hook.trigger(gl_id, oldrev, newrev, ref) else # Remove tmp ref and return error to user rugged.references.delete(tmp_ref) diff --git a/app/models/user.rb b/app/models/user.rb index 25371f9138a..1069f8e3664 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -129,6 +129,7 @@ class User < ActiveRecord::Base has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy + has_one :abuse_report, dependent: :destroy # @@ -172,7 +173,7 @@ class User < ActiveRecord::Base # User's Dashboard preference # Note: When adding an option, it MUST go on the end of the array. - enum dashboard: [:projects, :stars] + enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity] # User's Project preference # Note: When adding an option, it MUST go on the end of the array. @@ -327,6 +328,10 @@ class User < ActiveRecord::Base @reset_token end + def recently_sent_password_reset? + reset_password_sent_at.present? && reset_password_sent_at >= 1.minute.ago + end + def disable_two_factor! update_attributes( two_factor_enabled: false, @@ -700,13 +705,7 @@ class User < ActiveRecord::Base end def manageable_namespaces - @manageable_namespaces ||= - begin - namespaces = [] - namespaces << namespace - namespaces += owned_groups - namespaces += masters_groups - end + @manageable_namespaces ||= [namespace] + owned_groups + masters_groups end def namespaces diff --git a/app/services/ci/create_project_service.rb b/app/services/ci/create_project_service.rb deleted file mode 100644 index f42babd2388..00000000000 --- a/app/services/ci/create_project_service.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Ci - class CreateProjectService - include Gitlab::Application.routes.url_helpers - - def execute(current_user, params, forked_project = nil) - @project = Ci::Project.parse(params) - - Ci::Project.transaction do - @project.save! - - gl_project = ::Project.find(@project.gitlab_id) - gl_project.build_missing_services - gl_project.gitlab_ci_service.update_attributes(active: true) - end - - if forked_project - # Copy settings - settings = forked_project.attributes.select do |attr_name, value| - ["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name - end - - @project.update(settings) - end - - Ci::EventService.new.create_project(current_user, @project) - - @project - end - end -end diff --git a/app/services/ci/register_build_service.rb b/app/services/ci/register_build_service.rb index 33f1c1e918d..71b61bbe389 100644 --- a/app/services/ci/register_build_service.rb +++ b/app/services/ci/register_build_service.rb @@ -8,10 +8,10 @@ module Ci builds = if current_runner.shared? # don't run projects which have not enables shared runners - builds.includes(:project).where(ci_projects: { shared_runners_enabled: true }) + builds.joins(commit: { gl_project: :gitlab_ci_project }).where(ci_projects: { shared_runners_enabled: true }) else # do run projects which are only assigned to this runner - builds.where(project_id: current_runner.projects) + builds.joins(:commit).where(ci_commits: { gl_project_id: current_runner.gl_projects_ids }) end builds = builds.order('created_at ASC') @@ -19,7 +19,7 @@ module Ci build = builds.find do |build| (build.tag_list - current_runner.tag_list).empty? end - + if build # In case when 2 runners try to assign the same build, second runner will be declined diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 7aecee217d8..008833eed80 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -21,7 +21,7 @@ module Files create_target_branch end - if sha = commit + if commit success else error("Something went wrong. Your changes were not committed") diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 8193b6e192d..f9a8265d2d4 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -58,7 +58,7 @@ class GitPushService # If CI was disabled but .gitlab-ci.yml file was pushed # we enable CI automatically if !project.gitlab_ci? && gitlab_ci_yaml?(newrev) - project.enable_ci(user) + project.enable_ci end EventCreateService.new.push(project, user, @push_data) diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 98a67c0bc99..fcc0f2a6a8d 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -38,6 +38,10 @@ module MergeRequests } repository.merge(current_user, merge_request.source_sha, merge_request.target_branch, options) + rescue Exception => e + merge_request.update(merge_error: "Something went wrong during merge") + Rails.logger.error(e.message) + return false end def after_merge diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index e294b23bc23..a6b22348650 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -183,12 +183,12 @@ class NotificationService mailer.group_access_granted_email(group_member.id) end - def project_was_moved(project) + def project_was_moved(project, old_path_with_namespace) recipients = project.team.members recipients = reject_muted_users(recipients, project) recipients.each do |recipient| - mailer.project_was_moved_email(project.id, recipient.id) + mailer.project_was_moved_email(project.id, recipient.id, old_path_with_namespace) end end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index e54a13ed6c5..faf1ee008e7 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -62,7 +62,7 @@ module Projects after_create_actions if @project.persisted? @project - rescue => ex + rescue @project.errors.add(:base, "Can't save project. Please try again later") @project end diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index 2e995d6fd51..46374a3909a 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -18,7 +18,13 @@ module Projects if new_project.persisted? if @project.gitlab_ci? - @project.gitlab_ci_service.fork_registration(new_project, @current_user) + new_project.enable_ci + + settings = @project.gitlab_ci_project.attributes.select do |attr_name, value| + ["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name + end + + new_project.gitlab_ci_project.update(settings) end end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 550ed6897dd..c327c244f0d 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -38,7 +38,7 @@ module Projects project.save! # Notifications - project.send_move_instructions + project.send_move_instructions(old_path) # Move main repository unless gitlab_shell.mv_repository(old_path, new_path) diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index fc921a966f3..f8cd98f0ec4 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -2,7 +2,7 @@ %h3.page-title System OAuth applications %p.light - System OAuth application does not belong to certain user and can be managed only by admins + System OAuth applications don't belong to any user and can only be managed by admins %hr %p= link_to 'New Application', new_admin_application_path, class: 'btn btn-success' %table.table.table-striped diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index 9d5e934c8ba..4245d0f1eda 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -6,6 +6,8 @@ %span.cred (Admin) .pull-right + - unless @user == current_user + = link_to 'Log in as this user', login_as_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info" = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do %i.fa.fa-pencil-square-o Edit diff --git a/app/views/ci/admin/projects/_project.html.haml b/app/views/ci/admin/projects/_project.html.haml index c461206c72a..a342d6e1cf0 100644 --- a/app/views/ci/admin/projects/_project.html.haml +++ b/app/views/ci/admin/projects/_project.html.haml @@ -1,4 +1,4 @@ -- last_commit = project.last_commit +- last_commit = project.commits.last %tr %td = project.id diff --git a/app/views/ci/projects/show.html.haml b/app/views/ci/projects/show.html.haml index 6443378af99..888b1ea41d5 100644 --- a/app/views/ci/projects/show.html.haml +++ b/app/views/ci/projects/show.html.haml @@ -3,7 +3,7 @@ - if current_user && can?(current_user, :manage_project, gl_project) && !@project.any_runners? .alert.alert-danger Builds for this project wont be served unless you configure runners on - = link_to "Runners page", ci_project_runners_path(@project) + = link_to "Runners page", runners_path(@project.gl_project) %ul.nav.nav-tabs.append-bottom-20 %li{class: ref_tab_class} @@ -17,7 +17,7 @@ = link_to @ref, ci_project_path(@project, ref: @ref) %li.pull-right - = link_to 'View on GitLab', @project.gitlab_url, no_turbolink.merge( class: 'btn btn-sm' ) + = link_to 'Go to project', project_path(gl_project), class: 'btn btn-sm' - if @ref %p diff --git a/app/views/ci/shared/_guide.html.haml b/app/views/ci/shared/_guide.html.haml index 8a42f29b77c..db2d7f2f4b6 100644 --- a/app/views/ci/shared/_guide.html.haml +++ b/app/views/ci/shared/_guide.html.haml @@ -4,7 +4,7 @@ %ol %li Add at least one runner to the project. - Go to #{link_to 'Runners page', ci_project_runners_path(@project), target: :blank} for instructions. + Go to #{link_to 'Runners page', runners_path(@project.gl_project), target: :blank} for instructions. %li Put the .gitlab-ci.yml in the root of your repository. Examples can be found in #{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}. You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path} diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml index c8c315c73d8..e09e032a7f1 100644 --- a/app/views/dashboard/projects/_projects.html.haml +++ b/app/views/dashboard/projects/_projects.html.haml @@ -4,7 +4,7 @@ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' - if current_user.can_create_project? %span.input-group-btn - = link_to new_project_path, class: 'btn btn-success' do + = link_to new_project_path, class: 'btn btn-green' do New project = render 'shared/projects/list', projects: @projects, ci: true diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml index 339362701d4..f75f2e0a32a 100644 --- a/app/views/dashboard/projects/starred.html.haml +++ b/app/views/dashboard/projects/starred.html.haml @@ -3,6 +3,9 @@ = render 'dashboard/projects_head' +- if @last_push + = render "events/event_last_push", event: @last_push + - if @projects.any? = render 'projects' - else diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml index 29ffe8a8be3..535e85869e5 100644 --- a/app/views/devise/passwords/new.html.haml +++ b/app/views/devise/passwords/new.html.haml @@ -6,7 +6,7 @@ .devise-errors = devise_error_messages! .clearfix.append-bottom-20 - = f.email_field :email, placeholder: "Email", class: "form-control", required: true, value: params[:user_email] + = f.email_field :email, placeholder: "Email", class: "form-control", required: true, value: params[:user_email], autofocus: true .clearfix = f.submit "Reset password", class: "btn-primary btn" diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 9ac56b1e5fe..2b27a88794d 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -4,7 +4,7 @@ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control' - if can? current_user, :create_projects, @group %span.input-group-btn - = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-success' do + = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-green' do New project = render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml index 3c58f10e759..035fe0056d3 100644 --- a/app/views/layouts/_init_auto_complete.html.haml +++ b/app/views/layouts/_init_auto_complete.html.haml @@ -1,3 +1,4 @@ +- project = @target_project || @project :javascript - GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(@project.namespace, @project, type: @noteable.class, type_id: params[:id])}" + GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}" GitLab.GfmAutoComplete.setup(); diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 2468687b56d..1f4ade81ed2 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -25,5 +25,5 @@ = render "layouts/flash" %div{ class: container_class } .content - .clearfix + .clearfix.max-height = yield diff --git a/app/views/layouts/ci/_nav_project.html.haml b/app/views/layouts/ci/_nav_project.html.haml index 7daf9342e42..3a2741367c1 100644 --- a/app/views/layouts/ci/_nav_project.html.haml +++ b/app/views/layouts/ci/_nav_project.html.haml @@ -11,26 +11,11 @@ %span Commits %span.count= @project.commits.count - = nav_link path: ['runners#index', 'runners#show', 'runners#edit'] do - = link_to ci_project_runners_path(@project) do - = icon('cog fw') - %span - Runners - = nav_link path: 'variables#show' do - = link_to ci_project_variables_path(@project) do - = icon('code fw') - %span - Variables = nav_link path: 'web_hooks#index' do = link_to ci_project_web_hooks_path(@project) do = icon('link fw') %span Web Hooks - = nav_link path: 'triggers#index' do - = link_to ci_project_triggers_path(@project) do - = icon('retweet fw') - %span - Triggers = nav_link path: ['services#index', 'services#edit'] do = link_to ci_project_services_path(@project) do = icon('share fw') @@ -41,9 +26,3 @@ = icon('book fw') %span Events - %li.separate-item - = nav_link path: 'projects#edit' do - = link_to edit_ci_project_path(@project) do - = icon('cogs fw') - %span - Settings diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 21d8655131f..b1a1d531846 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -1,6 +1,6 @@ %ul.nav.nav-sidebar = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do - = link_to root_path, title: 'Projects', data: {placement: 'right'} do + = link_to dashboard_projects_path, title: 'Projects', data: {placement: 'right'} do = icon('home fw') %span Projects diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 857fb199957..26cccb48f68 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -34,3 +34,24 @@ %span Protected Branches + - if @project.gitlab_ci? + = nav_link(controller: :runners) do + = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners', data: {placement: 'right'} do + = icon('cog fw') + %span + Runners + = nav_link(controller: :variables) do + = link_to namespace_project_variables_path(@project.namespace, @project) do + = icon('code fw') + %span + Variables + = nav_link path: 'triggers#index' do + = link_to namespace_project_triggers_path(@project.namespace, @project) do + = icon('retweet fw') + %span + Triggers + = nav_link path: 'ci_settings#edit' do + = link_to edit_namespace_project_ci_settings_path(@project.namespace, @project) do + = icon('building fw') + %span + CI Settings diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index ec209c38eed..2f7d7e86f56 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -42,5 +42,3 @@ - else #{link_to "View it on GitLab", @target_url} = email_action @target_url - - if @project && !@disable_footer - You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} project team. diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index 78dafcd8bfa..abf73bcc709 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -3,10 +3,11 @@ - sidebar "project" unless sidebar - content_for :scripts_body_top do + - project = @target_project || @project - if current_user :javascript - window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}"; - window.markdown_preview_path = "#{markdown_preview_namespace_project_path(@project.namespace, @project)}"; + window.project_uploads_path = "#{namespace_project_uploads_path project.namespace,project}"; + window.markdown_preview_path = "#{markdown_preview_namespace_project_path(project.namespace, project)}"; - content_for :scripts_body do = render "layouts/init_auto_complete" if current_user diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml index 9db75bdb19e..34dbc60e19b 100644 --- a/app/views/notify/merged_merge_request_email.text.haml +++ b/app/views/notify/merged_merge_request_email.text.haml @@ -1,6 +1,6 @@ = "Merge Request ##{@merge_request.iid} was merged" -Merge Request Url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)} +Merge Request url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)} = merge_path_description(@merge_request, 'to') diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml index 3cd759f1f57..87b3ff7f0b3 100644 --- a/app/views/notify/project_was_moved_email.html.haml +++ b/app/views/notify/project_was_moved_email.html.haml @@ -1,5 +1,5 @@ %p - Project was moved to another location + Project #{@old_path_with_namespace} was moved to another location %p The project is now located under = link_to namespace_project_url(@project.namespace, @project) do diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb index b3f18b35a4d..d8a23dabf49 100644 --- a/app/views/notify/project_was_moved_email.text.erb +++ b/app/views/notify/project_was_moved_email.text.erb @@ -1,4 +1,4 @@ -Project was moved to another location +Project #{@old_path_with_namespace} was moved to another location The project is now located under <%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 6e53f55b0ab..8c0980369fd 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -16,18 +16,19 @@ .project-repo-buttons - = render 'projects/buttons/star' - - - unless empty_repo - = render 'projects/buttons/fork' - - - if can? current_user, :download_code, @project - = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do - = icon('download fw') - Download - + .split-one + = render 'projects/buttons/star' + + - unless empty_repo + = render 'projects/buttons/fork' + + = render "shared/clone_panel" + .split-repo-buttons + - unless empty_repo + - if can? current_user, :download_code, @project + = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do + = icon('download fw') + + = render 'projects/buttons/dropdown' = render 'projects/buttons/notifications' - - = render 'projects/buttons/dropdown' - - = render "shared/clone_panel" + diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml index 5038edb95ed..5bc1999ec9d 100644 --- a/app/views/projects/_readme.html.haml +++ b/app/views/projects/_readme.html.haml @@ -5,7 +5,7 @@ - if can?(current_user, :push_code, @project) = link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do - %i.fa.fa-pencil + %i.fa-align.fa.fa-pencil .wiki = cache(readme_cache_key) do = render_readme(readme) diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index bc7625e8989..4580c912692 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -1,6 +1,6 @@ - if current_user %span.dropdown - %a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"} + %a.dropdown-new.btn.btn-new{href: '#', "data-toggle" => "dropdown"} = icon('plus') %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown - if can?(current_user, :create_issue, @project) diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml index 854c154824d..8f2f631eb7d 100644 --- a/app/views/projects/buttons/_fork.html.haml +++ b/app/views/projects/buttons/_fork.html.haml @@ -8,6 +8,5 @@ - else = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn' do = icon('code-fork fw') - Fork %span.count = @project.forks_count diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index 57f764178d5..4b69a6d7a6f 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -5,7 +5,7 @@ = hidden_field_tag :notification_id, @membership.id = hidden_field_tag :notification_level %span.dropdown - %a.dropdown-toggle.btn.btn-new#notifications-button{href: '#', "data-toggle" => "dropdown"} + %a.dropdown-new.btn.btn-new#notifications-button{href: '#', "data-toggle" => "dropdown"} = icon('bell') = notification_label(@membership) = icon('angle-down') diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index 5d7df5ae099..3501dddefbe 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -1,10 +1,6 @@ - if current_user = link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star', method: :post, remote: true do = icon('star fw') - - if current_user.starred?(@project) - Unstar - - else - Star %span.count = @project.star_count @@ -17,6 +13,5 @@ - else = link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do = icon('star fw') - Star %span.count = @project.star_count diff --git a/app/views/ci/projects/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml index e782fd8a0f7..9f891f557a9 100644 --- a/app/views/ci/projects/_form.html.haml +++ b/app/views/projects/ci_settings/_form.html.haml @@ -1,17 +1,20 @@ +%h3.page-title + CI settings +%hr .bs-callout.help-callout %p If you want to test your .gitlab-ci.yml, you can use special tool - #{link_to "Lint", ci_lint_path} %p - Edit your - #{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@project)} + Edit your + #{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@ci_project)} -= nested_form_for [:ci, @project], html: { class: 'form-horizontal' } do |f| - - if @project.errors.any? += nested_form_for @ci_project, url: namespace_project_ci_settings_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f| + - if @ci_project.errors.any? #error_explanation - %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:" + %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:" .alert.alert-error %ul - - @project.errors.full_messages.each do |msg| + - @ci_project.errors.full_messages.each do |msg| %li= msg %fieldset @@ -93,8 +96,8 @@ = f.label :token, "CI token", class: 'control-label' .col-sm-10 = f.text_field :token, class: 'form-control', placeholder: 'xEeFCaDAB89' - + .form-actions = f.submit 'Save changes', class: 'btn btn-save' - - unless @project.new_record? - = link_to 'Remove Project', ci_project_path(@project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right' + - unless @ci_project.new_record? + = link_to 'Remove Project', ci_project_path(@ci_project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right' diff --git a/app/views/ci/projects/edit.html.haml b/app/views/projects/ci_settings/edit.html.haml index 876ae5182d4..e9040fe4337 100644 --- a/app/views/ci/projects/edit.html.haml +++ b/app/views/projects/ci_settings/edit.html.haml @@ -1,6 +1,6 @@ -- if @project.generated_yaml_config +- if @ci_project.generated_yaml_config %p.alert.alert-danger - CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@project)} + CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)} or %a.preview-yml{:href => "#yaml-content", "data-toggle" => "modal"} preview yaml file which is based on your old jobs. @@ -8,7 +8,7 @@ = render 'form' -- if @project.generated_yaml_config +- if @ci_project.generated_yaml_config #yaml-content.modal.fade{"aria-hidden" => "true", "aria-labelledby" => ".gitlab-ci.yml", :role => "dialog", :tabindex => "-1"} .modal-dialog .modal-content @@ -16,6 +16,6 @@ %button.close{"aria-hidden" => "true", "data-dismiss" => "modal", :type => "button"} × %h4.modal-title Content of .gitlab-ci.yml .modal-body - = text_area_tag :yaml, @project.generated_yaml_config, size: "70x25", class: "form-control" + = text_area_tag :yaml, @ci_project.generated_yaml_config, size: "70x25", class: "form-control" .modal-footer %button.btn.btn-default{"data-dismiss" => "modal", :type => "button"} Close diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index efad4cb1473..cddd5aa3a83 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -5,7 +5,7 @@ - note_count = notes.user.count - ci_commit = project.ci_commit(commit.sha) -- cache_key = [project.id, commit.id, note_count] +- cache_key = [project.path_with_namespace, commit.id, note_count] - cache_key.push(ci_commit.status) if ci_commit = cache(cache_key) do diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 2f24dc7c909..4f1965bfb39 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -1,21 +1,26 @@ - if params[:view] == 'parallel' - fluid_layout true +- diff_files = safe_diff_files(diffs) + .gray-content-block.second-block .inline-parallel-buttons .btn-group = inline_diff_btn = parallel_diff_btn - = render 'projects/diffs/stats', diffs: diffs - -- diff_files = safe_diff_files(diffs) + = render 'projects/diffs/stats', diff_files: diff_files - if diff_files.count < diffs.size = render 'projects/diffs/warning', diffs: diffs, shown_files_count: diff_files.count .files - diff_files.each_with_index do |diff_file, index| - = render 'projects/diffs/file', diff_file: diff_file, i: index, project: project + - diff_commit = commit_for_diff(diff_file.diff) + - blob = project.repository.blob_for_diff(diff_commit, diff_file.diff) + - next unless blob + + = render 'projects/diffs/file', i: index, project: project, + diff_file: diff_file, diff_commit: diff_commit, blob: blob - if @diff_timeout .alert.alert-danger diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 99ee23a1ddc..4617b188150 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -1,24 +1,18 @@ -- blob = project.repository.blob_for_diff(@commit, diff_file.diff) -- return unless blob -- blob_diff_path = namespace_project_blob_diff_path(project.namespace, project, tree_join(@commit.id, diff_file.file_path)) -.diff-file{id: "diff-#{i}", data: {blob_diff_path: blob_diff_path }} +.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)} .diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"} - - if diff_file.deleted_file - %span="#{diff_file.old_path} deleted" - - .diff-btn-group - - if @commit.parent_ids.present? - = view_file_btn(@commit.parent_id, diff_file, project) - - elsif diff_file.diff.submodule? + - if diff_file.diff.submodule? %span - submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path) = submodule_link(submodule_item, @commit.id, project.repository) - else %span - - if diff_file.renamed_file + - if diff_file.deleted_file + = "#{diff_file.old_path} deleted" + - elsif diff_file.renamed_file = "#{diff_file.old_path} renamed to #{diff_file.new_path}" - else = diff_file.new_path + - if diff_file.mode_changed? %span.file-mode= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}" @@ -28,12 +22,12 @@ %i.fa.fa-comments - - if @merge_request && @merge_request.source_project + - if editable_diff?(diff_file) = edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path, after: ' ', from_merge_request_id: @merge_request.id) - = view_file_btn(@commit.id, diff_file, project) + = view_file_btn(diff_commit.id, diff_file, project) .diff-content.diff-wrap-lines -# Skipp all non non-supported blobs diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml index c4d7f26430b..ea2a3e01277 100644 --- a/app/views/projects/diffs/_stats.html.haml +++ b/app/views/projects/diffs/_stats.html.haml @@ -2,37 +2,35 @@ .commit-stat-summary Showing = link_to '#', class: 'js-toggle-button' do - %strong #{pluralize(diffs.count, "changed file")} - - if current_controller?(:commit) - - unless @commit.has_zero_stats? - with - %strong.cgreen #{@commit.stats.additions} additions - and - %strong.cred #{@commit.stats.deletions} deletions + %strong #{pluralize(diff_files.count, "changed file")} + with + %strong.cgreen #{diff_files.sum(&:added_lines)} additions + and + %strong.cred #{diff_files.sum(&:removed_lines)} deletions .file-stats.js-toggle-content.hide %ul - - diffs.each_with_index do |diff, i| + - diff_files.each_with_index do |diff_file, i| %li - - if diff.deleted_file + - if diff_file.deleted_file %span.deleted-file %a{href: "#diff-#{i}"} %i.fa.fa-minus - = diff.old_path - - elsif diff.renamed_file + = diff_file.old_path + - elsif diff_file.renamed_file %span.renamed-file %a{href: "#diff-#{i}"} %i.fa.fa-minus - = diff.old_path + = diff_file.old_path → - = diff.new_path - - elsif diff.new_file + = diff_file.new_path + - elsif diff_file.new_file %span.new-file %a{href: "#diff-#{i}"} %i.fa.fa-plus - = diff.new_path + = diff_file.new_path - else %span.edit-file %a{href: "#diff-#{i}"} %i.fa.fa-adjust - = diff.new_path + = diff_file.new_path diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 185ebf23934..e06454fd148 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,7 +1,8 @@ -- if current_user && can?(current_user, :download_code, @project) - = render 'shared/no_ssh' - = render 'shared/no_password' - +.alert_holder + - if current_user && can?(current_user, :download_code, @project) + = render 'shared/no_ssh' + = render 'shared/no_password' + = render "home_panel" .gray-content-block.center @@ -15,38 +16,39 @@ file to this project. .prepend-top-20 -%h3.page-title - Command line instructions -%div.git-empty - %fieldset - %h5 Git global setup - %pre.light-well - :preserve - git config --global user.name "#{h git_user_name}" - git config --global user.email "#{h git_user_email}" +.empty_wrapper + %h3.page-title-empty + Command line instructions + %div.git-empty + %fieldset + %h5 Git global setup + %pre.light-well + :preserve + git config --global user.name "#{h git_user_name}" + git config --global user.email "#{h git_user_email}" - %fieldset - %h5 Create a new repository - %pre.light-well - :preserve - git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')} - cd #{h @project.path} - touch README.md - git add README.md - git commit -m "add README" - git push -u origin master + %fieldset + %h5 Create a new repository + %pre.light-well + :preserve + git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')} + cd #{h @project.path} + touch README.md + git add README.md + git commit -m "add README" + git push -u origin master - %fieldset - %h5 Existing folder or Git repository - %pre.light-well - :preserve - cd existing_folder - git init - git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')} - git add . - git commit - git push -u origin master + %fieldset + %h5 Existing folder or Git repository + %pre.light-well + :preserve + cd existing_folder + git init + git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')} + git add . + git commit + git push -u origin master -- if can? current_user, :remove_project, @project - .prepend-top-20 - = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right" + - if can? current_user, :remove_project, @project + .prepend-top-20 + = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right" diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 46aeecd8733..6244d3ba0b4 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -1,10 +1,11 @@ %h3.page-title New merge request %p.slead + - source_title, target_title = format_mr_branch_names(@merge_request) From - %strong.label-branch #{@merge_request.source_project_namespace}:#{@merge_request.source_branch} + %strong.label-branch #{source_title} %span into - %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch} + %strong.label-branch #{target_title} %span.pull-right = link_to 'Change branches', mr_change_branches_path(@merge_request) diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 9bfbde02ca2..1638ad6891a 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -14,10 +14,10 @@ = icon('trash-o') - unless note.system - - member = note.project.team.find_member(note.author.id) - - if member + - access = note.project.team.human_max_access(note.author.id) + - if access %span.note-role.label - = member.human_access + = access = link_to_member(note.project, note.author, avatar: false) @@ -59,7 +59,9 @@ .note-text = preserve do = markdown(note.note, {no_header_anchors: true}) - = render 'projects/notes/edit_form', note: note + - unless note.system? + -# System notes can't be edited + = render 'projects/notes/edit_form', note: note - if note.attachment.url .note-attachment diff --git a/app/views/ci/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml index ef8622e2807..e6b8a2e6fe7 100644 --- a/app/views/ci/runners/_runner.html.haml +++ b/app/views/projects/runners/_runner.html.haml @@ -3,9 +3,9 @@ = runner_status_icon(runner) %span.monospace - if @runners.include?(runner) - = link_to runner.short_sha, ci_project_runner_path(@project, runner) + = link_to runner.short_sha, runner_path(runner) %small - =link_to edit_ci_project_runner_path(@project, runner) do + =link_to edit_namespace_project_runner_path(@project.namespace, @project, runner) do %i.fa.fa-edit.btn - else = runner.short_sha @@ -13,12 +13,12 @@ .pull-right - if @runners.include?(runner) - if runner.belongs_to_one_project? - = link_to 'Remove runner', [:ci, @project, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' + = link_to 'Remove runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' - else - - runner_project = @project.runner_projects.find_by(runner_id: runner) - = link_to 'Disable for this project', [:ci, @project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' + - runner_project = @ci_project.runner_projects.find_by(runner_id: runner) + = link_to 'Disable for this project', [:ci, @ci_project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' - elsif runner.specific? - = form_for [:ci, @project, @project.runner_projects.new] do |f| + = form_for [:ci, @ci_project, @ci_project.runner_projects.new] do |f| = f.hidden_field :runner_id, value: runner.id = f.submit 'Enable for this project', class: 'btn btn-sm' .pull-right @@ -32,4 +32,3 @@ - runner.tag_list.each do |tag| %span.label.label-primary = tag - diff --git a/app/views/ci/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml index 944b3fd930d..316ea747b14 100644 --- a/app/views/ci/runners/_shared_runners.html.haml +++ b/app/views/projects/runners/_shared_runners.html.haml @@ -3,11 +3,11 @@ .bs-callout.bs-callout-warning GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X. %hr - - if @project.shared_runners_enabled - = link_to toggle_shared_runners_ci_project_path(@project), class: 'btn btn-warning', method: :post do + - if @ci_project.shared_runners_enabled + = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-warning', method: :post do Disable shared runners - else - = link_to toggle_shared_runners_ci_project_path(@project), class: 'btn btn-success', method: :post do + = link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-success', method: :post do Enable shared runners for this project @@ -17,7 +17,7 @@ - else %h4.underlined-title Available shared runners - #{@shared_runners_count} %ul.bordered-list.available-shared-runners - = render @shared_runners.first(10) + = render partial: 'runner', collection: @shared_runners, as: :runner - if @shared_runners_count > 10 .light and #{@shared_runners_count - 10} more... diff --git a/app/views/ci/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml index 0604e7a46c5..c13625c7e49 100644 --- a/app/views/ci/runners/_specific_runners.html.haml +++ b/app/views/projects/runners/_specific_runners.html.haml @@ -12,7 +12,7 @@ %code #{ci_root_url(only_path: false)} %li Use the following registration token during setup: - %code #{@project.token} + %code #{@ci_project.token} %li Start runner! @@ -20,10 +20,10 @@ - if @runners.any? %h4.underlined-title Runners activated for this project %ul.bordered-list.activated-specific-runners - = render @runners + = render partial: 'runner', collection: @runners, as: :runner - if @specific_runners.any? %h4.underlined-title Available specific runners %ul.bordered-list.available-specific-runners - = render @specific_runners + = render partial: 'runner', collection: @specific_runners, as: :runner = paginate @specific_runners diff --git a/app/views/ci/runners/edit.html.haml b/app/views/projects/runners/edit.html.haml index 81c8e58ae2b..66851d38316 100644 --- a/app/views/ci/runners/edit.html.haml +++ b/app/views/projects/runners/edit.html.haml @@ -1,6 +1,6 @@ %h4 Runner ##{@runner.id} %hr -= form_for [:ci, @project, @runner], html: { class: 'form-horizontal' } do |f| += form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f| .form-group = label :active, "Active", class: 'control-label' .col-sm-10 diff --git a/app/views/ci/runners/index.html.haml b/app/views/projects/runners/index.html.haml index 529fb9c296d..529fb9c296d 100644 --- a/app/views/ci/runners/index.html.haml +++ b/app/views/projects/runners/index.html.haml diff --git a/app/views/ci/runners/show.html.haml b/app/views/projects/runners/show.html.haml index ffec495f85a..ffec495f85a 100644 --- a/app/views/ci/runners/show.html.haml +++ b/app/views/projects/runners/show.html.haml diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 6a5fc689803..efa119edd5a 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -75,7 +75,7 @@ - if current_user - access = user_max_access_in_project(current_user, @project) - if access - .prepend-top-20 + .prepend-top-20.project-footer .gray-content-block.footer-block.center You have #{access} access to this project. - if @project.project_member_by_id(current_user) diff --git a/app/views/ci/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml index addfbfcb0d4..48b3b5c9920 100644 --- a/app/views/ci/triggers/_trigger.html.haml +++ b/app/views/projects/triggers/_trigger.html.haml @@ -11,4 +11,4 @@ %td .pull-right - = link_to 'Revoke', ci_project_trigger_path(@project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped" + = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped" diff --git a/app/views/ci/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml index 44374a1a4d5..17dcb78e256 100644 --- a/app/views/ci/triggers/index.html.haml +++ b/app/views/projects/triggers/index.html.haml @@ -12,11 +12,11 @@ %th Token %th Last used %th - = render @triggers + = render partial: 'trigger', collection: @triggers, as: :trigger - else %h4 No triggers -= form_for [:ci, @project, @trigger], html: { class: 'form-horizontal' } do |f| += form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create'), html: { class: 'form-horizontal' } do |f| .clearfix = f.submit "Add Trigger", class: 'btn btn-success pull-right' @@ -34,7 +34,7 @@ :plain curl -X POST \ -F token=TOKEN \ - #{ci_build_trigger_url(@project.id, 'REF_NAME')} + #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')} %h3 Use .gitlab-ci.yml @@ -49,7 +49,7 @@ trigger: type: deploy script: - - "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@project.id, 'REF_NAME')}" + - "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}" %h3 Pass build variables @@ -64,4 +64,4 @@ curl -X POST \ -F token=TOKEN \ -F "variables[RUN_NIGHTLY_BUILD]=true" \ - #{ci_build_trigger_url(@project.id, 'REF_NAME')} + #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')} diff --git a/app/views/ci/variables/show.html.haml b/app/views/projects/variables/show.html.haml index ebf68341e08..29416a94ff6 100644 --- a/app/views/ci/variables/show.html.haml +++ b/app/views/projects/variables/show.html.haml @@ -1,21 +1,21 @@ %h3.page-title Secret Variables -%p.light +%p.light These variables will be set to environment by the runner and will be hidden in the build log. %br - So you can use them for passwords, secret keys or whatever you want. + So you can use them for passwords, secret keys or whatever you want. %hr -= nested_form_for @project, url: url_for(controller: 'ci/variables', action: 'update'), html: { class: 'form-horizontal' } do |f| += nested_form_for @ci_project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f| - if @project.errors.any? #error_explanation - %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:" + %p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:" .alert.alert-error %ul - - @project.errors.full_messages.each do |msg| + - @ci_project.errors.full_messages.each do |msg| %li= msg = f.fields_for :variables do |variable_form| diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index 2cd422e772a..b23b2f0d5eb 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -24,4 +24,4 @@ .input-group-addon .visibility-level-label.has_tooltip{'data-title' => "#{visibility_level_label(project.visibility_level)} project" } = visibility_level_icon(project.visibility_level) - = visibility_level_label(project.visibility_level).downcase + diff --git a/app/views/shared/_field.html.haml b/app/views/shared/_field.html.haml index 45ec49280d2..8d6e16f74c3 100644 --- a/app/views/shared/_field.html.haml +++ b/app/views/shared/_field.html.haml @@ -8,7 +8,10 @@ - help = field[:help] .form-group - = form.label name, title, class: "control-label" + - if type == "password" && value.present? + = form.label name, "Change #{title}", class: "control-label" + - else + = form.label name, title, class: "control-label" .col-sm-10 - if type == 'text' = form.text_field name, class: "form-control", placeholder: placeholder @@ -19,6 +22,6 @@ - elsif type == 'select' = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } - elsif type == 'password' - = form.password_field name, value: value, class: 'form-control' + = form.password_field name, autocomplete: "new-password", class: 'form-control' - if help %span.help-block= help diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 37d5dba0330..11beb3e3239 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -19,14 +19,13 @@ = icon('user') Profile settings - elsif current_user - .pull-right - %span.dropdown - %a.light.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"} + .report_abuse.pull-right + - if @user.abuse_report + %span#report_abuse_btn.light.btn.btn-sm.btn-close{title: 'Already reported for abuse', data: {toggle: 'tooltip', placement: 'right', container: 'body'}} + = icon('exclamation-circle') + - else + %a.light.btn.btn-sm{href: new_abuse_report_path(user_id: @user.id), title: 'Report abuse', data: {toggle: 'tooltip', placement: 'right', container: 'body'}} = icon('exclamation-circle') - %ul.dropdown-menu.dropdown-menu-right - %li - = link_to new_abuse_report_path(user_id: @user.id) do - Report abuse .username @#{@user.username} diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 15930fc9079..4f7f0b6ef19 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -159,7 +159,7 @@ production: &base method: 'plain' # "tls" or "ssl" or "plain" bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' - + # This setting specifies if LDAP server is Active Directory LDAP server. # For non AD servers it skips the AD specific queries. # If your LDAP server is not AD, set this to false. @@ -204,13 +204,13 @@ production: &base # The username will be used in paths for the user's own projects # (like `gitlab.example.com/username/project`) and when mentioning # them in issues, merge request and comments (like `@username`). - # If the attribute specified for `username` contains an email address, + # If the attribute specified for `username` contains an email address, # the GitLab username will be the part of the email address before the '@'. username: ['uid', 'userid', 'sAMAccountName'] email: ['mail', 'email', 'userPrincipalName'] # If no full name could be found at the attribute specified for `name`, - # the full name is determined using the attributes specified for + # the full name is determined using the attributes specified for # `first_name` and `last_name`. name: 'cn' first_name: 'givenName' @@ -252,28 +252,28 @@ production: &base # arguments, followed by optional 'args' which can be either a hash or an array. # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html providers: - # - { name: 'google_oauth2', + # - { name: 'google_oauth2', # label: 'Google', - # app_id: 'YOUR_APP_ID', + # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', # args: { access_type: 'offline', approval_prompt: '' } } - # - { name: 'twitter', - # app_id: 'YOUR_APP_ID', + # - { name: 'twitter', + # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET' } - # - { name: 'github', + # - { name: 'github', # label: 'GitHub', - # app_id: 'YOUR_APP_ID', + # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', # args: { scope: 'user:email' } } - # - { name: 'gitlab', + # - { name: 'gitlab', # label: 'GitLab.com', - # app_id: 'YOUR_APP_ID', + # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', # args: { scope: 'api' } } - # - { name: 'bitbucket', - # app_id: 'YOUR_APP_ID', + # - { name: 'bitbucket', + # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET' } - # - { name: 'saml', + # - { name: 'saml', # label: 'Our SAML Provider', # args: { # assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', @@ -319,6 +319,8 @@ production: &base # # Use multipart uploads when file size reaches 100MB, see # # http://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html # multipart_chunk_size: 104857600 + # # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional + # # encryption: 'AES256' ## GitLab Shell settings gitlab_shell: @@ -422,7 +424,6 @@ test: user_filter: '' group_base: 'ou=groups,dc=example,dc=com' admin_group: '' - sync_ssh_keys: false staging: <<: *base diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 48601b67335..4e4a8ecbdb3 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -229,6 +229,7 @@ if Settings.backup['upload']['connection'] Settings.backup['upload']['connection'] = Hash[Settings.backup['upload']['connection'].map { |k, v| [k.to_sym, v] }] end Settings.backup['upload']['multipart_chunk_size'] ||= 104857600 +Settings.backup['upload']['encryption'] ||= nil # # Git diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 2ce24592f8b..29506970af2 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -148,6 +148,10 @@ Devise.setup do |config| # When someone else invites you to GitLab this time is also used so it should be pretty long. config.reset_password_within = 2.days + # When set to false, does not sign a user in automatically after their password is + # reset. Defaults to true, so a user is signed in automatically after a reset. + config.sign_in_after_reset_password = false + # ==> Configuration for :encryptable # Allow you to use another encryption algorithm besides bcrypt (default). You can use # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index d8bf0878a3d..22070e37f07 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -1,61 +1,63 @@ -# Additional translations at http://github.com/plataformatec/devise/wiki/I18n +# Additional translations at https://github.com/plataformatec/devise/wiki/I18n en: + devise: + confirmations: + confirmed: "Your email address has been successfully confirmed." + send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." + failure: + already_authenticated: "You are already signed in." + inactive: "Your account is not activated yet." + invalid: "Invalid %{authentication_keys} or password." + locked: "Your account is locked." + last_attempt: "You have one more attempt before your account is locked." + not_found_in_database: "Invalid %{authentication_keys} or password." + timeout: "Your session expired. Please sign in again to continue." + unauthenticated: "You need to sign in or sign up before continuing." + unconfirmed: "You have to confirm your email address before continuing." + mailer: + confirmation_instructions: + subject: "Confirmation instructions" + reset_password_instructions: + subject: "Reset password instructions" + unlock_instructions: + subject: "Unlock instructions" + password_change: + subject: "Password Changed" + omniauth_callbacks: + failure: "Could not authenticate you from %{kind} because \"%{reason}\"." + success: "Successfully authenticated from %{kind} account." + passwords: + no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." + recently_reset: "Instructions about how to reset your password have already been sent recently. Please wait a few minutes to try again." + send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." + updated: "Your password has been changed successfully. You are now signed in." + updated_not_active: "Your password has been changed successfully." + registrations: + destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." + signed_up: "Welcome! You have signed up successfully." + signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." + signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." + signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." + update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." + updated: "Your account has been updated successfully." + sessions: + signed_in: "Signed in successfully." + signed_out: "Signed out successfully." + already_signed_out: "Signed out successfully." + unlocks: + send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." + send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." + unlocked: "Your account has been unlocked successfully. Please sign in to continue." errors: messages: + already_confirmed: "was already confirmed, please try signing in" + confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" expired: "has expired, please request a new one" not_found: "not found" - already_confirmed: "was already confirmed, please try signing in" not_locked: "was not locked" not_saved: one: "1 error prohibited this %{resource} from being saved:" other: "%{count} errors prohibited this %{resource} from being saved:" - - devise: - failure: - already_authenticated: 'You are already signed in.' - unauthenticated: 'You need to sign in before continuing.' - unconfirmed: 'You have to confirm your account before continuing.' - locked: 'Your account is locked.' - not_found_in_database: 'Invalid email or password.' - invalid: 'Invalid email or password.' - invalid_token: 'Invalid authentication token.' - timeout: 'Your session expired, please sign in again to continue.' - inactive: 'Your account was not activated yet.' - sessions: - signed_in: '' - signed_out: '' - users_sessions: - user: - signed_in: 'Signed in successfully.' - passwords: - send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' - updated: 'Your password was changed successfully. You are now signed in.' - updated_not_active: 'Your password was changed successfully.' - send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." - no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." - confirmations: - send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' - send_paranoid_instructions: 'If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.' - confirmed: 'Your account was successfully confirmed. You are now signed in.' - registrations: - signed_up: 'Welcome! You have signed up successfully.' - updated: 'You updated your account successfully.' - destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' - signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.' - signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.' - signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.' - unlocks: - send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' - unlocked: 'Your account was successfully unlocked. You are now signed in.' - send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' - omniauth_callbacks: - success: 'Successfully authorized from %{kind} account.' - failure: 'Could not authorize you from %{kind} because "%{reason}".' - mailer: - confirmation_instructions: - subject: 'Confirmation instructions' - reset_password_instructions: - subject: 'Reset password instructions' - unlock_instructions: - subject: 'Unlock Instructions' diff --git a/config/routes.rb b/config/routes.rb index 4a07c449b4e..6d96d8801cd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,19 +53,9 @@ Gitlab::Application.routes.draw do end end - resources :triggers, only: [:index, :create, :destroy] - - resources :runners, only: [:index, :edit, :update, :destroy, :show] do - member do - get :resume - get :pause - end - end - resources :runner_projects, only: [:create, :destroy] resources :events, only: [:index] - resource :variables, only: [:show, :update] end resource :user_sessions do @@ -262,6 +252,7 @@ Gitlab::Application.routes.draw do put :unblock put :unlock put :confirm + post :login_as patch :disable_two_factor delete 'remove/:email_id', action: 'remove_email', as: 'remove_email' end @@ -597,6 +588,9 @@ Gitlab::Application.routes.draw do resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } + resource :variables, only: [:show, :update] + resources :triggers, only: [:index, :create, :destroy] + resource :ci_settings, only: [:edit, :update, :destroy] resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do member do @@ -652,8 +646,14 @@ Gitlab::Application.routes.draw do get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ } end end - end + resources :runners, only: [:index, :edit, :update, :destroy, :show] do + member do + get :resume + get :pause + end + end + end end end diff --git a/db/migrate/20150924125150_add_project_id_to_ci_commit.rb b/db/migrate/20150924125150_add_project_id_to_ci_commit.rb new file mode 100644 index 00000000000..1a761fe0f86 --- /dev/null +++ b/db/migrate/20150924125150_add_project_id_to_ci_commit.rb @@ -0,0 +1,5 @@ +class AddProjectIdToCiCommit < ActiveRecord::Migration + def up + add_column :ci_commits, :gl_project_id, :integer + end +end diff --git a/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb b/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb new file mode 100644 index 00000000000..2be57b6062e --- /dev/null +++ b/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb @@ -0,0 +1,6 @@ +class MigrateProjectIdForCiCommits < ActiveRecord::Migration + def up + subquery = 'SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = ci_commits.project_id' + execute("UPDATE ci_commits SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL") + end +end diff --git a/db/migrate/20150930001110_merge_request_error_field.rb b/db/migrate/20150930001110_merge_request_error_field.rb new file mode 100644 index 00000000000..c2ee498ef3f --- /dev/null +++ b/db/migrate/20150930001110_merge_request_error_field.rb @@ -0,0 +1,5 @@ +class MergeRequestErrorField < ActiveRecord::Migration + def up + add_column :merge_requests, :merge_error, :string + end +end diff --git a/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb b/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb new file mode 100644 index 00000000000..8d47dac6441 --- /dev/null +++ b/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb @@ -0,0 +1,9 @@ +class AddNullToNameForCiProjects < ActiveRecord::Migration + def up + change_column_null :ci_projects, :name, true + end + + def down + change_column_null :ci_projects, :name, false + end +end diff --git a/db/schema.rb b/db/schema.rb index 01ccda7a75e..72609da93f1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150920161119) do +ActiveRecord::Schema.define(version: 20150930095736) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -115,9 +115,10 @@ ActiveRecord::Schema.define(version: 20150920161119) do t.text "push_data" t.datetime "created_at" t.datetime "updated_at" - t.boolean "tag", default: false + t.boolean "tag", default: false t.text "yaml_errors" t.datetime "committed_at" + t.integer "gl_project_id" end add_index "ci_commits", ["project_id", "committed_at", "id"], name: "index_ci_commits_on_project_id_and_committed_at_and_id", using: :btree @@ -157,7 +158,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree create_table "ci_projects", force: true do |t| - t.string "name", null: false + t.string "name" t.integer "timeout", default: 3600, null: false t.datetime "created_at" t.datetime "updated_at" @@ -452,6 +453,7 @@ ActiveRecord::Schema.define(version: 20150920161119) do t.integer "position", default: 0 t.datetime "locked_at" t.integer "updated_by_id" + t.string "merge_error" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree diff --git a/doc/ci/api/projects.md b/doc/ci/api/projects.md index 54584db0938..5585191e826 100644 --- a/doc/ci/api/projects.md +++ b/doc/ci/api/projects.md @@ -100,8 +100,6 @@ Parameters: * `name` (required) - The name of the project * `gitlab_id` (required) - The ID of the project on the Gitlab instance - * `path` (required) - The gitlab project path - * `ssh_url_to_repo` (required) - The gitlab SSH url to the repo * `default_ref` (optional) - The branch to run on (default to `master`) ### Update Project @@ -114,9 +112,6 @@ authenticated user has access to. Parameters: * `name` - The name of the project - * `gitlab_id` - The ID of the project on the Gitlab instance - * `path` - The gitlab project path - * `ssh_url_to_repo` - The gitlab SSH url to the repo * `default_ref` - The branch to run on (default to `master`) ### Remove Project diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md index b904c70e980..493e1d1b09c 100644 --- a/doc/gitlab-basics/README.md +++ b/doc/gitlab-basics/README.md @@ -23,3 +23,5 @@ Step-by-step guides on the basics of working with Git and GitLab. * [Add an image](add-image.md) * [Create a Merge Request](add-merge-request.md) + +* [Create an Issue](create-issue.md) diff --git a/doc/gitlab-basics/create-issue.md b/doc/gitlab-basics/create-issue.md new file mode 100644 index 00000000000..87f078def04 --- /dev/null +++ b/doc/gitlab-basics/create-issue.md @@ -0,0 +1,27 @@ +# How to create an Issue in GitLab + +The Issue Tracker is a good place to add things that need to be improved or solved in a project. + +To create an Issue, sign in to GitLab. + +Go to the project where you'd like to create the Issue: + +![Select a project](basicsimages/select_project.png) + +Click on "Issues" on the left side of your screen: + +![Issues](basicsimages/issues.png) + +Click on the "+ new issue" button on the right side of your screen: + +![New issue](basicsimages/new_issue.png) + +Add a title and a description to your issue: + +![Issue title and description](basicsimages/issue_title.png) + +You may assign the Issue to a user, add a milestone and add labels (they are all optional). Then click on "submit new issue": + +![Submit new issue](basicsimages/submit_new_issue.png) + +Your Issue will now be added to the Issue Tracker and will be ready to be reviewed. You can comment on it and mention the people involved. You can also link Issues to the Merge Requests where the Issues are solved. To do this, you can use an [Issue closing pattern](http://doc.gitlab.com/ce/customization/issue_closing.html). diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md index f7d4f3de68b..548c484bc08 100644 --- a/doc/hooks/custom_hooks.md +++ b/doc/hooks/custom_hooks.md @@ -2,7 +2,7 @@ **Note: Custom git hooks must be configured on the filesystem of the GitLab server. Only GitLab server administrators will be able to complete these tasks. -Please explore webhooks as an option if you do not have filesystem access.** +Please explore webhooks as an option if you do not have filesystem access. For a user configurable Git Hooks interface, please see [GitLab Enterprise Edition Git Hooks](http://doc.gitlab.com/ee/git_hooks/git_hooks.html).** Git natively supports hooks that are executed on different actions. Examples of server-side git hooks include pre-receive, post-receive, and update. diff --git a/doc/install/installation.md b/doc/install/installation.md index 039bb3c2561..518b914fe67 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -115,8 +115,9 @@ Remove the old Ruby 1.8 if present Download Ruby and compile it: mkdir /tmp/ruby && cd /tmp/ruby - curl -L --progress http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.6.tar.gz | tar xz - cd ruby-2.1.6 + curl -O --progress https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.7.tar.gz + echo 'e2e195a4a58133e3ad33b955c829bb536fa3c075 ruby-2.1.7.tar.gz' | shasum -c - && tar xzf ruby-2.1.7.tar.gz + cd ruby-2.1.7 ./configure --disable-install-rdoc make sudo make install @@ -131,11 +132,11 @@ Since GitLab 8.0, Git HTTP requests are handled by gitlab-git-http-server. This is a small daemon written in Go. To install gitlab-git-http-server we need a Go compiler. - curl -O --progress https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz - echo '5817fa4b2252afdb02e11e8b9dc1d9173ef3bd5a go1.5.linux-amd64.tar.gz' | shasum -c - && \ - sudo tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz + curl -O --progress https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz + echo '46eecd290d8803887dec718c691cc243f2175fe0 go1.5.1.linux-amd64.tar.gz' | shasum -c - && \ + sudo tar -C /usr/local -xzf go1.5.1.linux-amd64.tar.gz sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/ - rm go1.5.linux-amd64.tar.gz + rm go1.5.1.linux-amd64.tar.gz ## 4. System Users diff --git a/doc/integration/ldap.md b/doc/integration/ldap.md index 3bc5df21ef4..9b7d8fa3969 100644 --- a/doc/integration/ldap.md +++ b/doc/integration/ldap.md @@ -173,3 +173,23 @@ Tip: if you want to limit access to the nested members of an Active Directory gr ``` Please note that GitLab does not support the custom filter syntax used by omniauth-ldap. + +## Limitations + +GitLab's LDAP client is based on [omniauth-ldap](https://gitlab.com/gitlab-org/omniauth-ldap) +which encapsulates Ruby's `Net::LDAP` class. It provides a pure-Ruby implementation +of the LDAP client protocol. As a result, GitLab is limited by `omniauth-ldap` and may impact your LDAP +server settings. + +### TLS Client Authentication +Not implemented by `Net::LDAP`. +So you should disable anonymous LDAP authentication and enable simple or SASL +authentication. TLS client authentication setting in your LDAP server cannot be +mandatory and clients cannot be authenticated with the TLS protocol. + +### TLS Server Authentication +Not supported by GitLab's configuration options. +When setting `method: ssl`, the underlying authentication method used by +`omniauth-ldap` is `simple_tls`. This method establishes TLS encryption with +the LDAP server before any LDAP-protocol data is exchanged but no validation of +the LDAP server's SSL certificate is performed.
\ No newline at end of file diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md index 2725bf343ee..1cb1bc2e762 100644 --- a/doc/migrate_ci_to_ce/README.md +++ b/doc/migrate_ci_to_ce/README.md @@ -36,6 +36,11 @@ mv /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds.$(date +%s) and run `sudo gitlab-ctl reconfigure`. +#### 0. Updating Omnibus from versions prior to 7.13 + +If you are updating from older versions you should first update to 7.14 and then to 8.0. +Otherwise it's pretty likely that you will encounter problems described in the [Troubleshooting](#troubleshooting). + #### 1. Verify that backups work Make sure that the backup script on both servers can connect to the database. @@ -43,6 +48,7 @@ Make sure that the backup script on both servers can connect to the database. ``` # On your CI server: # Omnibus +sudo chown gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds sudo gitlab-ci-rake backup:create # Source @@ -143,7 +149,7 @@ sudo gitlab-ctl stop ci-sidekiq # Source sudo service gitlab_ci stop cd /home/gitlab_ci/gitlab-ci -sudo -u gitlab_ci -H bundle exec whenever --clear-crontab +sudo -u gitlab_ci -H bundle exec whenever --clear-crontab RAILS_ENV=production ``` ### II. Moving data @@ -176,6 +182,7 @@ will need this file later. ``` # On your CI server: # Omnibus +sudo chown gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds sudo gitlab-ci-rake backup:create # Source @@ -222,6 +229,7 @@ be no CI data yet because you turned CI on the GitLab server off earlier. ``` # On your GitLab server: # Omnibus +sudo chown git:git /var/opt/gitlab/gitlab-ci/builds sudo gitlab-rake ci:migrate # Source @@ -319,3 +327,107 @@ You should also make sure that you can: If something went wrong and you need to restore a backup, consult the [Backup restoration](../raketasks/backup_restore.md) guide. + +### Troubleshooting + +#### show:secrets problem (Omnibus-only) +If you see errors like this: +``` +Missing `secret_key_base` or `db_key_base` for 'production' environment. The secrets will be generated and stored in `config/secrets.yml` +rake aborted! +Errno::EACCES: Permission denied @ rb_sysopen - config/secrets.yml +``` + +This can happen if you are updating from versions prior to 7.13 straight to 8.0. +The fix for this is to update to Omnibus 7.14 first and then update it to 8.0. + +#### Permission denied when accessing /var/opt/gitlab/gitlab-ci/builds +To fix that issue you have to change builds/ folder permission before doing final backup: +``` +sudo chown -R gitlab-ci:gitlab-ci /var/opt/gitlab/gitlab-ci/builds +``` + +Then before executing `ci:migrate` you need to fix builds folder permission: +``` +sudo chown git:git /var/opt/gitlab/gitlab-ci/builds +``` + +#### Problems when importing CI database to GitLab +If you were migrating CI database from MySQL to PostgreSQL manually you can see errros during import about missing sequences: +``` +ALTER SEQUENCE +ERROR: relation "ci_builds_id_seq" does not exist +ERROR: relation "ci_commits_id_seq" does not exist +ERROR: relation "ci_events_id_seq" does not exist +ERROR: relation "ci_jobs_id_seq" does not exist +ERROR: relation "ci_projects_id_seq" does not exist +ERROR: relation "ci_runner_projects_id_seq" does not exist +ERROR: relation "ci_runners_id_seq" does not exist +ERROR: relation "ci_services_id_seq" does not exist +ERROR: relation "ci_taggings_id_seq" does not exist +ERROR: relation "ci_tags_id_seq" does not exist +CREATE TABLE +``` + +To fix that you need to apply this SQL statement before doing final backup: +``` +# Omnibus +gitlab-ci-rails dbconsole <<EOF +-- ALTER TABLES - DROP DEFAULTS +ALTER TABLE ONLY ci_application_settings ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_builds ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_commits ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_events ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_jobs ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_projects ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_runner_projects ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_runners ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_services ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_taggings ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_tags ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_trigger_requests ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_triggers ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_variables ALTER COLUMN id DROP DEFAULT; +ALTER TABLE ONLY ci_web_hooks ALTER COLUMN id DROP DEFAULT; + +-- ALTER SEQUENCES +ALTER SEQUENCE ci_application_settings_id_seq OWNED BY ci_application_settings.id; +ALTER SEQUENCE ci_builds_id_seq OWNED BY ci_builds.id; +ALTER SEQUENCE ci_commits_id_seq OWNED BY ci_commits.id; +ALTER SEQUENCE ci_events_id_seq OWNED BY ci_events.id; +ALTER SEQUENCE ci_jobs_id_seq OWNED BY ci_jobs.id; +ALTER SEQUENCE ci_projects_id_seq OWNED BY ci_projects.id; +ALTER SEQUENCE ci_runner_projects_id_seq OWNED BY ci_runner_projects.id; +ALTER SEQUENCE ci_runners_id_seq OWNED BY ci_runners.id; +ALTER SEQUENCE ci_services_id_seq OWNED BY ci_services.id; +ALTER SEQUENCE ci_taggings_id_seq OWNED BY ci_taggings.id; +ALTER SEQUENCE ci_tags_id_seq OWNED BY ci_tags.id; +ALTER SEQUENCE ci_trigger_requests_id_seq OWNED BY ci_trigger_requests.id; +ALTER SEQUENCE ci_triggers_id_seq OWNED BY ci_triggers.id; +ALTER SEQUENCE ci_variables_id_seq OWNED BY ci_variables.id; +ALTER SEQUENCE ci_web_hooks_id_seq OWNED BY ci_web_hooks.id; + +-- ALTER TABLES - RE-APPLY DEFAULTS +ALTER TABLE ONLY ci_application_settings ALTER COLUMN id SET DEFAULT nextval('ci_application_settings_id_seq'::regclass); +ALTER TABLE ONLY ci_builds ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass); +ALTER TABLE ONLY ci_commits ALTER COLUMN id SET DEFAULT nextval('ci_commits_id_seq'::regclass); +ALTER TABLE ONLY ci_events ALTER COLUMN id SET DEFAULT nextval('ci_events_id_seq'::regclass); +ALTER TABLE ONLY ci_jobs ALTER COLUMN id SET DEFAULT nextval('ci_jobs_id_seq'::regclass); +ALTER TABLE ONLY ci_projects ALTER COLUMN id SET DEFAULT nextval('ci_projects_id_seq'::regclass); +ALTER TABLE ONLY ci_runner_projects ALTER COLUMN id SET DEFAULT nextval('ci_runner_projects_id_seq'::regclass); +ALTER TABLE ONLY ci_runners ALTER COLUMN id SET DEFAULT nextval('ci_runners_id_seq'::regclass); +ALTER TABLE ONLY ci_services ALTER COLUMN id SET DEFAULT nextval('ci_services_id_seq'::regclass); +ALTER TABLE ONLY ci_taggings ALTER COLUMN id SET DEFAULT nextval('ci_taggings_id_seq'::regclass); +ALTER TABLE ONLY ci_tags ALTER COLUMN id SET DEFAULT nextval('ci_tags_id_seq'::regclass); +ALTER TABLE ONLY ci_trigger_requests ALTER COLUMN id SET DEFAULT nextval('ci_trigger_requests_id_seq'::regclass); +ALTER TABLE ONLY ci_triggers ALTER COLUMN id SET DEFAULT nextval('ci_triggers_id_seq'::regclass); +ALTER TABLE ONLY ci_variables ALTER COLUMN id SET DEFAULT nextval('ci_variables_id_seq'::regclass); +ALTER TABLE ONLY ci_web_hooks ALTER COLUMN id SET DEFAULT nextval('ci_web_hooks_id_seq'::regclass); +EOF + +# Source +cd /home/gitlab_ci/gitlab-ci +sudo -u gitlab_ci -H bundle exec rails dbconsole production <<EOF +... COPY SQL STATEMENTS FROM ABOVE ... +EOF +``` diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 4ff5e74d438..db3f6bb40bd 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -7,7 +7,9 @@ A backup creates an archive file that contains the database, all repositories and all attachments. This archive will be saved in backup_path (see `config/gitlab.yml`). The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup. -You can only restore a backup to exactly the same version of GitLab that you created it on, for example 7.2.1. The best way to migrate your repositories from one server to another is through backup restore. +You can only restore a backup to exactly the same version of GitLab that you created it +on, for example 7.2.1. The best way to migrate your repositories from one server to +another is through backup restore. You need to keep a separate copy of `/etc/gitlab/gitlab-secrets.json` (for omnibus packages) or `/home/git/gitlab/.secret` (for installations @@ -95,6 +97,8 @@ For installations from source: aws_secret_access_key: 'secret123' # The remote 'directory' to store your backups. For S3, this would be the bucket name. remote_directory: 'my.s3.bucket' + # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional + # encryption: 'AES256' ``` If you are uploading your backups to S3 you will probably want to create a new @@ -369,7 +373,11 @@ For more information see similar questions on postgresql issue tracker[here](htt ## Note This documentation is for GitLab CE. -We backup GitLab.com and make sure your data is secure, but you can't use these methods -to export / backup your data yourself from GitLab.com. +We backup GitLab.com and make sure your data is secure, but you can't use these methods to export / backup your data yourself from GitLab.com. Issues are stored in the database. They can't be stored in Git itself. + +To migrate your repositories from one server to another with an up-to-date version of +GitLab, you can use the [import rake task](import.md) to do a mass import of the +repository. Note that if you do an import rake task, rather than a backup restore, you +will have all your repositories, but not any other data. diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md index 96d67f7b5d6..8fbcbb983e9 100644 --- a/doc/raketasks/cleanup.md +++ b/doc/raketasks/cleanup.md @@ -12,7 +12,8 @@ sudo gitlab-rake gitlab:cleanup:dirs bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production ``` -Remove repositories (global only for now) from `/home/git/repositories` if they don't exist in GitLab database. +Rename repositories from `/home/git/repositories` if they don't exist in GitLab database. +The repositories get a `+orphaned+TIMESTAMP` suffix so that they cannot block new repositories from being created. ``` # omnibus-gitlab diff --git a/doc/update/7.14-to-8.0.md b/doc/update/7.14-to-8.0.md index 86c0825dff9..0e65c32098c 100644 --- a/doc/update/7.14-to-8.0.md +++ b/doc/update/7.14-to-8.0.md @@ -101,7 +101,7 @@ EOF ``` If your Git repositories are in a directory other than `/home/git/repositories`, -you need to tell `gitlab-git-http-server` about it via `/etc/gitlab/default`. +you need to tell `gitlab-git-http-server` about it via `/etc/default/gitlab`. See `lib/support/init.d/gitlab.default.example` for the options. ### 6. Copy secrets @@ -168,6 +168,7 @@ git diff origin/7-14-stable:lib/support/nginx/gitlab origin/8-0-stable:lib/suppo ``` If you are using Apache instead of NGINX please see the updated [Apache templates](https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache). +Also note that because Apache does not support upstreams behind Unix sockets you will need to let gitlab-git-http-server listen on a TCP port. You can do this via [/etc/default/gitlab](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-0-stable/lib/support/init.d/gitlab.default.example#L34). ### 9. Migrate GitLab CI to GitLab CE/EE diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000000..e5a5d8dd53d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,2 @@ +app: + image: gitlab/gitlab-ce:latest diff --git a/docker/.dockerignore b/docker/.dockerignore deleted file mode 100644 index dd449725e18..00000000000 --- a/docker/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -*.md diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 304bb97409e..00000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM ubuntu:14.04 -MAINTAINER Sytse Sijbrandij - -# Install required packages -RUN apt-get update -q \ - && DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - ca-certificates \ - openssh-server \ - wget \ - apt-transport-https \ - vim \ - nano - -# Download & Install GitLab -# If you run GitLab Enterprise Edition point it to a location where you have downloaded it. -RUN echo "deb https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/gitlab_gitlab-ce.list -RUN wget -q -O - https://packages.gitlab.com/gpg.key | apt-key add - -RUN apt-get update && apt-get install -yq --no-install-recommends gitlab-ce - -# Manage SSHD through runit -RUN mkdir -p /opt/gitlab/sv/sshd/supervise \ - && mkfifo /opt/gitlab/sv/sshd/supervise/ok \ - && printf "#!/bin/sh\nexec 2>&1\numask 077\nexec /usr/sbin/sshd -D" > /opt/gitlab/sv/sshd/run \ - && chmod a+x /opt/gitlab/sv/sshd/run \ - && ln -s /opt/gitlab/sv/sshd /opt/gitlab/service \ - && mkdir -p /var/run/sshd - -# Disabling use DNS in ssh since it tends to slow connecting -RUN echo "UseDNS no" >> /etc/ssh/sshd_config - -# Prepare default configuration -RUN ( \ - echo "" && \ - echo "# Docker options" && \ - echo "# Prevent Postgres from trying to allocate 25% of total memory" && \ - echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb && \ - mkdir -p /assets/ && \ - cp /etc/gitlab/gitlab.rb /assets/gitlab.rb - -# Expose web & ssh -EXPOSE 443 80 22 - -# Define data volumes -VOLUME ["/etc/gitlab", "/var/opt/gitlab", "/var/log/gitlab"] - -# Copy assets -COPY assets/wrapper /usr/local/bin/ - -# Wrapper to handle signal, trigger runit and reconfigure GitLab -CMD ["/usr/local/bin/wrapper"] diff --git a/docker/README.md b/docker/README.md index e4d56cdb336..7514d610aec 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,169 +1,7 @@ # GitLab Docker images -The GitLab docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/). - -## After starting a container - -After starting a container you can go to [http://localhost:8080/](http://localhost:8080/) or [http://192.168.59.103:8080/](http://192.168.59.103:8080/) if you use boot2docker. - -It might take a while before the docker container is responding to queries. - -You can check the status with something like `sudo docker logs -f gitlab`. - -You can login to the web interface with username `root` and password `5iveL!fe`. - -Next time, you can just use docker start and stop to run the container. - -## Run the image - -Run the image: -```bash -sudo docker run --detach \ - --publish 8443:443 --publish 8080:80 --publish 2222:22 \ - --name gitlab \ - --restart always \ - --volume /srv/gitlab/config:/etc/gitlab \ - --volume /srv/gitlab/logs:/var/log/gitlab \ - --volume /srv/gitlab/data:/var/opt/gitlab \ - gitlab/gitlab-ce:latest -``` - -This will download and start GitLab CE container and publish ports needed to access SSH, HTTP and HTTPS. -All GitLab data will be stored as subdirectories of `/srv/gitlab/`. -The container will automatically `restart` after system reboot. - -After this you can login to the web interface as explained above in 'After starting a container'. - -## Where is the data stored? - -The GitLab container uses host mounted volumes to store persistent data: -- `/srv/gitlab/data` mounted as `/var/opt/gitlab` in the container is used for storing *application data* -- `/srv/gitlab/logs` mounted as `/var/log/gitlab` in the container is used for storing *logs* -- `/srv/gitlab/config` mounted as `/etc/gitlab` in the container is used for storing *configuration* - -You can fine tune these directories to meet your requirements. - -### Configure GitLab - -This container uses the official Omnibus GitLab distribution, so all configuration is done in the unique configuration file `/etc/gitlab/gitlab.rb`. - -To access GitLab configuration, you can start an bash in a new the context of running container, you will be able to browse all directories and use your favorite text editor: -```bash -sudo docker exec -it gitlab /bin/bash -``` - -You can also edit just `/etc/gitlab/gitlab.rb`: -```bash -sudo docker exec -it gitlab vi /etc/gitlab/gitlab.rb -``` - -**You should set the `external_url` to point to a valid URL.** - -**You may also be interesting in [Enabling HTTPS](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md#enable-https).** - -**To receive e-mails from GitLab you have to configure the [SMTP settings](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/smtp.md), -because Docker image doesn't have a SMTP server.** - -**Note** that GitLab will reconfigure itself **at each container start.** You will need to restart the container to reconfigure your GitLab: - -```bash -sudo docker restart gitlab -``` - -For more options for configuring the container please check [Omnibus GitLab documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#configuration). - -## Diagnose potential problems - -Read container logs: -```bash -sudo docker logs gitlab -``` - -Enter running container: -```bash -sudo docker exec -it gitlab /bin/bash -``` - -From within container you can administrer GitLab container as you would normally administer Omnibus installation: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md. - -### Upgrade GitLab to newer version - -To upgrade GitLab to new version you have to do: -1. pull new image, -```bash -sudo docker stop gitlab -``` - -1. stop running container, -```bash -sudo docker rm gitlab -``` - -1. remove existing container, -```bash -sudo docker pull gitlab/gitlab-ce:latest -``` - -1. create the container once again with previously specified options. -```bash -sudo docker run --detach \ - --publish 8443:443 --publish 8080:80 --publish 2222:22 \ - --name gitlab \ - --restart always \ - --volume /srv/gitlab/config:/etc/gitlab \ - --volume /srv/gitlab/logs:/var/log/gitlab \ - --volume /srv/gitlab/data:/var/opt/gitlab \ - gitlab/gitlab-ce:latest -``` - -On the first run GitLab will reconfigure and update itself. - -### Run GitLab CE on public IP address - -You can make Docker to use your IP address and forward all traffic to the GitLab CE container. -You can do that by modifying the `--publish` ([Binding container ports to the host](https://docs.docker.com/articles/networking/#binding-ports)): - -> --publish=[] : Publish a container᾿s port or a range of ports to the host format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort - -To expose GitLab CE on IP 1.1.1.1: - -```bash -sudo docker run --detach \ - --publish 1.1.1.1:443:443 --publish 1.1.1.1:80:80 --publish 1.1.1.1:22:22 \ - --name gitlab \ - --restart always \ - --volume /srv/gitlab/config:/etc/gitlab \ - --volume /srv/gitlab/logs:/var/log/gitlab \ - --volume /srv/gitlab/data:/var/opt/gitlab \ - gitlab/gitlab-ce:latest -``` - -You can then access GitLab instance at http://1.1.1.1/ and https://1.1.1.1/. - -### Build the image - -This guide will also let you know how to build docker image yourself. -Please run the command from the GitLab repo root directory. -People using boot2docker should run all the commands without sudo. - -```bash -sudo docker build --tag gitlab/gitlab-ce:latest docker/ -``` - -### Publish the image to Dockerhub - -- Ensure the containers are running -- Login to Dockerhub with `sudo docker login` - -```bash -sudo docker login -sudo docker push gitlab/gitlab-ce:latest -``` - -## Troubleshooting - -Please see the [troubleshooting](troubleshooting.md) file in this directory. - -Note: We use `fig.yml` to have compatibility with fig and because docker-compose also supports it. - -Our docker image runs chef at every start to generate GitLab configuration. +* The official GitLab Community Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/). +* The official GitLab Enterprise Edition Docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ee/). +* The complete usage guide can be found in [Using GitLab Docker images](http://doc.gitlab.com/omnibus/docker/) +* The Dockerfile used for building public images is in [Omnibus Repository](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker) +* Check the guide for [creating Omnibus-based Docker Image](http://doc.gitlab.com/omnibus/build/README.html#Build-Docker-image) diff --git a/docker/assets/wrapper b/docker/assets/wrapper deleted file mode 100755 index 8bc8370fbc9..00000000000 --- a/docker/assets/wrapper +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -function sigterm_handler() { - echo "SIGTERM signal received, try to gracefully shutdown all services..." - gitlab-ctl stop -} - -trap "sigterm_handler; exit" TERM - -function entrypoint() { - /opt/gitlab/embedded/bin/runsvdir-start & - gitlab-ctl reconfigure # will also start everything - gitlab-ctl tail # tail all logs -} - -if [[ ! -e /etc/gitlab/gitlab.rb ]]; then - cp /assets/gitlab.rb /etc/gitlab/gitlab.rb - chmod 0600 /etc/gitlab/gitlab.rb -fi - -entrypoint diff --git a/docker/fig.yml b/docker/fig.yml deleted file mode 100644 index 989551cbfe2..00000000000 --- a/docker/fig.yml +++ /dev/null @@ -1,2 +0,0 @@ -app: - build: . diff --git a/docker/marathon.json b/docker/marathon.json deleted file mode 100644 index 9b2091a8c22..00000000000 --- a/docker/marathon.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "id": "/gitlab", - "ports": [0,0], - "cpus": 2, - "mem": 2048.0, - "disk": 10240.0, - "container": { - "type": "DOCKER", - "docker": { - "network": "HOST", - "image": "gitlab/gitlab-ce:latest" - }, - "volumes": [ - { - "containerPath": "/etc/gitlab", - "hostPath": "/var/data/etc/gitlab", - "mode": "RW" - }, - { - "containerPath": "/var/opt/gitlab", - "hostPath": "/var/data/opt/gitlab", - "mode": "RW" - }, - { - "containerPath": "/var/log/gitlab", - "hostPath": "/var/data/log/gitlab", - "mode": "RW" - } - ] - } -}
\ No newline at end of file diff --git a/docker/troubleshooting.md b/docker/troubleshooting.md deleted file mode 100644 index 63482547daa..00000000000 --- a/docker/troubleshooting.md +++ /dev/null @@ -1,84 +0,0 @@ -# Troubleshooting - -This is to troubleshoot https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/245 -But it might contain useful commands for other cases as well. - -The configuration to add the postgres log in vim is: -postgresql['log_directory'] = '/var/log/gitlab/postgresql' - -# Commands - -```bash -sudo docker build --tag gitlab/gitlab-ce:latest docker/ - -sudo docker rm -f gitlab - -sudo docker exec -it gitlab vim /etc/gitlab/gitlab.rb - -sudo docker exec gitlab tail -f /var/log/gitlab/reconfigure.log - -sudo docker exec gitlab tail -f /var/log/gitlab/postgresql/current - -sudo docker exec gitlab cat /var/opt/gitlab/postgresql/data/postgresql.conf | grep shared_buffers - -sudo docker exec gitlab cat /etc/gitlab/gitlab.rb -``` - -# Interactively - -```bash -# First start a GitLab container without starting GitLab -# This is almost the same as starting the GitLab container except: -# - we run interactively (-t -i) -# - we define TERM=linux because it allows to use arrow keys in vi (!!!) -# - we choose another startup command (bash) -sudo docker run --ti \ - -e TERM=linux - --publish 80443:443 --publish 8080:80 --publish 2222:22 \ - --name gitlab \ - --restart always \ - --volume /srv/gitlab/config:/etc/gitlab \ - --volume /srv/gitlab/logs:/var/log/gitlab \ - --volume /srv/gitlab/data:/var/opt/gitlab \ - gitlab/gitlab-ce:latest \ - bash - -# Configure GitLab to redirect PostgreSQL logs -echo "postgresql['log_directory'] = '/var/log/gitlab/postgresql'" >> /etc/gitlab/gitlab.rb - -# Prevent Postgres from allocating 25% of total memory -echo "postgresql['shared_buffers'] = '1MB'" >> /etc/gitlab/gitlab.rb - -# You can now start GitLab manually from Bash (in the background) -# Maybe the command below is still missing something to run in the background -gitlab-ctl reconfigure > /var/log/gitlab/reconfigure.log & /opt/gitlab/embedded/bin/runsvdir-start & - -# Inspect PostgreSQL config -cat /var/opt/gitlab/postgresql/data/postgresql.conf | grep shared_buffers - -# And tail the logs (PostgreSQL log may not exist immediately) -tail -f /var/log/gitlab/reconfigure.log /var/log/gitlab/postgresql/current - -# And get the memory -cat /proc/meminfo -head /proc/sys/kernel/shmmax /proc/sys/kernel/shmall -free -m - -``` - -# Cleanup - -Remove ALL docker containers and images (also non GitLab ones). -**Be careful, because the `-v` also removes volumes attached to the images.** - -```bash -# Remove all containers with attached volumes -docker rm -v $(docker ps -a -q) - -# Remove all images -docker rmi $(docker images -q) - -# Remove GitLab persistent data -rm -rf /srv/gitlab -``` - diff --git a/features/abuse_report.feature b/features/abuse_report.feature index 3e1cb455b77..212972a762a 100644 --- a/features/abuse_report.feature +++ b/features/abuse_report.feature @@ -8,3 +8,10 @@ Feature: Abuse reports And I click "Report abuse" button When I fill and submit abuse form Then I should see success message + + Scenario: Report abuse available only once + Given I visit "Mike" user page + And I click "Report abuse" button + When I fill and submit abuse form + And I visit "Mike" user page + Then I should see a red "Report abuse" button diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 947f668e432..83055188bac 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -115,40 +115,40 @@ Feature: Project Merge Requests Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the Changes tab - And I leave a comment like "Line is wrong" on line 39 of the second file - And I click link "Hide inline discussion" of the second file - Then I should not see a comment like "Line is wrong here" in the second file + And I leave a comment like "Line is wrong" on line 39 of the third file + And I click link "Hide inline discussion" of the third file + Then I should not see a comment like "Line is wrong here" in the third file @javascript Scenario: I show comments on a merge request diff with comments in a single file Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the Changes tab - And I leave a comment like "Line is wrong" on line 39 of the second file - Then I should see a comment like "Line is wrong" in the second file + And I leave a comment like "Line is wrong" on line 39 of the third file + Then I should see a comment like "Line is wrong" in the third file @javascript Scenario: I hide comments on a merge request diff with comments in multiple files Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the Changes tab - And I leave a comment like "Line is correct" on line 12 of the first file - And I leave a comment like "Line is wrong" on line 39 of the second file - And I click link "Hide inline discussion" of the second file - Then I should not see a comment like "Line is wrong here" in the second file - And I should still see a comment like "Line is correct" in the first file + And I leave a comment like "Line is correct" on line 12 of the second file + And I leave a comment like "Line is wrong" on line 39 of the third file + And I click link "Hide inline discussion" of the third file + Then I should not see a comment like "Line is wrong here" in the third file + And I should still see a comment like "Line is correct" in the second file @javascript Scenario: I show comments on a merge request diff with comments in multiple files Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the Changes tab - And I leave a comment like "Line is correct" on line 12 of the first file - And I leave a comment like "Line is wrong" on line 39 of the second file - And I click link "Hide inline discussion" of the second file - And I click link "Show inline discussion" of the second file - Then I should see a comment like "Line is wrong" in the second file - And I should still see a comment like "Line is correct" in the first file + And I leave a comment like "Line is correct" on line 12 of the second file + And I leave a comment like "Line is wrong" on line 39 of the third file + And I click link "Hide inline discussion" of the third file + And I click link "Show inline discussion" of the third file + Then I should see a comment like "Line is wrong" in the third file + And I should still see a comment like "Line is correct" in the second file @javascript Scenario: I unfold diff @@ -163,8 +163,8 @@ Feature: Project Merge Requests Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the Changes tab - And I leave a comment like "Line is correct" on line 12 of the first file - And I leave a comment like "Line is wrong" on line 39 of the second file + And I leave a comment like "Line is correct" on line 12 of the second file + And I leave a comment like "Line is wrong" on line 39 of the third file And I click Side-by-side Diff tab Then I should see comments on the side-by-side diff page diff --git a/features/project/service.feature b/features/project/service.feature index fdff640ec85..5014b52b9f6 100644 --- a/features/project/service.feature +++ b/features/project/service.feature @@ -72,6 +72,7 @@ Feature: Project Services And I click Atlassian Bamboo CI service link And I fill Atlassian Bamboo CI settings Then I should see Atlassian Bamboo CI service settings saved + And I should see empty field Change Password Scenario: Activate jetBrains TeamCity CI service When I visit project "Shop" services page diff --git a/features/steps/abuse_reports.rb b/features/steps/abuse_reports.rb index 8f9ddb2899f..56652ff6f05 100644 --- a/features/steps/abuse_reports.rb +++ b/features/steps/abuse_reports.rb @@ -22,6 +22,10 @@ class Spinach::Features::AbuseReports < Spinach::FeatureSteps user_mike end + step 'I should see a red "Report abuse" button' do + expect(find(:css, '.report_abuse')).to have_selector(:css, 'span.btn-close') + end + def user_mike @user_mike ||= create(:user, name: 'Mike') end diff --git a/features/steps/groups.rb b/features/steps/groups.rb index 95bc9baf8d8..69ddfa42c06 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -282,9 +282,9 @@ class Spinach::Features::Groups < Spinach::FeatureSteps milestone1_project2 = create :milestone, title: "Version 7.2", project: project2 - milestone1_project3 = create :milestone, - title: "Version 7.2", - project: @project3 + create :milestone, + title: "Version 7.2", + project: @project3 milestone2_project1 = create :milestone, title: "GL-113", project: @project1 @@ -301,28 +301,28 @@ class Spinach::Features::Groups < Spinach::FeatureSteps assignee: current_user, author: current_user, milestone: milestone2_project1 - issue2 = create :issue, - project: project2, - assignee: current_user, - author: current_user, - milestone: milestone1_project2 - issue3 = create :issue, - project: @project3, - assignee: current_user, - author: current_user, - milestone: milestone1_project1 - mr1 = create :merge_request, - source_project: @project1, - target_project: @project1, - assignee: current_user, - author: current_user, - milestone: milestone2_project1 - mr2 = create :merge_request, - source_project: project2, - target_project: project2, - assignee: current_user, - author: current_user, - milestone: milestone2_project2 + create :issue, + project: project2, + assignee: current_user, + author: current_user, + milestone: milestone1_project2 + create :issue, + project: @project3, + assignee: current_user, + author: current_user, + milestone: milestone1_project1 + create :merge_request, + source_project: @project1, + target_project: @project1, + assignee: current_user, + author: current_user, + milestone: milestone2_project1 + create :merge_request, + source_project: project2, + target_project: project2, + assignee: current_user, + author: current_user, + milestone: milestone2_project2 @mr3 = create :merge_request, source_project: @project3, target_project: @project3, diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb index 56f1f06fb06..5ebc3a49760 100644 --- a/features/steps/project/commits/commits.rb +++ b/features/steps/project/commits/commits.rb @@ -103,8 +103,8 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps end step 'commit has ci status' do - @project.enable_ci(@user) - create :ci_commit, project: @project.gitlab_ci_project, sha: sample_commit.id + @project.enable_ci + create :ci_commit, gl_project: @project, sha: sample_commit.id end step 'I see commit ci info' do diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index 370960845cc..b0230add34f 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -5,8 +5,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps step 'I click link "Fork"' do expect(page).to have_content "Shop" - expect(page).to have_content "Fork" - click_link "Fork" + click_link "Fork project" end step 'I am a member of project "Shop"' do diff --git a/features/steps/project/graph.rb b/features/steps/project/graph.rb index 9453d636445..4abd5288d51 100644 --- a/features/steps/project/graph.rb +++ b/features/steps/project/graph.rb @@ -32,6 +32,6 @@ class Spinach::Features::ProjectGraph < Spinach::FeatureSteps end def project - project ||= Project.find_by(name: "Shop") + @project ||= Project.find_by(name: "Shop") end end diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index 239392eab96..af2da41badb 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -223,11 +223,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps end step 'project \'Shop\' has issue \'Bugfix1\' with description: \'Description for issue1\'' do - issue = create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project) + create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project) end step 'project \'Shop\' has issue \'Feature1\' with description: \'Feature submitted for issue1\'' do - issue = create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project) + create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project) end step 'I fill in issue search with \'Description for issue1\'' do diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index c92998631ff..875bf6c4676 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -224,43 +224,43 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end end - step 'I click link "Hide inline discussion" of the second file' do - page.within '.files [id^=diff]:nth-child(2)' do + step 'I click link "Hide inline discussion" of the third file' do + page.within '.files [id^=diff]:nth-child(3)' do find('.js-toggle-diff-comments').trigger('click') end end - step 'I click link "Show inline discussion" of the second file' do - page.within '.files [id^=diff]:nth-child(2)' do + step 'I click link "Show inline discussion" of the third file' do + page.within '.files [id^=diff]:nth-child(3)' do find('.js-toggle-diff-comments').trigger('click') end end - step 'I should not see a comment like "Line is wrong" in the second file' do - page.within '.files [id^=diff]:nth-child(2)' do + step 'I should not see a comment like "Line is wrong" in the third file' do + page.within '.files [id^=diff]:nth-child(3)' do expect(page).not_to have_visible_content "Line is wrong" end end - step 'I should see a comment like "Line is wrong" in the second file' do - page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do + step 'I should see a comment like "Line is wrong" in the third file' do + page.within '.files [id^=diff]:nth-child(3) .note-body > .note-text' do expect(page).to have_visible_content "Line is wrong" end end - step 'I should not see a comment like "Line is wrong here" in the second file' do - page.within '.files [id^=diff]:nth-child(2)' do + step 'I should not see a comment like "Line is wrong here" in the third file' do + page.within '.files [id^=diff]:nth-child(3)' do expect(page).not_to have_visible_content "Line is wrong here" end end - step 'I should see a comment like "Line is wrong here" in the second file' do - page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do + step 'I should see a comment like "Line is wrong here" in the third file' do + page.within '.files [id^=diff]:nth-child(3) .note-body > .note-text' do expect(page).to have_visible_content "Line is wrong here" end end - step 'I leave a comment like "Line is correct" on line 12 of the first file' do + step 'I leave a comment like "Line is correct" on line 12 of the second file' do init_diff_note_first_file page.within(".js-discussion-note-form") do @@ -268,12 +268,12 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps click_button "Add Comment" end - page.within ".files [id^=diff]:nth-child(1) .note-body > .note-text" do + page.within ".files [id^=diff]:nth-child(2) .note-body > .note-text" do expect(page).to have_content "Line is correct" end end - step 'I leave a comment like "Line is wrong" on line 39 of the second file' do + step 'I leave a comment like "Line is wrong" on line 39 of the third file' do init_diff_note_second_file page.within(".js-discussion-note-form") do @@ -282,8 +282,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end end - step 'I should still see a comment like "Line is correct" in the first file' do - page.within '.files [id^=diff]:nth-child(1) .note-body > .note-text' do + step 'I should still see a comment like "Line is correct" in the second file' do + page.within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do expect(page).to have_visible_content "Line is correct" end end @@ -303,7 +303,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see comments on the side-by-side diff page' do - page.within '.files [id^=diff]:nth-child(1) .parallel .note-body > .note-text' do + page.within '.files [id^=diff]:nth-child(2) .parallel .note-body > .note-text' do expect(page).to have_visible_content "Line is correct" end end diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb index 0e724138a8a..1ffd5cb9de5 100644 --- a/features/steps/project/redirects.rb +++ b/features/steps/project/redirects.rb @@ -39,7 +39,6 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps step 'Authenticate' do admin = create(:admin) - project = Project.find_by(name: 'Community') fill_in "user_login", with: admin.email fill_in "user_password", with: admin.password click_button "Sign in" @@ -54,7 +53,6 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps step 'I get redirected to signin page where I sign in' do admin = create(:admin) - project = Project.find_by(name: 'Enterprise') fill_in "user_login", with: admin.email fill_in "user_password", with: admin.password click_button "Sign in" diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb index d3b462bfd31..1c700df0c63 100644 --- a/features/steps/project/services.rb +++ b/features/steps/project/services.rb @@ -202,6 +202,10 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps expect(find_field('Username').value).to eq 'user' end + step 'I should see empty field Change Password' do + expect(find_field('Change Password').value).to be_nil + end + step 'I click JetBrains TeamCity CI service link' do click_link 'JetBrains TeamCity CI' end diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb index 2d17fb34ccb..83a04576973 100644 --- a/features/steps/shared/group.rb +++ b/features/steps/shared/group.rb @@ -37,7 +37,7 @@ module SharedGroup group = Group.find_by(name: groupname) || create(:group, name: groupname) group.add_user(user, role) project ||= create(:project, namespace: group, path: "project#{@project_count}") - event ||= create(:closed_issue_event, project: project) + create(:closed_issue_event, project: project) project.team << [user, :master] @project_count += 1 end diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index fa841f67510..5744e455ebd 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -199,11 +199,11 @@ module SharedProject step 'project "Shop" has CI enabled' do project = Project.find_by(name: "Shop") - project.enable_ci(@user) + project.enable_ci end step 'project "Shop" has CI build' do project = Project.find_by(name: "Shop") - create :ci_commit, project: project.gitlab_ci_project, sha: project.commit.sha + create :ci_commit, gl_project: project, sha: project.commit.sha end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 7fada98fcdc..549b1f9e9a7 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -63,11 +63,11 @@ module API user_project.build_missing_services service_method = "#{underscored_service}_service" - + send_service(service_method) end end - + @project_service || not_found!("Service") end @@ -149,7 +149,6 @@ module API end def attributes_for_keys(keys, custom_params = nil) - params_hash = custom_params || params attrs = {} keys.each do |key| if params[key].present? or (params.has_key?(key) and params[key] == false) diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index ac63f89c6ec..5c42f25f4a2 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -45,7 +45,8 @@ module Backup directory = connection.directories.get(remote_directory) if directory.files.create(key: tar_file, body: File.open(tar_file), public: false, - multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size) + multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size, + encryption: Gitlab.config.backup.upload.encryption) $progress.puts "done".green else puts "uploading backup to #{remote_directory} failed".red @@ -55,7 +56,7 @@ module Backup def cleanup $progress.print "Deleting tmp directories ... " - + backup_contents.each do |dir| next unless File.exist?(File.join(Gitlab.config.backup.path, dir)) @@ -75,7 +76,7 @@ module Backup if keep_time > 0 removed = 0 - + Dir.chdir(Gitlab.config.backup.path) do file_list = Dir.glob('*_gitlab_backup.tar') file_list.map! { |f| $1.to_i if f =~ /(\d+)_gitlab_backup.tar/ } diff --git a/lib/ci/api/projects.rb b/lib/ci/api/projects.rb index 66bcf65e8c4..d719ad9e8d5 100644 --- a/lib/ci/api/projects.rb +++ b/lib/ci/api/projects.rb @@ -75,23 +75,17 @@ module Ci # Create Gitlab CI project using Gitlab project info # # Parameters: - # name (required) - The name of the project # gitlab_id (required) - The gitlab id of the project - # path (required) - The gitlab project path, ex. randx/six - # ssh_url_to_repo (required) - The gitlab ssh url to the repo # default_ref - The branch to run against (defaults to `master`) # Example Request: # POST /projects post do - required_attributes! [:name, :gitlab_id, :ssh_url_to_repo] + required_attributes! [:gitlab_id] filtered_params = { - name: params[:name], gitlab_id: params[:gitlab_id], # we accept gitlab_url for backward compatibility for a while (added to 7.11) - path: params[:path] || params[:gitlab_url].sub(/.*\/(.*\/.*)$/, '\1'), - default_ref: params[:default_ref] || 'master', - ssh_url_to_repo: params[:ssh_url_to_repo] + default_ref: params[:default_ref] || 'master' } project = Ci::Project.new(filtered_params) @@ -109,11 +103,7 @@ module Ci # # Parameters: # id (required) - The ID of a project - # name - The name of the project - # gitlab_id - The gitlab id of the project - # path - The gitlab project path, ex. randx/six - # ssh_url_to_repo - The gitlab ssh url to the repo - # default_ref - The branch to run against (defaults to `master`) + # default_ref - The branch to run against (defaults to `master`) # Example Request: # PUT /projects/:id put ":id" do @@ -121,12 +111,7 @@ module Ci unauthorized! unless can?(current_user, :admin_project, project.gl_project) - attrs = attributes_for_keys [:name, :gitlab_id, :path, :gitlab_url, :default_ref, :ssh_url_to_repo] - - # we accept gitlab_url for backward compatibility for a while (added to 7.11) - if attrs[:gitlab_url] && !attrs[:path] - attrs[:path] = attrs[:gitlab_url].sub(/.*\/(.*\/.*)$/, '\1') - end + attrs = attributes_for_keys [:default_ref] if project.update_attributes(attrs) present project, with: Entities::Project diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 163937c02cf..f15b2cfd231 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -47,7 +47,7 @@ class EventFilter actions << Event::COMMENTED if filter.include? 'comments' - events = events.where(action: actions) + events.where(action: actions) end def options(key) diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb index 45bb904ed7a..8a7f8dc5003 100644 --- a/lib/gitlab/contributions_calendar.rb +++ b/lib/gitlab/contributions_calendar.rb @@ -12,7 +12,6 @@ module Gitlab @timestamps = {} date_from = 1.year.ago - date_to = Date.today events = Event.reorder(nil).contributions.where(author_id: user.id). where("created_at > ?", date_from).where(project_id: projects). diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 4daf65331e8..142058aa69d 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -44,6 +44,14 @@ module Gitlab diff.old_path end end + + def added_lines + diff_lines.select(&:added?).size + end + + def removed_lines + diff_lines.select(&:removed?).size + end end end end diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb index 8ac1b15e88a..0072194606e 100644 --- a/lib/gitlab/diff/line.rb +++ b/lib/gitlab/diff/line.rb @@ -7,6 +7,14 @@ module Gitlab @text, @type, @index = text, type, index @old_pos, @new_pos = old_pos, new_pos end + + def added? + type == 'new' + end + + def removed? + type == 'old' + end end end end diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb index c1d9520ddf1..7015fe36c3d 100644 --- a/lib/gitlab/diff/parser.rb +++ b/lib/gitlab/diff/parser.rb @@ -14,8 +14,6 @@ module Gitlab lines_arr = ::Gitlab::InlineDiff.processing lines lines_arr.each do |line| - raw_line = line.dup - next if filename?(line) full_line = html_escape(line.gsub(/\n/, '')) diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb index f02ea43910f..8b1b6f48ed5 100644 --- a/lib/gitlab/fogbugz_import/project_creator.rb +++ b/lib/gitlab/fogbugz_import/project_creator.rb @@ -23,7 +23,7 @@ module Gitlab import_url: Project::UNKNOWN_IMPORT_URL ).execute - import_data = project.create_import_data( + project.create_import_data( data: { 'repo' => repo.raw_data, 'user_map' => user_map, diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb index 0cfeaf9d61c..1cb7d16aeb3 100644 --- a/lib/gitlab/google_code_import/project_creator.rb +++ b/lib/gitlab/google_code_import/project_creator.rb @@ -23,7 +23,7 @@ module Gitlab import_url: repo.import_url ).execute - import_data = project.create_import_data( + project.create_import_data( data: { "repo" => repo.raw_data, "user_map" => user_map diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index cb66fd500fe..1ea7751e27d 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -14,7 +14,7 @@ module Gitlab # LDAP distinguished name is case-insensitive identity = ::Identity. where(provider: provider). - where('lower(extern_uid) = ?', uid.downcase).last + where('lower(extern_uid) = ?', uid.mb_chars.downcase.to_s).last identity && identity.user end end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index 6b1e3716147..9f5852ac613 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -46,43 +46,24 @@ namespace :gitlab do desc "GitLab | Cleanup | Clean repositories" task repos: :environment do warn_user_is_not_gitlab - remove_flag = ENV['REMOVE'] - - git_base_path = Gitlab.config.gitlab_shell.repos_path - all_dirs = Dir.glob(git_base_path + '/*') - - global_projects = Project.in_namespace(nil).pluck(:path) - - puts git_base_path.yellow - puts "Looking for global repos to remove... " - - # skip non git repo - all_dirs.select! do |dir| - dir =~ /.git$/ - end - - # skip existing repos - all_dirs.reject! do |dir| - repo_name = File.basename dir - path = repo_name.gsub(/\.git$/, "") - global_projects.include?(path) - end - all_dirs.each do |dir_path| - if remove_flag - if FileUtils.rm_rf dir_path - puts "Removed...#{dir_path}".red - else - puts "Cannot remove #{dir_path}".red - end - else - puts "Can be removed: #{dir_path}".red + move_suffix = "+orphaned+#{Time.now.to_i}" + repo_root = Gitlab.config.gitlab_shell.repos_path + # Look for global repos (legacy, depth 1) and normal repos (depth 2) + IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find| + find.each_line do |path| + path.chomp! + repo_with_namespace = path. + sub(repo_root, ''). + sub(%r{^/*}, ''). + chomp('.git'). + chomp('.wiki') + next if Project.find_with_namespace(repo_with_namespace) + new_path = path + move_suffix + puts path.inspect + ' -> ' + new_path.inspect + File.rename(path, new_path) end end - - unless remove_flag - puts "To cleanup this directories run this command with REMOVE=true".yellow - end end desc "GitLab | Cleanup | Block users that have been removed in LDAP" diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index c40b2c2a583..7168db117d6 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -7,6 +7,21 @@ describe Admin::UsersController do sign_in(admin) end + describe 'POST login_as' do + let(:user) { create(:user) } + + it 'logs admin as another user' do + expect(warden.authenticate(scope: :user)).not_to eq(user) + post :login_as, id: user.username + expect(warden.authenticate(scope: :user)).to eq(user) + end + + it 'redirects user to homepage' do + post :login_as, id: user.username + expect(response).to redirect_to(root_path) + end + end + describe 'DELETE #user with projects' do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } diff --git a/spec/controllers/ci/commits_controller_spec.rb b/spec/controllers/ci/commits_controller_spec.rb index b71e7505731..cc39ce7687c 100644 --- a/spec/controllers/ci/commits_controller_spec.rb +++ b/spec/controllers/ci/commits_controller_spec.rb @@ -1,14 +1,10 @@ require "spec_helper" describe Ci::CommitsController do - before do - @project = FactoryGirl.create :ci_project - end - describe "GET /status" do it "returns status of commit" do - commit = FactoryGirl.create :ci_commit, project: @project - get :status, id: commit.sha, ref_id: commit.ref, project_id: @project.id + commit = FactoryGirl.create :ci_commit + get :status, id: commit.sha, ref_id: commit.ref, project_id: commit.project.id expect(response).to be_success expect(response.code).to eq('200') @@ -16,8 +12,8 @@ describe Ci::CommitsController do end it "returns not_found status" do - commit = FactoryGirl.create :ci_commit, project: @project - get :status, id: commit.sha, ref_id: "deploy", project_id: @project.id + commit = FactoryGirl.create :ci_commit + get :status, id: commit.sha, ref_id: "deploy", project_id: commit.project.id expect(response).to be_success expect(response.code).to eq('200') diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 871b9219ca9..76d56bc989d 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -8,28 +8,34 @@ describe Projects::IssuesController do before do sign_in(user) project.team << [user, :developer] - controller.instance_variable_set(:@project, project) end describe "GET #index" do it "returns index" do - get :index, namespace_id: project.namespace.id, project_id: project.id + get :index, namespace_id: project.namespace.path, project_id: project.path expect(response.status).to eq(200) end + it "return 301 if request path doesn't match project path" do + get :index, namespace_id: project.namespace.path, project_id: project.path.upcase + + expect(response).to redirect_to(namespace_project_issues_path(project.namespace, project)) + end + it "returns 404 when issues are disabled" do project.issues_enabled = false project.save - get :index, namespace_id: project.namespace.id, project_id: project.id + get :index, namespace_id: project.namespace.path, project_id: project.path expect(response.status).to eq(404) end it "returns 404 when external issue tracker is enabled" do + controller.instance_variable_set(:@project, project) allow(project).to receive(:default_issues_tracker?).and_return(false) - get :index, namespace_id: project.namespace.id, project_id: project.id + get :index, namespace_id: project.namespace.path, project_id: project.path expect(response.status).to eq(404) end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 29233e9fae6..21beaf37fce 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -21,6 +21,20 @@ describe ProjectsController do expect(response.body).to include("content='#{content}'") end end + + context "when requested with case sensitive namespace and project path" do + it "redirects to the normalized path for case mismatch" do + get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase + + expect(response).to redirect_to("/#{public_project.path_with_namespace}") + end + + it "loads the page if normalized path matches request path" do + get :show, namespace_id: public_project.namespace.path, id: public_project.path + + expect(response.status).to eq(200) + end + end end describe "POST #toggle_star" do diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb index 64dfe8f34e3..5a104ae7c99 100644 --- a/spec/controllers/root_controller_spec.rb +++ b/spec/controllers/root_controller_spec.rb @@ -10,7 +10,7 @@ describe RootController do allow(subject).to receive(:current_user).and_return(user) end - context 'who has customized their dashboard setting' do + context 'who has customized their dashboard setting for starred projects' do before do user.update_attribute(:dashboard, 'stars') end @@ -21,6 +21,28 @@ describe RootController do end end + context 'who has customized their dashboard setting for project activities' do + before do + user.update_attribute(:dashboard, 'project_activity') + end + + it 'redirects to the activity list' do + get :index + expect(response).to redirect_to activity_dashboard_path + end + end + + context 'who has customized their dashboard setting for starred project activities' do + before do + user.update_attribute(:dashboard, 'starred_project_activity') + end + + it 'redirects to the activity list' do + get :index + expect(response).to redirect_to activity_dashboard_path(filter: 'starred') + end + end + context 'who uses the default dashboard setting' do it 'renders the default dashboard' do get :index diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb index 70930c789c3..9c7a0e9cbe0 100644 --- a/spec/factories/ci/commits.rb +++ b/spec/factories/ci/commits.rb @@ -51,6 +51,8 @@ FactoryGirl.define do } end + gl_project factory: :empty_project + factory :ci_commit_without_jobs do after(:create) do |commit, evaluator| commit.push_data[:ci_yaml_file] = YAML.dump({}) diff --git a/spec/factories/ci/projects.rb b/spec/factories/ci/projects.rb index e6bd0685f8d..111e1a82816 100644 --- a/spec/factories/ci/projects.rb +++ b/spec/factories/ci/projects.rb @@ -29,21 +29,9 @@ FactoryGirl.define do factory :ci_project_without_token, class: Ci::Project do - sequence :name do |n| - "GitLab / gitlab-shell#{n}" - end - default_ref 'master' - sequence :path do |n| - "gitlab/gitlab-shell#{n}" - end - - sequence :ssh_url_to_repo do |n| - "git@demo.gitlab.com:gitlab/gitlab-shell#{n}.git" - end - - gl_project factory: :project + gl_project factory: :empty_project factory :ci_project do token 'iPWx6WM4lhHNedGfBpPJNP' diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 86717761582..c2c7364f6c5 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -111,6 +111,27 @@ describe "Admin::Users", feature: true do expect(page).to have_content(@user.name) end + describe 'Login as another user' do + it 'should show login button for other users and check that it works' do + another_user = create(:user) + + visit admin_user_path(another_user) + + click_link 'Log in as this user' + + expect(page).to have_content("Logged in as #{another_user.username}") + + page.within '.sidebar-user .username' do + expect(page).to have_content(another_user.username) + end + end + + it 'should not show login button for admin itself' do + visit admin_user_path(@user) + expect(page).not_to have_content('Log in as this user') + end + end + describe 'Two-factor Authentication status' do it 'shows when enabled' do @user.update_attribute(:two_factor_enabled, true) diff --git a/spec/features/ci/admin/builds_spec.rb b/spec/features/ci/admin/builds_spec.rb index 88ef9c144af..623d466c67b 100644 --- a/spec/features/ci/admin/builds_spec.rb +++ b/spec/features/ci/admin/builds_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' describe "Admin Builds" do - let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit) { FactoryGirl.create :ci_commit } let(:build) { FactoryGirl.create :ci_build, commit: commit } before do @@ -22,10 +21,10 @@ describe "Admin Builds" do describe "Tabs" do it "shows all builds" do - build = FactoryGirl.create :ci_build, commit: commit, status: "pending" - build1 = FactoryGirl.create :ci_build, commit: commit, status: "running" - build2 = FactoryGirl.create :ci_build, commit: commit, status: "success" - build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed" + FactoryGirl.create :ci_build, commit: commit, status: "pending" + FactoryGirl.create :ci_build, commit: commit, status: "running" + FactoryGirl.create :ci_build, commit: commit, status: "success" + FactoryGirl.create :ci_build, commit: commit, status: "failed" visit ci_admin_builds_path diff --git a/spec/features/ci/admin/runners_spec.rb b/spec/features/ci/admin/runners_spec.rb index b25121f0806..b83744f53a8 100644 --- a/spec/features/ci/admin/runners_spec.rb +++ b/spec/features/ci/admin/runners_spec.rb @@ -2,8 +2,7 @@ require 'spec_helper' describe "Admin Runners" do before do - skip_ci_admin_auth - login_as :user + login_as :admin end describe "Runners page" do @@ -20,16 +19,16 @@ describe "Admin Runners" do describe 'search' do before do - FactoryGirl.create :ci_runner, description: 'foo' - FactoryGirl.create :ci_runner, description: 'bar' + FactoryGirl.create :ci_runner, description: 'runner-foo' + FactoryGirl.create :ci_runner, description: 'runner-bar' search_form = find('#runners-search') - search_form.fill_in 'search', with: 'foo' + search_form.fill_in 'search', with: 'runner-foo' search_form.click_button 'Search' end - it { expect(page).to have_content("foo") } - it { expect(page).not_to have_content("bar") } + it { expect(page).to have_content("runner-foo") } + it { expect(page).not_to have_content("runner-bar") } end end @@ -37,8 +36,8 @@ describe "Admin Runners" do let(:runner) { FactoryGirl.create :ci_runner } before do - FactoryGirl.create(:ci_project, name: "foo") - FactoryGirl.create(:ci_project, name: "bar") + @project1 = FactoryGirl.create(:ci_project) + @project2 = FactoryGirl.create(:ci_project) visit ci_admin_runner_path(runner) end @@ -47,19 +46,19 @@ describe "Admin Runners" do end describe 'projects' do - it { expect(page).to have_content("foo") } - it { expect(page).to have_content("bar") } + it { expect(page).to have_content(@project1.name_with_namespace) } + it { expect(page).to have_content(@project2.name_with_namespace) } end describe 'search' do before do search_form = find('#runner-projects-search') - search_form.fill_in 'search', with: 'foo' + search_form.fill_in 'search', with: @project1.gl_project.name search_form.click_button 'Search' end - it { expect(page).to have_content("foo") } - it { expect(page).not_to have_content("bar") } + it { expect(page).to have_content(@project1.name_with_namespace) } + it { expect(page).not_to have_content(@project2.name_with_namespace) } end end end diff --git a/spec/features/ci/builds_spec.rb b/spec/features/ci/builds_spec.rb index 2f020e524e2..d65699dbefa 100644 --- a/spec/features/ci/builds_spec.rb +++ b/spec/features/ci/builds_spec.rb @@ -3,16 +3,15 @@ require 'spec_helper' describe "Builds" do context :private_project do before do - @project = FactoryGirl.create :ci_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit @build = FactoryGirl.create :ci_build, commit: @commit login_as :user - @project.gl_project.team << [@user, :master] + @commit.project.gl_project.team << [@user, :master] end describe "GET /:project/builds/:id" do before do - visit ci_project_build_path(@project, @build) + visit ci_project_build_path(@commit.project, @build) end it { expect(page).to have_content @commit.sha[0..7] } @@ -23,7 +22,7 @@ describe "Builds" do describe "GET /:project/builds/:id/cancel" do before do @build.run! - visit cancel_ci_project_build_path(@project, @build) + visit cancel_ci_project_build_path(@commit.project, @build) end it { expect(page).to have_content 'canceled' } @@ -33,7 +32,7 @@ describe "Builds" do describe "POST /:project/builds/:id/retry" do before do @build.cancel! - visit ci_project_build_path(@project, @build) + visit ci_project_build_path(@commit.project, @build) click_link 'Retry' end @@ -45,13 +44,15 @@ describe "Builds" do context :public_project do describe "Show page public accessible" do before do - @project = FactoryGirl.create :ci_public_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit + @commit.project.public = true + @commit.project.save + @runner = FactoryGirl.create :ci_specific_runner @build = FactoryGirl.create :ci_build, commit: @commit, runner: @runner stub_gitlab_calls - visit ci_project_build_path(@project, @build) + visit ci_project_build_path(@commit.project, @build) end it { expect(page).to have_content @commit.sha[0..7] } diff --git a/spec/features/ci/commits_spec.rb b/spec/features/ci/commits_spec.rb index 40a62ca4574..657a9dabe9e 100644 --- a/spec/features/ci/commits_spec.rb +++ b/spec/features/ci/commits_spec.rb @@ -5,11 +5,10 @@ describe "Commits" do context "Authenticated user" do before do - @project = FactoryGirl.create :ci_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit @build = FactoryGirl.create :ci_build, commit: @commit login_as :user - @project.gl_project.team << [@user, :master] + @commit.project.gl_project.team << [@user, :master] end describe "GET /:project/commits/:sha" do @@ -51,8 +50,10 @@ describe "Commits" do context "Public pages" do before do - @project = FactoryGirl.create :ci_public_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit + @commit.project.public = true + @commit.project.save + @build = FactoryGirl.create :ci_build, commit: @commit end diff --git a/spec/features/ci/projects_spec.rb b/spec/features/ci/projects_spec.rb index 7c8cd1ce5c7..c633acf85fb 100644 --- a/spec/features/ci/projects_spec.rb +++ b/spec/features/ci/projects_spec.rb @@ -17,22 +17,4 @@ describe "Projects" do it { expect(page).to have_content @project.name } it { expect(page).to have_content 'All commits' } end - - describe "GET /ci/projects/:id/edit" do - before do - visit edit_ci_project_path(@project) - end - - it { expect(page).to have_content @project.name } - it { expect(page).to have_content 'Build Schedule' } - - it "updates configuration" do - fill_in 'Timeout', with: '70' - click_button 'Save changes' - - expect(page).to have_content 'was successfully updated' - - expect(find_field('Timeout').value).to eq '70' - end - end end diff --git a/spec/features/ci_settings_spec.rb b/spec/features/ci_settings_spec.rb new file mode 100644 index 00000000000..7e25e883018 --- /dev/null +++ b/spec/features/ci_settings_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe "CI settings" do + let(:user) { create(:user) } + before { login_as(user) } + + before do + @project = FactoryGirl.create :ci_project + @gl_project = @project.gl_project + @gl_project.team << [user, :master] + visit edit_namespace_project_ci_settings_path(@gl_project.namespace, @gl_project) + end + + it { expect(page).to have_content 'Build Schedule' } + + it "updates configuration" do + fill_in 'Timeout', with: '70' + click_button 'Save changes' + expect(page).to have_content 'was successfully updated' + expect(find_field('Timeout').value).to eq '70' + end +end diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index cef432e512b..922c76285d1 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -95,7 +95,7 @@ feature 'Login', feature: true do user = create(:user, password: 'not-the-default') login_with(user) - expect(page).to have_content('Invalid email or password.') + expect(page).to have_content('Invalid login or password.') end end end diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb index 2b6311e4fd7..85e70b4d47f 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/features/password_reset_spec.rb @@ -1,53 +1,43 @@ require 'spec_helper' feature 'Password reset', feature: true do - def forgot_password - click_on 'Forgot your password?' - fill_in 'Email', with: user.email - click_button 'Reset password' - user.reload - end - - def get_reset_token - mail = ActionMailer::Base.deliveries.last - body = mail.body.encoded - body.scan(/reset_password_token=(.+)\"/).flatten.first - end - - def reset_password(password = 'password') - visit edit_user_password_path(reset_password_token: get_reset_token) + describe 'throttling' do + it 'sends reset instructions when not previously sent' do + visit root_path + forgot_password(create(:user)) - fill_in 'New password', with: password - fill_in 'Confirm new password', with: password - click_button 'Change your password' - end + expect(page).to have_content(I18n.t('devise.passwords.send_instructions')) + expect(current_path).to eq new_user_session_path + end - describe 'with two-factor authentication' do - let(:user) { create(:user, :two_factor) } + it 'sends reset instructions when previously sent more than a minute ago' do + user = create(:user) + user.send_reset_password_instructions + user.update_attribute(:reset_password_sent_at, 5.minutes.ago) - it 'requires login after password reset' do visit root_path + forgot_password(user) - forgot_password - reset_password - - expect(page).to have_content("Your password was changed successfully.") - expect(page).not_to have_content("You are now signed in.") + expect(page).to have_content(I18n.t('devise.passwords.send_instructions')) expect(current_path).to eq new_user_session_path end - end - describe 'without two-factor authentication' do - let(:user) { create(:user) } + it "throttles multiple resets in a short timespan" do + user = create(:user) + user.send_reset_password_instructions - it 'automatically logs in after password reset' do visit root_path + forgot_password(user) - forgot_password - reset_password - - expect(current_path).to eq root_path - expect(page).to have_content("Your password was changed successfully. You are now signed in.") + expect(page).to have_content(I18n.t('devise.passwords.recently_reset')) + expect(current_path).to eq new_user_password_path end end + + def forgot_password(user) + click_on 'Forgot your password?' + fill_in 'Email', with: user.email + click_button 'Reset password' + user.reload + end end diff --git a/spec/features/ci/runners_spec.rb b/spec/features/runners_spec.rb index 15147f15eb3..06adb7633b2 100644 --- a/spec/features/ci/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -1,11 +1,10 @@ require 'spec_helper' describe "Runners" do - let(:user) { create(:user) } + include GitlabRoutingHelper - before do - login_as(user) - end + let(:user) { create(:user) } + before { login_as(user) } describe "specific runners" do before do @@ -20,18 +19,17 @@ describe "Runners" do @specific_runner2 = FactoryGirl.create :ci_specific_runner @project.runners << @specific_runner @project2.runners << @specific_runner2 + + visit runners_path(@project.gl_project) end it "places runners in right places" do - visit ci_project_runners_path(@project) expect(page.find(".available-specific-runners")).to have_content(@specific_runner2.display_name) expect(page.find(".activated-specific-runners")).to have_content(@specific_runner.display_name) expect(page.find(".available-shared-runners")).to have_content(@shared_runner.display_name) end it "enables specific runner for project" do - visit ci_project_runners_path(@project) - within ".available-specific-runners" do click_on "Enable for this project" end @@ -41,8 +39,7 @@ describe "Runners" do it "disables specific runner for project" do @project2.runners << @specific_runner - - visit ci_project_runners_path(@project) + visit runners_path(@project.gl_project) within ".activated-specific-runners" do click_on "Disable for this project" @@ -52,8 +49,6 @@ describe "Runners" do end it "removes specific runner for project if this is last project for that runners" do - visit ci_project_runners_path(@project) - within ".activated-specific-runners" do click_on "Remove runner" end @@ -66,13 +61,11 @@ describe "Runners" do before do @project = FactoryGirl.create :ci_project @project.gl_project.team << [user, :master] + visit runners_path(@project.gl_project) end it "enables shared runners" do - visit ci_project_runners_path(@project) - click_on "Enable shared runners" - expect(@project.reload.shared_runners_enabled).to be_truthy end end @@ -83,13 +76,11 @@ describe "Runners" do @project.gl_project.team << [user, :master] @specific_runner = FactoryGirl.create :ci_specific_runner @project.runners << @specific_runner + visit runners_path(@project.gl_project) end it "shows runner information" do - visit ci_project_runners_path(@project) - click_on @specific_runner.short_sha - expect(page).to have_content(@specific_runner.platform) end end diff --git a/spec/features/ci/triggers_spec.rb b/spec/features/triggers_spec.rb index c6afeb74628..69492d58878 100644 --- a/spec/features/ci/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -1,13 +1,14 @@ require 'spec_helper' describe 'Triggers' do - let(:user) { create(:user) } + let(:user) { create(:user) } + before { login_as(user) } before do - login_as(user) @project = FactoryGirl.create :ci_project - @project.gl_project.team << [user, :master] - visit ci_project_triggers_path(@project) + @gl_project = @project.gl_project + @gl_project.team << [user, :master] + visit namespace_project_triggers_path(@gl_project.namespace, @gl_project) end context 'create a trigger' do diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index efcb8a31abe..c1248162031 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Users', feature: true do + let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') } + scenario 'GET /users/sign_in creates a new user account' do visit new_user_session_path fill_in 'user_name', with: 'Name Surname' @@ -11,7 +13,6 @@ feature 'Users', feature: true do end scenario 'Successful user signin invalidates password reset token' do - user = create(:user) expect(user.reset_password_token).to be_nil visit new_user_password_path @@ -28,7 +29,6 @@ feature 'Users', feature: true do expect(user.reset_password_token).to be_nil end - let!(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') } scenario 'Should show one error if email is already taken' do visit new_user_session_path fill_in 'user_name', with: 'Another user name' diff --git a/spec/features/ci/variables_spec.rb b/spec/features/variables_spec.rb index e387b3be555..adb602f3edd 100644 --- a/spec/features/ci/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -1,28 +1,25 @@ require 'spec_helper' describe "Variables" do - let(:user) { create(:user) } - - before do - login_as(user) - end + let(:user) { create(:user) } + before { login_as(user) } describe "specific runners" do before do @project = FactoryGirl.create :ci_project - @project.gl_project.team << [user, :master] + @gl_project = @project.gl_project + @gl_project.team << [user, :master] end it "creates variable", js: true do - visit ci_project_variables_path(@project) + visit namespace_project_variables_path(@gl_project.namespace, @gl_project) click_on "Add a variable" fill_in "Key", with: "SECRET_KEY" fill_in "Value", with: "SECRET_VALUE" click_on "Save changes" - + expect(page).to have_content("Variables were successfully updated.") expect(@project.variables.count).to eq(1) end - end end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index be0e0c747b7..20ae29e2bd3 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -106,6 +106,12 @@ describe GitlabMarkdownHelper do act = link_to_gfm(text, '/foo') expect(act).to eq %Q(<a href="/foo">#{issues[0].to_reference}</a>) end + + it 'should replace commit message with emoji to link' do + actual = link_to_gfm(':book:Book', '/foo') + expect(actual). + to eq %Q(<img class="emoji" title=":book:" alt=":book:" src="http://localhost/assets/emoji/1F4D6.png" height="20" width="20" align="absmiddle"><a href="/foo">Book</a>) + end end describe '#render_wiki_content' do diff --git a/spec/helpers/merge_requests_helper.rb b/spec/helpers/merge_requests_helper.rb deleted file mode 100644 index 5262d644048..00000000000 --- a/spec/helpers/merge_requests_helper.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'spec_helper' - -describe MergeRequestsHelper do - describe :issues_sentence do - subject { issues_sentence(issues) } - let(:issues) do - [build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)] - end - - it { is_expected.to eq('#1, #2, and #3') } - end -end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb new file mode 100644 index 00000000000..0ef1efb8bce --- /dev/null +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe MergeRequestsHelper do + describe "#issues_sentence" do + subject { issues_sentence(issues) } + let(:issues) do + [build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)] + end + + it { is_expected.to eq('#1, #2, and #3') } + end + + describe "#format_mr_branch_names" do + describe "within the same project" do + let(:merge_request) { create(:merge_request) } + subject { format_mr_branch_names(merge_request) } + + it { is_expected.to eq([merge_request.source_branch, merge_request.target_branch]) } + end + + describe "within different projects" do + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } + let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) } + subject { format_mr_branch_names(merge_request) } + let(:source_title) { "#{fork_project.path_with_namespace}:#{merge_request.source_branch}" } + let(:target_title) { "#{project.path_with_namespace}:#{merge_request.target_branch}" } + + it { is_expected.to eq([source_title, target_title]) } + end + end +end diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 06f69262b71..e5df59c4fba 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -8,14 +8,18 @@ describe PreferencesHelper do end it 'raises an exception when defined choices may be using the wrong key' do - expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar') + dashboards = User.dashboards.dup + dashboards[:projects_changed] = dashboards.delete :projects + expect(User).to receive(:dashboards).and_return(dashboards) expect { helper.dashboard_choices }.to raise_error(KeyError) end it 'provides better option descriptions' do expect(helper.dashboard_choices).to match_array [ ['Your Projects (default)', 'projects'], - ['Starred Projects', 'stars'] + ['Starred Projects', 'stars'], + ["Your Projects' Activity", 'project_activity'], + ["Starred Projects' Activity", 'starred_project_activity'] ] end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 99abb95d906..53e56ebff44 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -61,13 +61,13 @@ describe ProjectsHelper do end it "returns a valid cach key" do - expect(helper.send(:readme_cache_key)).to eq("#{project.id}-#{project.commit.id}-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-#{project.commit.id}-readme") end it "returns a valid cache key if HEAD does not exist" do allow(project).to receive(:commit) { nil } - expect(helper.send(:readme_cache_key)).to eq("#{project.id}-nil-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme") end end end diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/runners_helper_spec.rb index 6d0e2d3d1e1..b3d635a1932 100644 --- a/spec/helpers/ci/runners_helper_spec.rb +++ b/spec/helpers/runners_helper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::RunnersHelper do +describe RunnersHelper do it "returns - not contacted yet" do runner = FactoryGirl.build :ci_runner expect(runner_status_icon(runner)).to include("not connected yet") diff --git a/spec/helpers/ci/application_helper_spec.rb b/spec/helpers/time_helper_spec.rb index 6a216715b7f..3f62527c5bb 100644 --- a/spec/helpers/ci/application_helper_spec.rb +++ b/spec/helpers/time_helper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::ApplicationHelper do +describe TimeHelper do describe "#duration_in_words" do it "returns minutes and seconds" do intervals_in_words = { diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb index 24894e81983..83e2ad220b8 100644 --- a/spec/lib/ci/charts_spec.rb +++ b/spec/lib/ci/charts_spec.rb @@ -4,13 +4,12 @@ describe "Charts" do context "build_times" do before do - @project = FactoryGirl.create(:ci_project) - @commit = FactoryGirl.create(:ci_commit, project: @project) + @commit = FactoryGirl.create(:ci_commit) FactoryGirl.create(:ci_build, commit: @commit) end it 'should return build times in minutes' do - chart = Ci::Charts::BuildTime.new(@project) + chart = Ci::Charts::BuildTime.new(@commit.project) expect(chart.build_times).to eq([2]) end end diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb index 829a9c197ef..37c527221a0 100644 --- a/spec/lib/gitlab/backend/grack_auth_spec.rb +++ b/spec/lib/gitlab/backend/grack_auth_spec.rb @@ -151,14 +151,14 @@ describe Grack::Auth do end it "repeated attempts followed by successful attempt" do - for n in 0..maxretry do + maxretry.times.each do expect(attempt_login(false)).to eq(401) end expect(attempt_login(true)).to eq(200) expect(Rack::Attack::Allow2Ban.banned?(ip)).to be_falsey - for n in 0..maxretry do + maxretry.times.each do expect(attempt_login(false)).to eq(401) end end diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index c0083fc85be..fd3ab1fb7c8 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -19,10 +19,6 @@ describe Gitlab::OAuth::User do let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') } it "finds an existing user based on uid and provider (facebook)" do - # FIXME (rspeicher): It's unlikely that this test is actually doing anything - # `auth` is never used and removing it entirely doesn't break the test, so - # what's it doing? - auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider') expect( oauth_user.persisted? ).to be_truthy end diff --git a/spec/mailers/ci/notify_spec.rb b/spec/mailers/ci/notify_spec.rb index 20d8ddcd135..b83fb41603b 100644 --- a/spec/mailers/ci/notify_spec.rb +++ b/spec/mailers/ci/notify_spec.rb @@ -5,8 +5,7 @@ describe Ci::Notify do include EmailSpec::Matchers before do - @project = FactoryGirl.create :ci_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit @build = FactoryGirl.create :ci_build, commit: @commit end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 2c97a521d96..cb67ec95d57 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -52,6 +52,7 @@ describe Notify do end it 'has headers that reference an existing thread' do + is_expected.to have_header 'Message-ID', /<(.*)@#{Gitlab.config.gitlab.host}>/ is_expected.to have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/ is_expected.to have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/ is_expected.to have_header 'X-GitLab-Project', /#{project.name}/ @@ -399,7 +400,7 @@ describe Notify do describe 'project was moved' do let(:project) { create(:project) } let(:user) { create(:user) } - subject { Notify.project_was_moved_email(project.id, user.id) } + subject { Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab") } it_behaves_like 'an email sent from GitLab' diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index 635a6e2518c..d45319b25d4 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -16,4 +16,16 @@ RSpec.describe AbuseReport, type: :model do subject { create(:abuse_report) } it { expect(subject).to be_valid } + + describe 'associations' do + it { is_expected.to belong_to(:reporter).class_name('User') } + it { is_expected.to belong_to(:user) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:reporter) } + it { is_expected.to validate_presence_of(:user) } + it { is_expected.to validate_presence_of(:message) } + it { is_expected.to validate_uniqueness_of(:user_id) } + end end diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 8ab72151a69..d80748f23a4 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -27,12 +27,12 @@ describe BroadcastMessage do end it "should return nil if time not come" do - broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days) + create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days) expect(BroadcastMessage.current).to be_nil end it "should return nil if time has passed" do - broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday) + create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday) expect(BroadcastMessage.current).to be_nil end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index ce801152042..ca070a14975 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -27,7 +27,8 @@ require 'spec_helper' describe Ci::Build do let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project } + let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project } let(:build) { FactoryGirl.create :ci_build, commit: commit } it { is_expected.to belong_to(:commit) } @@ -177,6 +178,17 @@ describe Ci::Build do it { is_expected.to include(text) } it { expect(subject.length).to be >= text.length } end + + context 'if build.trace hides token' do + let(:token) { 'my_secret_token' } + + before do + build.project.update_attributes(token: token) + build.update_attributes(trace: token) + end + + it { is_expected.to_not include(token) } + end end describe :timeout do diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index 586c9dc23a7..c04bbcbadc7 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -19,11 +19,12 @@ require 'spec_helper' describe Ci::Commit do let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } - let(:commit_with_project) { FactoryGirl.create :ci_commit, project: project } + let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project } + let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project } + let(:commit_with_project) { FactoryGirl.create :ci_commit, gl_project: gl_project } let(:config_processor) { Ci::GitlabCiYamlProcessor.new(gitlab_ci_yaml) } - it { is_expected.to belong_to(:project) } + it { is_expected.to belong_to(:gl_project) } it { is_expected.to have_many(:builds) } it { is_expected.to validate_presence_of :before_sha } it { is_expected.to validate_presence_of :sha } @@ -65,7 +66,8 @@ describe Ci::Commit do project = FactoryGirl.create :ci_project, email_add_pusher: true, email_recipients: '' - commit = FactoryGirl.create :ci_commit, project: project + gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project + commit = FactoryGirl.create :ci_commit, gl_project: gl_project expected = 'commit_pusher_email' allow(commit).to receive(:push_data) { { user_email: expected } } expect(commit.project_recipients).to eq([expected]) @@ -75,7 +77,8 @@ describe Ci::Commit do project = FactoryGirl.create :ci_project, email_add_pusher: true, email_recipients: 'rec1 rec2' - commit = FactoryGirl.create :ci_commit, project: project + gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project + commit = FactoryGirl.create :ci_commit, gl_project: gl_project expected = 'commit_pusher_email' allow(commit).to receive(:push_data) { { user_email: expected } } expect(commit.project_recipients).to eq(['rec1', 'rec2', expected]) @@ -85,7 +88,8 @@ describe Ci::Commit do project = FactoryGirl.create :ci_project, email_add_pusher: false, email_recipients: 'rec1 rec2' - commit = FactoryGirl.create :ci_commit, project: project + gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project + commit = FactoryGirl.create :ci_commit, gl_project: gl_project expect(commit.project_recipients).to eq(['rec1', 'rec2']) end @@ -93,7 +97,8 @@ describe Ci::Commit do project = FactoryGirl.create :ci_project, email_add_pusher: true, email_recipients: 'rec1 rec1 rec2' - commit = FactoryGirl.create :ci_commit, project: project + gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project + commit = FactoryGirl.create :ci_commit, gl_project: gl_project expected = 'rec2' allow(commit).to receive(:push_data) { { user_email: expected } } expect(commit.project_recipients).to eq(['rec1', 'rec2']) @@ -219,18 +224,17 @@ describe Ci::Commit do end describe "#finished_at" do - let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit) { FactoryGirl.create :ci_commit } it "returns finished_at of latest build" do build = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 60 - build1 = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120 + FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120 expect(commit.finished_at.to_i).to eq(build.finished_at.to_i) end it "returns nil if there is no finished build" do - build = FactoryGirl.create :ci_not_started_build, commit: commit + FactoryGirl.create :ci_not_started_build, commit: commit expect(commit.finished_at).to be_nil end @@ -238,7 +242,8 @@ describe Ci::Commit do describe "coverage" do let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project } + let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project } it "calculates average when there are two builds with coverage" do FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/mail_service_spec.rb index b5f37b349db..0d9f85959ba 100644 --- a/spec/models/ci/mail_service_spec.rb +++ b/spec/models/ci/mail_service_spec.rb @@ -32,7 +32,8 @@ describe Ci::MailService do describe 'failed build' do let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) } - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) } before do @@ -54,7 +55,8 @@ describe Ci::MailService do describe 'successfull build' do let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) } - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } before do @@ -81,7 +83,8 @@ describe Ci::MailService do email_only_broken_builds: false, email_recipients: "jeroen@example.com") end - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } before do @@ -109,7 +112,8 @@ describe Ci::MailService do email_only_broken_builds: true, email_recipients: "jeroen@example.com") end - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } before do @@ -137,7 +141,8 @@ describe Ci::MailService do email_only_broken_builds: false, email_recipients: "jeroen@example.com") end - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } before do @@ -159,7 +164,8 @@ describe Ci::MailService do email_only_broken_builds: true, email_recipients: "jeroen@example.com") end - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) } before do diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb index 49ac0860259..1903c036924 100644 --- a/spec/models/ci/project_services/hip_chat_message_spec.rb +++ b/spec/models/ci/project_services/hip_chat_message_spec.rb @@ -3,10 +3,8 @@ require 'spec_helper' describe Ci::HipChatMessage do subject { Ci::HipChatMessage.new(build) } - let(:project) { FactoryGirl.create(:ci_project) } - context "One build" do - let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) } + let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) } let(:build) do commit.create_builds @@ -37,7 +35,7 @@ describe Ci::HipChatMessage do end context "Several builds" do - let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs, project: project) } + let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) } let(:build) do commit.builds.first diff --git a/spec/models/ci/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb index 063d46b84d4..d9ccc855edf 100644 --- a/spec/models/ci/project_services/hip_chat_service_spec.rb +++ b/spec/models/ci/project_services/hip_chat_service_spec.rb @@ -33,15 +33,14 @@ describe Ci::HipChatService do describe "Execute" do let(:service) { Ci::HipChatService.new } - let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit) { FactoryGirl.create :ci_commit } let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' } let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' } before do allow(service).to receive_messages( - project: project, - project_id: project.id, + project: commit.project, + project_id: commit.project_id, notify_only_broken_builds: false, hipchat_room: 123, hipchat_token: 'a1b2c3d4e5f6' diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb index f5335903728..7b541802d7d 100644 --- a/spec/models/ci/project_services/slack_message_spec.rb +++ b/spec/models/ci/project_services/slack_message_spec.rb @@ -3,10 +3,8 @@ require 'spec_helper' describe Ci::SlackMessage do subject { Ci::SlackMessage.new(commit) } - let(:project) { FactoryGirl.create :ci_project } - context "One build" do - let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) } + let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) } let(:build) do commit.create_builds @@ -43,7 +41,7 @@ describe Ci::SlackMessage do end context "Several builds" do - let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs, project: project) } + let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) } context 'when all matrix builds succeeded' do let(:color) { 'good' } diff --git a/spec/models/ci/project_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb index 0524f472432..1ac7dfe568d 100644 --- a/spec/models/ci/project_services/slack_service_spec.rb +++ b/spec/models/ci/project_services/slack_service_spec.rb @@ -31,16 +31,15 @@ describe Ci::SlackService do describe "Execute" do let(:slack) { Ci::SlackService.new } - let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit) { FactoryGirl.create :ci_commit } let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' } let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } let(:notify_only_broken_builds) { false } before do allow(slack).to receive_messages( - project: project, - project_id: project.id, + project: commit.project, + project_id: commit.project_id, webhook: webhook_url, notify_only_broken_builds: notify_only_broken_builds ) diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb index 261ea69f5b4..dec4720a711 100644 --- a/spec/models/ci/project_spec.rb +++ b/spec/models/ci/project_spec.rb @@ -28,13 +28,20 @@ require 'spec_helper' describe Ci::Project do - subject { FactoryGirl.build :ci_project } + let(:gl_project) { FactoryGirl.create :empty_project } + let(:project) { FactoryGirl.create :ci_project, gl_project: gl_project } + subject { project } + + it { is_expected.to have_many(:runner_projects) } + it { is_expected.to have_many(:runners) } + it { is_expected.to have_many(:web_hooks) } + it { is_expected.to have_many(:events) } + it { is_expected.to have_many(:variables) } + it { is_expected.to have_many(:triggers) } + it { is_expected.to have_many(:services) } - it { is_expected.to have_many(:commits) } - - it { is_expected.to validate_presence_of :name } it { is_expected.to validate_presence_of :timeout } - it { is_expected.to validate_presence_of :default_ref } + it { is_expected.to validate_presence_of :gitlab_id } describe 'before_validation' do it 'should set an random token if none provided' do @@ -48,43 +55,107 @@ describe Ci::Project do end end + describe :name_with_namespace do + subject { project.name_with_namespace } + + it { is_expected.to eq(project.name) } + it { is_expected.to eq(gl_project.name_with_namespace) } + end + + describe :path_with_namespace do + subject { project.path_with_namespace } + + it { is_expected.to eq(project.path) } + it { is_expected.to eq(gl_project.path_with_namespace) } + end + + describe :path_with_namespace do + subject { project.web_url } + + it { is_expected.to eq(gl_project.web_url) } + end + + describe :web_url do + subject { project.web_url } + + it { is_expected.to eq(project.gitlab_url) } + it { is_expected.to eq(gl_project.web_url) } + end + + describe :http_url_to_repo do + subject { project.http_url_to_repo } + + it { is_expected.to eq(gl_project.http_url_to_repo) } + end + + describe :ssh_url_to_repo do + subject { project.ssh_url_to_repo } + + it { is_expected.to eq(gl_project.ssh_url_to_repo) } + end + + describe :commits do + subject { project.commits } + + before do + FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project + end + + it { is_expected.to eq(gl_project.ci_commits) } + end + + describe :builds do + subject { project.builds } + + before do + commit = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project + FactoryGirl.create :ci_build, commit: commit + end + + it { is_expected.to eq(gl_project.ci_builds) } + end + describe "ordered_by_last_commit_date" do it "returns ordered projects" do - newest_project = FactoryGirl.create :ci_project - oldest_project = FactoryGirl.create :ci_project - project_without_commits = FactoryGirl.create :ci_project + newest_project = FactoryGirl.create :empty_project + newest_ci_project = newest_project.ensure_gitlab_ci_project + oldest_project = FactoryGirl.create :empty_project + oldest_ci_project = oldest_project.ensure_gitlab_ci_project + project_without_commits = FactoryGirl.create :empty_project + ci_project_without_commits = project_without_commits.ensure_gitlab_ci_project - FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: newest_project - FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: oldest_project + FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: newest_project + FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: oldest_project - expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_project, oldest_project, project_without_commits]) + expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_ci_project, oldest_ci_project, ci_project_without_commits]) end end describe 'ordered commits' do - let(:project) { FactoryGirl.create :ci_project } + let(:project) { FactoryGirl.create :empty_project } it 'returns ordered list of commits' do - commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project - commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project - expect(project.commits).to eq([commit2, commit1]) + commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project + commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project + expect(project.ci_commits).to eq([commit2, commit1]) end it 'returns commits ordered by committed_at and id, with nulls last' do - commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project - commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project - commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project - commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project - expect(project.commits).to eq([commit2, commit4, commit3, commit1]) + commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project + commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project + commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project + commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project + expect(project.ci_commits).to eq([commit2, commit4, commit3, commit1]) end end context :valid_project do - let(:project) { FactoryGirl.create :ci_project } + let(:commit) { FactoryGirl.create(:ci_commit) } context :project_with_commit_and_builds do + let(:project) { commit.project } + before do - commit = FactoryGirl.create(:ci_commit, project: project) FactoryGirl.create(:ci_build, commit: commit) end @@ -165,13 +236,6 @@ describe Ci::Project do it { is_expected.to include(project.gitlab_url[7..-1]) } end - describe :search do - let!(:project) { FactoryGirl.create(:ci_project, name: "foo") } - - it { expect(Ci::Project.search('fo')).to include(project) } - it { expect(Ci::Project.search('bar')).to be_empty } - end - describe :any_runners do it "there are no runners available" do project = FactoryGirl.create(:ci_project) diff --git a/spec/models/ci/service_spec.rb b/spec/models/ci/service_spec.rb index 2c575056b08..2df70e88888 100644 --- a/spec/models/ci/service_spec.rb +++ b/spec/models/ci/service_spec.rb @@ -29,13 +29,12 @@ describe Ci::Service do end describe "Testable" do - let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit) { FactoryGirl.create :ci_commit } let(:build) { FactoryGirl.create :ci_build, commit: commit } before do allow(@service).to receive_messages( - project: project + project: commit.project ) build @testable = @service.can_test? diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index dae7e399cfb..a2dc66fce3e 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -22,7 +22,7 @@ describe ProjectHook do describe '.push_hooks' do it 'should return hooks for push events only' do hook = create(:project_hook, push_events: true) - hook2 = create(:project_hook, push_events: false) + create(:project_hook, push_events: false) expect(ProjectHook.push_hooks).to eq([hook]) end end @@ -30,7 +30,7 @@ describe ProjectHook do describe '.tag_push_hooks' do it 'should return hooks for tag push events only' do hook = create(:project_hook, tag_push_events: true) - hook2 = create(:project_hook, tag_push_events: false) + create(:project_hook, tag_push_events: false) expect(ProjectHook.tag_push_hooks).to eq([hook]) end end diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 4c8b8910ae7..16641c12124 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -39,8 +39,6 @@ describe ServiceHook do end it "POSTs the data as JSON" do - json = @data.to_json - @service_hook.execute(@data) expect(WebMock).to have_requested(:post, @service_hook.url).with( headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Service Hook' } diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 23f30881d99..2fdc49f02ee 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -60,8 +60,6 @@ describe ProjectHook do end it "POSTs the data as JSON" do - json = @data.to_json - @project_hook.execute(@data, 'push_hooks') expect(WebMock).to have_requested(:post, @project_hook.url).with( headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 36352e1ecce..c88d5349663 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -111,8 +111,8 @@ describe Milestone do describe :is_empty? do before do - issue = create :closed_issue, milestone: milestone - merge_request = create :merge_request, milestone: milestone + create :closed_issue, milestone: milestone + create :merge_request, milestone: milestone end it 'Should return total count of issues and merge requests assigned to milestone' do @@ -125,7 +125,7 @@ describe Milestone do milestone = create :milestone create :closed_issue, milestone: milestone - issue = create :issue + create :issue end it 'should be true if milestone active and all nested issues closed' do diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index 8cdd551a0ca..683a403a907 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -49,32 +49,10 @@ describe GitlabCiService do let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) } it "calls ci_yaml_file" do - service_hook = double expect(@service).to receive(:ci_yaml_file).with(push_sample_data[:checkout_sha]) @service.execute(push_sample_data) end end end - - describe "Fork registration" do - before do - @old_project = create(:ci_project).gl_project - @project = create(:empty_project) - @user = create(:user) - - @service = GitlabCiService.new - allow(@service).to receive_messages( - service_hook: true, - project_url: 'http://ci.gitlab.org/projects/2', - token: 'verySecret', - project: @old_project - ) - end - - it "creates fork on CI" do - expect_any_instance_of(Ci::CreateProjectService).to receive(:execute) - @service.fork_registration(@project, @user) - end - end end diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 65d16beef91..f67d7b30980 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -87,7 +87,7 @@ describe HipchatService do it "should create a push message" do message = hipchat.send(:create_push_message, push_sample_data) - obj_attr = push_sample_data[:object_attributes] + push_sample_data[:object_attributes] branch = push_sample_data[:ref].gsub('refs/heads/', '') expect(message).to include("#{user.name} pushed to branch " \ "<a href=\"#{project.web_url}/commits/#{branch}\">#{branch}</a> of " \ @@ -107,7 +107,7 @@ describe HipchatService do it "should create a tag push message" do message = hipchat.send(:create_push_message, push_sample_data) - obj_attr = push_sample_data[:object_attributes] + push_sample_data[:object_attributes] expect(message).to eq("#{user.name} pushed new tag " \ "<a href=\"#{project.web_url}/commits/test\">test</a> to " \ "<a href=\"#{project.web_url}\">#{project_name}</a>\n") diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9e7b6f5cb30..8b5d2c3a1c1 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -140,7 +140,7 @@ describe Project do describe 'last_activity_date' do it 'returns the creation date of the project\'s last event if present' do - last_activity_event = create(:event, project: project) + create(:event, project: project) expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i) end @@ -220,6 +220,7 @@ describe Project do end it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) } + it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) } it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil } end end @@ -404,19 +405,20 @@ describe Project do describe :ci_commit do let(:project) { create :project } - let(:ci_project) { create :ci_project, gl_project: project } - let(:commit) { create :ci_commit, project: ci_project } + let(:commit) { create :ci_commit, gl_project: project } - before { project.create_gitlab_ci_service(active: true) } + before do + project.ensure_gitlab_ci_project + project.create_gitlab_ci_service(active: true) + end it { expect(project.ci_commit(commit.sha)).to eq(commit) } end describe :enable_ci do let(:project) { create :project } - let(:user) { create :user } - before { project.enable_ci(user) } + before { project.enable_ci } it { expect(project.gitlab_ci?).to be_truthy } it { expect(project.gitlab_ci_project).to be_a(Ci::Project) } diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index cc1138490a0..26e8fdae472 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -66,4 +66,16 @@ describe ProjectTeam do it { expect(project.team.member?(guest)).to be_truthy } end end + + describe "#human_max_access" do + it "return master role" do + user = create :user + group = create :group + group.add_users([user.id], GroupMember::MASTER) + project = create(:project, namespace: group) + project.team << [user, :guest] + + expect(project.team.human_max_access(user.id)).to eq("Master") + end + end end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index f785203af7d..94802dcfb79 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -231,7 +231,7 @@ describe ProjectWiki do end def commit_details - commit = { name: user.name, email: user.email, message: "test commit" } + { name: user.name, email: user.email, message: "test commit" } end def create_page(name, content) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 480950859a2..c71cfb3ebe3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -85,6 +85,7 @@ describe User do it { is_expected.to have_many(:merge_requests).dependent(:destroy) } it { is_expected.to have_many(:assigned_merge_requests).dependent(:destroy) } it { is_expected.to have_many(:identities).dependent(:destroy) } + it { is_expected.to have_one(:abuse_report) } end describe 'validations' do @@ -227,6 +228,26 @@ describe User do end end + describe '#recently_sent_password_reset?' do + it 'is false when reset_password_sent_at is nil' do + user = build_stubbed(:user, reset_password_sent_at: nil) + + expect(user.recently_sent_password_reset?).to eq false + end + + it 'is false when sent more than one minute ago' do + user = build_stubbed(:user, reset_password_sent_at: 5.minutes.ago) + + expect(user.recently_sent_password_reset?).to eq false + end + + it 'is true when sent less than one minute ago' do + user = build_stubbed(:user, reset_password_sent_at: Time.now) + + expect(user.recently_sent_password_reset?).to eq true + end + end + describe '#disable_two_factor!' do it 'clears all 2FA-related fields' do user = create(:user, :two_factor) diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index dc84a14bb40..d7802d1734f 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -196,7 +196,7 @@ describe WikiPage do end def commit_details - commit = { name: user.name, email: user.email, message: "test commit" } + { name: user.name, email: user.email, message: "test commit" } end def create_page(name, content) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index c25d1823306..bad250fbf48 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -5,10 +5,12 @@ describe Ci::API::API do let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) } let(:project) { FactoryGirl.create(:ci_project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } describe "Builds API for runners" do let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") } let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") } + let(:shared_gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: shared_project) } before do FactoryGirl.create :ci_runner_project, project_id: project.id, runner_id: runner.id @@ -16,7 +18,7 @@ describe Ci::API::API do describe "POST /builds/register" do it "should start a build" do - commit = FactoryGirl.create(:ci_commit, project: project) + commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) commit.create_builds build = commit.builds.first @@ -34,7 +36,7 @@ describe Ci::API::API do end it "should return 404 error if no builds for specific runner" do - commit = FactoryGirl.create(:ci_commit, project: shared_project) + commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project) FactoryGirl.create(:ci_build, commit: commit, status: 'pending' ) post ci_api("/builds/register"), token: runner.token @@ -43,7 +45,7 @@ describe Ci::API::API do end it "should return 404 error if no builds for shared runner" do - commit = FactoryGirl.create(:ci_commit, project: project) + commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) FactoryGirl.create(:ci_build, commit: commit, status: 'pending' ) post ci_api("/builds/register"), token: shared_runner.token @@ -52,7 +54,7 @@ describe Ci::API::API do end it "returns options" do - commit = FactoryGirl.create(:ci_commit, project: project) + commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) commit.create_builds post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin } @@ -62,7 +64,7 @@ describe Ci::API::API do end it "returns variables" do - commit = FactoryGirl.create(:ci_commit, project: project) + commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) commit.create_builds project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value") @@ -77,7 +79,7 @@ describe Ci::API::API do it "returns variables for triggers" do trigger = FactoryGirl.create(:ci_trigger, project: project) - commit = FactoryGirl.create(:ci_commit, project: project) + commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger) commit.create_builds(trigger_request) @@ -95,7 +97,7 @@ describe Ci::API::API do end describe "PUT /builds/:id" do - let(:commit) { FactoryGirl.create(:ci_commit, project: project)} + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project)} let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) } it "should update a running build" do diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb index e89b6651499..a41c321a300 100644 --- a/spec/requests/ci/api/commits_spec.rb +++ b/spec/requests/ci/api/commits_spec.rb @@ -4,7 +4,8 @@ describe Ci::API::API, 'Commits' do include ApiHelpers let(:project) { FactoryGirl.create(:ci_project) } - let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } let(:options) do { diff --git a/spec/requests/ci/api/projects_spec.rb b/spec/requests/ci/api/projects_spec.rb index 409f47fa448..53f7f91cc1f 100644 --- a/spec/requests/ci/api/projects_spec.rb +++ b/spec/requests/ci/api/projects_spec.rb @@ -134,7 +134,7 @@ describe Ci::API::API do describe "PUT /projects/:id" do let!(:project) { FactoryGirl.create(:ci_project) } - let!(:project_info) { { name: "An updated name!" } } + let!(:project_info) { { default_ref: "develop" } } before do options.merge!(project_info) @@ -144,7 +144,7 @@ describe Ci::API::API do project.gl_project.team << [user, :master] put ci_api("/projects/#{project.id}"), options expect(response.status).to eq(200) - expect(json_response["name"]).to eq(project_info[:name]) + expect(json_response["default_ref"]).to eq(project_info[:default_ref]) end it "fails to update a non-existing project" do @@ -181,12 +181,10 @@ describe Ci::API::API do end describe "POST /projects" do + let(:gl_project) { FactoryGirl.create :empty_project } let(:project_info) do { - name: "My project", - gitlab_id: 1, - path: "testing/testing", - ssh_url_to_repo: "ssh://example.com/testing/testing.git" + gitlab_id: gl_project.id } end @@ -200,7 +198,7 @@ describe Ci::API::API do it "should create a project with valid data" do post ci_api("/projects"), options expect(response.status).to eq(201) - expect(json_response['name']).to eq(project_info[:name]) + expect(json_response['name']).to eq(gl_project.name_with_namespace) end end diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index ff6fdbdd6f1..bbe98e7dacd 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -6,6 +6,7 @@ describe Ci::API::API do describe 'POST /projects/:project_id/refs/:ref/trigger' do let!(:trigger_token) { 'secure token' } let!(:project) { FactoryGirl.create(:ci_project) } + let!(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } let!(:project2) { FactoryGirl.create(:ci_project) } let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) } let(:options) do @@ -33,7 +34,7 @@ describe Ci::API::API do context 'Have a commit' do before do - @commit = FactoryGirl.create(:ci_commit, project: project) + @commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) end it 'should create builds' do diff --git a/spec/requests/ci/builds_spec.rb b/spec/requests/ci/builds_spec.rb index 998c386ead4..f68116c52aa 100644 --- a/spec/requests/ci/builds_spec.rb +++ b/spec/requests/ci/builds_spec.rb @@ -2,14 +2,13 @@ require 'spec_helper' describe "Builds" do before do - @project = FactoryGirl.create :ci_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit @build = FactoryGirl.create :ci_build, commit: @commit end describe "GET /:project/builds/:id/status.json" do before do - get status_ci_project_build_path(@project, @build), format: :json + get status_ci_project_build_path(@commit.project, @build), format: :json end it { expect(response.status).to eq(200) } diff --git a/spec/requests/ci/commits_spec.rb b/spec/requests/ci/commits_spec.rb index fb317670339..3ab8c915dfd 100644 --- a/spec/requests/ci/commits_spec.rb +++ b/spec/requests/ci/commits_spec.rb @@ -2,13 +2,12 @@ require 'spec_helper' describe "Commits" do before do - @project = FactoryGirl.create :ci_project - @commit = FactoryGirl.create :ci_commit, project: @project + @commit = FactoryGirl.create :ci_commit end describe "GET /:project/refs/:ref_name/commits/:id/status.json" do before do - get status_ci_project_ref_commits_path(@project, @commit.ref, @commit.sha), format: :json + get status_ci_project_ref_commits_path(@commit.project, @commit.ref, @commit.sha), format: :json end it { expect(response.status).to eq(200) } diff --git a/spec/services/ci/create_project_service_spec.rb b/spec/services/ci/create_project_service_spec.rb deleted file mode 100644 index 2de7b0deca7..00000000000 --- a/spec/services/ci/create_project_service_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'spec_helper' - -describe Ci::CreateProjectService do - let(:service) { Ci::CreateProjectService.new } - let(:current_user) { double.as_null_object } - let(:project) { FactoryGirl.create :project } - - describe :execute do - context 'valid params' do - subject { service.execute(current_user, project) } - - it { is_expected.to be_kind_of(Ci::Project) } - it { is_expected.to be_persisted } - end - - context 'without project dump' do - it 'should raise exception' do - expect { service.execute(current_user, '', '') }. - to raise_error(NoMethodError) - end - end - - context "forking" do - let(:ci_origin_project) do - FactoryGirl.create(:ci_project, shared_runners_enabled: true, public: true, allow_git_fetch: true) - end - - subject { service.execute(current_user, project, ci_origin_project) } - - it "uses project as a template for settings and jobs" do - expect(subject.shared_runners_enabled).to be_truthy - expect(subject.public).to be_truthy - expect(subject.allow_git_fetch).to be_truthy - end - end - end -end diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index d12cd9773dc..525a24cc200 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' describe Ci::CreateTriggerRequestService do let(:service) { Ci::CreateTriggerRequestService.new } let(:project) { FactoryGirl.create :ci_project } + let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project } let(:trigger) { FactoryGirl.create :ci_trigger, project: project } describe :execute do @@ -10,7 +11,7 @@ describe Ci::CreateTriggerRequestService do subject { service.execute(project, trigger, 'master') } before do - @commit = FactoryGirl.create :ci_commit, project: project + @commit = FactoryGirl.create :ci_commit, gl_project: gl_project end it { expect(subject).to be_kind_of(Ci::TriggerRequest) } @@ -27,7 +28,7 @@ describe Ci::CreateTriggerRequestService do subject { service.execute(project, trigger, 'master') } before do - FactoryGirl.create :ci_commit_without_jobs, project: project + FactoryGirl.create :ci_commit_without_jobs, gl_project: gl_project end it { expect(subject).to be_nil } @@ -37,9 +38,9 @@ describe Ci::CreateTriggerRequestService do subject { service.execute(project, trigger, 'master') } before do - @commit1 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project - @commit2 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project - @commit3 = FactoryGirl.create :ci_commit, committed_at: 3.hour.ago, project: project + @commit1 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: gl_project + @commit2 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project + @commit3 = FactoryGirl.create :ci_commit, committed_at: 3.hour.ago, gl_project: gl_project end context 'retries latest one' do diff --git a/spec/services/ci/event_service_spec.rb b/spec/services/ci/event_service_spec.rb index 9b330a90ae2..1264e17ff5e 100644 --- a/spec/services/ci/event_service_spec.rb +++ b/spec/services/ci/event_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::EventService do - let(:project) { FactoryGirl.create :ci_project, name: "GitLab / gitlab-shell" } + let(:project) { FactoryGirl.create :ci_project } let(:user) { double(username: "root", id: 1) } before do @@ -12,7 +12,7 @@ describe Ci::EventService do it "creates event" do Ci::EventService.new.remove_project(user, project) - expect(Ci::Event.admin.last.description).to eq("Project \"GitLab / gitlab-shell\" has been removed by root") + expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been removed by root") end end @@ -20,7 +20,7 @@ describe Ci::EventService do it "creates event" do Ci::EventService.new.create_project(user, project) - expect(Ci::Event.admin.last.description).to eq("Project \"GitLab / gitlab-shell\" has been created by root") + expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been created by root") end end diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb index 7565eb8f032..d7242d684c6 100644 --- a/spec/services/ci/image_for_build_service_spec.rb +++ b/spec/services/ci/image_for_build_service_spec.rb @@ -4,7 +4,8 @@ module Ci describe ImageForBuildService do let(:service) { ImageForBuildService.new } let(:project) { FactoryGirl.create(:ci_project) } - let(:commit) { FactoryGirl.create(:ci_commit, project: project, ref: 'master') } + let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project, ref: 'master') } let(:build) { FactoryGirl.create(:ci_build, commit: commit) } describe :execute do diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb index 7b5af6c3dd0..781764627ac 100644 --- a/spec/services/ci/register_build_service_spec.rb +++ b/spec/services/ci/register_build_service_spec.rb @@ -3,14 +3,14 @@ require 'spec_helper' module Ci describe RegisterBuildService do let!(:service) { RegisterBuildService.new } - let!(:project) { FactoryGirl.create :ci_project } - let!(:commit) { FactoryGirl.create :ci_commit, project: project } - let!(:pending_build) { FactoryGirl.create :ci_build, project: project, commit: commit } + let!(:gl_project) { FactoryGirl.create :empty_project } + let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project } + let!(:pending_build) { FactoryGirl.create :ci_build, commit: commit } let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) } let!(:specific_runner) { FactoryGirl.create(:ci_runner, is_shared: false) } before do - specific_runner.assign_to(project) + specific_runner.assign_to(gl_project.ensure_gitlab_ci_project) end describe :execute do @@ -47,8 +47,7 @@ module Ci context 'allow shared runners' do before do - project.shared_runners_enabled = true - project.save + gl_project.gitlab_ci_project.update(shared_runners_enabled: true) end context 'shared runner' do diff --git a/spec/services/ci/web_hook_service_spec.rb b/spec/services/ci/web_hook_service_spec.rb index cebdd145e40..aa48fcbcbfd 100644 --- a/spec/services/ci/web_hook_service_spec.rb +++ b/spec/services/ci/web_hook_service_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' describe Ci::WebHookService do let(:project) { FactoryGirl.create :ci_project } - let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project } + let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project } let(:build) { FactoryGirl.create :ci_build, commit: commit } let(:hook) { FactoryGirl.create :ci_web_hook, project: project } diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 7b564d34d7b..7483f51de03 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -35,5 +35,19 @@ describe MergeRequests::MergeService do expect(note.note).to include 'Status changed to merged' end end + + context "error handling" do + let(:service) { MergeRequests::MergeService.new(project, user, {}) } + + it 'saves error if there is an exception' do + allow(service).to receive(:repository).and_raise("error") + + allow(service).to receive(:execute_hooks) + + service.execute(merge_request, 'Awesome message') + + expect(merge_request.merge_error).to eq("Something went wrong during merge") + end + end end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 8865335d0d1..520140917aa 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -427,15 +427,15 @@ describe NotificationService do should_email(@u_watcher.id) should_email(@u_participating.id) should_not_email(@u_disabled.id) - notification.project_was_moved(project) + notification.project_was_moved(project, "gitlab/gitlab") end def should_email(user_id) - expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id) + expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab") end def should_not_email(user_id) - expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id) + expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab") end end end diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 18ab333c1d1..65a8c81204d 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -43,14 +43,10 @@ describe Projects::ForkService do end context 'GitLab CI is enabled' do - it "calls fork registrator for CI" do - create(:ci_project, gl_project: @from_project) - @from_project.build_missing_services - @from_project.gitlab_ci_service.update_attributes(active: true) - - expect_any_instance_of(Ci::CreateProjectService).to receive(:execute) - - fork_project(@from_project, @to_user) + it "fork and enable CI for fork" do + @from_project.enable_ci + @to_project = fork_project(@from_project, @to_user) + expect(@to_project.gitlab_ci?).to be_truthy end end end diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 2e63e5f36af..3be7dd4e52b 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -159,7 +159,7 @@ describe 'gitlab:app namespace rake task' do end it "does not contain skipped item" do - tar_contents, exit_status = Gitlab::Popen.popen( + tar_contents, _exit_status = Gitlab::Popen.popen( %W{tar -tvf #{@backup_tar} db uploads repositories builds} ) |