Commit 8434e78b authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'master' into fix-personal-snippet-access-workflow

parents f2885bed 264dc3f7
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.2.0 (unreleased) v 8.2.0 (unreleased)
- Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749)
- Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu)
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Improved performance of finding users by one of their Email addresses - Improved performance of finding users by one of their Email addresses
- Improved performance of replacing references in comments - Improved performance of replacing references in comments
...@@ -14,6 +17,7 @@ v 8.2.0 (unreleased) ...@@ -14,6 +17,7 @@ v 8.2.0 (unreleased)
- Use git follow flag for commits page when retrieve history for file or directory - Use git follow flag for commits page when retrieve history for file or directory
- Show merge request CI status on merge requests index page - Show merge request CI status on merge requests index page
- Extend yml syntax for only and except to support specifying repository path - Extend yml syntax for only and except to support specifying repository path
- Enable shared runners to all new projects
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page - Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention. - Use issue editor as cross reference comment author when issue is edited with a new mention.
...@@ -23,10 +27,19 @@ v 8.2.0 (unreleased) ...@@ -23,10 +27,19 @@ v 8.2.0 (unreleased)
- Include commit logs in project search - Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook - Add "added", "modified" and "removed" properties to commit object in webhook
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from - Rename "Back to" links to "Go to" because its not always a case it point to place user come from
- Allow groups to appear in the search results if the group owner allows it
- New design for project graphs page
- Fix incoming email config defaults
v 8.1.4
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
- Prevent redirect loop when home_page_url is set to the root URL
v 8.1.3 v 8.1.3
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Spread out runner contacted_at updates - Spread out runner contacted_at updates
- New design for user profile page - Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication
v 8.1.1 v 8.1.1
- Fix cloning Wiki repositories via HTTP (Stan Hu) - Fix cloning Wiki repositories via HTTP (Stan Hu)
......
...@@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0' ...@@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3' gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2' gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0' gem 'omniauth-google-oauth2', '~> 0.2.0'
...@@ -39,7 +40,7 @@ gem "browser", '~> 1.0.0' ...@@ -39,7 +40,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.19' gem "gitlab_git", '~> 7.2.20'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -50,11 +51,7 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap" ...@@ -50,11 +51,7 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
gem 'gollum-lib', '~> 4.0.2' gem 'gollum-lib', '~> 4.0.2'
# Language detection # Language detection
# GitLab fork of linguist does not require pygments/python dependency. gem "github-linguist", "~> 4.7.0", require: "linguist"
# New version of original gem also dropped pygments support but it has strict
# dependency to unstable rugged version. We have internal issue for replacing
# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052.
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
# API # API
gem 'grape', '~> 0.6.1' gem 'grape', '~> 0.6.1'
...@@ -63,7 +60,7 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' ...@@ -63,7 +60,7 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times # Format dates and times
# based on human-friendly examples # based on human-friendly examples
gem "stamp", '~> 0.5.0' gem "stamp", '~> 0.6.0'
# Enumeration fields # Enumeration fields
gem 'enumerize', '~> 0.7.0' gem 'enumerize', '~> 0.7.0'
...@@ -184,7 +181,7 @@ gem 'ace-rails-ap', '~> 2.0.1' ...@@ -184,7 +181,7 @@ gem 'ace-rails-ap', '~> 2.0.1'
gem 'mousetrap-rails', '~> 1.4.6' gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding # Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.6.9.4' gem 'charlock_holmes', '~> 0.7.3'
gem "sass-rails", '~> 4.0.5' gem "sass-rails", '~> 4.0.5'
gem "coffee-rails", '~> 4.1.0' gem "coffee-rails", '~> 4.1.0'
...@@ -214,11 +211,9 @@ group :development do ...@@ -214,11 +211,9 @@ group :development do
gem "annotate", "~> 2.6.0" gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2' gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2' gem 'quiet_assets', '~> 1.0.2'
gem 'rack-mini-profiler', '~> 0.9.0', require: false
gem 'rerun', '~> 0.10.0' gem 'rerun', '~> 0.10.0'
gem 'bullet', require: false gem 'bullet', require: false
gem 'active_record_query_trace', require: false gem 'rblineprof', platform: :mri, require: false
gem 'rack-lineprof', platform: :mri
# Better errors handler # Better errors handler
gem 'better_errors', '~> 1.0.1' gem 'better_errors', '~> 1.0.1'
......
...@@ -17,7 +17,6 @@ GEM ...@@ -17,7 +17,6 @@ GEM
activesupport (= 4.1.12) activesupport (= 4.1.12)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
active_record_query_trace (1.5)
activemodel (4.1.12) activemodel (4.1.12)
activesupport (= 4.1.12) activesupport (= 4.1.12)
builder (~> 3.1) builder (~> 3.1)
...@@ -176,7 +175,7 @@ GEM ...@@ -176,7 +175,7 @@ GEM
activesupport (>= 3.2) activesupport (>= 3.2)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
escape_utils (0.2.4) escape_utils (1.1.0)
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.45.4) excon (0.45.4)
execjs (2.6.0) execjs (2.6.0)
...@@ -267,6 +266,11 @@ GEM ...@@ -267,6 +266,11 @@ GEM
json json
get_process_mem (0.2.0) get_process_mem (0.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
github-linguist (4.7.0)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
rugged (>= 0.23.0b)
github-markup (1.3.3) github-markup (1.3.3)
gitlab-flowdock-git-hook (1.0.1) gitlab-flowdock-git-hook (1.0.1)
flowdock (~> 0.7) flowdock (~> 0.7)
...@@ -277,17 +281,13 @@ GEM ...@@ -277,17 +281,13 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-linguist (3.0.1)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
mime-types (~> 1.19)
gitlab_emoji (0.1.1) gitlab_emoji (0.1.1)
gemojione (~> 2.0) gemojione (~> 2.0)
gitlab_git (7.2.19) gitlab_git (7.2.20)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.7.3)
gitlab-linguist (~> 3.0) github-linguist (~> 4.7.0)
rugged (~> 0.22.2) rugged (~> 0.23.3)
gitlab_meta (7.0) gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1) gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9) net-ldap (~> 0.9)
...@@ -423,6 +423,8 @@ GEM ...@@ -423,6 +423,8 @@ GEM
multi_json (~> 1.7) multi_json (~> 1.7)
omniauth (~> 1.1) omniauth (~> 1.1)
omniauth-oauth (~> 1.0) omniauth-oauth (~> 1.0)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2) omniauth-github (1.1.2)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
...@@ -489,12 +491,6 @@ GEM ...@@ -489,12 +491,6 @@ GEM
rack-attack (4.3.0) rack-attack (4.3.0)
rack rack
rack-cors (0.4.0) rack-cors (0.4.0)
rack-lineprof (0.0.3)
rack (~> 1.5)
rblineprof (~> 0.3.6)
term-ansicolor (~> 1.3)
rack-mini-profiler (0.9.7)
rack (>= 1.1.3)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-oauth2 (1.0.10) rack-oauth2 (1.0.10)
...@@ -689,7 +685,7 @@ GEM ...@@ -689,7 +685,7 @@ GEM
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
stamp (0.5.0) stamp (0.6.0)
state_machine (1.2.0) state_machine (1.2.0)
stringex (2.5.2) stringex (2.5.2)
systemu (2.6.5) systemu (2.6.5)
...@@ -777,7 +773,6 @@ PLATFORMS ...@@ -777,7 +773,6 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
RedCloth (~> 4.2.9) RedCloth (~> 4.2.9)
ace-rails-ap (~> 2.0.1) ace-rails-ap (~> 2.0.1)
active_record_query_trace
activerecord-deprecated_finders (~> 1.0.3) activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0) activerecord-session_store (~> 0.1.0)
acts-as-taggable-on (~> 3.4) acts-as-taggable-on (~> 3.4)
...@@ -800,7 +795,7 @@ DEPENDENCIES ...@@ -800,7 +795,7 @@ DEPENDENCIES
capybara (~> 2.4.0) capybara (~> 2.4.0)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.9.0) carrierwave (~> 0.9.0)
charlock_holmes (~> 0.6.9.4) charlock_holmes (~> 0.7.3)
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
colored (~> 1.2) colored (~> 1.2)
colorize (~> 0.5.8) colorize (~> 0.5.8)
...@@ -825,11 +820,11 @@ DEPENDENCIES ...@@ -825,11 +820,11 @@ DEPENDENCIES
foreman foreman
fuubar (~> 2.0.0) fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
github-linguist (~> 4.7.0)
github-markup (~> 1.3.1) github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1) gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.19) gitlab_git (~> 7.2.20)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.0.2) gollum-lib (~> 4.0.2)
...@@ -859,6 +854,7 @@ DEPENDENCIES ...@@ -859,6 +854,7 @@ DEPENDENCIES
octokit (~> 3.7.0) octokit (~> 3.7.0)
omniauth (~> 1.2.2) omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0) omniauth-google-oauth2 (~> 0.2.0)
...@@ -875,11 +871,10 @@ DEPENDENCIES ...@@ -875,11 +871,10 @@ DEPENDENCIES
quiet_assets (~> 1.0.2) quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.0) rack-attack (~> 4.3.0)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-lineprof
rack-mini-profiler (~> 0.9.0)
rack-oauth2 (~> 1.0.5) rack-oauth2 (~> 1.0.5)
rails (= 4.1.12) rails (= 4.1.12)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof
rdoc (~> 3.6) rdoc (~> 3.6)
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
...@@ -909,7 +904,7 @@ DEPENDENCIES ...@@ -909,7 +904,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0) spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3) sprockets (~> 2.12.3)
stamp (~> 0.5.0) stamp (~> 0.6.0)
state_machine (~> 1.2.0) state_machine (~> 1.2.0)
task_list (~> 1.0.2) task_list (~> 1.0.2)
teaspoon (~> 1.0.0) teaspoon (~> 1.0.0)
......
...@@ -119,6 +119,6 @@ rebase with master to see if that solves the issue. ...@@ -119,6 +119,6 @@ rebase with master to see if that solves the issue.
### Closing down the issue tracker on GitHub ### Closing down the issue tracker on GitHub
We are currently in the process of closing down the issue tracker on GitHub, to We are currently in the process of closing down the issue tracker on GitHub, to
prevent duplication with the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues]. prevent duplication with the GitLab.com issue tracker.
Since this is an older issue I'll be closing this for now. If you think this is Since this is an older issue I'll be closing this for now. If you think this is
still an issue I encourage you to open it on the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues]. still an issue I encourage you to open it on the \[GitLab.com issue tracker\](https://gitlab.com/gitlab-org/gitlab-ce/issues).
...@@ -25,7 +25,7 @@ class @Calendar ...@@ -25,7 +25,7 @@ class @Calendar
30 30
] ]
legendCellPadding: 3 legendCellPadding: 3
cellSize: $('.user-calendar').width() / 76 cellSize: $('.user-calendar').width() / 73
onClick: (date, count) -> onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax $.ajax
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
color: $gl-gray; color: $gl-gray;
&.oneline-block {
line-height: 42px;
}
&.white { &.white {
background-color: white; background-color: white;
} }
......
...@@ -389,12 +389,32 @@ table { ...@@ -389,12 +389,32 @@ table {
.center-middle-menu { .center-middle-menu {
@include nav-menu; @include nav-menu;
padding: 0;
text-align: center; text-align: center;
margin: -$gl-padding; margin: -$gl-padding;
height: auto;
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
height: 58px;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
li {
&:after {
content: "|";
color: $border-gray-light;
}
&:last-child {
&:after {
content: none;
}
}
> a {
display: inline-block;
text-transform: uppercase;
font-size: 13px;
}
}
} }
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
......
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
} }
.markdown-area { .markdown-area {
@include border-radius(0);
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
......
...@@ -137,6 +137,7 @@ ...@@ -137,6 +137,7 @@
&:hover, &:active, &:focus { &:hover, &:active, &:focus {
text-decoration: none; text-decoration: none;
outline: none;
} }
} }
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
text-decoration: none; text-decoration: none;
padding-left: 22px; padding-left: 22px;
font-weight: normal; font-weight: normal;
outline: none;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
...@@ -176,6 +177,7 @@ ...@@ -176,6 +177,7 @@
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
transition-duration: .3s; transition-duration: .3s;
outline: none;
} }
.collapse-nav a:hover { .collapse-nav a:hover {
...@@ -238,6 +240,7 @@ ...@@ -238,6 +240,7 @@
width: 100%; width: 100%;
padding: 10px 22px; padding: 10px 22px;
overflow: hidden; overflow: hidden;
outline: none;
img { img {
width: 36px; width: 36px;
......
...@@ -367,7 +367,6 @@ ...@@ -367,7 +367,6 @@
.inline-parallel-buttons { .inline-parallel-buttons {
float: right; float: right;
margin-top: -5px;
} }
// Mobile // Mobile
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
.event-item { .event-item {
font-size: $gl-font-size; font-size: $gl-font-size;
padding: $gl-padding; padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px);
margin-left: -$gl-padding; margin-left: -$gl-padding;
margin-right: -$gl-padding; margin-right: -$gl-padding;
border-bottom: 1px solid $table-border-color; border-bottom: 1px solid $table-border-color;
...@@ -16,10 +16,7 @@ ...@@ -16,10 +16,7 @@
top: -2px; top: -2px;
} }
.event-title { .event-title,
line-height: 44px;
}
.event-item-timestamp { .event-item-timestamp {
line-height: 44px; line-height: 44px;
} }
...@@ -30,7 +27,7 @@ ...@@ -30,7 +27,7 @@
} }
.avatar { .avatar {
margin-right: 15px; margin-left: -($gl-avatar-size + 15px);
} }
.event-title { .event-title {
...@@ -43,8 +40,7 @@ ...@@ -43,8 +40,7 @@
} }
.event-body { .event-body {
margin-left: 63px; margin-right: 174px;
margin-right: 80px;
.event-note { .event-note {
margin-top: 5px; margin-top: 5px;
...@@ -155,6 +151,8 @@ ...@@ -155,6 +151,8 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.event-item { .event-item {
padding-left: $gl-padding;
.event-title { .event-title {
white-space: normal; white-space: normal;
overflow: visible; overflow: visible;
......
...@@ -19,6 +19,20 @@ ...@@ -19,6 +19,20 @@
.accept-merge-holder { .accept-merge-holder {
.accept-action { .accept-action {
display: inline-block; display: inline-block;
.accept_merge_request {
&.ci-pending,
&.ci-running {
@include btn-orange;
}
&.ci-skipped,
&.ci-failed,
&.ci-canceled,
&.ci-error {
@include btn-red;
}
}
} }
.accept-control { .accept-control {
......
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
.note_text { .note_text {
width: 100%; width: 100%;
} }
.comment-hints {
margin-top: -12px;
}
} }
/* loading indicator */ /* loading indicator */
...@@ -168,7 +172,7 @@ ...@@ -168,7 +172,7 @@
color: #999; color: #999;
background: #FFF; background: #FFF;
padding: 7px; padding: 7px;
margin-top: -11px; margin-top: -7px;
border: 1px solid $border-color; border: 1px solid $border-color;
font-size: 13px; font-size: 13px;
} }
...@@ -75,7 +75,3 @@ ...@@ -75,7 +75,3 @@
text-decoration: none; text-decoration: none;
} }
} }
.cal-heatmap-container {
margin: 0 auto;
}
...@@ -552,4 +552,4 @@ pre.light-well { ...@@ -552,4 +552,4 @@ pre.light-well {
z-index: 100; z-index: 100;
position: relative; position: relative;
} }
} }
\ No newline at end of file
table .sherlock-code {
max-width: 700px;
}
.sherlock-code {
pre {
word-wrap: normal;
}
pre code {
white-space: pre;
}
}
.sherlock-line-samples-table {
margin-bottom: 0px !important;
thead tr th,
tbody tr td {
font-size: 13px !important;
text-align: right;
padding: 0px 10px !important;
}
}
.sherlock-file-sample pre {
padding-top: 28px !important;
}
.sherlock-line-samples-table .slow {
color: $red-light;
font-weight: bold;
}
...@@ -57,6 +57,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -57,6 +57,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled, :version_check_enabled,
:admin_notification_email, :admin_notification_email,
:user_oauth_applications, :user_oauth_applications,
:shared_runners_enabled,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [] import_sources: []
) )
......
...@@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base ...@@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base
end end
def authenticate_user!(*args) def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page if redirect_to_home_page_url?
# Don't redirect to the default URL to prevent endless redirections redirect_to current_application_settings.home_page_url and return
if current_application_settings.home_page_url.present? &&
current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path
redirect_to current_application_settings.home_page_url and return
end
end end
super(*args) super(*args)
...@@ -346,4 +341,17 @@ class ApplicationController < ActionController::Base ...@@ -346,4 +341,17 @@ class ApplicationController < ActionController::Base
def git_import_enabled? def git_import_enabled?
current_application_settings.import_sources.include?('git') current_application_settings.import_sources.include?('git')
end end
def redirect_to_home_page_url?
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
return false unless current_application_settings.home_page_url.present?
home_page_url = current_application_settings.home_page_url.chomp('/')
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
return false if root_urls.include?(home_page_url)
current_user.nil? && root_path == request.path
end
end end
...@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController ...@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController
before_action :group, except: [:new, :create] before_action :group, except: [:new, :create]
# Authorize # Authorize
before_action :authorize_read_group!, except: [:show, :new, :create] before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update] before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show before_action :event_filter, only: :show
layout :determine_layout layout :determine_layout
...@@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController ...@@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar) params.require(:group).permit(:name, :description, :path, :avatar, :public)
end end
def load_events def load_events
......
...@@ -30,7 +30,7 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -30,7 +30,7 @@ class Projects::BuildsController < Projects::ApplicationController
def show def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC') @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20) @builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit @commit = @build.commit
respond_to do |format| respond_to do |format|
...@@ -42,17 +42,13 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -42,17 +42,13 @@ class Projects::BuildsController < Projects::ApplicationController
end end
def retry def retry
if @build.commands.blank? unless @build.retryable?
return page_404 return page_404
end end
build = Ci::Build.retry(@build) build = Ci::Build.retry(@build)
if params[:return_to] redirect_to build_path(build)
redirect_to URI.parse(params[:return_to]).path
else
redirect_to build_path(build)
end
end end
def status def status
......
...@@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController
before_action :authorize_download_code!, except: [:cancel_builds] before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds] before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit before_action :commit
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
def show def show
return git_not_found! unless @commit return git_not_found! unless @commit
@line_notes = commit.notes.inline @line_notes = commit.notes.inline
@diffs = @commit.diffs
@note = @project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = commit.notes.count
@notes = commit.notes.not_inline.fresh @notes = commit.notes.not_inline.fresh
@noteable = @commit @noteable = @commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
...@@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController
commit_id: @commit.id commit_id: @commit.id
} }
@ci_commit = project.ci_commit(commit.sha)
respond_to do |format| respond_to do |format|
format.html format.html
format.diff { render text: @commit.to_diff } format.diff { render text: @commit.to_diff }
...@@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController
end end
end end
def ci def builds
@ci_commit = @project.ci_commit(@commit.sha)
@builds = @ci_commit.builds if @ci_commit
@notes_count = @commit.notes.count
@ci_project = @project.gitlab_ci_project @ci_project = @project.gitlab_ci_project
end end
def cancel_builds def cancel_builds
@ci_commit = @project.ci_commit(@commit.sha) ci_commit.builds.running_or_pending.each(&:cancel)
@ci_commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha) redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end end
def retry_builds
ci_commit.builds.latest.failed.each do |build|
if build.retryable?
Ci::Build.retry(build)
end
end
redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def branches def branches
@branches = @project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
...@@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController
render layout: false render layout: false
end end
private
def commit def commit
@commit ||= @project.commit(params[:id]) @commit ||= @project.commit(params[:id])
end end
private def ci_commit
@ci_commit ||= project.ci_commit(commit.sha)
end
def define_show_vars
@diffs = commit.diffs
@notes_count = commit.notes.count
@builds = ci_commit.builds if ci_commit
end
def authorize_manage_builds! def authorize_manage_builds!
unless can?(current_user, :manage_builds, project) unless can?(current_user, :manage_builds, project)
......
module Sherlock
class ApplicationController < ::ApplicationController
before_action :find_transaction
def find_transaction
if params[:transaction_id]
@transaction = Gitlab::Sherlock.collection.
find_transaction(params[:transaction_id])
end
end
end
end
module Sherlock
class FileSamplesController < Sherlock::ApplicationController
def show
@file_sample = @transaction.find_file_sample(params[:id])
end
end
end
module Sherlock
class QueriesController < Sherlock::ApplicationController
def show
@query = @transaction.find_query(params[:id])
end
end
end
module Sherlock
class TransactionsController < Sherlock::ApplicationController
def index
@transactions = Gitlab::Sherlock.collection.newest_first
end
def show
@transaction = Gitlab::Sherlock.collection.find_transaction(params[:id])
render_404 unless @transaction
end
def destroy_all
Gitlab::Sherlock.collection.clear
redirect_to(:back)
end
end
end
...@@ -6,33 +6,34 @@ class GroupsFinder ...@@ -6,33 +6,34 @@ class GroupsFinder
private private
def all_groups(current_user) def all_groups(current_user)
if current_user group_ids = if current_user
if current_user.authorized_groups.any? if current_user.authorized_groups.any?
# User has access to groups # User has access to groups
# #
# Return only: # Return only:
# groups with public projects # groups with public projects
# groups with internal projects # groups with internal projects
# groups with joined projects # groups with joined projects
# #
group_ids = Project.public_and_internal_only.pluck(:namespace_id) + Project.public_and_internal_only.pluck(:namespace_id) +
current_user.authorized_groups.pluck(:id) current_user.authorized_groups.pluck(:id)
Group.where(id: group_ids) else
else # User has no group membership
# User has no group membership #
# # Return only:
# Return only: # groups with public projects
# groups with public projects # groups with internal projects
# groups with internal projects #
# Project.public_and_internal_only.pluck(:namespace_id)
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id)) end
end else
else # Not authenticated
# Not authenticated #
# # Return only:
# Return only: # groups with public projects
# groups with public projects Project.public_only.pluck(:namespace_id)
Group.where(id: Project.public_only.pluck(:namespace_id)) end
end
Group.where("public IS TRUE OR id IN(?)", group_ids)
end end
end end
module AuthHelper module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
def ldap_enabled? def ldap_enabled?
......
module BuildsHelper
def build_ref_link build
gitlab_ref_link build.project, build.ref
end
def build_commit_link build
gitlab_commit_link build.project, build.short_sha
end
def build_url(build)
namespace_project_build_path(build.gl_project, build.project, build)
end
end
...@@ -4,25 +4,6 @@ module Ci ...@@ -4,25 +4,6 @@ module Ci
{ :"data-no-turbolink" => "data-no-turbolink" } { :"data-no-turbolink" => "data-no-turbolink" }
end end
def gitlab_ref_link project, ref
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commits/#{ref}"
link_to ref, gitlab_url, no_turbolink
end
def gitlab_compare_link project, before, after
gitlab_url = project.gitlab_url.dup
gitlab_url << "/compare/#{before}...#{after}"
link_to "#{before}...#{after}", gitlab_url, no_turbolink
end
def gitlab_commit_link project, sha
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commit/#{sha}"
link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink
end
def yaml_web_editor_link(project) def yaml_web_editor_link(project)
commits = project.commits commits = project.commits
......
module CiStatusHelper module CiStatusHelper
def ci_status_path(ci_commit) def ci_status_path(ci_commit)
project = ci_commit.gl_project project = ci_commit.gl_project
ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha) builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end end
def ci_status_icon(ci_commit) def ci_status_icon(ci_commit)
......
...@@ -137,7 +137,7 @@ module DiffHelper ...@@ -137,7 +137,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button # Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format) params_copy.delete(:format)
link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do
'Inline' 'Inline'
end end
end end
...@@ -148,7 +148,7 @@ module DiffHelper ...@@ -148,7 +148,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button # Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format) params_copy.delete(:format)
link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do
'Side-by-side' 'Side-by-side'
end end
end end
......
...@@ -70,7 +70,7 @@ module SearchHelper ...@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups # Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5) def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group| GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{ {
label: "group: #{search_result_sanitize(group.name)}", label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group) url: group_path(group)
......
...@@ -87,7 +87,8 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -87,7 +87,8 @@ class ApplicationSetting < ActiveRecord::Base
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
restricted_signup_domains: Settings.gitlab['restricted_signup_domains'], restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'] import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'],
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
) )
end end
......
...@@ -106,6 +106,14 @@ module Ci ...@@ -106,6 +106,14 @@ module Ci
failed? && allow_failure? failed? && allow_failure?
end end
def retryable?
commands.present?
end
def retried?
!self.commit.latest_builds_for_ref(self.ref).include?(self)
end
def trace_html def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present? html = Ci::Ansi2html::convert(trace) if trace.present?
html || '' html || ''
...@@ -222,7 +230,7 @@ module Ci ...@@ -222,7 +230,7 @@ module Ci
end end
def retry_url def retry_url
if commands.present? if retryable?
Gitlab::Application.routes.url_helpers. Gitlab::Application.routes.url_helpers.
retry_namespace_project_build_path(gl_project.namespace, gl_project, self) retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
end end
......
...@@ -15,8 +15,8 @@ class CommitStatus < ActiveRecord::Base ...@@ -15,8 +15,8 @@ class CommitStatus < ActiveRecord::Base
scope :pending, -> { where(status: 'pending') } scope :pending, -> { where(status: 'pending') }
scope :success, -> { where(status: 'success') } scope :success, -> { where(status: 'success') }
scope :failed, -> { where(status: 'failed') } scope :failed, -> { where(status: 'failed') }
scope :running_or_pending, -> { where(status:[:running, :pending]) } scope :running_or_pending, -> { where(status: [:running, :pending]) }
scope :finished, -> { where(status:[:success, :failed, :canceled]) } scope :finished, -> { where(status: [:success, :failed, :canceled]) }
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) } scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) } scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) } scope :for_ref, ->(ref) { where(ref: ref) }
......
...@@ -8,12 +8,12 @@ module Sortable ...@@ -8,12 +8,12 @@ module Sortable
included do included do
# By default all models should be ordered # By default all models should be ordered
# by created_at field starting from newest # by created_at field starting from newest
default_scope { order(created_at: :desc, id: :desc) } default_scope { order(id: :desc) }
scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) } scope :order_created_desc, -> { reorder(created_at: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) } scope :order_created_asc, -> { reorder(created_at: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) } scope :order_updated_desc, -> { reorder(updated_at: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) } scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) } scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) } scope :order_name_desc, -> { reorder(name: :desc) }
end end
......
...@@ -120,7 +120,7 @@ class Group < Namespace ...@@ -120,7 +120,7 @@ class Group < Namespace
end end
def public_profile? def public_profile?
projects.public_only.any? self.public || projects.public_only.any?
end end
def post_create_hook def post_create_hook
......
...@@ -37,6 +37,7 @@ class Project < ActiveRecord::Base ...@@ -37,6 +37,7 @@ class Project < ActiveRecord::Base
include Gitlab::ConfigHelper include Gitlab::ConfigHelper
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
include Gitlab::CurrentSettings
include Referable include Referable
include Sortable include Sortable
include AfterCommitQueue include AfterCommitQueue
...@@ -775,7 +776,9 @@ class Project < ActiveRecord::Base ...@@ -775,7 +776,9 @@ class Project < ActiveRecord::Base
end end
def ensure_gitlab_ci_project def ensure_gitlab_ci_project
gitlab_ci_project || create_gitlab_ci_project gitlab_ci_project || create_gitlab_ci_project(
shared_runners_enabled: current_application_settings.shared_runners_enabled
)
end end
def enable_ci def enable_ci
......
...@@ -11,7 +11,7 @@ module Ci ...@@ -11,7 +11,7 @@ module Ci
def to_s def to_s
lines = Array.new lines = Array.new
lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ") lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
lines.push("<a href=\"#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>") lines.push("<a href=\"#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>")
lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>") lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).") lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
lines.join('') lines.join('')
......
...@@ -45,7 +45,7 @@ module Ci ...@@ -45,7 +45,7 @@ module Ci
def attachment_message def attachment_message
out = "<#{ci_project_url(project)}|#{project_name}>: " out = "<#{ci_project_url(project)}|#{project_name}>: "
out << "Commit <#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> " out << "Commit <#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> "
out << "(<#{commit_sha_link}|#{commit.short_sha}>) " out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
out << "of <#{commit_ref_link}|#{commit.ref}> " out << "of <#{commit_ref_link}|#{commit.ref}> "
out << "by #{commit.git_author_name} " if commit.git_author_name out << "by #{commit.git_author_name} " if commit.git_author_name
......
...@@ -71,7 +71,7 @@ class GitlabCiService < CiService ...@@ -71,7 +71,7 @@ class GitlabCiService < CiService
def build_page(sha, ref) def build_page(sha, ref)
if project.gitlab_ci_project.present? if project.gitlab_ci_project.present?
ci_namespace_project_commit_url(project.namespace, project, sha) builds_namespace_project_commit_url(project.namespace, project, sha)
end end
end end
......
...@@ -89,7 +89,7 @@ class Repository ...@@ -89,7 +89,7 @@ class Repository
def find_commits_by_message(query) def find_commits_by_message(query)
# Limited to 1000 commits for now, could be parameterized? # Limited to 1000 commits for now, could be parameterized?
args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query})
git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
commits = git_log_results.map { |c| commit(c) } commits = git_log_results.map { |c| commit(c) }
...@@ -296,7 +296,7 @@ class Repository ...@@ -296,7 +296,7 @@ class Repository
end end
def last_commit_for_path(sha, path) def last_commit_for_path(sha, path)
args = %W(git rev-list --max-count=1 #{sha} -- #{path}) args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path})
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha) commit(sha)
end end
...@@ -347,7 +347,7 @@ class Repository ...@@ -347,7 +347,7 @@ class Repository
end end
def branch_names_contains(sha) def branch_names_contains(sha)
args = %W(git branch --contains #{sha}) args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split) if names.respond_to?(:split)
...@@ -364,7 +364,7 @@ class Repository ...@@ -364,7 +364,7 @@ class Repository
end end
def tag_names_contains(sha) def tag_names_contains(sha)
args = %W(git tag --contains #{sha}) args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split) if names.respond_to?(:split)
...@@ -505,7 +505,7 @@ class Repository ...@@ -505,7 +505,7 @@ class Repository
def search_files(query, ref) def search_files(query, ref)
offset = 2 offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end end
...@@ -537,7 +537,7 @@ class Repository ...@@ -537,7 +537,7 @@ class Repository
end end
def fetch_ref(source_path, source_ref, target_ref) def fetch_ref(source_path, source_ref, target_ref)
args = %W(git fetch -f #{source_path} #{source_ref}:#{target_ref}) args = %W(#{Gitlab.config.git.bin_path} fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo) Gitlab::Popen.popen(args, path_to_repo)
end end
......
...@@ -7,17 +7,17 @@ module MergeRequests ...@@ -7,17 +7,17 @@ module MergeRequests
@branch_name = Gitlab::Git.ref_name(ref) @branch_name = Gitlab::Git.ref_name(ref)
find_new_commits find_new_commits
# Be sure to close outstanding MRs before reloading them to avoid generating an
# empty diff during a manual merge
close_merge_requests
reload_merge_requests reload_merge_requests
# Leave a system note if a branch was deleted/added # Leave a system note if a branch was deleted/added
if branch_added? || branch_removed? if branch_added? || branch_removed?
comment_mr_branch_presence_changed comment_mr_branch_presence_changed
comment_mr_with_commits
else
comment_mr_with_commits
close_merge_requests
end end
comment_mr_with_commits
execute_mr_web_hooks execute_mr_web_hooks
true true
......
...@@ -94,8 +94,6 @@ module Projects ...@@ -94,8 +94,6 @@ module Projects
@project.team << [current_user, :master, current_user] @project.team << [current_user, :master, current_user]
end end
@project.update_column(:last_activity_at, @project.created_at)
if @project.import? if @project.import?
@project.import_start @project.import_start
end end
......
...@@ -130,5 +130,14 @@ ...@@ -130,5 +130,14 @@
= f.text_area :help_page_text, class: 'form-control', rows: 4 = f.text_area :help_page_text, class: 'form-control', rows: 4
.help-block Markdown enabled .help-block Markdown enabled
%fieldset
%legend Continuous Integration
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :shared_runners_enabled do
= f.check_box :shared_runners_enabled
Enable shared runners for a new projects
.form-actions .form-actions
= f.submit 'Save', class: 'btn btn-primary' = f.submit 'Save', class: 'btn btn-primary'
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= @project.name = @project.name
%p %p
Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.commit.git_author_name}
%p %p
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
Message: #{@build.commit.git_commit_message} Message: #{@build.commit.git_commit_message}
%p %p
Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= @project.name = @project.name
%p %p
Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.commit.git_author_name}
%p %p
...@@ -17,4 +17,4 @@ ...@@ -17,4 +17,4 @@
Message: #{@build.commit.git_commit_message} Message: #{@build.commit.git_commit_message}
%p %p
Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
- group = group_member.group - group = group_member.group
= render 'shared/groups/group', group: group, group_member: group_member = render 'shared/groups/group', group: group, group_member: group_member
= paginate @group_members = paginate @group_members, theme: 'gitlab'
...@@ -7,26 +7,34 @@ ...@@ -7,26 +7,34 @@
%h3 Sign in %h3 Sign in
.login-body .login-body
- if form_based_providers.any? - if form_based_providers.any?
%ul.nav.nav-tabs - if form_based_providers.count >= 2 || signin_enabled?
%ul.nav.nav-tabs
- if crowd_enabled?
%li.active
= link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab'
- @ldap_servers.each_with_index do |server, i|
%li{class: (:active if i.zero? && !crowd_enabled?)}
= link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
- if signin_enabled?
%li
= link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
- if crowd_enabled?
%div.tab-pane.active{id: "tab-crowd"}
= render 'devise/sessions/new_crowd'
- @ldap_servers.each_with_index do |server, i|
%div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)}
= render 'devise/sessions/new_ldap', server: server
- if signin_enabled?
%div#tab-signin.tab-pane
= render 'devise/sessions/new_base'
- else
- if crowd_enabled? - if crowd_enabled?
%li.active = render 'devise/sessions/new_crowd'
= link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab' - elsif @ldap_servers.any?
- @ldap_servers.each_with_index do |server, i| = render 'devise/sessions/new_ldap', server: @ldap_servers.first
%li{class: (:active if i.zero? && !crowd_enabled?)} - elsif signin_enabled?
= link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab' = render 'devise/sessions/new_base'
- if signin_enabled?
%li
= link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
- if crowd_enabled?
%div.tab-pane.active{id: "tab-crowd"}
= render 'devise/sessions/new_crowd'
- @ldap_servers.each_with_index do |server, i|
%div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)}
= render 'devise/sessions/new_ldap', server: server
- if signin_enabled?
%div#tab-signin.tab-pane
= render 'devise/sessions/new_base'
- elsif signin_enabled? - elsif signin_enabled?
= render 'devise/sessions/new_base' = render 'devise/sessions/new_base'
...@@ -25,6 +25,15 @@ ...@@ -25,6 +25,15 @@
%hr %hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
.form-group
%hr
= f.label :public, class: 'control-label' do
Public
.col-sm-10
.checkbox
= f.check_box :public
%span.descr Make this group public (even if there is no any public project inside this group)
.form-actions .form-actions
= f.submit 'Save group', class: "btn btn-save" = f.submit 'Save group', class: "btn btn-save"
......
<!-- Piwik -->
:javascript :javascript
var _paq = _paq || []; var _paq = _paq || [];
_paq.push(["trackPageView"]); _paq.push(['trackPageView']);
_paq.push(["enableLinkTracking"]); _paq.push(['enableLinkTracking']);
(function() { (function() {
var u=(("https:" == document.location.protocol) ? "https" : "http") + "://#{extra_config.piwik_url}/"; var u="//#{extra_config.piwik_url}/";
_paq.push(["setTrackerUrl", u+"piwik.php"]); _paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(["setSiteId", "#{extra_config.piwik_site_id}"]); _paq.push(['setSiteId', #{extra_config.piwik_site_id}]);
var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript"; var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s); g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})(); })();
<noscript><p><img src="//#{extra_config.piwik_url}/piwik.php?idsite=#{extra_config.piwik_site_id}" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
...@@ -9,23 +9,25 @@ ...@@ -9,23 +9,25 @@
= nav_link path: 'projects#index' do = nav_link path: 'projects#index' do
= link_to ci_admin_projects_path do = link_to ci_admin_projects_path do
= icon('list-alt fw') = icon('list-alt fw')
Projects %span
Projects
= nav_link path: 'events#index' do = nav_link path: 'events#index' do
= link_to ci_admin_events_path do = link_to ci_admin_events_path do
= icon('book fw') = icon('book fw')
Events %span
Events
= nav_link path: ['runners#index', 'runners#show'] do = nav_link path: ['runners#index', 'runners#show'] do
= link_to ci_admin_runners_path do = link_to ci_admin_runners_path do
= icon('cog fw') = icon('cog fw')
Runners %span
%small.pull-right Runners
= Ci::Runner.count(:all) %span.count= Ci::Runner.count(:all)
= nav_link path: 'builds#index' do = nav_link path: 'builds#index' do
= link_to ci_admin_builds_path do = link_to ci_admin_builds_path do
= icon('link fw') = icon('link fw')
Builds %span
%small.pull-right Builds
= Ci::Build.count(:all) %span.count= Ci::Build.count(:all)
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to ci_admin_application_settings_path do = link_to ci_admin_application_settings_path do
= icon('cogs fw') = icon('cogs fw')
......
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
%li %li
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('plus fw') = icon('plus fw')
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, title: 'Sherlock Transactions',
data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('tachometer fw')
%li %li
= link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('sign-out') = icon('sign-out')
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
Reply to this email directly or Reply to this email directly or
#{link_to "view it on GitLab", @target_url}. #{link_to "view it on GitLab", @target_url}.
- else - else
#{link_to "View it on GitLab", @target_url} #{link_to "View it on GitLab", @target_url}.
%br %br
You're receiving this email because of your account on #{link_to Gitlab.config.gitlab.host, root_url}. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}.
If you'd like to receive fewer emails, you can adjust your notification settings. If you'd like to receive fewer emails, you can adjust your notification settings.
= email_action @target_url = email_action @target_url
...@@ -14,4 +14,4 @@ ...@@ -14,4 +14,4 @@
= form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
= hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
= hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
= select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'trigger-submit' = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'form-control trigger-submit'
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
= ci_commit.status = ci_commit.status
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message"
&middot; &middot;
#{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by
= commit_author_link(commit, avatar: true, size: 24) = commit_author_link(commit, avatar: true, size: 24)
%tr.build
%td.status
= ci_status_with_icon(build.status)
%td.commit_status-link
- if build.target_url
= link_to build.target_url do
%strong Build ##{build.id}
- else
%strong Build ##{build.id}
- if build.show_warning?
%i.fa.fa-warning.text-warning
%td
= link_to build.short_sha, namespace_project_commit_path(@project.namespace, @project, build.sha)
%td
= link_to build.ref, namespace_project_commits_path(@project.namespace, @project, build.ref)
%td
- if build.runner
= runner_link(build.runner)
- else
.light none
%td
= build.name
.pull-right
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.trigger_request
%span.label.label-info triggered
- if build.allow_failure
%span.label.label-danger allowed to fail
%td.duration
- if build.duration
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
%span #{time_ago_in_words build.finished_at} ago
%td
.pull-right
- if current_user && can?(current_user, :manage_builds, @project)
- if build.cancel_url
= link_to build.cancel_url, title: 'Cancel' do
%i.fa.fa-remove.cred
- header_title project_title(@project, "Builds", project_builds_path(@project))
- page_title "Builds" - page_title "Builds"
- header_title project_title(@project, "Builds", project_builds_path(@project)) = render "header_title"
.project-issuable-filter .project-issuable-filter
.controls .controls
- if @ci_project && current_user && can?(current_user, :manage_builds, @project) - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs .pull-left.hidden-xs
- if @all_builds.running_or_pending.any? - if @all_builds.running_or_pending.any?
= link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
%ul.center-top-menu %ul.center-top-menu
%li{class: ('active' if @scope.nil?)} %li{class: ('active' if @scope.nil?)}
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
%span.badge.js-totalbuilds-count= @all_builds.count(:id) %span.badge.js-totalbuilds-count= @all_builds.count(:id)
.gray-content-block .gray-content-block
List of #{@scope || 'running'} builds from this project #{(@scope || 'running').capitalize} builds from this project
%ul.content-list %ul.content-list
- if @builds.blank? - if @builds.blank?
...@@ -40,14 +40,14 @@ ...@@ -40,14 +40,14 @@
%th Build ID %th Build ID
%th Commit %th Commit
%th Ref %th Ref
%th Runner %th Stage
%th Name %th Name
%th Duration %th Duration
%th Finished at %th Finished at
%th %th
- @builds.each do |build| - @builds.each do |build|
= render 'projects/builds/build', build: build = render 'projects/commit_statuses/commit_status', commit_status: build, commit_sha: true, stage: true, allow_retry: true
= paginate @builds = paginate @builds, theme: 'gitlab'
- page_title "#{@build.name} (#{@build.id})", "Builds"
= render "header_title"
.build-page .build-page
.gray-content-block .gray-content-block
Build for commit Build ##{@build.id} for commit
%strong.monospace %strong.monospace
= link_to @build.commit.short_sha, ci_status_path(@build.commit) = link_to @build.commit.short_sha, ci_status_path(@build.commit)
from from
%code #{@build.ref} = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
#up-build-trace #up-build-trace
- if @commit.matrix_for_ref?(@build.ref) - if @commit.matrix_for_ref?(@build.ref)
...@@ -20,7 +23,7 @@ ...@@ -20,7 +23,7 @@
= build.id = build.id
- unless @commit.latest_builds_for_ref(@build.ref).include?(@build) - if @build.retried?
%li.active %li.active
%a %a
Build ##{@build.id} Build ##{@build.id}
...@@ -37,7 +40,7 @@ ...@@ -37,7 +40,7 @@
%i.fa.fa-time %i.fa.fa-time
#{duration_in_words(@build.finished_at, @build.started_at)} #{duration_in_words(@build.finished_at, @build.started_at)}
.pull-right .pull-right
= @build.updated_at.stamp('19:00 Aug 27') #{time_ago_with_tooltip(@build.finished_at) if @build.finished_at}
- if @build.show_warning? - if @build.show_warning?
- unless @build.any_runners_online? - unless @build.any_runners_online?
...@@ -87,13 +90,13 @@ ...@@ -87,13 +90,13 @@
.build-widget .build-widget
%h4.title %h4.title
Build Build ##{@build.id}
- if current_user && can?(current_user, :manage_builds, @project) - if current_user && can?(current_user, :manage_builds, @project)
.pull-right .pull-right
- if @build.active? - if @build.cancel_url
= link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger' = link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post
- elsif @build.commands.present? - elsif @build.retry_url
= link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post = link_to "Retry", @build.retry_url, class: 'btn btn-sm btn-primary', method: :post
- if @build.duration - if @build.duration
%p %p
...@@ -101,15 +104,15 @@ ...@@ -101,15 +104,15 @@
#{duration_in_words(@build.finished_at, @build.started_at)} #{duration_in_words(@build.finished_at, @build.started_at)}
%p %p
%span.attr-name Created: %span.attr-name Created:
#{time_ago_in_words(@build.created_at)} ago #{time_ago_with_tooltip(@build.created_at)}
- if @build.finished_at - if @build.finished_at
%p %p
%span.attr-name Finished: %span.attr-name Finished:
#{time_ago_in_words(@build.finished_at)} ago #{time_ago_with_tooltip(@build.finished_at)}
%p %p
%span.attr-name Runner: %span.attr-name Runner:
- if @build.runner && current_user && current_user.admin - if @build.runner && current_user && current_user.admin
\#{link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)} = link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)
- elsif @build.runner - elsif @build.runner
\##{@build.runner.id} \##{@build.runner.id}
...@@ -134,10 +137,11 @@ ...@@ -134,10 +137,11 @@
%h4.title %h4.title
Commit Commit
.pull-right .pull-right
%small #{build_commit_link @build} %small
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
%p %p
%span.attr-name Branch: %span.attr-name Branch:
#{build_ref_link @build} = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
%p %p
%span.attr-name Author: %span.attr-name Author:
#{@build.commit.git_author_name} #{@build.commit.git_author_name}
...@@ -155,7 +159,9 @@ ...@@ -155,7 +159,9 @@
- if @builds.present? - if @builds.present?
.build-widget .build-widget
%h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}: %h4.title #{pluralize(@builds.count(:id), "other build")} for
= succeed ":" do
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
%table.table.builds %table.table.builds
- @builds.each_with_index do |build, i| - @builds.each_with_index do |build, i|
%tr.build %tr.build
...@@ -171,8 +177,5 @@ ...@@ -171,8 +177,5 @@
%td.status= build.status %td.status= build.status
= paginate @builds
:javascript :javascript
new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}") new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}")
- page_title @service.title, "CI Services"
= render 'form' = render 'form'
- page_title "CI Services"
%h3.page-title Project services %h3.page-title Project services
%p.light Project services allow you to integrate GitLab CI with other applications %p.light Project services allow you to integrate GitLab CI with other applications
......
...@@ -102,9 +102,10 @@ ...@@ -102,9 +102,10 @@
%code \(\d+.\d+\%\) covered %code \(\d+.\d+\%\) covered
%li %li
pytest-cov (Python) - pytest-cov (Python) -
%code \d+\%$ %code \d+\%\s*$
%li
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
%fieldset %fieldset
%legend Advanced settings %legend Advanced settings
......
- page_title "CI Settings"
- if @ci_project.generated_yaml_config - if @ci_project.generated_yaml_config
%p.alert.alert-danger %p.alert.alert-danger
CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)} CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)}
......
- page_title "CI Web Hooks"
%h3.page-title %h3.page-title
CI Web hooks CI Web hooks
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
= nav_link(path: 'commit#show') do = nav_link(path: 'commit#show') do
= link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do
Changes Changes
= nav_link(path: 'commit#ci') do %span.badge= @diffs.count
= link_to ci_namespace_project_commit_path(@project.namespace, @project, @commit.id) do = nav_link(path: 'commit#builds') do
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id) do
Builds Builds
%span.badge= @builds.count(:id)
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
%p %p
%span.light Commit %span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit) = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
.commit-info-row .commit-info-row
%span.light Authored by %span.light Authored by
%strong %strong
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
.commit-info-row .commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent") %span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent| - @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent) = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
- if @ci_commit - if @ci_commit
.pull-right .pull-right
......
- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" - page_title "Builds", "#{@commit.title} (#{@commit.short_id})", "Commits"
= render "projects/commits/header_title" = render "projects/commits/header_title"
= render "commit_box" = render "commit_box"
= render "ci_menu" = render "ci_menu"
...@@ -26,8 +26,11 @@ ...@@ -26,8 +26,11 @@
&nbsp; &nbsp;
- if @ci_project && current_user && can?(current_user, :manage_builds, @project) - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-primary', method: :post
- if @ci_commit.builds.running_or_pending.any? - if @ci_commit.builds.running_or_pending.any?
= link_to "Cancel all", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger' = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger', method: :post
.table-holder .table-holder
%table.table.builds %table.table.builds
...@@ -45,7 +48,7 @@ ...@@ -45,7 +48,7 @@
%th %th
- @ci_commit.refs.each do |ref| - @ci_commit.refs.each do |ref|
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered, = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
locals: { coverage: @ci_project.try(:coverage_enabled?), allow_retry: true } locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true, allow_retry: true }
- if @ci_commit.retried.any? - if @ci_commit.retried.any?
.gray-content-block.second-block .gray-content-block.second-block
...@@ -66,4 +69,4 @@ ...@@ -66,4 +69,4 @@
%th Coverage %th Coverage
%th %th
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
locals: { coverage: @ci_project.try(:coverage_enabled?) } locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true }
...@@ -12,14 +12,30 @@ ...@@ -12,14 +12,30 @@
- if commit_status.show_warning? - if commit_status.show_warning?
%i.fa.fa-warning.text-warning %i.fa.fa-warning.text-warning
%td - if defined?(commit_sha) && commit_sha
= commit_status.ref %td
= link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace"
%td %td
= commit_status.stage - if commit_status.ref
= link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref)
- else
.light none
- if defined?(runner) && runner
%td
- if commit_status.try(:runner)
= runner_link(commit_status.runner)
- else
.light none
- if defined?(stage) && stage
%td
= commit_status.stage
%td %td
= commit_status.name = commit_status.name
.pull-right .pull-right
- if commit_status.tags.any? - if commit_status.tags.any?
- commit_status.tags.each do |tag| - commit_status.tags.each do |tag|
...@@ -36,7 +52,7 @@ ...@@ -36,7 +52,7 @@
%td.timestamp %td.timestamp
- if commit_status.finished_at - if commit_status.finished_at
%span #{time_ago_in_words commit_status.finished_at} ago %span #{time_ago_with_tooltip(commit_status.finished_at)}
- if defined?(coverage) && coverage - if defined?(coverage) && coverage
%td.coverage %td.coverage
...@@ -46,9 +62,10 @@ ...@@ -46,9 +62,10 @@
%td %td
.pull-right .pull-right
- if current_user && can?(current_user, :manage_builds, commit_status.gl_project) - if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
- if commit_status.cancel_url - if commit_status.active?
= link_to commit_status.cancel_url, title: 'Cancel' do - if commit_status.cancel_url
%i.fa.fa-remove.cred = link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && commit_status.retry_url - elsif defined?(allow_retry) && allow_retry && commit_status.retry_url
= link_to commit_status.retry_url, method: :post, title: 'Retry' do = link_to commit_status.retry_url, method: :post, title: 'Retry' do
%i.fa.fa-repeat %i.fa.fa-repeat
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- diff_files = safe_diff_files(diffs) - diff_files = safe_diff_files(diffs)
.gray-content-block.second-block .gray-content-block.second-block.oneline-block
.inline-parallel-buttons .inline-parallel-buttons
.btn-group .btn-group
= inline_diff_btn = inline_diff_btn
......
%ul.nav.nav-tabs %ul.center-top-menu
= nav_link(action: :show) do = nav_link(action: :show) do
= link_to 'Contributors', namespace_project_graph_path = link_to 'Contributors', namespace_project_graph_path
= nav_link(action: :commits) do = nav_link(action: :commits) do
......
- page_title "Continuous Integration", "Graphs" - page_title "Continuous Integration", "Graphs"
= render "header_title" = render "header_title"
= render 'head' = render 'head'
.gray-content-block
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
#charts.ci-charts #charts.ci-charts
= render 'projects/graphs/ci/builds' = render 'projects/graphs/ci/builds'
= render 'projects/graphs/ci/build_times' = render 'projects/graphs/ci/build_times'
......
- page_title "Commits", "Graphs" - page_title "Commits", "Graphs"
= render "header_title" = render "header_title"
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs_commits'
= render 'head' = render 'head'
.gray-content-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs_commits'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
%p.lead %p.lead
Commit statistics for Commit statistics for
%strong #{@ref} %strong #{@ref}
......
- page_title "Contributors", "Graphs" - page_title "Contributors", "Graphs"
= render "header_title" = render "header_title"
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs'
= render 'head' = render 'head'
.gray-content-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
.loading-graph .loading-graph
.center .center
%h3.page-title %h3.page-title
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
= f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json' = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json'
.form-group .form-group
= f.label :url, "Trigger", class: 'control-label' = f.label :url, "Trigger", class: 'control-label'
.col-sm-10 .col-sm-10.prepend-top-10
%div %div
= f.check_box :push_events, class: 'pull-left' = f.check_box :push_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= render 'shared/show_aside' = render 'shared/show_aside'
.gray-content-block.second-block .gray-content-block.second-block.oneline-block
.row .row
.col-md-9 .col-md-9
.votes-holder.pull-right .votes-holder.pull-right
......
.gray-content-block.second-block.oneline-block
= icon("sort-amount-desc")
Most recent commits displayed first
= render "projects/commits/commits", project: @merge_request.project = render "projects/commits/commits", project: @merge_request.project
- status_class = @merge_request.ci_commit ? " ci-#{@merge_request.ci_commit.status}" : nil
= form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| = form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token = hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container .accept-merge-holder.clearfix.js-toggle-container
.accept-action .accept-action
= f.button class: "btn btn-create accept_merge_request" do = f.button class: "btn btn-create accept_merge_request#{status_class}" do
Accept Merge Request Accept Merge Request
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
.accept-control.checkbox .accept-control.checkbox
......
- page_title "Edit", "#{@runner.description} ##{@runner.id}", "Runners"
%h4 Runner ##{@runner.id} %h4 Runner ##{@runner.id}
%hr %hr
= form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f| = form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f|
......
- page_title "Runners"
.light .light
%p %p
A 'runner' is a process which runs a build. A 'runner' is a process which runs a build.
......
= content_for :title do - page_title "#{@runner.description} ##{@runner.id}", "Runners"
%h3.project-title
Runner ##{@runner.id} %h3.page-title
.pull-right Runner ##{@runner.id}
- if @runner.shared? .pull-right
%span.runner-state.runner-state-shared - if @runner.shared?
Shared %span.runner-state.runner-state-shared
- else Shared
%span.runner-state.runner-state-specific - else
Specific %span.runner-state.runner-state-specific
Specific
.table-holder .table-holder
%table.table %table.table
......
- page_title "Triggers"
%h3.page-title %h3.page-title
Triggers Triggers
......
- page_title "Variables"
%h3.page-title %h3.page-title
Secret Variables Secret Variables
......
...@@ -23,9 +23,7 @@ ...@@ -23,9 +23,7 @@
.col-sm-10 .col-sm-10
= render layout: 'projects/md_preview', locals: { preview_class: "md-preview" } do = render layout: 'projects/md_preview', locals: { preview_class: "md-preview" } do
= render 'projects/zen', f: f, attr: :content, classes: 'description form-control js-quick-submit' = render 'projects/zen', f: f, attr: :content, classes: 'description form-control js-quick-submit'
.col-sm-12.hint = render 'projects/notes/hints'
.pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
.pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix .clearfix
.error-alert .error-alert
......
...@@ -27,14 +27,7 @@ ...@@ -27,14 +27,7 @@
= render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, = render 'projects/zen', f: f, attr: :description,
classes: 'description form-control js-quick-submit' classes: 'description form-control js-quick-submit'
.col-sm-12.hint = render 'projects/notes/hints'
.pull-left
Parsed with
#{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
.pull-right
Attach files by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector' }.
.clearfix .clearfix
.error-alert .error-alert
%hr %hr
......
- page_title t('sherlock.title'), t('sherlock.transaction'),
t('sherlock.file_sample')
- header_title t('sherlock.title'), sherlock_transactions_path
.gray-content-block
.pull-right
= link_to(sherlock_transaction_path(@transaction), class: 'btn') do
%i.fa.fa-arrow-left
= t('sherlock.transaction')
.oneline
= t('sherlock.file_sample')
= @file_sample.id
.prepend-top-default
%p
%span.light
#{t('sherlock.time')}:
%strong
= @file_sample.duration.round(2)
= t('sherlock.milliseconds')
%p
%span.light
#{t('sherlock.events')}:
%strong
= @file_sample.events
%article.file-holder
.file-title
%i.fa.fa-file-text-o.fa-fw
%strong
= @file_sample.file
.code.file-content.js-syntax-highlight
.line-numbers
%table.sherlock-line-samples-table
%thead
%tr
%th= t('sherlock.line_capitalized')
%th= t('sherlock.events')
%th= t('sherlock.time')
%th= t('sherlock.percent')
%tbody
- @file_sample.line_samples.each_with_index do |sample, index|
%tr{class: sample.majority_of?(@file_sample.duration) ? 'slow' : ''}
%td= index + 1
%td= sample.events
%td
= sample.duration.round(2)
= t('sherlock.milliseconds')
%td
= sample.percentage_of(@file_sample.duration).round
= t('sherlock.percent')
.sherlock-file-sample
= highlight(@file_sample.file, @file_sample.source)
.prepend-top-default
.panel.panel-default
.panel-heading
%strong
= t('sherlock.application_backtrace')
%ul.well-list
- @query.application_backtrace.each do |location|
%li
= location.path
%small.light
= t('sherlock.line')
= location.line
.panel.panel-default
.panel-heading
%strong
= t('sherlock.full_backtrace')
%ul.well-list
- @query.backtrace.each do |location|
%li
- if location.application?
%strong= location.path
- else
= location.path
%small.light
= t('sherlock.line')
= location.line
.prepend-top-default
.panel.panel-default
.panel-heading
%strong
= t('sherlock.general')
%ul.well-list
%li
%span.light
#{t('sherlock.time')}:
%strong
= @query.duration.round(4)
= t('sherlock.milliseconds')
%li
%span.light
#{t('sherlock.origin')}:
%strong
= @query.last_application_frame.path
%small.light
= t('sherlock.line')
= @query.last_application_frame.line
.panel.panel-default
.panel-heading
.pull-right
%button.js-clipboard-trigger.btn.btn-xs{title: t('sherlock.copy_to_clipboard'), type: :button}
%i.fa.fa-clipboard
%pre.hidden
= @query.formatted_query
%strong
= t('sherlock.query')
%ul.well-list
%li
.code.js-syntax-highlight.sherlock-code
:preserve
#{highlight("#{@query.id}.sql", @query.formatted_query)}
.panel.panel-default
.panel-heading
.pull-right
%button.js-clipboard-trigger.btn.btn-xs{title: t('sherlock.copy_to_clipboard'), type: :button}
%i.fa.fa-clipboard
%pre.hidden
= @query.explain
%strong
= t('sherlock.query_plan')
%ul.well-list
%li
.code.js-syntax-highlight.sherlock-code
%pre
%code= @query.explain
- page_title t('sherlock.title'), t('sherlock.transaction'), t('sherlock.query')
- header_title t('sherlock.title'), sherlock_transactions_path
%ul.center-top-menu
%li.active
%a(href="#tab-general" data-toggle="tab")
= t('sherlock.general')
%li
%a(href="#tab-backtrace" data-toggle="tab")
= t('sherlock.backtrace')
.gray-content-block
.pull-right
= link_to(sherlock_transaction_path(@transaction), class: 'btn') do
%i.fa.fa-arrow-left
= t('sherlock.transaction')
.oneline
= t('sherlock.query')
= @query.id
.tab-content
.tab-pane.active#tab-general
= render(partial: 'general')
.tab-pane#tab-backtrace
= render(partial: 'backtrace')
- if @transaction.file_samples.empty?
.nothing-here-block
= t('sherlock.no_file_samples')
- else
.table-holder
%table.table
%thead
%tr
%th= t('sherlock.time_inclusive')
%th= t('sherlock.count')
%th= t('sherlock.path')
%th
%tbody
- @transaction.sorted_file_samples.each do |sample|
%tr
%td
= sample.duration.round(2)
= t('sherlock.milliseconds')
%td= @transaction.view_counts.fetch(sample.file, 1)
%td= sample.relative_path
%td
= link_to(t('sherlock.view'),
sherlock_transaction_file_sample_path(@transaction, sample),
class: 'btn btn-xs')
.prepend-top-default
.panel.panel-default
.panel-heading
%strong
= t('sherlock.general')
%ul.well-list
%li
%span.light
#{t('sherlock.id')}:
%strong
= @transaction.id
%li
%span.light
#{t('sherlock.type')}:
%strong
= @transaction.type
%li
%span.light
#{t('sherlock.path')}:
%strong
= @transaction.path
%li
%span.light
#{t('sherlock.time')}:
%strong
= @transaction.duration.round(2)
= t('sherlock.seconds')
%li
%span.light
#{t('sherlock.finished_at')}:
%strong
= time_ago_in_words(@transaction.finished_at)
= t('sherlock.ago')
- if @transaction.queries.empty?
.nothing-here-block
= t('sherlock.no_queries')
- else
.table-holder
%table.table#sherlock-queries
%thead
%tr
%th= t('sherlock.time')
%th= t('sherlock.query')
%td
%tbody
- @transaction.sorted_queries.each do |query|
%tr
%td
= query.duration.round(2)
= t('sherlock.milliseconds')
%td
.code.js-syntax-highlight.sherlock-code
= highlight("#{query.id}.sql", query.formatted_query)
%td
= link_to(t('sherlock.view'),
sherlock_transaction_query_path(@transaction, query),
class: 'btn btn-xs')
- page_title t('sherlock.title')
- header_title t('sherlock.title'), sherlock_transactions_path
.gray-content-block
.pull-right
= link_to(destroy_all_sherlock_transactions_path,
class: 'btn btn-danger',
method: :delete) do
%i.fa.fa-trash
= t('sherlock.delete_all_transactions')
.oneline= t('sherlock.introduction')
- if @transactions.empty?
.nothing-here-block= t('sherlock.no_transactions')
- else
.table-holder
%table.table
%thead
%tr
%th= t('sherlock.type')
%th= t('sherlock.path')
%th= t('sherlock.time')
%th= t('sherlock.queries')
%th= t('sherlock.finished_at')
%th
%tbody
- @transactions.each do |trans|
%tr
%td= trans.type
%td
%span{title: trans.path}
= truncate(trans.path, length: 70)
%td
= trans.duration.round(2)
= t('sherlock.seconds')
%td= trans.queries.length
%td
= time_ago_in_words(trans.finished_at)
= t('sherlock.ago')
%td
= link_to(sherlock_transaction_path(trans), class: 'btn btn-xs') do
= t('sherlock.view')
- page_title t('sherlock.title'), t('sherlock.transaction')
- header_title t('sherlock.title'), sherlock_transactions_path
%ul.center-top-menu
%li.active
%a(href="#tab-general" data-toggle="tab")
= t('sherlock.general')
%li
%a(href="#tab-queries" data-toggle="tab")
= t('sherlock.queries')
%span.badge
#{@transaction.queries.length}
%li
%a(href="#tab-file-samples" data-toggle="tab")
= t('sherlock.file_samples')
%span.badge
#{@transaction.file_samples.length}
.gray-content-block
.pull-right
= link_to(sherlock_transactions_path, class: 'btn') do
%i.fa.fa-arrow-left
= t('sherlock.all_transactions')
.oneline
= t('sherlock.transaction')
= @transaction.id
.tab-content
.tab-pane.active#tab-general
= render(partial: 'general')
.tab-pane#tab-queries
= render(partial: 'queries')
.tab-pane#tab-file-samples
= render(partial: 'file_samples')
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
.user-calendar-activities .user-calendar-activities
%ul.nav.center-middle-menu %ul.center-middle-menu
%li.active %li.active
= link_to "#activity", 'data-toggle' => 'tab' do = link_to "#activity", 'data-toggle' => 'tab' do
Activity Activity
...@@ -106,14 +106,14 @@ ...@@ -106,14 +106,14 @@
.contributed-projects .contributed-projects
= render 'shared/projects/list', = render 'shared/projects/list',
projects: @contributed_projects.sort_by(&:star_count).reverse, projects: @contributed_projects.sort_by(&:star_count).reverse,
projects_limit: 5, stars: true, avatar: false projects_limit: 5, stars: true, avatar: true
- if @projects.present? - if @projects.present?
.tab-pane#personal .tab-pane#personal
.personal-projects .personal-projects
= render 'shared/projects/list', = render 'shared/projects/list',
projects: @projects.sort_by(&:star_count).reverse, projects: @projects.sort_by(&:star_count).reverse,
projects_limit: 10, stars: true, avatar: false projects_limit: 10, stars: true, avatar: true
:coffeescript :coffeescript
$(".user-calendar").load("#{user_calendar_path}") $(".user-calendar").load("#{user_calendar_path}")
...@@ -274,27 +274,28 @@ production: &base ...@@ -274,27 +274,28 @@ production: &base
# arguments, followed by optional 'args' which can be either a hash or an array. # 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 # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
providers: providers:
# - { name: 'google_oauth2',
# label: 'Google',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET',
# args: { access_type: 'offline', approval_prompt: '' } }
# - { 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', # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'user:email' } } # args: { scope: 'user:email' } }
# - { name: 'bitbucket',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' }
# - { name: 'gitlab', # - { name: 'gitlab',
# label: 'GitLab.com',
# app_id: 'YOUR_APP_ID', # app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET', # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'api' } } # args: { scope: 'api' } }
# - { name: 'bitbucket', # - { name: 'google_oauth2',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET',
# args: { access_type: 'offline', approval_prompt: '' } }
# - { name: 'facebook',
# app_id: 'YOUR_APP_ID', # app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' } # app_secret: 'YOUR_APP_SECRET' }
# - { name: 'twitter',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' }
#
# - { name: 'saml', # - { name: 'saml',
# label: 'Our SAML Provider', # label: 'Our SAML Provider',
# args: { # args: {
......
...@@ -181,10 +181,11 @@ Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious' ...@@ -181,10 +181,11 @@ Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious'
# CI # CI
# #
Settings['gitlab_ci'] ||= Settingslogic.new({}) Settings['gitlab_ci'] ||= Settingslogic.new({})
Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_broken_builds'].nil? Settings.gitlab_ci['shared_runners_enabled'] = true if Settings.gitlab_ci['shared_runners_enabled'].nil?
Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil? Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_broken_builds'].nil?
Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url) Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil?
Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root) Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url)
Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root)
# #
# Reply by email # Reply by email
...@@ -192,8 +193,8 @@ Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci[ ...@@ -192,8 +193,8 @@ Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci[
Settings['incoming_email'] ||= Settingslogic.new({}) Settings['incoming_email'] ||= Settingslogic.new({})
Settings.incoming_email['enabled'] = false if Settings.incoming_email['enabled'].nil? Settings.incoming_email['enabled'] = false if Settings.incoming_email['enabled'].nil?
Settings.incoming_email['port'] = 143 if Settings.incoming_email['port'].nil? Settings.incoming_email['port'] = 143 if Settings.incoming_email['port'].nil?
Settings.incoming_email['ssl'] = 143 if Settings.incoming_email['ssl'].nil? Settings.incoming_email['ssl'] = false if Settings.incoming_email['ssl'].nil?
Settings.incoming_email['start_tls'] = 143 if Settings.incoming_email['start_tls'].nil? Settings.incoming_email['start_tls'] = false if Settings.incoming_email['start_tls'].nil?
Settings.incoming_email['mailbox'] = "inbox" if Settings.incoming_email['mailbox'].nil? Settings.incoming_email['mailbox'] = "inbox" if Settings.incoming_email['mailbox'].nil?
# #
......
module Gitlab module Gitlab
VERSION = File.read(Rails.root.join("VERSION")).strip
REVISION = Gitlab::Popen.popen(%W(git log --pretty=format:%h -n 1)).first.chomp
def self.config def self.config
Settings Settings
end end
VERSION = File.read(Rails.root.join("VERSION")).strip
REVISION = Gitlab::Popen.popen(%W(#{config.git.bin_path} log --pretty=format:%h -n 1)).first.chomp
end end
if Rails.env.development?
require 'rack-mini-profiler'
# initialization is skipped so trigger it
Rack::MiniProfilerRails.initialize!(Gitlab::Application)
Rack::MiniProfiler.config.position = 'right'
Rack::MiniProfiler.config.start_hidden = false
Rack::MiniProfiler.config.skip_paths << '/teaspoon'
end
if Gitlab::Sherlock.enabled?
Gitlab::Application.configure do |config|
config.middleware.use(Gitlab::Sherlock::Middleware)
end
end
en:
sherlock:
title: Sherlock
delete_all_transactions: Delete All Transactions
introduction: >
Below is a list of all transactions recorded by Sherlock. Requests to
Sherlock's own routes are ignored.
no_transactions: No transactions to show
no_queries: No queries to show
no_file_samples: No file samples to show
all_transactions: All Transactions
transaction: Transaction
query: Query
file_sample: File Sample
type: Type
path: Path
time: Time
queries: Queries
finished_at: Finished at
ago: ago
view: View
seconds: seconds
milliseconds: ms
general: General
id: ID
time_inclusive: Time (inclusive)
backtrace: Backtrace
application_backtrace: Application Backtrace
full_backtrace: Full Backtrace
origin: Origin
line: line
line_capitalized: Line
copy_to_clipboard: Copy to clipboard
query_plan: Query Plan
events: Events
percent: '%'
count: Count
...@@ -2,6 +2,19 @@ require 'sidekiq/web' ...@@ -2,6 +2,19 @@ require 'sidekiq/web'
require 'api/api' require 'api/api'
Gitlab::Application.routes.draw do Gitlab::Application.routes.draw do
if Gitlab::Sherlock.enabled?
namespace :sherlock do
resources :transactions, only: [:index, :show] do
resources :queries, only: [:show]
resources :file_samples, only: [:show]
collection do
delete :destroy_all
end
end
end
end
namespace :ci do namespace :ci do
# CI API # CI API
Ci::API::API.logger Rails.logger Ci::API::API.logger Rails.logger
...@@ -472,8 +485,9 @@ Gitlab::Application.routes.draw do ...@@ -472,8 +485,9 @@ Gitlab::Application.routes.draw do
resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
member do member do
get :branches get :branches
get :ci get :builds
get :cancel_builds post :cancel_builds
post :retry_builds
end end
end end
...@@ -588,12 +602,12 @@ Gitlab::Application.routes.draw do ...@@ -588,12 +602,12 @@ Gitlab::Application.routes.draw do
resources :builds, only: [:index, :show] do resources :builds, only: [:index, :show] do
collection do collection do
get :cancel_all post :cancel_all
end end
member do member do
get :cancel
get :status get :status
post :cancel
post :retry post :retry
end end
end end
......
class FixBuildTags < ActiveRecord::Migration class FixBuildTags < ActiveRecord::Migration
def change def up
execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'") execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'")
end end
def down
execute("UPDATE taggings SET taggable_type='Ci::Build' WHERE taggable_type='CommitStatus'")
end
end end
class FailBuildWithoutNames < ActiveRecord::Migration class FailBuildWithoutNames < ActiveRecord::Migration
def change def up
execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'") execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'")
end end
def down
end
end end
class AddServicesTemplateIndex < ActiveRecord::Migration
def change
add_index :services, :template
end
end
class FailBuildWithEmptyName < ActiveRecord::Migration class FailBuildWithEmptyName < ActiveRecord::Migration
def change def up
execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'") execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'")
end end
def down
end
end end
class AddPublicToGroup < ActiveRecord::Migration
def change
add_column :namespaces, :public, :boolean, default: false
end
end
class AddSharedRunnersSetting < ActiveRecord::Migration
def up
add_column :application_settings, :shared_runners_enabled, :boolean, default: true, null: false
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151026182941) do ActiveRecord::Schema.define(version: 20151103133339) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -47,6 +47,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do ...@@ -47,6 +47,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do
t.text "import_sources" t.text "import_sources"
t.text "help_page_text" t.text "help_page_text"
t.string "admin_notification_email" t.string "admin_notification_email"
t.boolean "shared_runners_enabled", default: true, null: false
end end
create_table "audit_events", force: true do |t| create_table "audit_events", force: true do |t|
...@@ -501,14 +502,15 @@ ActiveRecord::Schema.define(version: 20151026182941) do ...@@ -501,14 +502,15 @@ ActiveRecord::Schema.define(version: 20151026182941) do
add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
create_table "namespaces", force: true do |t| create_table "namespaces", force: true do |t|
t.string "name", null: false t.string "name", null: false
t.string "path", null: false t.string "path", null: false
t.integer "owner_id" t.integer "owner_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "type" t.string "type"
t.string "description", default: "", null: false t.string "description", default: "", null: false
t.string "avatar" t.string "avatar"
t.boolean "public", default: false
end end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
...@@ -667,6 +669,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do ...@@ -667,6 +669,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
add_index "services", ["template"], name: "index_services_on_template", using: :btree
create_table "snippets", force: true do |t| create_table "snippets", force: true do |t|
t.string "title" t.string "title"
......
...@@ -17,20 +17,22 @@ ...@@ -17,20 +17,22 @@
## CI Documentation ## CI Documentation
+ [Quick Start](ci/quick_start/README.md) - [Quick Start](ci/quick_start/README.md)
+ [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md) - [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md)
+ [Configuring runner](ci/runners/README.md) - [Configuring runner](ci/runners/README.md)
+ [Configuring deployment](ci/deployment/README.md) - [Configuring deployment](ci/deployment/README.md)
+ [Using Docker Images](ci/docker/using_docker_images.md) - [Using Docker Images](ci/docker/using_docker_images.md)
+ [Using Docker Build](ci/docker/using_docker_build.md) - [Using Docker Build](ci/docker/using_docker_build.md)
+ [Using Variables](ci/variables/README.md) - [Using Variables](ci/variables/README.md)
- [User permissions](ci/permissions/README.md)
- [API](ci/api/README.md)
### CI Examples ### CI Examples
+ [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md) - [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md)
+ [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md) - [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md)
+ [Test Clojure applications](ci/examples/test-clojure-application.md) - [Test Clojure applications](ci/examples/test-clojure-application.md)
+ Help your favorite programming language and GitLab by sending a merge request with a guide for that language. - Help your favorite programming language and GitLab by sending a merge request with a guide for that language.
## Administrator documentation ## Administrator documentation
...@@ -49,11 +51,6 @@ ...@@ -49,11 +51,6 @@
- [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails. - [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails.
- [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE. - [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE.
### Administrator documentation
+ [User permissions](permissions/permissions.md)
+ [API](api/README.md)
## Contributor documentation ## Contributor documentation
- [Development](development/README.md) Explains the architecture and the guidelines for shell commands. - [Development](development/README.md) Explains the architecture and the guidelines for shell commands.
......
...@@ -4,11 +4,15 @@ To make it easier to track down performance problems GitLab comes with a set of ...@@ -4,11 +4,15 @@ To make it easier to track down performance problems GitLab comes with a set of
profiling tools, some of these are available by default while others need to be profiling tools, some of these are available by default while others need to be
explicitly enabled. explicitly enabled.
## rack-mini-profiler ## Sherlock
This Gem is enabled by default in development only. It allows you to see the Sherlock is a custom profiling tool built into GitLab. Sherlock is _only_
timings of the various components that made up a web request (e.g. the SQL available when running GitLab in development mode _and_ when setting the
queries executed and their execution timings). environment variable `ENABLE_SHERLOCK` to a non empty value. For example:
ENABLE_SHERLOCK=1 bundle exec rails s
Recorded transactions can be found by navigating to `/sherlock/transactions`.
## Bullet ## Bullet
...@@ -21,36 +25,3 @@ starting GitLab. For example: ...@@ -21,36 +25,3 @@ starting GitLab. For example:
Bullet will log query problems to both the Rails log as well as the Chrome Bullet will log query problems to both the Rails log as well as the Chrome
console. console.
## ActiveRecord Query Trace
This Gem adds backtraces for every ActiveRecord query in the Rails console. This
can be useful to track down where a query was executed. Because this Gem adds
quite a bit of noise (5-10 extra lines per ActiveRecord query) it's disabled by
default. To use this Gem you'll need to set `ENABLE_QUERY_TRACE` to a non empty
file before starting GitLab. For example:
ENABLE_QUERY_TRACE=true bundle exec rails s
## rack-lineprof
This is a Gem that can trace the execution time of code on a per line basis.
Because this Gem can add quite a bit of overhead it's disabled by default. To
enable it, set the environment variable `ENABLE_LINEPROF` to a non-empty value.
For example:
ENABLE_LINEPROF=true bundle exec rails s
Once enabled you'll need to add a query string parameter to a request to
actually profile code execution. The name of the parameter is `lineprof` and
should be set to a regular expression (minus the starting/ending slash) used to
select what files to profile. To profile all files containing "foo" somewhere in
the path you'd use the following parameter:
?lineprof=foo
Or when filtering for files containing "foo" and "bar" in their path:
?lineprof=foo|bar
Once set the profiling output will be displayed in your terminal.
...@@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete) ...@@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete)
This coding style could have prevented CVE-2013-4490. This coding style could have prevented CVE-2013-4490.
## Always use the configurable git binary path for git commands
```ruby
# Wrong
system(*%W(git branch -d -- #{branch_name}))
# Correct
system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
```
## Bypass the shell by splitting commands into separate tokens ## Bypass the shell by splitting commands into separate tokens
When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby
...@@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using ...@@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using
```ruby ```ruby
# Wrong # Wrong
system(*%W(git branch -d #{branch_name})) system(*%W(#{Gitlab.config.git.bin_path} branch -d #{branch_name}))
# Correct # Correct
system(*%W(git branch -d -- #{branch_name})) system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
``` ```
This coding style could have prevented CVE-2013-4582. This coding style could have prevented CVE-2013-4582.
...@@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are ...@@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are
```ruby ```ruby
# Wrong # Wrong
logs = `cd #{repo_dir} && git log` logs = `cd #{repo_dir} && #{Gitlab.config.git.bin_path} log`
# Correct # Correct
logs, exit_status = Gitlab::Popen.popen(%W(git log), repo_dir) logs, exit_status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} log), repo_dir)
# Wrong # Wrong
user = `whoami` user = `whoami`
...@@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`. ...@@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`.
```ruby ```ruby
# Safe IO.popen example # Safe IO.popen example
logs = IO.popen(%W(git log), chdir: repo_dir) { |p| p.read } logs = IO.popen(%W(#{Gitlab.config.git.bin_path} log), chdir: repo_dir) { |p| p.read }
``` ```
Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error. Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error.
......
...@@ -253,8 +253,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -253,8 +253,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
nproc nproc
# Enable cluster mode if you expect to have a high load instance # Enable cluster mode if you expect to have a high load instance
# Ex. change amount of workers to 3 for 2GB RAM server
# Set the number of workers to at least the number of cores # Set the number of workers to at least the number of cores
# Ex. change amount of workers to 3 for 2GB RAM server
sudo -u git -H editor config/unicorn.rb sudo -u git -H editor config/unicorn.rb
# Copy the example Rack attack config # Copy the example Rack attack config
...@@ -332,7 +332,7 @@ GitLab Shell is an SSH access and repository management software developed speci ...@@ -332,7 +332,7 @@ GitLab Shell is an SSH access and repository management software developed speci
# Go to Gitlab installation folder # Go to Gitlab installation folder
cd /home/git/gilab cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
......
# Facebook OAuth2 OmniAuth Provider
To enable the Facebook OmniAuth provider you must register your application with Facebook. Facebook will generate an app ID and secret key for you to use.
1. Sign in to the [Facebook Developer Platform](https://developers.facebook.com/).
1. Choose "My Apps" &gt; "Add a New App"
1. Select the type "Website"
1. Enter a name for your app. This can be anything. Consider something like "&lt;Organization&gt;'s GitLab" or "&lt;Your Name&gt;'s GitLab" or
something else descriptive.
1. Choose "Create New Facebook App ID"
1. Select a Category, for example "Productivity"
1. Choose "Create App ID"
1. Enter the address of your GitLab installation at the bottom of the package
![Facebook Website URL](facebook_website_url.png)
1. Choose "Next"
1. Choose "Skip Quick Start" in the upper right corner
1. Choose "Settings" in the menu on the left
1. Fill in a contact email for your app
![Facebook App Settings](facebook_app_settings.png)
1. Choose "Save Changes"
1. Choose "Status & Review" in the menu on the left
1. Change the switch on the right from No to Yes
1. Choose "Confirm" when prompted to make the app public
1. Choose "Dashboard" in the menu on the left
1. Choose "Show" next to the hidden "App Secret"
1. You should now see an app key and app secret (see screenshot). Keep this page open as you continue configuration.
![Facebook API Keys](facebook_api_keys.png)
1. On your GitLab server, open the configuration file.
For omnibus package:
```sh
sudo editor /etc/gitlab/gitlab.rb
```
For installations from source:
```sh
cd /home/git/gitlab
sudo -u git -H editor config/gitlab.yml
```
1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
1. Add the provider configuration:
For omnibus package:
```ruby
gitlab_rails['omniauth_providers'] = [
{
"name" => "facebook",
"app_id" => "YOUR_APP_ID",
"app_secret" => "YOUR_APP_SECRET"
}
]
```
For installations from source:
```
- { name: 'facebook', app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
```
1. Change 'YOUR_APP_ID' to the API key from Facebook page in step 10.
1. Change 'YOUR_APP_SECRET' to the API secret from the Facebook page in step 10.
1. Save the configuration file.
1. Restart GitLab for the changes to take effect.
On the sign in page there should now be a Facebook icon below the regular sign in form. Click the icon to begin the authentication process. Facebook will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
...@@ -73,8 +73,9 @@ Now we can choose one or more of the Supported Providers below to continue confi ...@@ -73,8 +73,9 @@ Now we can choose one or more of the Supported Providers below to continue confi
- [Bitbucket](bitbucket.md) - [Bitbucket](bitbucket.md)
- [GitLab.com](gitlab.md) - [GitLab.com](gitlab.md)
- [Google](google.md) - [Google](google.md)
- [Shibboleth](shibboleth.md) - [Facebook](facebook.md)
- [Twitter](twitter.md) - [Twitter](twitter.md)
- [Shibboleth](shibboleth.md)
- [SAML](saml.md) - [SAML](saml.md)
- [Crowd](crowd.md) - [Crowd](crowd.md)
......
...@@ -25,68 +25,84 @@ If the release is falling behind immediately warn the team. ...@@ -25,68 +25,84 @@ If the release is falling behind immediately warn the team.
## Create an overall issue and follow it ## Create an overall issue and follow it
Create issue for GitLab CE project(internal). Name it "Release x.x.x" for easier searching. Create an issue in the GitLab CE project. Name it "Release x.x" and tag it with
Replace the dates with actual dates based on the number of workdays before the release. the `release` label for easier searching. Replace the dates with actual dates
All steps from issue template are explained below based on the number of workdays before the release. All steps from issue
template are explained below:
``` ```
Xth: (7 working days before the 22nd) ### Xth: (7 working days before the 22nd)
- [ ] Triage the omnibus-gitlab milestone - [ ] Triage the [Omnibus milestone]
Xth: (6 working days before the 22nd) ### Xth: (6 working days before the 22nd)
- [ ] Merge CE master in to EE master via merge request (#LINK) - [ ] Merge CE `master` into EE `master` via merge request (#LINK)
- [ ] Determine QA person and notify this person - [ ] Determine QA person and notify this person
- [ ] Check the tasks in [how to rc1 guide](https://dev.gitlab.org/gitlab/gitlabhq/blob/master/doc/release/howto_rc1.md) and delegate tasks if necessary - [ ] Check the tasks in [how to rc1 guide](https://dev.gitlab.org/gitlab/gitlabhq/blob/master/doc/release/howto_rc1.md) and delegate tasks if necessary
- [ ] Create CE, EE, CI RC1 versions (#LINK) - [ ] Create CE and EE RC1 versions (#LINK)
- [ ] Build RC1 packages (EE first) (#LINK) - [ ] Build RC1 packages
Xth: (5 working days before the 22nd) ### Xth: (5 working days before the 22nd)
- [ ] Do QA and fix anything coming out of it (#LINK) - [ ] Do QA and fix anything coming out of it (#LINK)
- [ ] Close the omnibus-gitlab milestone - [ ] Close the [Omnibus milestone]
- [ ] Prepare the blog post (#LINK) - [ ] Prepare the [blog post]
Xth: (4 working days before the 22nd) ### Xth: (4 working days before the 22nd)
- [ ] Update GitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package) - [ ] Update GitLab.com with RC1
- [ ] Update ci.gitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package) - [ ] Create the regression issue in the CE issue tracker:
- [ ] Create regression issues (CE, CI) (#LINK)
- [ ] Tweet about rc1 (#LINK), proposed text:
> GitLab x.x.0.rc1 is available https://packages.gitlab.com/gitlab/unstable Use at your own risk. Please link regressions issues from LINK_TO_REGRESSION_ISSUE > This is a meta issue to index possible regressions in this monthly release
> and any patch versions.
>
> Please do not raise or discuss issues directly in this issue but link to
> issues that might warrant a patch release. If there is a Merge Request
> that fixes the issue, please link to that as well.
>
> Please only post one regression issue and/or merge request per comment.
> Comments will be updated by the release manager as they are addressed.
Xth: (3 working days before the 22nd) - [ ] Tweet about RC1 release:
- [ ] Merge CE stable branch into EE stable branch > GitLab x.y.0.rc1 is available: https://packages.gitlab.com/gitlab/unstable
> Use at your own risk. Please link regressions issues from
> LINK_TO_REGRESSION_ISSUE
Xth: (2 working days before the 22nd) ### Xth: (3 working days before the 22nd)
- [ ] Check that everyone is mentioned on the blog post using `@all` (the reviewer should have done this one working day ago) - [ ] Merge `x-y-stable` into `x-y-stable-ee`
- [ ] Check that MVP is added to the mvp page (source/mvp/index.html in www-gitlab-com) - [ ] Check that everyone is mentioned on the [blog post] using `@all`
Xth: (1 working day before the 22nd) ### Xth: (2 working days before the 22nd)
- [ ] Merge CE stable into EE stable - [ ] Check that MVP is added to the [MVP page]
- [ ] Create CE, EE, CI release candidates (#LINK) (hopefully final ones with the same commit as the release tomorrow)
### Xth: (1 working day before the 22nd)
- [ ] Merge `x-y-stable` into `x-y-stable-ee`
- [ ] Create CE and EE release candidates
- [ ] Create Omnibus tags and build packages for the latest release candidates - [ ] Create Omnibus tags and build packages for the latest release candidates
- [ ] Update GitLab.com with the latest RC (#LINK) - [ ] Update GitLab.com with the latest RC
- [ ] Update ci.gitLab.com with the latest RC (#LINK)
22nd before 1200 CET: ### 22nd before 1200 CET:
Release before 1200 CET / 2AM PST, to make sure the majority of our users Release before 1200 CET / 2AM PST, to make sure the majority of our users
get the new version on the 22nd and there is sufficient time in the European get the new version on the 22nd and there is sufficient time in the European
workday to quickly fix any issues. workday to quickly fix any issues.
- [ ] Merge CE stable into EE stable (#LINK) - [ ] Merge `x-y-stable` into `x-y-stable-ee`
- [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) (#LINK) - [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools)
- [ ] Create the 'x.y.0' version on version.gitlab.com - [ ] Create the 'x.y.0' version on version.gitlab.com
- [ ] Try to do before 1100 CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK) - [ ] Try to do before 1100 CET: Create and push Omnibus tags for x.y.0 (will auto-release the packages)
- [ ] Try to do before 1200 CET: Publish the release blog post (#LINK) - [ ] Try to do before 1200 CET: Publish the release [blog post]
- [ ] Tweet about the release (blog post) (#LINK) - [ ] Tweet about the release
- [ ] Schedule a second tweet of the release announcement with the same text at 1800 CET / 8AM PST - [ ] Schedule a second Tweet of the release announcement with the same text at 1800 CET / 8AM PST
[Omnibus milestone]: LINK_TO_OMNIBUS_MILESTONE
[blog post]: LINK_TO_WIP_BLOG_POST
[MVP page]: https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/source/mvp/index.html
``` ```
- - - - - -
......
...@@ -15,6 +15,8 @@ For subtitles, use '##', '###' and so on. ...@@ -15,6 +15,8 @@ For subtitles, use '##', '###' and so on.
- Do not duplicate information. - Do not duplicate information.
- Be brief and clear. - Be brief and clear.
- Whenever it applies, add documents in alphabetical order. - Whenever it applies, add documents in alphabetical order.
- Write in US English
- Use [single spaces](http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html) instead of double spaces.
## Images ## Images
......
...@@ -35,7 +35,7 @@ module Backup ...@@ -35,7 +35,7 @@ module Backup
if wiki.repository.empty? if wiki.repository.empty?
$progress.puts " [SKIPPED]".cyan $progress.puts " [SKIPPED]".cyan
else else
cmd = %W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all) cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all)
output, status = Gitlab::Popen.popen(cmd) output, status = Gitlab::Popen.popen(cmd)
if status.zero? if status.zero?
$progress.puts " [DONE]".green $progress.puts " [DONE]".green
...@@ -67,7 +67,7 @@ module Backup ...@@ -67,7 +67,7 @@ module Backup
FileUtils.mkdir_p(path_to_repo(project)) FileUtils.mkdir_p(path_to_repo(project))
cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)}) cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)})
else else
cmd = %W(git init --bare #{path_to_repo(project)}) cmd = %W(#{Gitlab.config.git.bin_path} init --bare #{path_to_repo(project)})
end end
if system(*cmd, silent) if system(*cmd, silent)
...@@ -87,7 +87,7 @@ module Backup ...@@ -87,7 +87,7 @@ module Backup
# that was initialized with ProjectWiki.new() and then # that was initialized with ProjectWiki.new() and then
# try to restore with 'git clone --bare'. # try to restore with 'git clone --bare'.
FileUtils.rm_rf(path_to_repo(wiki)) FileUtils.rm_rf(path_to_repo(wiki))
cmd = %W(git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)}) cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)})
if system(*cmd, silent) if system(*cmd, silent)
$progress.puts " [DONE]".green $progress.puts " [DONE]".green
......
...@@ -23,7 +23,8 @@ module Gitlab ...@@ -23,7 +23,8 @@ module Gitlab
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'], max_attachment_size: Settings.gitlab['max_attachment_size'],
session_expire_delay: Settings.gitlab['session_expire_delay'], session_expire_delay: Settings.gitlab['session_expire_delay'],
import_sources: Settings.gitlab['import_sources'] import_sources: Settings.gitlab['import_sources'],
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
) )
end end
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
false false
else else
missed_refs, _ = Gitlab::Popen.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
missed_refs.split("\n").size > 0 missed_refs.split("\n").size > 0
end end
end end
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
# Returns true for a valid reference name, false otherwise # Returns true for a valid reference name, false otherwise
def validate(ref_name) def validate(ref_name)
Gitlab::Utils.system_silent( Gitlab::Utils.system_silent(
%W(git check-ref-format refs/#{ref_name})) %W(#{Gitlab.config.git.bin_path} check-ref-format refs/#{ref_name}))
end end
end end
end end
module Gitlab module Gitlab
module OAuth module OAuth
class Provider class Provider
LABELS = {
"github" => "GitHub",
"gitlab" => "GitLab.com",
"google_oauth2" => "Google"
}.freeze
def self.providers def self.providers
Devise.omniauth_providers Devise.omniauth_providers
end end
...@@ -23,8 +29,9 @@ module Gitlab ...@@ -23,8 +29,9 @@ module Gitlab
end end
def self.label_for(name) def self.label_for(name)
name = name.to_s
config = config_for(name) config = config_for(name)
(config && config['label']) || name.to_s.titleize (config && config['label']) || LABELS[name] || name.titleize
end end
end end
end end
......
require 'securerandom'
module Gitlab
module Sherlock
@collection = Collection.new
class << self
attr_reader :collection
end
def self.enabled?
Rails.env.development? && !!ENV['ENABLE_SHERLOCK']
end
def self.enable_line_profiler?
RUBY_ENGINE == 'ruby'
end
end
end
module Gitlab
module Sherlock
# A collection of transactions recorded by Sherlock.
#
# Method calls for this class are synchronized using a mutex to allow
# sharing of a single Collection instance between threads (e.g. when using
# Puma as a webserver).
class Collection
include Enumerable
def initialize
@transactions = []
@mutex = Mutex.new
end
def add(transaction)
synchronize { @transactions << transaction }
end
alias_method :<<, :add
def each(&block)
synchronize { @transactions.each(&block) }
end
def clear
synchronize { @transactions.clear }
end
def empty?
synchronize { @transactions.empty? }
end
def find_transaction(id)
find { |trans| trans.id == id }
end
def newest_first
sort { |a, b| b.finished_at <=> a.finished_at }
end
private
def synchronize(&block)
@mutex.synchronize(&block)
end
end
end
end
module Gitlab
module Sherlock
class FileSample
attr_reader :id, :file, :line_samples, :events, :duration
# file - The full path to the file this sample belongs to.
# line_samples - An array of LineSample objects.
# duration - The total execution time in milliseconds.
# events - The total amount of events.
def initialize(file, line_samples, duration, events)
@id = SecureRandom.uuid
@file = file
@line_samples = line_samples
@duration = duration
@events = events
end
def relative_path
@relative_path ||= @file.gsub(/^#{Rails.root.to_s}\/?/, '')
end
def to_param
@id
end
def source
@source ||= File.read(@file)
end
end
end
end
module Gitlab
module Sherlock
# Class for profiling code on a per line basis.
#
# The LineProfiler class can be used to profile code on per line basis
# without littering your code with Ruby implementation specific profiling
# methods.
#
# This profiler only includes samples taking longer than a given threshold
# and those that occur in the actual application (e.g. files from Gems are
# ignored).
class LineProfiler
# The minimum amount of time that has to be spent in a file for it to be
# included in a list of samples.
MINIMUM_DURATION = 10.0
# Profiles the given block.
#
# Example:
#
# profiler = LineProfiler.new
#
# retval, samples = profiler.profile do
# "cats are amazing"
# end
#
# retval # => "cats are amazing"
# samples # => [#<Gitlab::Sherlock::FileSample ...>, ...]
#
# Returns an Array containing the block's return value and an Array of
# FileSample objects.
def profile(&block)
if mri?
profile_mri(&block)
else
raise NotImplementedError,
'Line profiling is not supported on this platform'
end
end
# Profiles the given block using rblineprof (MRI only).
def profile_mri
require 'rblineprof'
retval = nil
samples = lineprof(/^#{Rails.root.to_s}/) { retval = yield }
file_samples = aggregate_rblineprof(samples)
[retval, file_samples]
end
# Returns an Array of file samples based on the output of rblineprof.
#
# lineprof_stats - A Hash containing rblineprof statistics on a per file
# basis.
#
# Returns an Array of FileSample objects.
def aggregate_rblineprof(lineprof_stats)
samples = []
lineprof_stats.each do |(file, stats)|
source_lines = File.read(file).each_line.to_a
line_samples = []
total_duration = microsec_to_millisec(stats[0][0])
total_events = stats[0][2]
next if total_duration <= MINIMUM_DURATION
stats[1..-1].each_with_index do |data, index|
next unless source_lines[index]
duration = microsec_to_millisec(data[0])
events = data[2]
line_samples << LineSample.new(duration, events)
end
samples << FileSample.
new(file, line_samples, total_duration, total_events)
end
samples
end
private
def microsec_to_millisec(microsec)
microsec / 1000.0
end
def mri?
RUBY_ENGINE == 'ruby'
end
end
end
end
module Gitlab
module Sherlock
class LineSample
attr_reader :duration, :events
# duration - The execution time in milliseconds.
# events - The amount of events.
def initialize(duration, events)
@duration = duration
@events = events
end
# Returns the sample duration percentage relative to the given duration.
#
# Example:
#
# sample.duration # => 150
# sample.percentage_of(1500) # => 10.0
#
# total_duration - The total duration to compare with.
#
# Returns a float
def percentage_of(total_duration)
(duration.to_f / total_duration) * 100.0
end
# Returns true if the current sample takes up the majority of the given
# duration.
#
# total_duration - The total duration to compare with.
def majority_of?(total_duration)
percentage_of(total_duration) >= 30
end
end
end
end
module Gitlab
module Sherlock
class Location
attr_reader :path, :line
SHERLOCK_DIR = File.dirname(__FILE__)
# Creates a new Location from a `Thread::Backtrace::Location`.
def self.from_ruby_location(location)
new(location.path, location.lineno)
end
# path - The full path of the frame as a String.
# line - The line number of the frame as a Fixnum.
def initialize(path, line)
@path = path
@line = line
end
# Returns true if the current frame originated from the application.
def application?
@path.start_with?(Rails.root.to_s) && !path.start_with?(SHERLOCK_DIR)
end
end
end
end
module Gitlab
module Sherlock
# Rack middleware used for tracking request metrics.
class Middleware
CONTENT_TYPES = /text\/html|application\/json/i
IGNORE_PATHS = %r{^/sherlock}
def initialize(app)
@app = app
end
# env - A Hash containing Rack environment details.
def call(env)
if instrument?(env)
call_with_instrumentation(env)
else
@app.call(env)
end
end
def call_with_instrumentation(env)
trans = transaction_from_env(env)
retval = trans.run { @app.call(env) }
Sherlock.collection.add(trans)
retval
end
def instrument?(env)
!!(env['HTTP_ACCEPT'] =~ CONTENT_TYPES &&
env['REQUEST_URI'] !~ IGNORE_PATHS)
end
def transaction_from_env(env)
Transaction.new(env['REQUEST_METHOD'], env['REQUEST_URI'])
end
end
end
end
module Gitlab
module Sherlock
class Query
attr_reader :id, :query, :started_at, :finished_at, :backtrace
# SQL identifiers that should be prefixed with newlines.
PREFIX_NEWLINE = /
\s+(FROM
|(LEFT|RIGHT)?INNER\s+JOIN
|(LEFT|RIGHT)?OUTER\s+JOIN
|WHERE
|AND
|GROUP\s+BY
|ORDER\s+BY
|LIMIT
|OFFSET)\s+/ix # Vim indent breaks when this is on a newline :<
# Creates a new Query using a String and a separate Array of bindings.
#
# query - A String containing a SQL query, optionally with numeric
# placeholders (`$1`, `$2`, etc).
#
# bindings - An Array of ActiveRecord columns and their values.
# started_at - The start time of the query as a Time-like object.
# finished_at - The completion time of the query as a Time-like object.
#
# Returns a new Query object.
def self.new_with_bindings(query, bindings, started_at, finished_at)
bindings.each_with_index do |(_, value), index|
quoted_value = ActiveRecord::Base.connection.quote(value)
query = query.gsub("$#{index + 1}", quoted_value)
end
new(query, started_at, finished_at)
end
# query - The SQL query as a String (without placeholders).
# started_at - The start time of the query as a Time-like object.
# finished_at - The completion time of the query as a Time-like object.
def initialize(query, started_at, finished_at)
@id = SecureRandom.uuid
@query = query
@started_at = started_at
@finished_at = finished_at
@backtrace = caller_locations.map do |loc|
Location.from_ruby_location(loc)
end
unless @query.end_with?(';')
@query += ';'
end
end
# Returns the query duration in milliseconds.
def duration
@duration ||= (@finished_at - @started_at) * 1000.0
end
def to_param
@id
end
# Returns a human readable version of the query.
def formatted_query
@formatted_query ||= format_sql(@query)
end
# Returns the last application frame of the backtrace.
def last_application_frame
@last_application_frame ||= @backtrace.find(&:application?)
end
# Returns an Array of application frames (excluding Gems and the likes).
def application_backtrace
@application_backtrace ||= @backtrace.select(&:application?)
end
# Returns the query plan as a String.
def explain
unless @explain
ActiveRecord::Base.connection.transaction do
@explain = raw_explain(@query).values.flatten.join("\n")
# Roll back any queries that mutate data so we don't mess up
# anything when running explain on an INSERT, UPDATE, DELETE, etc.
raise ActiveRecord::Rollback
end
end
@explain
end
private
def raw_explain(query)
if Gitlab::Database.postgresql?
explain = "EXPLAIN ANALYZE #{query};"
else
explain = "EXPLAIN #{query};"
end
ActiveRecord::Base.connection.execute(explain)
end
def format_sql(query)
query.each_line.
map { |line| line.strip }.
join("\n").
gsub(PREFIX_NEWLINE) { "\n#{$1} " }
end
end
end
end
module Gitlab
module Sherlock
class Transaction
attr_reader :id, :type, :path, :queries, :file_samples, :started_at,
:finished_at, :view_counts
# type - The type of transaction (e.g. "GET", "POST", etc)
# path - The path of the transaction (e.g. the HTTP request path)
def initialize(type, path)
@id = SecureRandom.uuid
@type = type
@path = path
@queries = []
@file_samples = []
@started_at = nil
@finished_at = nil
@thread = Thread.current
@view_counts = Hash.new(0)
end
# Runs the transaction and returns the block's return value.
def run
@started_at = Time.now
retval = with_subscriptions do
profile_lines { yield }
end
@finished_at = Time.now
retval
end
# Returns the duration in seconds.
def duration
@duration ||= started_at && finished_at ? finished_at - started_at : 0
end
def to_param
@id
end
# Returns the queries sorted in descending order by their durations.
def sorted_queries
@queries.sort { |a, b| b.duration <=> a.duration }
end
# Returns the file samples sorted in descending order by their durations.
def sorted_file_samples
@file_samples.sort { |a, b| b.duration <=> a.duration }
end
# Finds a query by the given ID.
#
# id - The query ID as a String.
#
# Returns a Query object if one could be found, nil otherwise.
def find_query(id)
@queries.find { |query| query.id == id }
end
# Finds a file sample by the given ID.
#
# id - The query ID as a String.
#
# Returns a FileSample object if one could be found, nil otherwise.
def find_file_sample(id)
@file_samples.find { |sample| sample.id == id }
end
def profile_lines
retval = nil
if Sherlock.enable_line_profiler?
retval, @file_samples = LineProfiler.new.profile { yield }
else
retval = yield
end
retval
end
def subscribe_to_active_record
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
next unless same_thread?
track_query(data[:sql].strip, data[:binds], start, finish)
end
end
def subscribe_to_action_view
regex = /render_(template|partial)\.action_view/
ActiveSupport::Notifications.subscribe(regex) do |_, start, finish, _, data|
next unless same_thread?
track_view(data[:identifier])
end
end
private
def track_query(query, bindings, start, finish)
@queries << Query.new_with_bindings(query, bindings, start, finish)
end
def track_view(path)
@view_counts[path] += 1
end
def with_subscriptions
ar_subscriber = subscribe_to_active_record
av_subscriber = subscribe_to_action_view
retval = yield
ActiveSupport::Notifications.unsubscribe(ar_subscriber)
ActiveSupport::Notifications.unsubscribe(av_subscriber)
retval
end
# In case somebody uses a multi-threaded server locally (e.g. Puma) we
# _only_ want to track notifications that originate from the transaction
# thread.
def same_thread?
Thread.current == @thread
end
end
end
end
...@@ -50,15 +50,15 @@ module Gitlab ...@@ -50,15 +50,15 @@ module Gitlab
end end
def fetch_git_tags def fetch_git_tags
remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git)) remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
remote_tags.split("\n").grep(/tags\/v#{current_version.major}/) remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
end end
def update_commands def update_commands
{ {
"Stash changed files" => %W(git stash), "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash),
"Get latest code" => %W(git fetch), "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch),
"Switch to new version" => %W(git checkout v#{latest_version}), "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
"Install gems" => %W(bundle), "Install gems" => %W(bundle),
"Migrate DB" => %W(bundle exec rake db:migrate), "Migrate DB" => %W(bundle exec rake db:migrate),
"Recompile assets" => %W(bundle exec rake assets:clean assets:precompile), "Recompile assets" => %W(bundle exec rake assets:clean assets:precompile),
......
...@@ -824,7 +824,7 @@ namespace :gitlab do ...@@ -824,7 +824,7 @@ namespace :gitlab do
repo_dirs = Dir.glob(File.join(namespace_dir, '*')) repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
repo_dirs.each do |dir| repo_dirs.each do |dir|
puts "\nChecking repo at #{dir}" puts "\nChecking repo at #{dir}"
system(*%w(git fsck), chdir: dir) system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir)
end end
end end
end end
......
...@@ -17,7 +17,7 @@ namespace :gitlab do ...@@ -17,7 +17,7 @@ namespace :gitlab do
# Clone if needed # Clone if needed
unless File.directory?(target_dir) unless File.directory?(target_dir)
system(*%W(git clone -- #{args.repo} #{target_dir})) system(*%W(#{Gitlab.config.git.bin_path} clone -- #{args.repo} #{target_dir}))
end end
# Make sure we're on the right tag # Make sure we're on the right tag
...@@ -27,7 +27,7 @@ namespace :gitlab do ...@@ -27,7 +27,7 @@ namespace :gitlab do
reseted = reset_to_commit(args) reseted = reset_to_commit(args)
unless reseted unless reseted
system(*%W(git fetch origin)) system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
reset_to_commit(args) reset_to_commit(args)
end end
...@@ -128,14 +128,14 @@ namespace :gitlab do ...@@ -128,14 +128,14 @@ namespace :gitlab do
end end
def reset_to_commit(args) def reset_to_commit(args)
tag, status = Gitlab::Popen.popen(%W(git describe -- #{args.tag})) tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- #{args.tag}))
unless status.zero? unless status.zero?
tag, status = Gitlab::Popen.popen(%W(git describe -- origin/#{args.tag})) tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- origin/#{args.tag}))
end end
tag = tag.strip tag = tag.strip
system(*%W(git reset --hard #{tag})) system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag}))
end end
end end
require 'spec_helper' require 'spec_helper'
describe User, benchmark: true do describe User, benchmark: true do
describe '.all' do
before do
10.times { create(:user) }
end
benchmark_subject { User.all.to_a }
it { is_expected.to iterate_per_second(500) }
end
describe '.by_login' do describe '.by_login' do
before do before do
%w{Alice Bob Eve}.each do |name| %w{Alice Bob Eve}.each do |name|
......
require 'spec_helper'
describe Projects::CreateService, benchmark: true do
describe '#execute' do
let(:user) { create(:user, :admin) }
let(:group) do
group = create(:group)
create(:group_member, group: group, user: user)
group
end
benchmark_subject do
name = SecureRandom.hex
service = described_class.new(user,
name: name,
path: name,
namespace_id: group.id,
visibility_level: Gitlab::VisibilityLevel::PUBLIC)
service.execute
end
it { is_expected.to iterate_per_second(0.5) }
end
end
...@@ -33,6 +33,8 @@ FactoryGirl.define do ...@@ -33,6 +33,8 @@ FactoryGirl.define do
gl_project factory: :empty_project gl_project factory: :empty_project
shared_runners_enabled false
factory :ci_project do factory :ci_project do
token 'iPWx6WM4lhHNedGfBpPJNP' token 'iPWx6WM4lhHNedGfBpPJNP'
end end
......
...@@ -47,10 +47,11 @@ describe "Builds" do ...@@ -47,10 +47,11 @@ describe "Builds" do
end end
end end
describe "GET /:project/builds/:id/cancel_all" do describe "POST /:project/builds/:id/cancel_all" do
before do before do
@build.run! @build.run!
visit cancel_all_namespace_project_builds_path(@gl_project.namespace, @gl_project) visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
click_link "Cancel all"
end end
it { expect(page).to have_content 'No builds to show' } it { expect(page).to have_content 'No builds to show' }
...@@ -67,10 +68,11 @@ describe "Builds" do ...@@ -67,10 +68,11 @@ describe "Builds" do
it { expect(page).to have_content @commit.git_author_name } it { expect(page).to have_content @commit.git_author_name }
end end
describe "GET /:project/builds/:id/cancel" do describe "POST /:project/builds/:id/cancel" do
before do before do
@build.run! @build.run!
visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
click_link "Cancel"
end end
it { expect(page).to have_content 'canceled' } it { expect(page).to have_content 'canceled' }
...@@ -79,7 +81,9 @@ describe "Builds" do ...@@ -79,7 +81,9 @@ describe "Builds" do
describe "POST /:project/builds/:id/retry" do describe "POST /:project/builds/:id/retry" do
before do before do
visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) @build.run!
visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
click_link "Cancel"
click_link 'Retry' click_link 'Retry'
end end
......
...@@ -32,7 +32,7 @@ describe "Commits" do ...@@ -32,7 +32,7 @@ describe "Commits" do
describe "Cancel all builds" do describe "Cancel all builds" do
it "cancels commit" do it "cancels commit" do
visit ci_status_path(@commit) visit ci_status_path(@commit)
click_on "Cancel all" click_on "Cancel running"
expect(page).to have_content "canceled" expect(page).to have_content "canceled"
end end
end end
......
require 'spec_helper'
describe GroupsFinder do
let(:user) { create :user }
let!(:group) { create :group }
let!(:public_group) { create :group, public: true }
describe :execute do
it 'finds public group' do
groups = GroupsFinder.new.execute(user)
expect(groups.size).to eq(1)
expect(groups.first).to eq(public_group)
end
end
end
...@@ -42,6 +42,11 @@ describe SearchHelper do ...@@ -42,6 +42,11 @@ describe SearchHelper do
expect(search_autocomplete_opts(project.name).size).to eq(1) expect(search_autocomplete_opts(project.name).size).to eq(1)
end end
it "includes the public group" do
group = create(:group, public: true)
expect(search_autocomplete_opts(group.name).size).to eq(1)
end
context "with a current project" do context "with a current project" do
before { @project = create(:project) } before { @project = create(:project) }
......
require 'spec_helper'
describe Gitlab::Sherlock::Collection do
let(:collection) { described_class.new }
let(:transaction) do
Gitlab::Sherlock::Transaction.new('POST', '/cat_pictures')
end
describe '#add' do
it 'adds a new transaction' do
collection.add(transaction)
expect(collection).to_not be_empty
end
it 'is aliased as <<' do
collection << transaction
expect(collection).to_not be_empty
end
end
describe '#each' do
it 'iterates over every transaction' do
collection.add(transaction)
expect { |b| collection.each(&b) }.to yield_with_args(transaction)
end
end
describe '#clear' do
it 'removes all transactions' do
collection.add(transaction)
collection.clear
expect(collection).to be_empty
end
end
describe '#empty?' do
it 'returns true for an empty collection' do
expect(collection).to be_empty
end
it 'returns false for a collection with a transaction' do
collection.add(transaction)
expect(collection).to_not be_empty
end
end
describe '#find_transaction' do
it 'returns the transaction for the given ID' do
collection.add(transaction)
expect(collection.find_transaction(transaction.id)).to eq(transaction)
end
it 'returns nil when no transaction could be found' do
collection.add(transaction)
expect(collection.find_transaction('cats')).to be_nil
end
end
describe '#newest_first' do
it 'returns transactions sorted from new to old' do
trans1 = Gitlab::Sherlock::Transaction.new('POST', '/cat_pictures')
trans2 = Gitlab::Sherlock::Transaction.new('POST', '/more_cat_pictures')
allow(trans1).to receive(:finished_at).and_return(Time.utc(2015, 1, 1))
allow(trans2).to receive(:finished_at).and_return(Time.utc(2015, 1, 2))
collection.add(trans1)
collection.add(trans2)
expect(collection.newest_first).to eq([trans2, trans1])
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::FileSample do
let(:sample) { described_class.new(__FILE__, [], 150.4, 2) }
describe '#id' do
it 'returns the ID' do
expect(sample.id).to be_an_instance_of(String)
end
end
describe '#file' do
it 'returns the file path' do
expect(sample.file).to eq(__FILE__)
end
end
describe '#line_samples' do
it 'returns the line samples' do
expect(sample.line_samples).to eq([])
end
end
describe '#events' do
it 'returns the total number of events' do
expect(sample.events).to eq(2)
end
end
describe '#duration' do
it 'returns the total execution time' do
expect(sample.duration).to eq(150.4)
end
end
describe '#relative_path' do
it 'returns the relative path' do
expect(sample.relative_path).
to eq('spec/lib/gitlab/sherlock/file_sample_spec.rb')
end
end
describe '#to_param' do
it 'returns the sample ID' do
expect(sample.to_param).to eq(sample.id)
end
end
describe '#source' do
it 'returns the contents of the file' do
expect(sample.source).to eq(File.read(__FILE__))
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::LineProfiler do
let(:profiler) { described_class.new }
describe '#profile' do
it 'runs the profiler when using MRI' do
allow(profiler).to receive(:mri?).and_return(true)
allow(profiler).to receive(:profile_mri)
profiler.profile { 'cats' }
end
it 'raises NotImplementedError when profiling an unsupported platform' do
allow(profiler).to receive(:mri?).and_return(false)
expect { profiler.profile { 'cats' } }.to raise_error(NotImplementedError)
end
end
describe '#profile_mri' do
it 'returns an Array containing the return value and profiling samples' do
allow(profiler).to receive(:lineprof).
and_yield.
and_return({ __FILE__ => [[0, 0, 0, 0]] })
retval, samples = profiler.profile_mri { 42 }
expect(retval).to eq(42)
expect(samples).to eq([])
end
end
describe '#aggregate_rblineprof' do
let(:raw_samples) do
{ __FILE__ => [[30000, 30000, 5, 0], [15000, 15000, 4, 0]] }
end
it 'returns an Array of FileSample objects' do
samples = profiler.aggregate_rblineprof(raw_samples)
expect(samples).to be_an_instance_of(Array)
expect(samples[0]).to be_an_instance_of(Gitlab::Sherlock::FileSample)
end
describe 'the first FileSample object' do
let(:file_sample) do
profiler.aggregate_rblineprof(raw_samples)[0]
end
it 'uses the correct file path' do
expect(file_sample.file).to eq(__FILE__)
end
it 'contains a list of line samples' do
line_sample = file_sample.line_samples[0]
expect(line_sample).to be_an_instance_of(Gitlab::Sherlock::LineSample)
expect(line_sample.duration).to eq(15.0)
expect(line_sample.events).to eq(4)
end
it 'contains the total file execution time' do
expect(file_sample.duration).to eq(30.0)
end
it 'contains the total amount of file events' do
expect(file_sample.events).to eq(5)
end
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::LineSample do
let(:sample) { described_class.new(150.0, 4) }
describe '#duration' do
it 'returns the duration' do
expect(sample.duration).to eq(150.0)
end
end
describe '#events' do
it 'returns the amount of events' do
expect(sample.events).to eq(4)
end
end
describe '#percentage_of' do
it 'returns the percentage of 1500.0' do
expect(sample.percentage_of(1500.0)).to be_within(0.1).of(10.0)
end
end
describe '#majority_of' do
it 'returns true if the sample takes up the majority of the given duration' do
expect(sample.majority_of?(500.0)).to eq(true)
end
it "returns false if the sample doesn't take up the majority of the given duration" do
expect(sample.majority_of?(1500.0)).to eq(false)
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::Location do
let(:location) { described_class.new(__FILE__, 1) }
describe 'from_ruby_location' do
it 'creates a Location from a Thread::Backtrace::Location' do
input = caller_locations[0]
output = described_class.from_ruby_location(input)
expect(output).to be_an_instance_of(described_class)
expect(output.path).to eq(input.path)
expect(output.line).to eq(input.lineno)
end
end
describe '#path' do
it 'returns the file path' do
expect(location.path).to eq(__FILE__)
end
end
describe '#line' do
it 'returns the line number' do
expect(location.line).to eq(1)
end
end
describe '#application?' do
it 'returns true for an application frame' do
expect(location.application?).to eq(true)
end
it 'returns false for a non application frame' do
loc = described_class.new('/tmp/cats.rb', 1)
expect(loc.application?).to eq(false)
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::Middleware do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
describe '#call' do
describe 'when instrumentation is enabled' do
it 'instruments a request' do
allow(middleware).to receive(:instrument?).and_return(true)
allow(middleware).to receive(:call_with_instrumentation)
middleware.call({})
end
end
describe 'when instrumentation is disabled' do
it "doesn't instrument a request" do
allow(middleware).to receive(:instrument).and_return(false)
allow(app).to receive(:call)
middleware.call({})
end
end
end
describe '#call_with_instrumentation' do
it 'instruments a request' do
trans = double(:transaction)
retval = 'cats are amazing'
env = {}
allow(app).to receive(:call).with(env).and_return(retval)
allow(middleware).to receive(:transaction_from_env).and_return(trans)
allow(trans).to receive(:run).and_yield.and_return(retval)
allow(Gitlab::Sherlock.collection).to receive(:add).with(trans)
middleware.call_with_instrumentation(env)
end
end
describe '#instrument?' do
it 'returns false for a text/css request' do
env = { 'HTTP_ACCEPT' => 'text/css', 'REQUEST_URI' => '/' }
expect(middleware.instrument?(env)).to eq(false)
end
it 'returns false for a request to a Sherlock route' do
env = {
'HTTP_ACCEPT' => 'text/html',
'REQUEST_URI' => '/sherlock/transactions'
}
expect(middleware.instrument?(env)).to eq(false)
end
it 'returns true for a request that should be instrumented' do
env = {
'HTTP_ACCEPT' => 'text/html',
'REQUEST_URI' => '/cats'
}
expect(middleware.instrument?(env)).to eq(true)
end
end
describe '#transaction_from_env' do
it 'returns a Transaction' do
env = {
'HTTP_ACCEPT' => 'text/html',
'REQUEST_URI' => '/cats'
}
expect(middleware.transaction_from_env(env)).
to be_an_instance_of(Gitlab::Sherlock::Transaction)
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::Query do
let(:started_at) { Time.utc(2015, 1, 1) }
let(:finished_at) { started_at + 5 }
let(:query) do
described_class.new('SELECT COUNT(*) FROM users', started_at, finished_at)
end
describe 'new_with_bindings' do
it 'returns a Query' do
sql = 'SELECT COUNT(*) FROM users WHERE id = $1'
bindings = [[double(:column), 10]]
query = described_class.
new_with_bindings(sql, bindings, started_at, finished_at)
expect(query.query).to eq('SELECT COUNT(*) FROM users WHERE id = 10;')
end
end
describe '#id' do
it 'returns a String' do
expect(query.id).to be_an_instance_of(String)
end
end
describe '#query' do
it 'returns the query with a trailing semi-colon' do
expect(query.query).to eq('SELECT COUNT(*) FROM users;')
end
end
describe '#started_at' do
it 'returns the start time' do
expect(query.started_at).to eq(started_at)
end
end
describe '#finished_at' do
it 'returns the completion time' do
expect(query.finished_at).to eq(finished_at)
end
end
describe '#backtrace' do
it 'returns the backtrace' do
expect(query.backtrace).to be_an_instance_of(Array)
end
end
describe '#duration' do
it 'returns the duration in milliseconds' do
expect(query.duration).to be_within(0.1).of(5000.0)
end
end
describe '#to_param' do
it 'returns the query ID' do
expect(query.to_param).to eq(query.id)
end
end
describe '#formatted_query' do
it 'returns a formatted version of the query' do
expect(query.formatted_query).to eq(<<-EOF.strip)
SELECT COUNT(*)
FROM users;
EOF
end
end
describe '#last_application_frame' do
it 'returns the last application frame' do
frame = query.last_application_frame
expect(frame).to be_an_instance_of(Gitlab::Sherlock::Location)
expect(frame.path).to eq(__FILE__)
end
end
describe '#application_backtrace' do
it 'returns an Array of application frames' do
frames = query.application_backtrace
expect(frames).to be_an_instance_of(Array)
expect(frames).to_not be_empty
frames.each do |frame|
expect(frame.path).to start_with(Rails.root.to_s)
end
end
end
describe '#explain' do
it 'returns the query plan as a String' do
lines = [
['Aggregate (cost=123 rows=1)'],
[' -> Index Only Scan using index_cats_are_amazing']
]
result = double(:result, values: lines)
allow(query).to receive(:raw_explain).and_return(result)
expect(query.explain).to eq(<<-EOF.strip)
Aggregate (cost=123 rows=1)
-> Index Only Scan using index_cats_are_amazing
EOF
end
end
end
require 'spec_helper'
describe Gitlab::Sherlock::Transaction do
let(:transaction) { described_class.new('POST', '/cat_pictures') }
describe '#id' do
it 'returns the transaction ID' do
expect(transaction.id).to be_an_instance_of(String)
end
end
describe '#type' do
it 'returns the type' do
expect(transaction.type).to eq('POST')
end
end
describe '#path' do
it 'returns the path' do
expect(transaction.path).to eq('/cat_pictures')
end
end
describe '#queries' do
it 'returns an Array of queries' do
expect(transaction.queries).to be_an_instance_of(Array)
end
end
describe '#file_samples' do
it 'returns an Array of file samples' do
expect(transaction.file_samples).to be_an_instance_of(Array)
end
end
describe '#started_at' do
it 'returns the start time' do
allow(transaction).to receive(:profile_lines).and_yield
transaction.run { 'cats are amazing' }
expect(transaction.started_at).to be_an_instance_of(Time)
end
end
describe '#finished_at' do
it 'returns the completion time' do
allow(transaction).to receive(:profile_lines).and_yield
transaction.run { 'cats are amazing' }
expect(transaction.finished_at).to be_an_instance_of(Time)
end
end
describe '#view_counts' do
it 'returns a Hash' do
expect(transaction.view_counts).to be_an_instance_of(Hash)
end
it 'sets the default value of a key to 0' do
expect(transaction.view_counts['cats.rb']).to be_zero
end
end
describe '#run' do
it 'runs the transaction' do
allow(transaction).to receive(:profile_lines).and_yield
retval = transaction.run { 'cats are amazing' }
expect(retval).to eq('cats are amazing')
end
end
describe '#duration' do
it 'returns the duration in seconds' do
start_time = Time.now
allow(transaction).to receive(:started_at).and_return(start_time)
allow(transaction).to receive(:finished_at).and_return(start_time + 5)
expect(transaction.duration).to be_within(0.1).of(5.0)
end
end
describe '#to_param' do
it 'returns the transaction ID' do
expect(transaction.to_param).to eq(transaction.id)
end
end
describe '#sorted_queries' do
it 'returns the queries in descending order' do
start_time = Time.now
query1 = Gitlab::Sherlock::Query.new('SELECT 1', start_time, start_time)
query2 = Gitlab::Sherlock::Query.
new('SELECT 2', start_time, start_time + 5)
transaction.queries << query1
transaction.queries << query2
expect(transaction.sorted_queries).to eq([query2, query1])
end
end
describe '#sorted_file_samples' do
it 'returns the file samples in descending order' do
sample1 = Gitlab::Sherlock::FileSample.new(__FILE__, [], 10.0, 1)
sample2 = Gitlab::Sherlock::FileSample.new(__FILE__, [], 15.0, 1)
transaction.file_samples << sample1
transaction.file_samples << sample2
expect(transaction.sorted_file_samples).to eq([sample2, sample1])
end
end
describe '#find_query' do
it 'returns a Query when found' do
query = Gitlab::Sherlock::Query.new('SELECT 1', Time.now, Time.now)
transaction.queries << query
expect(transaction.find_query(query.id)).to eq(query)
end
it 'returns nil when no query could be found' do
expect(transaction.find_query('cats')).to be_nil
end
end
describe '#find_file_sample' do
it 'returns a FileSample when found' do
sample = Gitlab::Sherlock::FileSample.new(__FILE__, [], 10.0, 1)
transaction.file_samples << sample
expect(transaction.find_file_sample(sample.id)).to eq(sample)
end
it 'returns nil when no file sample could be found' do
expect(transaction.find_file_sample('cats')).to be_nil
end
end
describe '#profile_lines' do
describe 'when line profiling is enabled' do
it 'yields the block using the line profiler' do
allow(Gitlab::Sherlock).to receive(:enable_line_profiler?).
and_return(true)
allow_any_instance_of(Gitlab::Sherlock::LineProfiler).
to receive(:profile).and_return('cats are amazing', [])
retval = transaction.profile_lines { 'cats are amazing' }
expect(retval).to eq('cats are amazing')
end
end
describe 'when line profiling is disabled' do
it 'yields the block' do
allow(Gitlab::Sherlock).to receive(:enable_line_profiler?).
and_return(false)
retval = transaction.profile_lines { 'cats are amazing' }
expect(retval).to eq('cats are amazing')
end
end
end
describe '#subscribe_to_active_record' do
let(:subscription) { transaction.subscribe_to_active_record }
let(:time) { Time.now }
let(:query_data) { { sql: 'SELECT 1', binds: [] } }
after do
ActiveSupport::Notifications.unsubscribe(subscription)
end
it 'tracks executed queries' do
expect(transaction).to receive(:track_query).
with('SELECT 1', [], time, time)
subscription.publish('test', time, time, nil, query_data)
end
it 'only tracks queries triggered from the transaction thread' do
expect(transaction).to_not receive(:track_query)
Thread.new { subscription.publish('test', time, time, nil, query_data) }.
join
end
end
describe '#subscribe_to_action_view' do
let(:subscription) { transaction.subscribe_to_action_view }
let(:time) { Time.now }
let(:view_data) { { identifier: 'foo.rb' } }
after do
ActiveSupport::Notifications.unsubscribe(subscription)
end
it 'tracks rendered views' do
expect(transaction).to receive(:track_view).with('foo.rb')
subscription.publish('test', time, time, nil, view_data)
end
it 'only tracks views rendered from the transaction thread' do
expect(transaction).to_not receive(:track_view)
Thread.new { subscription.publish('test', time, time, nil, view_data) }.
join
end
end
end
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
require 'spec_helper' require 'spec_helper'
describe ApplicationSetting, models: true do describe ApplicationSetting, models: true do
it { expect(ApplicationSetting.create_from_defaults).to be_valid } let(:setting) { ApplicationSetting.create_from_defaults }
context 'restricted signup domains' do it { expect(setting).to be_valid }
let(:setting) { ApplicationSetting.create_from_defaults }
context 'restricted signup domains' do
it 'set single domain' do it 'set single domain' do
setting.restricted_signup_domains_raw = 'example.com' setting.restricted_signup_domains_raw = 'example.com'
expect(setting.restricted_signup_domains).to eq(['example.com']) expect(setting.restricted_signup_domains).to eq(['example.com'])
...@@ -53,4 +53,26 @@ describe ApplicationSetting, models: true do ...@@ -53,4 +53,26 @@ describe ApplicationSetting, models: true do
expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com'])
end end
end end
context 'shared runners' do
let(:gl_project) { create(:empty_project) }
before do
allow_any_instance_of(Project).to receive(:current_application_settings).and_return(setting)
end
subject { gl_project.ensure_gitlab_ci_project.shared_runners_enabled }
context 'enabled' do
before { setting.update_attributes(shared_runners_enabled: true) }
it { is_expected.to be_truthy }
end
context 'disabled' do
before { setting.update_attributes(shared_runners_enabled: false) }
it { is_expected.to be_falsey }
end
end
end end
...@@ -84,4 +84,23 @@ describe Group do ...@@ -84,4 +84,23 @@ describe Group do
expect(group.avatar_type).to eq(["only images allowed"]) expect(group.avatar_type).to eq(["only images allowed"])
end end
end end
describe "public_profile?" do
it "returns true for public group" do
group = create(:group, public: true)
expect(group.public_profile?).to be_truthy
end
it "returns true for non-public group with public project" do
group = create(:group)
create(:project, :public, group: group)
expect(group.public_profile?).to be_truthy
end
it "returns false for non-public group with no public projects" do
group = create(:group)
create(:project, group: group)
expect(group.public_profile?).to be_falsy
end
end
end end
...@@ -39,7 +39,7 @@ describe GitlabCiService do ...@@ -39,7 +39,7 @@ describe GitlabCiService do
end end
describe :build_page do describe :build_page do
it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/ci")} it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/builds")}
end end
describe "execute" do describe "execute" do
......
...@@ -223,7 +223,7 @@ describe ProjectWiki do ...@@ -223,7 +223,7 @@ describe ProjectWiki do
def create_temp_repo(path) def create_temp_repo(path)
FileUtils.mkdir_p path FileUtils.mkdir_p path
system(*%W(git init --quiet --bare -- #{path})) system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end end
def remove_temp_repo(path) def remove_temp_repo(path)
......
...@@ -663,24 +663,24 @@ describe User do ...@@ -663,24 +663,24 @@ describe User do
@user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega' @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
end end
it "sorts users as recently_signed_in" do it "sorts users by the recent sign-in time" do
expect(User.sort('recent_sign_in').first).to eq(@user) expect(User.sort('recent_sign_in').first).to eq(@user)
end end
it "sorts users as late_signed_in" do it "sorts users by the oldest sign-in time" do
expect(User.sort('oldest_sign_in').first).to eq(@user1) expect(User.sort('oldest_sign_in').first).to eq(@user1)
end end
it "sorts users as recently_created" do it "sorts users in descending order by their creation time" do
expect(User.sort('created_desc').first).to eq(@user) expect(User.sort('created_desc').first).to eq(@user)
end end
it "sorts users as late_created" do it "sorts users in ascending order by their creation time" do
expect(User.sort('created_asc').first).to eq(@user1) expect(User.sort('created_asc').first).to eq(@user1)
end end
it "sorts users by name when nil is passed" do it "sorts users by id in descending order when nil is passed" do
expect(User.sort(nil).first).to eq(@user) expect(User.sort(nil).first).to eq(@user1)
end end
end end
......
...@@ -36,8 +36,8 @@ describe API::API, api: true do ...@@ -36,8 +36,8 @@ describe API::API, api: true do
it 'should create a new annotated tag' do it 'should create a new annotated tag' do
# Identity must be set in .gitconfig to create annotated tag. # Identity must be set in .gitconfig to create annotated tag.
repo_path = project.repository.path_to_repo repo_path = project.repository.path_to_repo
system(*%W(git --git-dir=#{repo_path} config user.name #{user.name})) system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name}))
system(*%W(git --git-dir=#{repo_path} config user.email #{user.email})) system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email}))
post api("/projects/#{project.id}/repository/tags", user), post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v7.1.0', tag_name: 'v7.1.0',
......
...@@ -70,6 +70,10 @@ module Ci ...@@ -70,6 +70,10 @@ module Ci
end end
context 'disallow shared runners' do context 'disallow shared runners' do
before do
gl_project.gitlab_ci_project.update(shared_runners_enabled: false)
end
context 'shared runner' do context 'shared runner' do
let(:build) { service.execute(shared_runner) } let(:build) { service.execute(shared_runner) }
......
...@@ -62,6 +62,25 @@ describe MergeRequests::RefreshService do ...@@ -62,6 +62,25 @@ describe MergeRequests::RefreshService do
it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') } it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') }
end end
context 'manual merge of source branch' do
before do
# Merge master -> feature branch
author = { email: 'test@gitlab.com', time: Time.now, name: "Me" }
commit_options = { message: 'Test message', committer: author, author: author }
master_commit = @project.repository.commit('master')
@project.repository.merge(@user, master_commit.id, 'feature', commit_options)
commit = @project.repository.commit('feature')
service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature')
reload_mrs
end
it { expect(@merge_request.notes.last.note).to include('changed to merged') }
it { expect(@merge_request).to be_merged }
it { expect(@merge_request.diffs.length).to be > 0 }
it { expect(@fork_merge_request).to be_merged }
it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') }
end
context 'push to fork repo source branch' do context 'push to fork repo source branch' do
let(:refresh_service) { service.new(@fork_project, @user) } let(:refresh_service) { service.new(@fork_project, @user) }
before do before do
......
...@@ -96,15 +96,15 @@ module TestEnv ...@@ -96,15 +96,15 @@ module TestEnv
clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git" clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git"
unless File.directory?(repo_path) unless File.directory?(repo_path)
system(*%W(git clone -q #{clone_url} #{repo_path})) system(*%W(#{Gitlab.config.git.bin_path} clone -q #{clone_url} #{repo_path}))
end end
Dir.chdir(repo_path) do Dir.chdir(repo_path) do
branch_sha.each do |branch, sha| branch_sha.each do |branch, sha|
# Try to reset without fetching to avoid using the network. # Try to reset without fetching to avoid using the network.
reset = %W(git update-ref refs/heads/#{branch} #{sha}) reset = %W(#{Gitlab.config.git.bin_path} update-ref refs/heads/#{branch} #{sha})
unless system(*reset) unless system(*reset)
if system(*%w(git fetch origin)) if system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
unless system(*reset) unless system(*reset)
raise 'The fetched test seed '\ raise 'The fetched test seed '\
'does not contain the required revision.' 'does not contain the required revision.'
...@@ -117,7 +117,7 @@ module TestEnv ...@@ -117,7 +117,7 @@ module TestEnv
end end
# We must copy bare repositories because we will push to them. # We must copy bare repositories because we will push to them.
system(git_env, *%W(git clone -q --bare #{repo_path} #{repo_path_bare})) system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
end end
def copy_repo(project) def copy_repo(project)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment