mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-21 02:26:12 +10:00
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into awardables
# Conflicts: # app/controllers/projects/merge_requests_controller.rb # app/models/note.rb # db/schema.rb # spec/models/note_spec.rb
This commit is contained in:
+3
-3
@@ -276,7 +276,7 @@ Style/IdenticalConditionalBranches:
|
||||
Enabled: false
|
||||
|
||||
# Checks the indentation of the first line of the right-hand-side of a
|
||||
# multi-line assignment.
|
||||
# multi-line assignment.
|
||||
Style/IndentAssignment:
|
||||
Enabled: false
|
||||
|
||||
@@ -531,7 +531,7 @@ Style/SpaceAroundKeyword:
|
||||
|
||||
# Use a single space around operators.
|
||||
Style/SpaceAroundOperators:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Checks that the left block brace has or doesn't have space before it.
|
||||
Style/SpaceBeforeBlockBraces:
|
||||
@@ -770,7 +770,7 @@ Lint/DefEndAlignment:
|
||||
|
||||
# Check for deprecated class method calls.
|
||||
Lint/DeprecatedClassMethods:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Check for duplicate method definitions.
|
||||
Lint/DuplicateMethods:
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.8.0 (unreleased)
|
||||
- Snippets tab under user profile. !4001 (Long Nguyen)
|
||||
- Fix error when using link to uploads in global snippets
|
||||
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
|
||||
- Use a case-insensitive comparison in sanitizing URI schemes
|
||||
- Toggle sign-up confirmation emails in application settings
|
||||
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
|
||||
- Escape HTML in commit titles in system note messages
|
||||
- Improve multiple branch push performance by memoizing permission checking
|
||||
@@ -13,35 +15,63 @@ v 8.8.0 (unreleased)
|
||||
- Reduce delay in destroying a project from 1-minute to immediately
|
||||
- Make build status canceled if any of the jobs was canceled and none failed
|
||||
- Upgrade Sidekiq to 4.1.2
|
||||
- Added /health_check endpoint for checking service status
|
||||
- Make 'upcoming' filter for milestones work better across projects
|
||||
- Sanitize repo paths in new project error message
|
||||
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
|
||||
- Remove future dates from contribution calendar graph.
|
||||
- Support e-mail notifications for comments on project snippets
|
||||
- Fix API leak of notes of unauthorized issues, snippets and merge requests
|
||||
- Use ActionDispatch Remote IP for Akismet checking
|
||||
- Fix error when visiting commit builds page before build was updated
|
||||
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
|
||||
- Update SVG sanitizer to conform to SVG 1.1
|
||||
- Speed up push emails with multiple recipients by only generating the email once
|
||||
- Updated search UI
|
||||
- Added authentication service for Container Registry
|
||||
- Display informative message when new milestone is created
|
||||
- Sanitize milestones and labels titles
|
||||
- Support multi-line tag messages. !3833 (Calin Seciu)
|
||||
- Force users to reset their password after an admin changes it
|
||||
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
|
||||
- Added button to toggle whitespaces changes on diff view
|
||||
- Backport GitHub Enterprise import support from EE
|
||||
- Create tags using Rugged for performance reasons. !3745
|
||||
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
|
||||
- Don't show forks button when user can't view forks
|
||||
- Fix atom feed links and rendering
|
||||
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
|
||||
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
|
||||
- Add eager load paths to help prevent dependency load issues in Sidekiq workers. !3724
|
||||
- Added multiple colors for labels in dropdowns when dups happen.
|
||||
- Always group commits by server timezone, not commit timestamp
|
||||
- Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
|
||||
- API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
|
||||
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
|
||||
- Expire repository exists? and has_visible_content? caches after a push if necessary
|
||||
- Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
|
||||
- Fix unintentional filtering bug in Issue/MR sorted by milestone due (Takuya Noguchi)
|
||||
- Fix adding a todo for private group members (Ahmad Sherif)
|
||||
- Bump ace-rails-ap gem version from 2.0.1 to 4.0.2 which upgrades Ace Editor from 1.1.2 to 1.2.3
|
||||
- Total method execution timings are no longer tracked
|
||||
- Allow Admins to remove the Login with buttons for OAuth services and still be able to import !4034. (Andrei Gliga)
|
||||
- Add API endpoints for un/subscribing from/to a label. !4051 (Ahmad Sherif)
|
||||
- Hide left sidebar on phone screens to give more space for content
|
||||
- Redesign navigation for profile and group pages
|
||||
- Add counter metrics for rails cache
|
||||
- Import pull requests from GitHub where the source or target branches were removed
|
||||
- All Grape API helpers are now instrumented
|
||||
- Improve Issue formatting for the Slack Service (Jeroen van Baarsen)
|
||||
|
||||
v 8.7.6
|
||||
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
|
||||
- Fix import from GitLab.com to a private instance failure. !4181
|
||||
- Fix external imports not finding the import data. !4106
|
||||
|
||||
v 8.7.5
|
||||
- Fix relative links in wiki pages. !4050
|
||||
- Fix always showing build notification message when switching between merge requests !4086
|
||||
- Fix an issue when filtering merge requests with more than one label. !3886
|
||||
- Fix short note for the default scope on build page (Takuya Noguchi)
|
||||
|
||||
v 8.7.4
|
||||
- Links for Redmine issue references are generated correctly again !4048 (Benedikt Huss)
|
||||
@@ -865,7 +895,7 @@ v 8.1.3
|
||||
- Use issue editor as cross reference comment author when issue is edited with a new mention
|
||||
- Add Facebook authentication
|
||||
|
||||
v 8.1.2
|
||||
v 8.1.1
|
||||
- Fix cloning Wiki repositories via HTTP (Stan Hu)
|
||||
- Add migration to remove satellites directory
|
||||
- Fix specific runners visibility
|
||||
|
||||
@@ -36,6 +36,7 @@ gem 'omniauth-shibboleth', '~> 1.2.0'
|
||||
gem 'omniauth-twitter', '~> 1.2.0'
|
||||
gem 'omniauth_crowd', '~> 2.2.0'
|
||||
gem 'rack-oauth2', '~> 1.2.1'
|
||||
gem 'jwt'
|
||||
|
||||
# Spam and anti-bot protection
|
||||
gem 'recaptcha', require: 'recaptcha/rails'
|
||||
@@ -224,6 +225,7 @@ gem 'request_store', '~> 1.3.0'
|
||||
gem 'select2-rails', '~> 3.5.9'
|
||||
gem 'virtus', '~> 1.0.1'
|
||||
gem 'net-ssh', '~> 3.0.1'
|
||||
gem 'base32', '~> 0.3.0'
|
||||
|
||||
# Sentry integration
|
||||
gem 'sentry-raven', '~> 0.15'
|
||||
@@ -323,7 +325,6 @@ gem "mail_room", "~> 0.7"
|
||||
gem 'email_reply_parser', '~> 0.5.8'
|
||||
|
||||
## CI
|
||||
gem 'activerecord-deprecated_finders', '~> 1.0.3'
|
||||
gem 'activerecord-session_store', '~> 0.1.0'
|
||||
gem "nested_form", '~> 0.3.2'
|
||||
|
||||
@@ -332,3 +333,6 @@ gem 'oauth2', '~> 1.0.0'
|
||||
|
||||
# Soft deletion
|
||||
gem "paranoia", "~> 2.0"
|
||||
|
||||
# Health check
|
||||
gem 'health_check', '~> 1.5.1'
|
||||
|
||||
+6
-2
@@ -33,7 +33,6 @@ GEM
|
||||
activemodel (= 4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
arel (~> 6.0)
|
||||
activerecord-deprecated_finders (1.0.4)
|
||||
activerecord-session_store (0.1.2)
|
||||
actionpack (>= 4.0.0, < 5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
@@ -71,6 +70,7 @@ GEM
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
babosa (1.0.2)
|
||||
base32 (0.3.2)
|
||||
bcrypt (3.1.10)
|
||||
benchmark-ips (2.3.0)
|
||||
better_errors (1.0.1)
|
||||
@@ -402,6 +402,8 @@ GEM
|
||||
html2haml (>= 1.0.1)
|
||||
railties (>= 4.0.1)
|
||||
hashie (3.4.3)
|
||||
health_check (1.5.1)
|
||||
rails (>= 2.3.0)
|
||||
highline (1.7.8)
|
||||
hipchat (1.5.2)
|
||||
httparty
|
||||
@@ -881,7 +883,6 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
RedCloth (~> 4.2.9)
|
||||
ace-rails-ap (~> 4.0.2)
|
||||
activerecord-deprecated_finders (~> 1.0.3)
|
||||
activerecord-session_store (~> 0.1.0)
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
addressable (~> 2.3.8)
|
||||
@@ -893,6 +894,7 @@ DEPENDENCIES
|
||||
attr_encrypted (~> 1.3.4)
|
||||
awesome_print (~> 1.2.0)
|
||||
babosa (~> 1.0.2)
|
||||
base32 (~> 0.3.0)
|
||||
benchmark-ips
|
||||
better_errors (~> 1.0.1)
|
||||
binding_of_caller (~> 0.7.2)
|
||||
@@ -945,6 +947,7 @@ DEPENDENCIES
|
||||
grape (~> 0.13.0)
|
||||
grape-entity (~> 0.4.2)
|
||||
haml-rails (~> 0.9.0)
|
||||
health_check (~> 1.5.1)
|
||||
hipchat (~> 1.5.0)
|
||||
html-pipeline (~> 1.11.0)
|
||||
httparty (~> 0.13.3)
|
||||
@@ -953,6 +956,7 @@ DEPENDENCIES
|
||||
jquery-rails (~> 4.1.0)
|
||||
jquery-turbolinks (~> 2.1.0)
|
||||
jquery-ui-rails (~> 5.0.0)
|
||||
jwt
|
||||
kaminari (~> 0.16.3)
|
||||
letter_opener_web (~> 1.3.0)
|
||||
licensee (~> 8.0.0)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 74 KiB |
@@ -1,9 +1,12 @@
|
||||
class CiBuild
|
||||
@interval: null
|
||||
@state: null
|
||||
|
||||
constructor: (build_url, build_status) ->
|
||||
constructor: (build_url, build_status, build_state) ->
|
||||
clearInterval(CiBuild.interval)
|
||||
|
||||
@state = build_state
|
||||
|
||||
@initScrollButtonAffix()
|
||||
|
||||
if build_status == "running" || build_status == "pending"
|
||||
@@ -26,14 +29,18 @@ class CiBuild
|
||||
CiBuild.interval = setInterval =>
|
||||
if window.location.href.split("#").first() is build_url
|
||||
$.ajax
|
||||
url: build_url
|
||||
url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
|
||||
dataType: "json"
|
||||
success: (build) =>
|
||||
if build.status == "running"
|
||||
$('#build-trace code').html build.trace_html
|
||||
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
|
||||
success: (log) =>
|
||||
@state = log.state
|
||||
if log.status is "running"
|
||||
if log.append
|
||||
$('.fa-refresh').before log.html
|
||||
else
|
||||
$('#build-trace code').html log.html
|
||||
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
|
||||
@checkAutoscroll()
|
||||
else if build.status != build_status
|
||||
else if log.status isnt build_status
|
||||
Turbolinks.visit build_url
|
||||
, 4000
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ class @Notes
|
||||
form.addClass "js-main-target-form"
|
||||
|
||||
form.find("#note_line_code").remove()
|
||||
form.find("#note_type").remove()
|
||||
|
||||
###
|
||||
General note form setup.
|
||||
@@ -472,6 +473,7 @@ class @Notes
|
||||
setupDiscussionNoteForm: (dataHolder, form) =>
|
||||
# setup note target
|
||||
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
|
||||
form.find("#note_type").val dataHolder.data("noteType")
|
||||
form.find("#line_type").val dataHolder.data("lineType")
|
||||
form.find("#note_commit_id").val dataHolder.data("commitId")
|
||||
form.find("#note_line_code").val dataHolder.data("lineCode")
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
# Personal projects
|
||||
# </a>
|
||||
# </li>
|
||||
# <li class="snippets-tab">
|
||||
# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
|
||||
# </a>
|
||||
# </li>
|
||||
# </ul>
|
||||
#
|
||||
# <div class="tab-content">
|
||||
@@ -41,6 +45,9 @@
|
||||
# <div class="tab-pane" id="projects">
|
||||
# Projects content
|
||||
# </div>
|
||||
# <div class="tab-pane" id="snippets">
|
||||
# Snippets content
|
||||
# </div>
|
||||
# </div>
|
||||
#
|
||||
# <div class="loading-status">
|
||||
@@ -100,7 +107,7 @@ class @UserTabs
|
||||
if action is 'activity'
|
||||
@loadActivities(source)
|
||||
|
||||
if action in ['groups', 'contributed', 'projects']
|
||||
if action in ['groups', 'contributed', 'projects', 'snippets']
|
||||
@loadTab(source, action)
|
||||
|
||||
loadTab: (source, action) ->
|
||||
|
||||
@@ -289,7 +289,7 @@ table {
|
||||
text-shadow: none;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
margin-top: 11px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
|
||||
.page-with-sidebar {
|
||||
.header-logo {
|
||||
background-color: $color;
|
||||
border-color: $color;
|
||||
background: $color-darker;
|
||||
|
||||
a {
|
||||
color: $color-light;
|
||||
@@ -21,7 +20,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-darker;
|
||||
background-color: $color-dark;
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
@@ -91,8 +90,8 @@
|
||||
}
|
||||
|
||||
$theme-blue: #2980b9;
|
||||
$theme-charcoal: #333c47;
|
||||
$theme-graphite: #888;
|
||||
$theme-charcoal: #3d454d;
|
||||
$theme-graphite: #666;
|
||||
$theme-gray: #373737;
|
||||
$theme-green: #019875;
|
||||
$theme-violet: #548;
|
||||
@@ -103,11 +102,11 @@ body {
|
||||
}
|
||||
|
||||
&.ui_charcoal {
|
||||
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
|
||||
@include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41);
|
||||
}
|
||||
|
||||
&.ui_graphite {
|
||||
@include gitlab-theme(#ccc, $theme-graphite, #777, #666);
|
||||
@include gitlab-theme(#ccc, #777, $theme-graphite, #555);
|
||||
}
|
||||
|
||||
&.ui_gray {
|
||||
|
||||
@@ -6,12 +6,12 @@ header {
|
||||
transition-duration: .3s;
|
||||
|
||||
&.navbar-empty {
|
||||
height: 58px;
|
||||
height: $header-height;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid $btn-gray-hover;
|
||||
|
||||
.center-logo {
|
||||
margin: 11px 0;
|
||||
margin: 8px 0;
|
||||
text-align: center;
|
||||
|
||||
#tanuki-logo, img {
|
||||
|
||||
@@ -209,6 +209,15 @@
|
||||
float: right;
|
||||
padding: 7px 0 0;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
float: none;
|
||||
padding: 0 9px;
|
||||
|
||||
.dropdown-new {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
color: $layout-link-gray;
|
||||
}
|
||||
@@ -225,6 +234,10 @@
|
||||
|
||||
.dropdown {
|
||||
margin-left: 7px;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,4 +273,10 @@
|
||||
|
||||
.page-with-layout-nav {
|
||||
margin-top: 50px;
|
||||
|
||||
&.controls-dropdown-visible {
|
||||
@media (max-width: $screen-xs-min) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
}
|
||||
|
||||
.nav-sidebar li a {
|
||||
width: 230px;
|
||||
width: $sidebar_width;
|
||||
|
||||
&.back-link {
|
||||
i {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Layout
|
||||
*/
|
||||
$sidebar_collapsed_width: 62px;
|
||||
$sidebar_width: 230px;
|
||||
$sidebar_width: 220px;
|
||||
$gutter_collapsed_width: 62px;
|
||||
$gutter_width: 290px;
|
||||
$gutter_inner_width: 258px;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.zen-cotrol {
|
||||
.zen-control {
|
||||
padding: 0;
|
||||
color: #555;
|
||||
background: none;
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
.right-sidebar {
|
||||
position: fixed;
|
||||
top: 58px;
|
||||
top: $header-height;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
|
||||
@@ -226,8 +226,7 @@ ul.notes {
|
||||
}
|
||||
}
|
||||
|
||||
.note-action-button,
|
||||
.discussion-action-button {
|
||||
.note-action-button {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
line-height: 24px;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
.no-ssh-key-message, .project-limit-message {
|
||||
background-color: #f28d35;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.new_project,
|
||||
.edit_project {
|
||||
|
||||
@@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
|
||||
abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
|
||||
abuse_report.destroy
|
||||
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
||||
redirect_to admin_runners_path
|
||||
end
|
||||
|
||||
def reset_health_check_token
|
||||
@application_setting.reset_health_check_access_token!
|
||||
flash[:notice] = 'New health check access token has been generated!'
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
def clear_repository_check_states
|
||||
RepositoryCheck::ClearWorker.perform_async
|
||||
|
||||
@@ -53,6 +59,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
enabled_oauth_sign_in_sources = params[:application_setting].delete(:enabled_oauth_sign_in_sources)
|
||||
|
||||
params[:application_setting][:disabled_oauth_sign_in_sources] =
|
||||
AuthHelper.button_based_providers.map(&:to_s) -
|
||||
Array(enabled_oauth_sign_in_sources)
|
||||
|
||||
params.require(:application_setting).permit(
|
||||
:default_projects_limit,
|
||||
:default_branch_protection,
|
||||
@@ -94,8 +106,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
||||
:email_author_in_body,
|
||||
:repository_checks_enabled,
|
||||
:metrics_packet_size,
|
||||
:send_user_confirmation_email,
|
||||
restricted_visibility_levels: [],
|
||||
import_sources: []
|
||||
import_sources: [],
|
||||
disabled_oauth_sign_in_sources: []
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default(default: { action: 'index' }) }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Admin::HealthCheckController < Admin::ApplicationController
|
||||
def show
|
||||
@errors = HealthCheck::Utils.process_checks('standard')
|
||||
end
|
||||
end
|
||||
@@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -58,6 +58,6 @@ class Admin::RunnersController < Admin::ApplicationController
|
||||
end
|
||||
|
||||
def runner_params
|
||||
params.require(:runner).permit(:token, :description, :tag_list, :active)
|
||||
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
|
||||
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
|
||||
else
|
||||
spam_log.destroy
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,6 +119,7 @@ class Admin::UsersController < Admin::ApplicationController
|
||||
user_params_with_pass.merge!(
|
||||
password: params[:user][:password],
|
||||
password_confirmation: params[:user][:password_confirmation],
|
||||
password_expires_at: Time.now
|
||||
)
|
||||
end
|
||||
|
||||
@@ -153,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def check_password_expiration
|
||||
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
|
||||
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
|
||||
redirect_to new_profile_password_path and return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -122,7 +122,7 @@ module CreatesCommit
|
||||
# Merge request from fork to this project
|
||||
@mr_source_project = @tree_edit_project
|
||||
@mr_target_project = @project
|
||||
@mr_target_branch ||= @ref
|
||||
@mr_target_branch ||= @ref
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ module ToggleSubscriptionAction
|
||||
|
||||
subscribable_resource.toggle_subscription(current_user)
|
||||
|
||||
render nothing: true
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_todos_path, notice: todo_notice }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
format.json do
|
||||
render json: { count: @todos.size, done_count: current_user.todos.done.count }
|
||||
end
|
||||
@@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
format.json do
|
||||
find_todos
|
||||
render json: { count: @todos.size, done_count: current_user.todos.done.count }
|
||||
|
||||
@@ -40,7 +40,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
class HealthCheckController < HealthCheck::HealthCheckController
|
||||
before_action :validate_health_check_access!
|
||||
|
||||
private
|
||||
|
||||
def validate_health_check_access!
|
||||
render_404 unless token_valid?
|
||||
end
|
||||
|
||||
def token_valid?
|
||||
token = params[:token].presence || request.headers['TOKEN']
|
||||
token.present? &&
|
||||
ActiveSupport::SecurityUtils.variable_size_secure_compare(
|
||||
token,
|
||||
current_application_settings.health_check_access_token
|
||||
)
|
||||
end
|
||||
|
||||
def render_404
|
||||
render file: Rails.root.join('public', '404'), layout: false, status: '404'
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,87 @@
|
||||
class JwtController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
skip_before_action :verify_authenticity_token
|
||||
before_action :authenticate_project_or_user
|
||||
|
||||
SERVICES = {
|
||||
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
|
||||
}
|
||||
|
||||
def auth
|
||||
service = SERVICES[params[:service]]
|
||||
return head :not_found unless service
|
||||
|
||||
result = service.new(@project, @user, auth_params).execute
|
||||
|
||||
render json: result, status: result[:http_status]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate_project_or_user
|
||||
authenticate_with_http_basic do |login, password|
|
||||
# if it's possible we first try to authenticate project with login and password
|
||||
@project = authenticate_project(login, password)
|
||||
return if @project
|
||||
|
||||
@user = authenticate_user(login, password)
|
||||
return if @user
|
||||
|
||||
render_403
|
||||
end
|
||||
end
|
||||
|
||||
def auth_params
|
||||
params.permit(:service, :scope, :offline_token, :account, :client_id)
|
||||
end
|
||||
|
||||
def authenticate_project(login, password)
|
||||
if login == 'gitlab_ci_token'
|
||||
Project.find_by(builds_enabled: true, runners_token: password)
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_user(login, password)
|
||||
# TODO: this is a copy and paste from grack_auth,
|
||||
# it should be refactored in the future
|
||||
|
||||
user = Gitlab::Auth.new.find(login, password)
|
||||
|
||||
# If the user authenticated successfully, we reset the auth failure count
|
||||
# from Rack::Attack for that IP. A client may attempt to authenticate
|
||||
# with a username and blank password first, and only after it receives
|
||||
# a 401 error does it present a password. Resetting the count prevents
|
||||
# false positives from occurring.
|
||||
#
|
||||
# Otherwise, we let Rack::Attack know there was a failed authentication
|
||||
# attempt from this IP. This information is stored in the Rails cache
|
||||
# (Redis) and will be used by the Rack::Attack middleware to decide
|
||||
# whether to block requests from this IP.
|
||||
config = Gitlab.config.rack_attack.git_basic_auth
|
||||
|
||||
if config.enabled
|
||||
if user
|
||||
# A successful login will reset the auth failure count from this IP
|
||||
Rack::Attack::Allow2Ban.reset(request.ip, config)
|
||||
else
|
||||
banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
|
||||
# Unless the IP is whitelisted, return true so that Allow2Ban
|
||||
# increments the counter (stored in Rails.cache) for the IP
|
||||
if config.ip_whitelist.include?(request.ip)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
if banned
|
||||
Rails.logger.info "IP #{request.ip} failed to login " \
|
||||
"as #{login} but has been temporarily banned from Git auth"
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
end
|
||||
@@ -24,7 +24,7 @@ class Profiles::EmailsController < Profiles::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to profile_emails_url }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class Profiles::KeysController < Profiles::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to profile_keys_url }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -38,6 +38,14 @@ class Projects::BuildsController < Projects::ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def trace
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: @build.trace_with_state(params[:state]).merge!(id: @build.id, status: @build.status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def retry
|
||||
unless @build.retryable?
|
||||
return render_404
|
||||
|
||||
@@ -17,12 +17,12 @@ class Projects::CommitController < Projects::ApplicationController
|
||||
def show
|
||||
apply_diff_view_cookie!
|
||||
|
||||
@line_notes = commit.notes.inline
|
||||
@grouped_diff_notes = commit.notes.grouped_diff_notes
|
||||
|
||||
@note = @project.build_commit_note(commit)
|
||||
@notes = commit.notes.not_inline.fresh
|
||||
@notes = commit.notes.non_diff_notes.fresh
|
||||
@noteable = @commit
|
||||
@comments_allowed = @reply_allowed = true
|
||||
@comments_target = {
|
||||
@comments_target = {
|
||||
noteable_type: 'Commit',
|
||||
commit_id: @commit.id
|
||||
}
|
||||
@@ -67,10 +67,10 @@ class Projects::CommitController < Projects::ApplicationController
|
||||
create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title} has been successfully reverted.",
|
||||
success_path: successful_change_path, failure_path: failed_change_path)
|
||||
end
|
||||
|
||||
|
||||
def cherry_pick
|
||||
assign_change_commit_vars(@commit.cherry_pick_branch_name)
|
||||
|
||||
|
||||
return render_404 if @target_branch.blank?
|
||||
|
||||
create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title} has been successfully cherry-picked.",
|
||||
|
||||
@@ -22,7 +22,8 @@ class Projects::CompareController < Projects::ApplicationController
|
||||
@base_commit = @project.merge_base_commit(@base_ref, @head_ref)
|
||||
@diffs = compare.diffs(diff_options)
|
||||
@diff_refs = [@base_commit, @commit]
|
||||
@line_notes = []
|
||||
@diff_notes_disabled = true
|
||||
@grouped_diff_notes = {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ class Projects::ImportsController < Projects::ApplicationController
|
||||
@project.import_retry
|
||||
else
|
||||
@project.import_start
|
||||
@project.add_import_job
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -74,12 +74,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
# but we need it for the "View file @ ..." link by deleted files
|
||||
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
|
||||
|
||||
@comments_allowed = @reply_allowed = true
|
||||
@comments_target = {
|
||||
noteable_type: 'MergeRequest',
|
||||
noteable_id: @merge_request.id
|
||||
}
|
||||
@line_notes = @merge_request.notes.where("line_code is not null")
|
||||
|
||||
@grouped_diff_notes = @merge_request.notes.grouped_diff_notes
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
@@ -118,6 +118,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
@commit = @merge_request.last_commit
|
||||
@base_commit = @merge_request.diff_base_commit
|
||||
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
|
||||
@diff_notes_disabled = true
|
||||
|
||||
@ci_commit = @merge_request.ci_commit
|
||||
@statuses = @ci_commit.statuses if @ci_commit
|
||||
|
||||
@@ -75,7 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_milestones_path }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
note.update_attribute(:attachment, nil)
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -74,7 +74,7 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def note_to_discussion_html(note)
|
||||
return unless note.for_diff_line?
|
||||
return unless note.diff_note?
|
||||
|
||||
if params[:view] == 'parallel'
|
||||
template = "projects/notes/_diff_notes_with_reply_parallel"
|
||||
@@ -98,7 +98,7 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def note_to_discussion_with_diff_html(note)
|
||||
return unless note.for_diff_line?
|
||||
return unless note.diff_note?
|
||||
|
||||
render_to_string(
|
||||
"projects/notes/_discussion",
|
||||
@@ -136,7 +136,7 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
def note_params
|
||||
params.require(:note).permit(
|
||||
:note, :noteable, :noteable_id, :noteable_type, :project_id,
|
||||
:attachment, :line_code, :commit_id
|
||||
:attachment, :line_code, :commit_id, :type
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
format.html do
|
||||
redirect_to namespace_project_project_members_path(@project.namespace, @project)
|
||||
end
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -81,7 +81,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
else
|
||||
if current_user == @project.owner
|
||||
|
||||
@@ -39,7 +39,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_protected_branches_path }
|
||||
format.js { render nothing: true }
|
||||
format.js { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -64,6 +64,6 @@ class Projects::RunnersController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def runner_params
|
||||
params.require(:runner).permit(:description, :tag_list, :active)
|
||||
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -235,7 +235,8 @@ class ProjectsController < Projects::ApplicationController
|
||||
def project_params
|
||||
params.require(:project).permit(
|
||||
:name, :path, :description, :issues_tracker, :tag_list, :runners_token,
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :container_registry_enabled,
|
||||
:issues_tracker_id, :default_branch,
|
||||
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
|
||||
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
|
||||
:public_builds,
|
||||
|
||||
@@ -37,8 +37,8 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
super
|
||||
end
|
||||
|
||||
def after_sign_up_path_for(_resource)
|
||||
users_almost_there_path
|
||||
def after_sign_up_path_for(user)
|
||||
user.confirmed_at.present? ? dashboard_projects_path : users_almost_there_path
|
||||
end
|
||||
|
||||
def after_inactive_sign_up_path_for(_resource)
|
||||
|
||||
@@ -10,7 +10,7 @@ class SnippetsController < ApplicationController
|
||||
# Allow destroy snippet
|
||||
before_action :authorize_admin_snippet!, only: [:destroy]
|
||||
|
||||
skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw]
|
||||
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
|
||||
|
||||
layout 'snippets'
|
||||
respond_to :html
|
||||
|
||||
@@ -58,6 +58,19 @@ class UsersController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def snippets
|
||||
load_snippets
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render 'show' }
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("snippets/_snippets", collection: @snippets)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def calendar
|
||||
calendar = contributions_calendar
|
||||
@timestamps = calendar.timestamps
|
||||
@@ -116,6 +129,15 @@ class UsersController < ApplicationController
|
||||
@groups = JoinedGroupsFinder.new(user).execute(current_user)
|
||||
end
|
||||
|
||||
def load_snippets
|
||||
@snippets = SnippetsFinder.new.execute(
|
||||
current_user,
|
||||
filter: :by_user,
|
||||
user: user,
|
||||
scope: params[:scope]
|
||||
).page(params[:page])
|
||||
end
|
||||
|
||||
def projects_for_current_user
|
||||
ProjectsFinder.new.execute(current_user)
|
||||
end
|
||||
|
||||
@@ -252,8 +252,8 @@ class IssuableFinder
|
||||
if filter_by_no_milestone?
|
||||
items = items.where(milestone_id: [-1, nil])
|
||||
elsif filter_by_upcoming_milestone?
|
||||
upcoming = Milestone.where(project_id: projects).upcoming
|
||||
items = items.joins(:milestone).where(milestones: { title: upcoming.try(:title) })
|
||||
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
|
||||
items = items.joins(:milestone).where(milestone_id: upcoming_ids)
|
||||
else
|
||||
items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class NotesFinder
|
||||
notes =
|
||||
case target_type
|
||||
when "commit"
|
||||
project.notes.for_commit_id(target_id).not_inline
|
||||
project.notes.for_commit_id(target_id).non_diff_notes
|
||||
when "issue"
|
||||
project.issues.find(target_id).notes.inc_author
|
||||
when "merge_request"
|
||||
|
||||
@@ -60,4 +60,18 @@ module ApplicationSettingsHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def oauth_providers_checkboxes
|
||||
button_based_providers.map do |source|
|
||||
disabled = current_application_settings.disabled_oauth_sign_in_sources.include?(source.to_s)
|
||||
css_class = 'btn'
|
||||
css_class << ' active' unless disabled
|
||||
checkbox_name = 'application_setting[enabled_oauth_sign_in_sources][]'
|
||||
|
||||
label_tag(checkbox_name, class: css_class) do
|
||||
check_box_tag(checkbox_name, source, !disabled,
|
||||
autocomplete: 'off') + Gitlab::OAuth::Provider.label_for(source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,6 +38,16 @@ module AuthHelper
|
||||
auth_providers.reject { |provider| form_based_provider?(provider) }
|
||||
end
|
||||
|
||||
def enabled_button_based_providers
|
||||
disabled_providers = current_application_settings.disabled_oauth_sign_in_sources || []
|
||||
|
||||
button_based_providers.map(&:to_s) - disabled_providers
|
||||
end
|
||||
|
||||
def button_based_providers_enabled?
|
||||
enabled_button_based_providers.any?
|
||||
end
|
||||
|
||||
def provider_image_tag(provider, size = 64)
|
||||
label = label_for_provider(provider)
|
||||
|
||||
|
||||
@@ -55,22 +55,18 @@ module DiffHelper
|
||||
end
|
||||
end
|
||||
|
||||
def line_comments
|
||||
@line_comments ||= @line_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
|
||||
end
|
||||
def organize_comments(left, right)
|
||||
notes_left = notes_right = nil
|
||||
|
||||
def organize_comments(type_left, type_right, line_code_left, line_code_right)
|
||||
comments_left = comments_right = nil
|
||||
|
||||
unless type_left.nil? && type_right == 'new'
|
||||
comments_left = line_comments[line_code_left]
|
||||
unless left[:type].nil? && right[:type] == 'new'
|
||||
notes_left = @grouped_diff_notes[left[:line_code]]
|
||||
end
|
||||
|
||||
unless type_left.nil? && type_right.nil?
|
||||
comments_right = line_comments[line_code_right]
|
||||
unless left[:type].nil? && right[:type].nil?
|
||||
notes_right = @grouped_diff_notes[right[:line_code]]
|
||||
end
|
||||
|
||||
[comments_left, comments_right]
|
||||
[notes_left, notes_right]
|
||||
end
|
||||
|
||||
def inline_diff_btn
|
||||
@@ -96,8 +92,8 @@ module DiffHelper
|
||||
].join(' ').html_safe
|
||||
end
|
||||
|
||||
def commit_for_diff(diff)
|
||||
if diff.deleted_file
|
||||
def commit_for_diff(diff_file)
|
||||
if diff_file.deleted_file
|
||||
@base_commit || @commit.parent || @commit
|
||||
else
|
||||
@commit
|
||||
|
||||
@@ -3,7 +3,7 @@ module EventsHelper
|
||||
author = event.author
|
||||
|
||||
if author
|
||||
link_to author.name, user_path(author.username), title: h(author.name)
|
||||
link_to author.name, user_path(author.username), title: author.name
|
||||
else
|
||||
event.author_name
|
||||
end
|
||||
@@ -39,15 +39,6 @@ module EventsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def icon_for_event
|
||||
{
|
||||
EventFilter.push => 'upload',
|
||||
EventFilter.merged => 'check-square-o',
|
||||
EventFilter.comments => 'comments',
|
||||
EventFilter.team => 'user',
|
||||
}
|
||||
end
|
||||
|
||||
def event_preposition(event)
|
||||
if event.push? || event.commented? || event.target
|
||||
"at"
|
||||
@@ -66,11 +57,7 @@ module EventsHelper
|
||||
words << event.ref_name
|
||||
words << "at"
|
||||
elsif event.commented?
|
||||
if event.note_commit?
|
||||
words << event.note_short_commit_id
|
||||
else
|
||||
words << "##{truncate event.note_target_iid}"
|
||||
end
|
||||
words << event.note_target_reference
|
||||
words << "at"
|
||||
elsif event.milestone?
|
||||
words << "##{event.target_iid}" if event.target_iid
|
||||
@@ -93,21 +80,12 @@ module EventsHelper
|
||||
elsif event.merge_request?
|
||||
namespace_project_merge_request_url(event.project.namespace,
|
||||
event.project, event.merge_request)
|
||||
elsif event.note? && event.note_commit?
|
||||
elsif event.note? && event.commit_note?
|
||||
namespace_project_commit_url(event.project.namespace, event.project,
|
||||
event.note_target)
|
||||
elsif event.note?
|
||||
if event.note_target
|
||||
if event.note_commit?
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_commit_id,
|
||||
anchor: dom_id(event.target))
|
||||
elsif event.note_project_snippet?
|
||||
namespace_project_snippet_path(event.project.namespace,
|
||||
event.project, event.note_target)
|
||||
else
|
||||
event_note_target_path(event)
|
||||
end
|
||||
event_note_target_path(event)
|
||||
end
|
||||
elsif event.push?
|
||||
push_event_feed_url(event)
|
||||
@@ -143,42 +121,30 @@ module EventsHelper
|
||||
end
|
||||
|
||||
def event_note_target_path(event)
|
||||
if event.note? && event.note_commit?
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_target)
|
||||
if event.note? && event.commit_note?
|
||||
namespace_project_commit_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target,
|
||||
anchor: dom_id(event.target))
|
||||
elsif event.project_snippet_note?
|
||||
namespace_project_snippet_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target,
|
||||
anchor: dom_id(event.target))
|
||||
else
|
||||
polymorphic_path([event.project.namespace.becomes(Namespace),
|
||||
event.project, event.note_target],
|
||||
anchor: dom_id(event.target))
|
||||
anchor: dom_id(event.target))
|
||||
end
|
||||
end
|
||||
|
||||
def event_note_title_html(event)
|
||||
if event.note_target
|
||||
if event.note_commit?
|
||||
link_to(
|
||||
namespace_project_commit_path(event.project.namespace, event.project,
|
||||
event.note_commit_id,
|
||||
anchor: dom_id(event.target), title: h(event.target_title)),
|
||||
class: "commit_short_id"
|
||||
) do
|
||||
"#{event.note_target_type} #{event.note_short_commit_id}"
|
||||
end
|
||||
elsif event.note_project_snippet?
|
||||
link_to(namespace_project_snippet_path(event.project.namespace,
|
||||
event.project,
|
||||
event.note_target), title: h(event.project.name)) do
|
||||
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
|
||||
end
|
||||
else
|
||||
link_to event_note_target_path(event) do
|
||||
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
|
||||
end
|
||||
link_to(event_note_target_path(event), title: event.target_title, class: 'has-tooltip') do
|
||||
"#{event.note_target_type} #{event.note_target_reference}"
|
||||
end
|
||||
else
|
||||
content_tag :strong do
|
||||
"(deleted)"
|
||||
end
|
||||
content_tag(:strong, '(deleted)')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -43,4 +43,12 @@ module NavHelper
|
||||
class_name += " with-horizontal-nav" if defined?(nav) && nav
|
||||
class_name
|
||||
end
|
||||
|
||||
def layout_nav_class
|
||||
"page-with-layout-nav" if defined?(nav) && nav
|
||||
end
|
||||
|
||||
def layout_dropdown_class
|
||||
"controls-dropdown-visible" if current_user
|
||||
end
|
||||
end
|
||||
|
||||
+13
-16
@@ -1,7 +1,7 @@
|
||||
module NotesHelper
|
||||
# Helps to distinguish e.g. commit notes in mr notes list
|
||||
def note_for_main_target?(note)
|
||||
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
|
||||
@noteable.class.name == note.noteable_type && !note.diff_note?
|
||||
end
|
||||
|
||||
def note_target_fields(note)
|
||||
@@ -15,16 +15,6 @@ module NotesHelper
|
||||
note.editable? && can?(current_user, :admin_note, note)
|
||||
end
|
||||
|
||||
def link_to_commit_diff_line_note(note)
|
||||
if note.for_commit_diff_line?
|
||||
link_to(
|
||||
"#{note.diff_file_name}:L#{note.diff_new_line}",
|
||||
namespace_project_commit_path(@project.namespace, @project,
|
||||
note.noteable, anchor: note.line_code)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def noteable_json(noteable)
|
||||
{
|
||||
id: noteable.id,
|
||||
@@ -35,7 +25,7 @@ module NotesHelper
|
||||
end
|
||||
|
||||
def link_to_new_diff_note(line_code, line_type = nil)
|
||||
discussion_id = Note.build_discussion_id(
|
||||
discussion_id = LegacyDiffNote.build_discussion_id(
|
||||
@comments_target[:noteable_type],
|
||||
@comments_target[:noteable_id] || @comments_target[:commit_id],
|
||||
line_code
|
||||
@@ -45,9 +35,10 @@ module NotesHelper
|
||||
noteable_type: @comments_target[:noteable_type],
|
||||
noteable_id: @comments_target[:noteable_id],
|
||||
commit_id: @comments_target[:commit_id],
|
||||
line_type: line_type,
|
||||
line_code: line_code,
|
||||
discussion_id: discussion_id,
|
||||
line_type: line_type
|
||||
note_type: LegacyDiffNote.name,
|
||||
discussion_id: discussion_id
|
||||
}
|
||||
|
||||
button_tag(class: 'btn add-diff-note js-add-diff-note-button',
|
||||
@@ -57,18 +48,24 @@ module NotesHelper
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_reply_diff(note, line_type = nil)
|
||||
def link_to_reply_discussion(note, line_type = nil)
|
||||
return unless current_user
|
||||
|
||||
data = {
|
||||
noteable_type: note.noteable_type,
|
||||
noteable_id: note.noteable_id,
|
||||
commit_id: note.commit_id,
|
||||
line_code: note.line_code,
|
||||
discussion_id: note.discussion_id,
|
||||
line_type: line_type
|
||||
}
|
||||
|
||||
if note.diff_note?
|
||||
data.merge!(
|
||||
line_code: note.line_code,
|
||||
note_type: LegacyDiffNote.name
|
||||
)
|
||||
end
|
||||
|
||||
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
|
||||
data: data, title: 'Add a reply'
|
||||
end
|
||||
|
||||
@@ -138,10 +138,10 @@ module ProjectsHelper
|
||||
private
|
||||
|
||||
def get_project_nav_tabs(project, current_user)
|
||||
nav_tabs = [:home, :forks]
|
||||
nav_tabs = [:home]
|
||||
|
||||
if !project.empty_repo? && can?(current_user, :download_code, project)
|
||||
nav_tabs << [:files, :commits, :network, :graphs]
|
||||
nav_tabs << [:files, :commits, :network, :graphs, :forks]
|
||||
end
|
||||
|
||||
if project.repo_exists? && can?(current_user, :read_merge_request, project)
|
||||
|
||||
@@ -59,7 +59,7 @@ module SearchHelper
|
||||
# Autocomplete results for the current project, if it's defined
|
||||
def project_autocomplete
|
||||
if @project && @project.repository.exists? && @project.repository.root_ref
|
||||
ref = @ref || @project.repository.root_ref
|
||||
ref = @ref || @project.repository.root_ref
|
||||
|
||||
[
|
||||
{ category: "Current Project", label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
|
||||
|
||||
@@ -18,7 +18,7 @@ module SelectsHelper
|
||||
first_user: first_user,
|
||||
current_user: opts[:current_user] || false,
|
||||
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
|
||||
author_id: opts[:author_id] || ''
|
||||
author_id: opts[:author_id] || ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -61,6 +61,7 @@ class Ability
|
||||
:read_merge_request,
|
||||
:read_note,
|
||||
:read_commit_status,
|
||||
:read_container_image,
|
||||
:download_code
|
||||
]
|
||||
|
||||
@@ -203,6 +204,7 @@ class Ability
|
||||
:admin_label,
|
||||
:read_commit_status,
|
||||
:read_build,
|
||||
:read_container_image,
|
||||
]
|
||||
end
|
||||
|
||||
@@ -216,7 +218,9 @@ class Ability
|
||||
:update_build,
|
||||
:create_merge_request,
|
||||
:create_wiki,
|
||||
:push_code
|
||||
:push_code,
|
||||
:create_container_image,
|
||||
:update_container_image,
|
||||
]
|
||||
end
|
||||
|
||||
@@ -242,7 +246,8 @@ class Ability
|
||||
:admin_wiki,
|
||||
:admin_project,
|
||||
:admin_commit_status,
|
||||
:admin_build
|
||||
:admin_build,
|
||||
:admin_container_image,
|
||||
]
|
||||
end
|
||||
|
||||
@@ -287,6 +292,10 @@ class Ability
|
||||
rules += named_abilities('build')
|
||||
end
|
||||
|
||||
unless project.container_registry_enabled
|
||||
rules += named_abilities('container_image')
|
||||
end
|
||||
|
||||
rules
|
||||
end
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
include TokenAuthenticatable
|
||||
add_authentication_token_field :runners_registration_token
|
||||
add_authentication_token_field :health_check_access_token
|
||||
|
||||
CACHE_KEY = 'application_setting.last'
|
||||
|
||||
serialize :restricted_visibility_levels
|
||||
serialize :import_sources
|
||||
serialize :disabled_oauth_sign_in_sources
|
||||
serialize :restricted_signup_domains, Array
|
||||
attr_accessor :restricted_signup_domains_raw
|
||||
|
||||
@@ -69,7 +71,18 @@ class ApplicationSetting < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
validates_each :disabled_oauth_sign_in_sources do |record, attr, value|
|
||||
unless value.nil?
|
||||
value.each do |source|
|
||||
unless Devise.omniauth_providers.include?(source.to_sym)
|
||||
record.errors.add(attr, "'#{source}' is not an OAuth sign-in source")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
before_save :ensure_runners_registration_token
|
||||
before_save :ensure_health_check_access_token
|
||||
|
||||
after_commit do
|
||||
Rails.cache.write(CACHE_KEY, self)
|
||||
@@ -107,6 +120,8 @@ class ApplicationSetting < ActiveRecord::Base
|
||||
recaptcha_enabled: false,
|
||||
akismet_enabled: false,
|
||||
repository_checks_enabled: true,
|
||||
disabled_oauth_sign_in_sources: [],
|
||||
send_user_confirmation_email: false
|
||||
)
|
||||
end
|
||||
|
||||
@@ -133,4 +148,8 @@ class ApplicationSetting < ActiveRecord::Base
|
||||
def runners_registration_token
|
||||
ensure_runners_registration_token!
|
||||
end
|
||||
|
||||
def health_check_access_token
|
||||
ensure_health_check_access_token!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,8 +95,12 @@ module Ci
|
||||
end
|
||||
|
||||
def trace_html
|
||||
html = Ci::Ansi2html::convert(trace) if trace.present?
|
||||
html || ''
|
||||
trace_with_state[:html] || ''
|
||||
end
|
||||
|
||||
def trace_with_state(state = nil)
|
||||
trace_with_state = Ci::Ansi2html::convert(trace, state) if trace.present?
|
||||
trace_with_state || {}
|
||||
end
|
||||
|
||||
def timeout
|
||||
@@ -201,7 +205,7 @@ module Ci
|
||||
end
|
||||
|
||||
def recreate_trace_dir
|
||||
unless Dir.exists?(dir_to_trace)
|
||||
unless Dir.exist?(dir_to_trace)
|
||||
FileUtils.mkdir_p(dir_to_trace)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,8 @@ module Ci
|
||||
extend Ci::Model
|
||||
|
||||
LAST_CONTACT_TIME = 5.minutes.ago
|
||||
AVAILABLE_SCOPES = ['specific', 'shared', 'active', 'paused', 'online']
|
||||
AVAILABLE_SCOPES = %w[specific shared active paused online]
|
||||
FORM_EDITABLE = %i[description tag_list active]
|
||||
|
||||
has_many :builds, class_name: 'Ci::Build'
|
||||
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
|
||||
|
||||
@@ -36,6 +36,12 @@ module Subscribable
|
||||
update(subscribed: !subscribed?(user))
|
||||
end
|
||||
|
||||
def subscribe(user)
|
||||
subscriptions.
|
||||
find_or_initialize_by(user_id: user.id).
|
||||
update(subscribed: true)
|
||||
end
|
||||
|
||||
def unsubscribe(user)
|
||||
subscriptions.
|
||||
find_or_initialize_by(user_id: user.id).
|
||||
|
||||
+15
-20
@@ -80,7 +80,7 @@ class Event < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def target_title
|
||||
target.title if target && target.respond_to?(:title)
|
||||
target.try(:title)
|
||||
end
|
||||
|
||||
def created?
|
||||
@@ -266,28 +266,20 @@ class Event < ActiveRecord::Base
|
||||
branch? && project.default_branch != branch_name
|
||||
end
|
||||
|
||||
def note_commit_id
|
||||
target.commit_id
|
||||
end
|
||||
|
||||
def target_iid
|
||||
target.respond_to?(:iid) ? target.iid : target_id
|
||||
end
|
||||
|
||||
def note_short_commit_id
|
||||
Commit.truncate_sha(note_commit_id)
|
||||
end
|
||||
|
||||
def note_commit?
|
||||
target.noteable_type == "Commit"
|
||||
def commit_note?
|
||||
target.for_commit?
|
||||
end
|
||||
|
||||
def issue_note?
|
||||
note? && target && target.noteable_type == "Issue"
|
||||
note? && target && target.for_issue?
|
||||
end
|
||||
|
||||
def note_project_snippet?
|
||||
target.noteable_type == "Snippet"
|
||||
def project_snippet_note?
|
||||
target.for_snippet?
|
||||
end
|
||||
|
||||
def note_target
|
||||
@@ -295,19 +287,22 @@ class Event < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def note_target_id
|
||||
if note_commit?
|
||||
if commit_note?
|
||||
target.commit_id
|
||||
else
|
||||
target.noteable_id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def note_target_iid
|
||||
if note_target.respond_to?(:iid)
|
||||
note_target.iid
|
||||
def note_target_reference
|
||||
return unless note_target
|
||||
|
||||
# Commit#to_reference returns the full SHA, but we want the short one here
|
||||
if commit_note?
|
||||
note_target.short_id
|
||||
else
|
||||
note_target_id
|
||||
end.to_s
|
||||
note_target.to_reference
|
||||
end
|
||||
end
|
||||
|
||||
def note_target_type
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
class LegacyDiffNote < Note
|
||||
serialize :st_diff
|
||||
|
||||
validates :line_code, presence: true, line_code: true
|
||||
|
||||
before_create :set_diff
|
||||
|
||||
class << self
|
||||
def build_discussion_id(noteable_type, noteable_id, line_code, active = true)
|
||||
[super(noteable_type, noteable_id), line_code, active].join("-")
|
||||
end
|
||||
end
|
||||
|
||||
def diff_note?
|
||||
true
|
||||
end
|
||||
|
||||
def legacy_diff_note?
|
||||
true
|
||||
end
|
||||
|
||||
def discussion_id
|
||||
@discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code, active?)
|
||||
end
|
||||
|
||||
def diff_file_hash
|
||||
line_code.split('_')[0] if line_code
|
||||
end
|
||||
|
||||
def diff_old_line
|
||||
line_code.split('_')[1].to_i if line_code
|
||||
end
|
||||
|
||||
def diff_new_line
|
||||
line_code.split('_')[2].to_i if line_code
|
||||
end
|
||||
|
||||
def diff
|
||||
@diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
|
||||
end
|
||||
|
||||
def diff_file_path
|
||||
diff.new_path.presence || diff.old_path
|
||||
end
|
||||
|
||||
def diff_lines
|
||||
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
|
||||
end
|
||||
|
||||
def diff_line
|
||||
@diff_line ||= diff_lines.find { |line| generate_line_code(line) == self.line_code }
|
||||
end
|
||||
|
||||
def diff_line_text
|
||||
diff_line.try(:text)
|
||||
end
|
||||
|
||||
def diff_line_type
|
||||
diff_line.try(:type)
|
||||
end
|
||||
|
||||
def highlighted_diff_lines
|
||||
Gitlab::Diff::Highlight.new(diff_lines).highlight
|
||||
end
|
||||
|
||||
def truncated_diff_lines
|
||||
max_number_of_lines = 16
|
||||
prev_match_line = nil
|
||||
prev_lines = []
|
||||
|
||||
highlighted_diff_lines.each do |line|
|
||||
if line.type == "match"
|
||||
prev_lines.clear
|
||||
prev_match_line = line
|
||||
else
|
||||
prev_lines << line
|
||||
|
||||
break if generate_line_code(line) == self.line_code
|
||||
|
||||
prev_lines.shift if prev_lines.length >= max_number_of_lines
|
||||
end
|
||||
end
|
||||
|
||||
prev_lines
|
||||
end
|
||||
|
||||
# Check if this note is part of an "active" discussion
|
||||
#
|
||||
# This will always return true for anything except MergeRequest noteables,
|
||||
# which have special logic.
|
||||
#
|
||||
# If the note's current diff cannot be matched in the MergeRequest's current
|
||||
# diff, it's considered inactive.
|
||||
def active?
|
||||
return @active if defined?(@active)
|
||||
return true if for_commit?
|
||||
return true unless self.diff
|
||||
return false unless noteable
|
||||
|
||||
noteable_diff = find_noteable_diff
|
||||
|
||||
if noteable_diff
|
||||
parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line)
|
||||
|
||||
@active = parsed_lines.any? { |line_obj| line_obj.text == diff_line_text }
|
||||
else
|
||||
@active = false
|
||||
end
|
||||
|
||||
@active
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_diff
|
||||
return nil unless noteable
|
||||
return @diff if defined?(@diff)
|
||||
|
||||
@diff = noteable.diffs(Commit.max_diff_options).find do |d|
|
||||
d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
|
||||
end
|
||||
end
|
||||
|
||||
def set_diff
|
||||
# First lets find notes with same diff
|
||||
# before iterating over all mr diffs
|
||||
diff = diff_for_line_code unless for_merge_request?
|
||||
diff ||= find_diff
|
||||
|
||||
self.st_diff = diff.to_hash if diff
|
||||
end
|
||||
|
||||
def diff_for_line_code
|
||||
attributes = {
|
||||
noteable_type: noteable_type,
|
||||
line_code: line_code
|
||||
}
|
||||
|
||||
if for_commit?
|
||||
attributes[:commit_id] = commit_id
|
||||
else
|
||||
attributes[:noteable_id] = noteable_id
|
||||
end
|
||||
|
||||
self.class.where(attributes).last.try(:diff)
|
||||
end
|
||||
|
||||
def generate_line_code(line)
|
||||
Gitlab::Diff::LineCode.generate(diff_file_path, line.new_pos, line.old_pos)
|
||||
end
|
||||
|
||||
# Find the diff on noteable that matches our own
|
||||
def find_noteable_diff
|
||||
diffs = noteable.diffs(Commit.max_diff_options)
|
||||
diffs.find { |d| d.new_path == self.diff.new_path }
|
||||
end
|
||||
end
|
||||
@@ -26,6 +26,10 @@ class MergeRequest < ActiveRecord::Base
|
||||
# when creating new merge request
|
||||
attr_accessor :can_be_created, :compare_commits, :compare
|
||||
|
||||
# Temporary fields to store target_sha, and base_sha to
|
||||
# compare when importing pull requests from GitHub
|
||||
attr_accessor :base_target_sha, :head_source_sha
|
||||
|
||||
state_machine :state, initial: :opened do
|
||||
event :close do
|
||||
transition [:reopened, :opened] => :closed
|
||||
@@ -490,10 +494,14 @@ class MergeRequest < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def target_sha
|
||||
@target_sha ||= target_project.repository.commit(target_branch).try(:sha)
|
||||
return @base_target_sha if defined?(@base_target_sha)
|
||||
|
||||
target_project.repository.commit(target_branch).try(:sha)
|
||||
end
|
||||
|
||||
def source_sha
|
||||
return @head_source_sha if defined?(@head_source_sha)
|
||||
|
||||
last_commit.try(:sha) || source_tip.try(:sha)
|
||||
end
|
||||
|
||||
@@ -514,7 +522,7 @@ class MergeRequest < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def ref_is_fetched?
|
||||
File.exists?(File.join(project.repository.path_to_repo, ref_path))
|
||||
File.exist?(File.join(project.repository.path_to_repo, ref_path))
|
||||
end
|
||||
|
||||
def ensure_ref_fetched
|
||||
|
||||
@@ -6,7 +6,7 @@ class MergeRequestDiff < ActiveRecord::Base
|
||||
|
||||
belongs_to :merge_request
|
||||
|
||||
delegate :target_branch, :source_branch, to: :merge_request, prefix: nil
|
||||
delegate :head_source_sha, :target_branch, :source_branch, to: :merge_request, prefix: nil
|
||||
|
||||
state_machine :state, initial: :empty do
|
||||
state :collected
|
||||
@@ -38,8 +38,8 @@ class MergeRequestDiff < ActiveRecord::Base
|
||||
@diffs_no_whitespace ||= begin
|
||||
compare = Gitlab::Git::Compare.new(
|
||||
self.repository.raw_repository,
|
||||
self.target_branch,
|
||||
self.source_sha,
|
||||
self.base,
|
||||
self.head,
|
||||
)
|
||||
compare.diffs(options)
|
||||
end
|
||||
@@ -144,7 +144,7 @@ class MergeRequestDiff < ActiveRecord::Base
|
||||
|
||||
self.st_diffs = new_diffs
|
||||
|
||||
self.base_commit_sha = self.repository.merge_base(self.source_sha, self.target_branch)
|
||||
self.base_commit_sha = self.repository.merge_base(self.head, self.base)
|
||||
|
||||
self.save
|
||||
end
|
||||
@@ -160,10 +160,24 @@ class MergeRequestDiff < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def source_sha
|
||||
return head_source_sha if head_source_sha.present?
|
||||
|
||||
source_commit = merge_request.source_project.commit(source_branch)
|
||||
source_commit.try(:sha)
|
||||
end
|
||||
|
||||
def target_sha
|
||||
merge_request.target_sha
|
||||
end
|
||||
|
||||
def base
|
||||
self.target_sha || self.target_branch
|
||||
end
|
||||
|
||||
def head
|
||||
self.source_sha
|
||||
end
|
||||
|
||||
def compare
|
||||
@compare ||=
|
||||
begin
|
||||
@@ -172,8 +186,8 @@ class MergeRequestDiff < ActiveRecord::Base
|
||||
|
||||
Gitlab::Git::Compare.new(
|
||||
self.repository.raw_repository,
|
||||
self.target_branch,
|
||||
self.source_sha
|
||||
self.base,
|
||||
self.head
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
+12
-2
@@ -67,8 +67,18 @@ class Milestone < ActiveRecord::Base
|
||||
@link_reference_pattern ||= super("milestones", /(?<milestone>\d+)/)
|
||||
end
|
||||
|
||||
def self.upcoming
|
||||
self.where('due_date > ?', Time.now).reorder(due_date: :asc).first
|
||||
def self.upcoming_ids_by_projects(projects)
|
||||
rel = unscoped.of_projects(projects).active.where('due_date > ?', Time.now)
|
||||
|
||||
if Gitlab::Database.postgresql?
|
||||
rel.order(:project_id, :due_date).select('DISTINCT ON (project_id) id')
|
||||
else
|
||||
rel.
|
||||
group(:project_id).
|
||||
having('due_date = MIN(due_date)').
|
||||
pluck(:id, :project_id, :due_date).
|
||||
map(&:first)
|
||||
end
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
|
||||
+38
-179
@@ -1,6 +1,5 @@
|
||||
require 'carrierwave/orm/activerecord'
|
||||
|
||||
class Note < ActiveRecord::Base
|
||||
extend ActiveModel::Naming
|
||||
include Gitlab::CurrentSettings
|
||||
include Participable
|
||||
include Mentionable
|
||||
@@ -20,6 +19,7 @@ class Note < ActiveRecord::Base
|
||||
delegate :gfm_reference, :local_reference, to: :noteable
|
||||
delegate :name, to: :project, prefix: true
|
||||
delegate :name, :email, to: :author, prefix: true
|
||||
delegate :title, to: :noteable, allow_nil: true
|
||||
|
||||
before_validation :clear_blank_line_code!
|
||||
|
||||
@@ -36,8 +36,6 @@ class Note < ActiveRecord::Base
|
||||
|
||||
# Scopes
|
||||
scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
|
||||
scope :inline, ->{ where("line_code IS NOT NULL") }
|
||||
scope :not_inline, ->{ where(line_code: nil) }
|
||||
scope :system, ->{ where(system: true) }
|
||||
scope :user, ->{ where(system: false) }
|
||||
scope :common, ->{ where(noteable_type: ["", nil]) }
|
||||
@@ -45,38 +43,31 @@ class Note < ActiveRecord::Base
|
||||
scope :inc_author_project, ->{ includes(:project, :author) }
|
||||
scope :inc_author, ->{ includes(:author) }
|
||||
|
||||
scope :legacy_diff_notes, ->{ where(type: 'LegacyDiffNote') }
|
||||
scope :non_diff_notes, ->{ where(type: ['Note', nil]) }
|
||||
|
||||
scope :with_associations, -> do
|
||||
includes(:author, :noteable, :updated_by,
|
||||
project: [:project_members, { group: [:group_members] }])
|
||||
end
|
||||
|
||||
serialize :st_diff
|
||||
before_create :set_diff, if: ->(n) { n.line_code.present? }
|
||||
before_validation :clear_blank_line_code!
|
||||
|
||||
class << self
|
||||
def discussions_from_notes(notes)
|
||||
discussion_ids = []
|
||||
discussions = []
|
||||
|
||||
notes.each do |note|
|
||||
next if discussion_ids.include?(note.discussion_id)
|
||||
|
||||
# don't group notes for the main target
|
||||
if !note.for_diff_line? && note.for_merge_request?
|
||||
discussions << [note]
|
||||
else
|
||||
discussions << notes.select do |other_note|
|
||||
note.discussion_id == other_note.discussion_id
|
||||
end
|
||||
discussion_ids << note.discussion_id
|
||||
end
|
||||
end
|
||||
|
||||
discussions
|
||||
def model_name
|
||||
ActiveModel::Name.new(self, nil, 'note')
|
||||
end
|
||||
|
||||
def build_discussion_id(type, id, line_code)
|
||||
[:discussion, type.try(:underscore), id, line_code].join("-").to_sym
|
||||
def build_discussion_id(noteable_type, noteable_id)
|
||||
[:discussion, noteable_type.try(:underscore), noteable_id].join("-")
|
||||
end
|
||||
|
||||
def discussions
|
||||
all.group_by(&:discussion_id).values
|
||||
end
|
||||
|
||||
def grouped_diff_notes
|
||||
legacy_diff_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
|
||||
end
|
||||
|
||||
# Searches for notes matching the given query.
|
||||
@@ -98,167 +89,39 @@ class Note < ActiveRecord::Base
|
||||
system && SystemNoteService.cross_reference?(note)
|
||||
end
|
||||
|
||||
def max_attachment_size
|
||||
current_application_settings.max_attachment_size.megabytes.to_i
|
||||
def diff_note?
|
||||
false
|
||||
end
|
||||
|
||||
def find_diff
|
||||
return nil unless noteable
|
||||
return @diff if defined?(@diff)
|
||||
def legacy_diff_note?
|
||||
false
|
||||
end
|
||||
|
||||
# Don't use ||= because nil is a valid value for @diff
|
||||
@diff = noteable.diffs(Commit.max_diff_options).find do |d|
|
||||
Digest::SHA1.hexdigest(d.new_path) == diff_file_index if d.new_path
|
||||
end
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def discussion_id
|
||||
@discussion_id ||=
|
||||
if for_merge_request?
|
||||
[:discussion, :note, id].join("-")
|
||||
else
|
||||
self.class.build_discussion_id(noteable_type, noteable_id || commit_id)
|
||||
end
|
||||
end
|
||||
|
||||
def max_attachment_size
|
||||
current_application_settings.max_attachment_size.megabytes.to_i
|
||||
end
|
||||
|
||||
def hook_attrs
|
||||
attributes
|
||||
end
|
||||
|
||||
def set_diff
|
||||
# First lets find notes with same diff
|
||||
# before iterating over all mr diffs
|
||||
diff = diff_for_line_code unless for_merge_request?
|
||||
diff ||= find_diff
|
||||
|
||||
self.st_diff = diff.to_hash if diff
|
||||
end
|
||||
|
||||
def diff
|
||||
@diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
|
||||
end
|
||||
|
||||
def diff_for_line_code
|
||||
Note.where(noteable_id: noteable_id, noteable_type: noteable_type, line_code: line_code).last.try(:diff)
|
||||
end
|
||||
|
||||
# Check if this note is part of an "active" discussion
|
||||
#
|
||||
# This will always return true for anything except MergeRequest noteables,
|
||||
# which have special logic.
|
||||
#
|
||||
# If the note's current diff cannot be matched in the MergeRequest's current
|
||||
# diff, it's considered inactive.
|
||||
def active?
|
||||
return true unless self.diff
|
||||
return false unless noteable
|
||||
return @active if defined?(@active)
|
||||
|
||||
noteable_diff = find_noteable_diff
|
||||
|
||||
if noteable_diff
|
||||
parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line)
|
||||
|
||||
@active = parsed_lines.any? { |line_obj| line_obj.text == diff_line }
|
||||
else
|
||||
@active = false
|
||||
end
|
||||
|
||||
@active
|
||||
end
|
||||
|
||||
def diff_file_index
|
||||
line_code.split('_')[0] if line_code
|
||||
end
|
||||
|
||||
def diff_file_name
|
||||
diff.new_path if diff
|
||||
end
|
||||
|
||||
def file_path
|
||||
if diff.new_path.present?
|
||||
diff.new_path
|
||||
elsif diff.old_path.present?
|
||||
diff.old_path
|
||||
end
|
||||
end
|
||||
|
||||
def diff_old_line
|
||||
line_code.split('_')[1].to_i if line_code
|
||||
end
|
||||
|
||||
def diff_new_line
|
||||
line_code.split('_')[2].to_i if line_code
|
||||
end
|
||||
|
||||
def generate_line_code(line)
|
||||
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
|
||||
end
|
||||
|
||||
def diff_line
|
||||
return @diff_line if @diff_line
|
||||
|
||||
if diff
|
||||
diff_lines.each do |line|
|
||||
if generate_line_code(line) == self.line_code
|
||||
@diff_line = line.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@diff_line
|
||||
end
|
||||
|
||||
def diff_line_type
|
||||
return @diff_line_type if @diff_line_type
|
||||
|
||||
if diff
|
||||
diff_lines.each do |line|
|
||||
if generate_line_code(line) == self.line_code
|
||||
@diff_line_type = line.type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@diff_line_type
|
||||
end
|
||||
|
||||
def truncated_diff_lines
|
||||
max_number_of_lines = 16
|
||||
prev_match_line = nil
|
||||
prev_lines = []
|
||||
|
||||
highlighted_diff_lines.each do |line|
|
||||
if line.type == "match"
|
||||
prev_lines.clear
|
||||
prev_match_line = line
|
||||
else
|
||||
prev_lines << line
|
||||
|
||||
break if generate_line_code(line) == self.line_code
|
||||
|
||||
prev_lines.shift if prev_lines.length >= max_number_of_lines
|
||||
end
|
||||
end
|
||||
|
||||
prev_lines
|
||||
end
|
||||
|
||||
def diff_lines
|
||||
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
|
||||
end
|
||||
|
||||
def highlighted_diff_lines
|
||||
Gitlab::Diff::Highlight.new(diff_lines).highlight
|
||||
end
|
||||
|
||||
def discussion_id
|
||||
@discussion_id ||= Note.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
|
||||
end
|
||||
|
||||
def for_commit?
|
||||
noteable_type == "Commit"
|
||||
end
|
||||
|
||||
def for_commit_diff_line?
|
||||
for_commit? && for_diff_line?
|
||||
end
|
||||
|
||||
def for_diff_line?
|
||||
line_code.present?
|
||||
end
|
||||
|
||||
def for_issue?
|
||||
noteable_type == "Issue"
|
||||
end
|
||||
@@ -267,10 +130,6 @@ class Note < ActiveRecord::Base
|
||||
noteable_type == "MergeRequest"
|
||||
end
|
||||
|
||||
def for_merge_request_diff_line?
|
||||
for_merge_request? && for_diff_line?
|
||||
end
|
||||
|
||||
def for_snippet?
|
||||
noteable_type == "Snippet"
|
||||
end
|
||||
|
||||
@@ -22,6 +22,7 @@ class Project < ActiveRecord::Base
|
||||
default_value_for :builds_enabled, gitlab_config_features.builds
|
||||
default_value_for :wiki_enabled, gitlab_config_features.wiki
|
||||
default_value_for :snippets_enabled, gitlab_config_features.snippets
|
||||
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
|
||||
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
|
||||
|
||||
# set last_activity_at to the same as created_at
|
||||
@@ -49,6 +50,8 @@ class Project < ActiveRecord::Base
|
||||
attr_accessor :new_default_branch
|
||||
attr_accessor :old_path_with_namespace
|
||||
|
||||
alias_attribute :title, :name
|
||||
|
||||
# Relations
|
||||
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
|
||||
belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id'
|
||||
@@ -201,7 +204,6 @@ class Project < ActiveRecord::Base
|
||||
state :finished
|
||||
state :failed
|
||||
|
||||
after_transition any => :started, do: :schedule_add_import_job
|
||||
after_transition any => :finished, do: :clear_import_data
|
||||
end
|
||||
|
||||
@@ -327,6 +329,12 @@ class Project < ActiveRecord::Base
|
||||
@repository ||= Repository.new(path_with_namespace, self)
|
||||
end
|
||||
|
||||
def container_registry_url
|
||||
if container_registry_enabled? && Gitlab.config.registry.enabled
|
||||
"#{Gitlab.config.registry.host_with_port}/#{path_with_namespace}"
|
||||
end
|
||||
end
|
||||
|
||||
def commit(id = 'HEAD')
|
||||
repository.commit(id)
|
||||
end
|
||||
@@ -340,10 +348,6 @@ class Project < ActiveRecord::Base
|
||||
id && persisted?
|
||||
end
|
||||
|
||||
def schedule_add_import_job
|
||||
run_after_commit(:add_import_job)
|
||||
end
|
||||
|
||||
def add_import_job
|
||||
if forked?
|
||||
job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
|
||||
|
||||
@@ -25,7 +25,7 @@ class ExternalWikiService < Service
|
||||
|
||||
def execute(_data)
|
||||
@response = HTTParty.get(properties['external_wiki_url'], verify: true) rescue nil
|
||||
if @response !=200
|
||||
if @response != 200
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,7 +34,12 @@ class SlackService
|
||||
private
|
||||
|
||||
def message
|
||||
"#{user_name} #{state} #{issue_link} in #{project_link}: *#{title}*"
|
||||
case state
|
||||
when "opened"
|
||||
"[#{project_link}] Issue #{state} by #{user_name}"
|
||||
else
|
||||
"[#{project_link}] Issue #{issue_link} #{state} by #{user_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def opened_issue?
|
||||
@@ -42,7 +47,11 @@ class SlackService
|
||||
end
|
||||
|
||||
def description_message
|
||||
[{ text: format(description), color: attachment_color }]
|
||||
[{
|
||||
title: issue_title,
|
||||
title_link: issue_url,
|
||||
text: format(description),
|
||||
color: "#C95823" }]
|
||||
end
|
||||
|
||||
def project_link
|
||||
@@ -50,7 +59,11 @@ class SlackService
|
||||
end
|
||||
|
||||
def issue_link
|
||||
"[issue ##{issue_iid}](#{issue_url})"
|
||||
"[#{issue_title}](#{issue_url})"
|
||||
end
|
||||
|
||||
def issue_title
|
||||
"##{issue_iid} #{title}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,7 @@ class ProjectWiki
|
||||
end
|
||||
|
||||
def wiki_base_path
|
||||
["/", @project.path_with_namespace, "/wikis"].join('')
|
||||
[Gitlab.config.gitlab.relative_url_root, "/", @project.path_with_namespace, "/wikis"].join('')
|
||||
end
|
||||
|
||||
# Returns the Gollum::Wiki object.
|
||||
@@ -113,7 +113,7 @@ class ProjectWiki
|
||||
end
|
||||
|
||||
def page_title_and_dir(title)
|
||||
title_array = title.split("/")
|
||||
title_array = title.split("/")
|
||||
title = title_array.pop
|
||||
[title, title_array.join("/")]
|
||||
end
|
||||
|
||||
@@ -195,6 +195,10 @@ class Repository
|
||||
cache.fetch(:branch_names) { branches.map(&:name) }
|
||||
end
|
||||
|
||||
def branch_exists?(branch_name)
|
||||
branch_names.include?(branch_name)
|
||||
end
|
||||
|
||||
def tag_names
|
||||
cache.fetch(:tag_names) { raw_repository.tag_names }
|
||||
end
|
||||
@@ -795,7 +799,7 @@ class Repository
|
||||
def check_revert_content(commit, base_branch)
|
||||
source_sha = find_branch(base_branch).target
|
||||
args = [commit.id, source_sha]
|
||||
args << { mainline: 1 } if commit.merge_commit?
|
||||
args << { mainline: 1 } if commit.merge_commit?
|
||||
|
||||
revert_index = rugged.revert_commit(*args)
|
||||
return false if revert_index.conflicts?
|
||||
@@ -809,7 +813,7 @@ class Repository
|
||||
def check_cherry_pick_content(commit, base_branch)
|
||||
source_sha = find_branch(base_branch).target
|
||||
args = [commit.id, source_sha]
|
||||
args << 1 if commit.merge_commit?
|
||||
args << 1 if commit.merge_commit?
|
||||
|
||||
cherry_pick_index = rugged.cherrypick_commit(*args)
|
||||
return false if cherry_pick_index.conflicts?
|
||||
|
||||
@@ -113,6 +113,7 @@ class User < ActiveRecord::Base
|
||||
before_save :ensure_external_user_rights
|
||||
after_save :ensure_namespace_correct
|
||||
after_initialize :set_projects_limit
|
||||
before_create :check_confirmation_email
|
||||
after_create :post_create_hook
|
||||
after_destroy :post_destroy_hook
|
||||
|
||||
@@ -308,6 +309,10 @@ class User < ActiveRecord::Base
|
||||
@reset_token
|
||||
end
|
||||
|
||||
def check_confirmation_email
|
||||
skip_confirmation! unless current_application_settings.send_user_confirmation_email
|
||||
end
|
||||
|
||||
def recently_sent_password_reset?
|
||||
reset_password_sent_at.present? && reset_password_sent_at >= 1.minute.ago
|
||||
end
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
module Auth
|
||||
class ContainerRegistryAuthenticationService < BaseService
|
||||
AUDIENCE = 'container_registry'
|
||||
|
||||
def execute
|
||||
return error('not found', 404) unless registry.enabled
|
||||
|
||||
if params[:offline_token]
|
||||
return error('forbidden', 403) unless current_user
|
||||
else
|
||||
return error('forbidden', 403) unless scope
|
||||
end
|
||||
|
||||
{ token: authorized_token(scope).encoded }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authorized_token(*accesses)
|
||||
token = JSONWebToken::RSAToken.new(registry.key)
|
||||
token.issuer = registry.issuer
|
||||
token.audience = params[:service]
|
||||
token.subject = current_user.try(:username)
|
||||
token[:access] = accesses.compact
|
||||
token
|
||||
end
|
||||
|
||||
def scope
|
||||
return unless params[:scope]
|
||||
|
||||
@scope ||= process_scope(params[:scope])
|
||||
end
|
||||
|
||||
def process_scope(scope)
|
||||
type, name, actions = scope.split(':', 3)
|
||||
actions = actions.split(',')
|
||||
return unless type == 'repository'
|
||||
|
||||
process_repository_access(type, name, actions)
|
||||
end
|
||||
|
||||
def process_repository_access(type, name, actions)
|
||||
requested_project = Project.find_with_namespace(name)
|
||||
return unless requested_project
|
||||
|
||||
actions = actions.select do |action|
|
||||
can_access?(requested_project, action)
|
||||
end
|
||||
|
||||
{ type: type, name: name, actions: actions } if actions.present?
|
||||
end
|
||||
|
||||
def can_access?(requested_project, requested_action)
|
||||
return false unless requested_project.container_registry_enabled?
|
||||
|
||||
case requested_action
|
||||
when 'pull'
|
||||
requested_project == project || can?(current_user, :read_container_image, requested_project)
|
||||
when 'push'
|
||||
requested_project == project || can?(current_user, :create_container_image, requested_project)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def registry
|
||||
Gitlab.config.registry
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -66,7 +66,7 @@ module MergeRequests
|
||||
commits = merge_request.compare_commits
|
||||
if commits && commits.count == 1
|
||||
commit = commits.first
|
||||
merge_request.title = commit.title
|
||||
merge_request.title = commit.title
|
||||
merge_request.description ||= commit.description.try(:strip)
|
||||
elsif iid && (issue = merge_request.target_project.get_issue(iid)) && !issue.try(:confidential?)
|
||||
case issue
|
||||
|
||||
@@ -6,6 +6,7 @@ module Projects
|
||||
|
||||
def execute
|
||||
forked_from_project_id = params.delete(:forked_from_project_id)
|
||||
import_data = params.delete(:import_data)
|
||||
|
||||
@project = Project.new(params)
|
||||
|
||||
@@ -49,16 +50,14 @@ module Projects
|
||||
@project.build_forked_project_link(forked_from_project_id: forked_from_project_id)
|
||||
end
|
||||
|
||||
Project.transaction do
|
||||
@project.save
|
||||
save_project_and_import_data(import_data)
|
||||
|
||||
if @project.persisted? && !@project.import?
|
||||
raise 'Failed to create repository' unless @project.create_repository
|
||||
end
|
||||
end
|
||||
@project.import_start if @project.import?
|
||||
|
||||
after_create_actions if @project.persisted?
|
||||
|
||||
@project.add_import_job if @project.import?
|
||||
|
||||
@project
|
||||
rescue => e
|
||||
message = "Unable to save project: #{e.message}"
|
||||
@@ -93,8 +92,16 @@ module Projects
|
||||
unless @project.group
|
||||
@project.team << [current_user, :master, current_user]
|
||||
end
|
||||
end
|
||||
|
||||
@project.import_start if @project.import?
|
||||
def save_project_and_import_data(import_data)
|
||||
Project.transaction do
|
||||
@project.create_or_update_import_data(data: import_data[:data], credentials: import_data[:credentials]) if import_data
|
||||
|
||||
if @project.save && !@project.import?
|
||||
raise 'Failed to create repository' unless @project.create_repository
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -85,7 +85,7 @@ class SystemHooksService
|
||||
path_with_namespace: model.path_with_namespace,
|
||||
project_id: model.id,
|
||||
owner_name: owner.name,
|
||||
owner_email: owner.respond_to?(:email) ? owner.email : "",
|
||||
owner_email: owner.respond_to?(:email) ? owner.email : "",
|
||||
project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
|
||||
}
|
||||
end
|
||||
|
||||
@@ -103,12 +103,25 @@
|
||||
= f.label :signup_enabled do
|
||||
= f.check_box :signup_enabled
|
||||
Sign-up enabled
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :send_user_confirmation_email do
|
||||
= f.check_box :send_user_confirmation_email
|
||||
Send confirmation email on sign-up
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :signin_enabled do
|
||||
= f.check_box :signin_enabled
|
||||
Sign-in enabled
|
||||
- if omniauth_enabled? && button_based_providers.any?
|
||||
.form-group
|
||||
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth Sign-In sources', class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
.btn-group{ data: { toggle: 'buttons' } }
|
||||
- oauth_providers_checkboxes.each do |source|
|
||||
= source
|
||||
.form-group
|
||||
= f.label :two_factor_authentication, 'Two-factor authentication', class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
= link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
|
||||
|
||||
.row-content-block.second-block
|
||||
#{(@scope || 'running').capitalize} builds
|
||||
#{(@scope || 'all').capitalize} builds
|
||||
|
||||
%ul.content-list
|
||||
- if @builds.blank?
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
- page_title "Health Check"
|
||||
|
||||
%h3.page-title
|
||||
Health Check
|
||||
.bs-callout.clearfix
|
||||
.pull-left
|
||||
%p
|
||||
Access token is
|
||||
%code#health-check-token= current_application_settings.health_check_access_token
|
||||
= button_to reset_health_check_token_admin_application_settings_path,
|
||||
method: :put, class: 'btn btn-default',
|
||||
data: { confirm: 'Are you sure you want to reset the health check token?' } do
|
||||
= icon('refresh')
|
||||
Reset health check access token
|
||||
%p.light
|
||||
Health information can be retrieved as plain text, JSON, or XML using:
|
||||
%ul
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token)
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token, format: :json)
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token, format: :xml)
|
||||
|
||||
%p.light
|
||||
You can also ask for the status of specific services:
|
||||
%ul
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token, checks: :cache)
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token, checks: :database)
|
||||
%li
|
||||
%code= health_check_url(token: current_application_settings.health_check_access_token, checks: :migrations)
|
||||
|
||||
%hr
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Current Status:
|
||||
- if @errors.blank?
|
||||
= icon('circle', class: 'cgreen')
|
||||
Healthy
|
||||
- else
|
||||
= icon('warning', class: 'cred')
|
||||
Unhealthy
|
||||
.panel-body
|
||||
- if @errors.blank?
|
||||
No Health Problems Detected
|
||||
- else
|
||||
= @errors
|
||||
@@ -22,25 +22,9 @@
|
||||
%h4 This runner will process builds only from ASSIGNED projects
|
||||
%p You can't make this a shared runner.
|
||||
%hr
|
||||
= form_for @runner, url: admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
|
||||
.form-group
|
||||
= label_tag :token, class: 'control-label' do
|
||||
Token
|
||||
.col-sm-10
|
||||
= f.text_field :token, class: 'form-control', readonly: true
|
||||
.form-group
|
||||
= label_tag :description, class: 'control-label' do
|
||||
Description
|
||||
.col-sm-10
|
||||
= f.text_field :description, class: 'form-control'
|
||||
.form-group
|
||||
= label_tag :tag_list, class: 'control-label' do
|
||||
Tags
|
||||
.col-sm-10
|
||||
= f.text_field :tag_list, value: @runner.tag_list.to_s, class: 'form-control'
|
||||
.help-block You can setup builds to only use runners with specific tags
|
||||
.form-actions
|
||||
= f.submit 'Save', class: 'btn btn-save'
|
||||
|
||||
.append-bottom-20
|
||||
= render '/projects/runners/form', runner: @runner, runner_form_url: admin_runner_path(@runner)
|
||||
|
||||
.row
|
||||
.col-md-6
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
= render 'devise/shared/signin_box'
|
||||
|
||||
-# Omniauth fits between signin/ldap signin and signup and does not have a surrounding box
|
||||
- if omniauth_enabled? && devise_mapping.omniauthable?
|
||||
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
|
||||
.clearfix.prepend-top-20
|
||||
= render 'devise/shared/omniauth_box'
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%p
|
||||
%span.light
|
||||
Sign in with
|
||||
- providers = button_based_providers
|
||||
- providers = enabled_button_based_providers
|
||||
- providers.each do |provider|
|
||||
%span.light
|
||||
- has_icon = provider_has_icon?(provider)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
= event_action_name(event)
|
||||
|
||||
- if event.target
|
||||
%strong= link_to event.target.reference_link_text, [event.project.namespace.becomes(Namespace), event.project, event.target]
|
||||
%strong= link_to event.target.reference_link_text, [event.project.namespace.becomes(Namespace), event.project, event.target], title: event.target_title
|
||||
|
||||
= event_preposition(event)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.nav-block
|
||||
- if current_user
|
||||
.controls
|
||||
= link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn' do
|
||||
= link_to group_path(@group, format: :atom, private_token: current_user.private_token), class: 'btn rss-btn' do
|
||||
%i.fa.fa-rss
|
||||
= render 'shared/event_filter'
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
xml.instruct!
|
||||
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
|
||||
xml.title "#{@user.name} issues"
|
||||
xml.link href: issues_dashboard_url(format: :atom, private_token: @user.private_token), rel: "self", type: "application/atom+xml"
|
||||
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
|
||||
xml.id issues_dashboard_url
|
||||
xml.title "#{@group.name} issues"
|
||||
xml.link href: issues_group_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
|
||||
xml.link href: issues_group_url, rel: "alternate", type: "text/html"
|
||||
xml.id issues_group_url
|
||||
xml.updated @issues.first.created_at.xmlschema if @issues.any?
|
||||
|
||||
@issues.each do |issue|
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" }
|
||||
= render "layouts/broadcast"
|
||||
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
|
||||
.header-logo
|
||||
%a#logo
|
||||
@@ -26,7 +25,8 @@
|
||||
.layout-nav
|
||||
.container-fluid
|
||||
= render "layouts/nav/#{nav}"
|
||||
.content-wrapper{ class: ('page-with-layout-nav' if defined?(nav) && nav) }
|
||||
.content-wrapper{ class: "#{layout_nav_class} #{layout_dropdown_class}" }
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/flash"
|
||||
= yield :flash_message
|
||||
%div{ class: (container_class unless @no_container) }
|
||||
|
||||
@@ -41,6 +41,11 @@
|
||||
= icon('file-text fw')
|
||||
%span
|
||||
Logs
|
||||
= nav_link(controller: :health_check) do
|
||||
= link_to admin_health_check_path, title: 'Health Check' do
|
||||
= icon('medkit fw')
|
||||
%span
|
||||
Health Check
|
||||
= nav_link(controller: :broadcast_messages) do
|
||||
= link_to admin_broadcast_messages_path, title: 'Messages' do
|
||||
= icon('bullhorn fw')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- if current_user
|
||||
- if access = @group.users.find_by(id: current_user.id)
|
||||
.controls
|
||||
%span.dropdown.group-settings-dropdown
|
||||
.dropdown.group-settings-dropdown
|
||||
%a.dropdown-new.btn.btn-default#group-settings-button{href: '#', 'data-toggle' => 'dropdown'}
|
||||
= icon('cog')
|
||||
= icon('caret-down')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- if @note.diff_file_name
|
||||
- if @note.legacy_diff_note?
|
||||
%p.details
|
||||
New comment on diff for
|
||||
= link_to @note.diff_file_name, @target_url
|
||||
= link_to @note.diff_file_path, @target_url
|
||||
\:
|
||||
|
||||
= render 'note_message'
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
%a.js-md-preview-button{ href: "#md-preview-holder", tabindex: -1 }
|
||||
Preview
|
||||
%li.pull-right
|
||||
%button.zen-cotrol.zen-control-full.js-zen-enter{ type: 'button', tabindex: -1 }
|
||||
%button.zen-control.zen-control-full.js-zen-enter{ type: 'button', tabindex: -1 }
|
||||
Go full screen
|
||||
|
||||
.md-write-holder
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user