mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-13 14:46:05 +10:00
Merge branch 'master' into eReGeBe/gitlab-ce-feature/milestone-md
This commit is contained in:
@@ -115,6 +115,11 @@ bundler:audit:
|
||||
script:
|
||||
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
|
||||
|
||||
db-migrate-reset:
|
||||
stage: test
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake db:migrate:reset
|
||||
|
||||
# Ruby 2.2 jobs
|
||||
|
||||
spec:feature:ruby22:
|
||||
|
||||
@@ -2,8 +2,14 @@ Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.8.0 (unreleased)
|
||||
|
||||
v 8.7.0 (unreleased)
|
||||
v 8.7.1 (unreleased)
|
||||
- Use the `can?` helper instead of `current_user.can?`
|
||||
|
||||
v 8.7.0
|
||||
- Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented
|
||||
- Fix vulnerability that made it possible to gain access to private labels and milestones
|
||||
- The number of InfluxDB points stored per UDP packet can now be configured
|
||||
- Fix error when cross-project label reference used with non-existent project
|
||||
- Transactions for /internal/allowed now have an "action" tag set
|
||||
- Method instrumentation now uses Module#prepend instead of aliasing methods
|
||||
- Repository.clean_old_archives is now instrumented
|
||||
@@ -50,8 +56,9 @@ v 8.7.0 (unreleased)
|
||||
- Add endpoints to archive or unarchive a project !3372
|
||||
- Fix a bug whith trailing slash in bamboo_url
|
||||
- Add links to CI setup documentation from project settings and builds pages
|
||||
- Display project members page to all members
|
||||
- Handle nil descriptions in Slack issue messages (Stan Hu)
|
||||
- Add automated repository integrity checks
|
||||
- Add automated repository integrity checks (OFF by default)
|
||||
- API: Expose open_issues_count, closed_issues_count, open_merge_requests_count for labels (Robert Schilling)
|
||||
- API: Ability to star and unstar a project (Robert Schilling)
|
||||
- Add default scope to projects to exclude projects pending deletion
|
||||
@@ -68,6 +75,7 @@ v 8.7.0 (unreleased)
|
||||
- Hide `Create a group` help block when creating a new project in a group
|
||||
- Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.)
|
||||
- Allow issues and merge requests to be assigned to the author !2765
|
||||
- Make Ci::Commit to group only similar builds and make it stateful (ref, tag)
|
||||
- Gracefully handle notes on deleted commits in merge requests (Stan Hu)
|
||||
- Decouple membership and notifications
|
||||
- Fix creation of merge requests for orphaned branches (Stan Hu)
|
||||
@@ -77,6 +85,7 @@ v 8.7.0 (unreleased)
|
||||
- Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
|
||||
- Fix admin/projects when using visibility levels on search (PotHix)
|
||||
- Build status notifications
|
||||
- Update email confirmation interface
|
||||
- API: Expose user location (Robert Schilling)
|
||||
- API: Do not leak group existence via return code (Robert Schilling)
|
||||
- ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591
|
||||
@@ -87,7 +96,6 @@ v 8.7.0 (unreleased)
|
||||
- Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu)
|
||||
- Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld)
|
||||
- Improved markdown forms
|
||||
- Show JavaScript errors in sentry
|
||||
- Diff design updates (colors, button styles, etc)
|
||||
- Copying and pasting a diff no longer pastes the line numbers or +/-
|
||||
- Add null check to formData when updating profile content to fix Firefox bug
|
||||
@@ -105,6 +113,7 @@ v 8.7.0 (unreleased)
|
||||
- Updated print style for issues
|
||||
- Use GitHub Issue/PR number as iid to keep references
|
||||
- Import GitHub labels
|
||||
- Add option to filter by "Owned projects" on dashboard page
|
||||
- Import GitHub milestones
|
||||
- Fix emoji catgories in the emoji picker
|
||||
- Execute system web hooks on push to the project
|
||||
|
||||
+3
-4
@@ -134,7 +134,7 @@ GEM
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
colorize (0.7.7)
|
||||
concurrent-ruby (1.0.0)
|
||||
concurrent-ruby (1.0.1)
|
||||
connection_pool (2.2.0)
|
||||
coveralls (0.8.13)
|
||||
json (~> 1.8)
|
||||
@@ -629,7 +629,7 @@ GEM
|
||||
recaptcha (1.0.2)
|
||||
json
|
||||
redcarpet (3.3.3)
|
||||
redis (3.2.2)
|
||||
redis (3.3.0)
|
||||
redis-actionpack (4.0.1)
|
||||
actionpack (~> 4)
|
||||
redis-rack (~> 1.5.0)
|
||||
@@ -736,10 +736,9 @@ GEM
|
||||
rack
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (4.0.1)
|
||||
sidekiq (4.1.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
json (~> 1.0)
|
||||
redis (~> 3.2, >= 3.2.1)
|
||||
sidekiq-cron (0.4.0)
|
||||
redis-namespace (>= 1.5.2)
|
||||
|
||||
+19
@@ -105,6 +105,25 @@ sensitive as to how you word things. Use Emoji to express your feelings (heart,
|
||||
star, smile, etc.). Some good tips about giving feedback to merge requests is in
|
||||
the [Thoughtbot code review guide].
|
||||
|
||||
## Feature Freeze
|
||||
|
||||
5 working days before the 22nd the stable branches for the upcoming release will
|
||||
be frozen for major changes. Merge requests may still be merged into master
|
||||
during this period. By freezing the stable branches prior to a release there's
|
||||
no need to worry about last minute merge requests potentially breaking a lot of
|
||||
things.
|
||||
|
||||
What is considered to be a major change is determined on a case by case basis as
|
||||
this definition depends very much on the context of changes. For example, a 5
|
||||
line change might have a big impact on the entire application. Ultimately the
|
||||
decision will be made by those reviewing a merge request and the release
|
||||
manager.
|
||||
|
||||
During the feature freeze all merge requests that are meant to go into the next
|
||||
release should have the correct milestone assigned _and_ have the label
|
||||
~"Pick into Stable" set. Merge requests without a milestone and this label will
|
||||
not be merged into any stable branches.
|
||||
|
||||
## Copy & paste responses
|
||||
|
||||
### Improperly formatted issue
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
#= require_tree .
|
||||
#= require fuzzaldrin-plus
|
||||
#= require cropper
|
||||
#= require raven
|
||||
|
||||
window.slugify = (text) ->
|
||||
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class @CommitsList
|
||||
@timer = null
|
||||
|
||||
@init: (ref, limit) ->
|
||||
@init: (limit) ->
|
||||
$("body").on "click", ".day-commits-table li.commit", (event) ->
|
||||
if event.target.nodeName != "A"
|
||||
location.href = $(this).attr("url")
|
||||
|
||||
@@ -221,6 +221,9 @@ class GitLabDropdown
|
||||
|
||||
menu.toggleClass PAGE_TWO_CLASS
|
||||
|
||||
# Focus first visible input on active page
|
||||
@dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus()
|
||||
|
||||
parseData: (data) ->
|
||||
@renderedData = data
|
||||
|
||||
@@ -240,7 +243,8 @@ class GitLabDropdown
|
||||
shouldPropagate: (e) =>
|
||||
if @options.multiSelect
|
||||
$target = $(e.target)
|
||||
if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon')
|
||||
|
||||
if not $target.hasClass('dropdown-menu-close') and not $target.hasClass('dropdown-menu-close-icon') and not $target.data('is-link')
|
||||
e.stopPropagation()
|
||||
return false
|
||||
else
|
||||
@@ -375,7 +379,6 @@ class GitLabDropdown
|
||||
selectedObject = @renderedData[selectedIndex]
|
||||
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
|
||||
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
|
||||
|
||||
if el.hasClass(ACTIVE_CLASS)
|
||||
el.removeClass(ACTIVE_CLASS)
|
||||
field.remove()
|
||||
|
||||
@@ -19,23 +19,19 @@ class @LabelsSelect
|
||||
$form = $dropdown.closest('form')
|
||||
$sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
|
||||
$value = $block.find('.value')
|
||||
$newLabelError = $('.js-label-error')
|
||||
$colorPreview = $('.js-dropdown-label-color-preview')
|
||||
$newLabelCreateButton = $('.js-new-label-btn')
|
||||
|
||||
$newLabelError.hide()
|
||||
$loading = $block.find('.block-loading').fadeOut()
|
||||
|
||||
if newLabelField.length
|
||||
$newLabelCreateButton = $('.js-new-label-btn')
|
||||
$colorPreview = $('.js-dropdown-label-color-preview')
|
||||
$newLabelError = $dropdown.parent().find('.js-label-error')
|
||||
$newLabelError.hide()
|
||||
|
||||
# Suggested colors in the dropdown to chose from pre-chosen colors
|
||||
$('.suggest-colors-dropdown a').on 'click', (e) ->
|
||||
|
||||
issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL?
|
||||
if issueUpdateURL
|
||||
labelHTMLTemplate = _.template(
|
||||
'<% _.each(labels, function(label){ %>
|
||||
<a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name=<%= _.escape(label.title) %>">
|
||||
<span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>;">
|
||||
<span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;">
|
||||
<%= _.escape(label.title) %>
|
||||
</span>
|
||||
</a>
|
||||
@@ -43,7 +39,9 @@ class @LabelsSelect
|
||||
)
|
||||
labelNoneHTMLTemplate = _.template('<div class="light">None</div>')
|
||||
|
||||
if newLabelField.length and $dropdown.hasClass 'js-extra-options'
|
||||
if newLabelField.length
|
||||
|
||||
# Suggested colors in the dropdown to chose from pre-chosen colors
|
||||
$('.suggest-colors-dropdown a').on "click", (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@@ -82,26 +80,25 @@ class @LabelsSelect
|
||||
enableLabelCreateButton = ->
|
||||
if newLabelField.val() isnt '' and newColorField.val() isnt ''
|
||||
$newLabelError.hide()
|
||||
$('.js-new-label-btn').disable()
|
||||
|
||||
# Create new label with API
|
||||
Api.newLabel projectId, {
|
||||
name: newLabelField.val()
|
||||
color: newColorField.val()
|
||||
}, (label) ->
|
||||
$('.js-new-label-btn').enable()
|
||||
|
||||
if label.message?
|
||||
$newLabelError
|
||||
.text label.message
|
||||
.show()
|
||||
else
|
||||
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
|
||||
|
||||
$newLabelCreateButton.enable()
|
||||
else
|
||||
$newLabelCreateButton.disable()
|
||||
|
||||
saveLabel = ->
|
||||
# Create new label with API
|
||||
Api.newLabel projectId, {
|
||||
name: newLabelField.val()
|
||||
color: newColorField.val()
|
||||
}, (label) ->
|
||||
$newLabelCreateButton.enable()
|
||||
|
||||
if label.message?
|
||||
$newLabelError
|
||||
.text label.message
|
||||
.show()
|
||||
else
|
||||
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
|
||||
|
||||
newLabelField.on 'keyup change', enableLabelCreateButton
|
||||
|
||||
newColorField.on 'keyup change', enableLabelCreateButton
|
||||
@@ -112,24 +109,7 @@ class @LabelsSelect
|
||||
.on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if newLabelField.val() isnt '' and newColorField.val() isnt ''
|
||||
$newLabelError.hide()
|
||||
$('.js-new-label-btn').disable()
|
||||
|
||||
# Create new label with API
|
||||
Api.newLabel projectId, {
|
||||
name: newLabelField.val()
|
||||
color: newColorField.val()
|
||||
}, (label) ->
|
||||
$('.js-new-label-btn').enable()
|
||||
|
||||
if label.message?
|
||||
$newLabelError
|
||||
.text label.message
|
||||
.show()
|
||||
else
|
||||
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
|
||||
saveLabel()
|
||||
|
||||
saveLabelData = ->
|
||||
selected = $dropdown
|
||||
@@ -243,7 +223,7 @@ class @LabelsSelect
|
||||
fieldName: $dropdown.data('field-name')
|
||||
id: (label) ->
|
||||
if $dropdown.hasClass("js-filter-submit") and not label.isAny?
|
||||
label.title
|
||||
_.escape label.title
|
||||
else
|
||||
label.id
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ class @MergeRequestTabs
|
||||
if window.location.hash
|
||||
navBarHeight = $('.navbar-gitlab').outerHeight()
|
||||
|
||||
$el = $("#{container} #{window.location.hash}")
|
||||
$.scrollTo("#{container} #{window.location.hash}", offset: -navBarHeight) if $el.length
|
||||
$el = $("#{container} #{window.location.hash}:not(.match)")
|
||||
$.scrollTo("#{container} #{window.location.hash}:not(.match)", offset: -navBarHeight) if $el.length
|
||||
|
||||
# Activate a tab based on the current action
|
||||
activateTab: (action) ->
|
||||
@@ -176,12 +176,12 @@ class @MergeRequestTabs
|
||||
|
||||
if locationHash isnt ''
|
||||
hashClassString = ".#{locationHash.replace('#', '')}"
|
||||
$diffLine = $(locationHash)
|
||||
$diffLine = $("#{locationHash}:not(.match)", $('#diffs'))
|
||||
|
||||
if $diffLine.is ':not(tr)'
|
||||
$diffLine = $("td#{locationHash}, td#{hashClassString}")
|
||||
if not $diffLine.is 'tr'
|
||||
$diffLine = $('#diffs').find("td#{locationHash}, td#{hashClassString}")
|
||||
else
|
||||
$diffLine = $('td', $diffLine)
|
||||
$diffLine = $diffLine.find('td')
|
||||
|
||||
if $diffLine.length
|
||||
$diffLine.addClass 'hll'
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
@raven =
|
||||
init: ->
|
||||
if gon.sentry_dsn?
|
||||
Raven.config(gon.sentry_dsn, {
|
||||
includePaths: [/gon.relative_url_root/]
|
||||
ignoreErrors: [
|
||||
# Random plugins/extensions
|
||||
'top.GLOBALS',
|
||||
# See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html
|
||||
'originalCreateNotification',
|
||||
'canvas.contentDocument',
|
||||
'MyApp_RemoveAllHighlights',
|
||||
'http://tt.epicplay.com',
|
||||
'Can\'t find variable: ZiteReader',
|
||||
'jigsaw is not defined',
|
||||
'ComboSearch is not defined',
|
||||
'http://loading.retry.widdit.com/',
|
||||
'atomicFindClose',
|
||||
# ISP "optimizing" proxy - `Cache-Control: no-transform` seems to
|
||||
# reduce this. (thanks @acdha)
|
||||
# See http://stackoverflow.com/questions/4113268
|
||||
'bmi_SafeAddOnload',
|
||||
'EBCallBackMessageReceived',
|
||||
# See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
|
||||
'conduitPage'
|
||||
],
|
||||
ignoreUrls: [
|
||||
# Chrome extensions
|
||||
/extensions\//i,
|
||||
/^chrome:\/\//i,
|
||||
# Other plugins
|
||||
/127\.0\.0\.1:4001\/isrunning/i, # Cacaoweb
|
||||
/webappstoolbarba\.texthelp\.com\//i,
|
||||
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i
|
||||
]
|
||||
}).install()
|
||||
|
||||
if gon.current_user_id
|
||||
Raven.setUserContext({
|
||||
id: gon.current_user_id
|
||||
})
|
||||
|
||||
$ ->
|
||||
raven.init()
|
||||
@@ -144,6 +144,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.btn-transparent {
|
||||
color: $btn-transparent-color;
|
||||
background-color: transparent;
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-input-field {
|
||||
.dropdown-input-field, .default-dropdown-input {
|
||||
width: 100%;
|
||||
padding: 0 7px;
|
||||
color: $dropdown-input-color;
|
||||
|
||||
@@ -38,12 +38,14 @@
|
||||
|
||||
.filename {
|
||||
&.old {
|
||||
display: inline-block;
|
||||
span.idiff {
|
||||
background-color: #f8cbcb;
|
||||
}
|
||||
}
|
||||
|
||||
&.new {
|
||||
display: inline-block;
|
||||
span.idiff {
|
||||
background-color: #a6f3a6;
|
||||
}
|
||||
@@ -129,6 +131,11 @@
|
||||
td.line-numbers {
|
||||
float: none;
|
||||
border-left: 1px solid #ddd;
|
||||
|
||||
i {
|
||||
float: none;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
td.lines {
|
||||
padding: 0;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
.well-confirmation {
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
> h1 {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.lead {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmation-content {
|
||||
a {
|
||||
color: $md-link-color;
|
||||
}
|
||||
}
|
||||
@@ -249,6 +249,10 @@
|
||||
background: $gray-dark;
|
||||
border: 1px solid $border-gray-dark;
|
||||
}
|
||||
|
||||
&.btn-primary {
|
||||
@extend .btn-primary
|
||||
}
|
||||
}
|
||||
|
||||
a:not(.issuable-pager) {
|
||||
|
||||
@@ -183,6 +183,9 @@ ul.notes {
|
||||
}
|
||||
}
|
||||
|
||||
.author_link {
|
||||
color: $gl-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.note-headline-light,
|
||||
|
||||
@@ -10,6 +10,8 @@ module FilterProjects
|
||||
def filter_projects(projects)
|
||||
projects = projects.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
projects = projects.non_archived if params[:archived].blank?
|
||||
projects = projects.personal(current_user) if params[:personal].present? && current_user
|
||||
|
||||
projects
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
class ConfirmationsController < Devise::ConfirmationsController
|
||||
|
||||
def almost_there
|
||||
flash[:notice] = nil
|
||||
render layout: "devise_empty"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def after_resending_confirmation_instructions_path_for(resource)
|
||||
users_almost_there_path
|
||||
end
|
||||
|
||||
def after_confirmation_path_for(resource_name, resource)
|
||||
if signed_in?(resource_name)
|
||||
after_sign_in_path_for(resource)
|
||||
|
||||
@@ -83,8 +83,7 @@ class Projects::ApplicationController < ApplicationController
|
||||
end
|
||||
|
||||
def apply_diff_view_cookie!
|
||||
view = params[:view] || cookies[:diff_view]
|
||||
cookies.permanent[:diff_view] = params[:view] = view if view
|
||||
cookies.permanent[:diff_view] = params.delete(:view) if params[:view].present?
|
||||
end
|
||||
|
||||
def builds_enabled
|
||||
|
||||
@@ -38,13 +38,13 @@ class Projects::CommitController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def cancel_builds
|
||||
ci_commit.builds.running_or_pending.each(&:cancel)
|
||||
ci_builds.running_or_pending.each(&:cancel)
|
||||
|
||||
redirect_back_or_default default: builds_namespace_project_commit_path(project.namespace, project, commit.sha)
|
||||
end
|
||||
|
||||
def retry_builds
|
||||
ci_commit.builds.latest.failed.each do |build|
|
||||
ci_builds.latest.failed.each do |build|
|
||||
if build.retryable?
|
||||
Ci::Build.retry(build)
|
||||
end
|
||||
@@ -99,8 +99,12 @@ class Projects::CommitController < Projects::ApplicationController
|
||||
@commit ||= @project.commit(params[:id])
|
||||
end
|
||||
|
||||
def ci_commit
|
||||
@ci_commit ||= project.ci_commit(commit.sha)
|
||||
def ci_commits
|
||||
@ci_commits ||= project.ci_commits.where(sha: commit.sha)
|
||||
end
|
||||
|
||||
def ci_builds
|
||||
@ci_builds ||= Ci::Build.where(commit: ci_commits)
|
||||
end
|
||||
|
||||
def define_show_vars
|
||||
@@ -113,7 +117,8 @@ class Projects::CommitController < Projects::ApplicationController
|
||||
@diff_refs = [commit.parent || commit, commit]
|
||||
@notes_count = commit.notes.count
|
||||
|
||||
@statuses = ci_commit.statuses if ci_commit
|
||||
@statuses = CommitStatus.where(commit: ci_commits)
|
||||
@builds = Ci::Build.where(commit: ci_commits)
|
||||
end
|
||||
|
||||
def assign_change_commit_vars(mr_source_branch)
|
||||
|
||||
@@ -101,7 +101,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html do
|
||||
if @issue.valid?
|
||||
redirect_to issue_path(@issue)
|
||||
@@ -110,7 +109,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
||||
end
|
||||
end
|
||||
format.json do
|
||||
render json: @issue.to_json(include: [:milestone, :labels, assignee: { methods: :avatar_url }])
|
||||
render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -149,13 +149,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
|
||||
if @merge_request.valid?
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html do
|
||||
redirect_to([@merge_request.target_project.namespace.becomes(Namespace),
|
||||
@merge_request.target_project, @merge_request])
|
||||
end
|
||||
format.json do
|
||||
render json: @merge_request.to_json(include: [:milestone, :labels, assignee: { methods: :avatar_url }])
|
||||
render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } })
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -321,6 +320,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
|
||||
def define_widget_vars
|
||||
@ci_commit = @merge_request.ci_commit
|
||||
@ci_commits = [@ci_commit].compact
|
||||
closes_issues
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_action :authorize_admin_project_member!, except: :leave
|
||||
before_action :authorize_admin_project_member!, except: [:leave, :index]
|
||||
|
||||
def index
|
||||
@project_members = @project.project_members
|
||||
|
||||
@@ -31,11 +31,11 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
end
|
||||
|
||||
def after_sign_up_path_for(_resource)
|
||||
new_user_session_path
|
||||
users_almost_there_path
|
||||
end
|
||||
|
||||
def after_inactive_sign_up_path_for(_resource)
|
||||
new_user_session_path
|
||||
users_almost_there_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -272,16 +272,13 @@ class IssuableFinder
|
||||
items = items.without_label
|
||||
else
|
||||
items = items.with_label(label_names)
|
||||
|
||||
if projects
|
||||
items = items.where(labels: { project_id: projects })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# When filtering by multiple labels we may end up duplicating issues (if one
|
||||
# has multiple labels). This ensures we only return unique issues.
|
||||
items.distinct
|
||||
items
|
||||
end
|
||||
|
||||
def by_due_date(items)
|
||||
@@ -321,7 +318,7 @@ class IssuableFinder
|
||||
end
|
||||
|
||||
def label_names
|
||||
params[:label_name].split(',')
|
||||
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
|
||||
end
|
||||
|
||||
def current_user_related?
|
||||
|
||||
@@ -4,14 +4,6 @@ module CiStatusHelper
|
||||
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
|
||||
end
|
||||
|
||||
def ci_status_icon(ci_commit)
|
||||
ci_icon_for_status(ci_commit.status)
|
||||
end
|
||||
|
||||
def ci_status_label(ci_commit)
|
||||
ci_label_for_status(ci_commit.status)
|
||||
end
|
||||
|
||||
def ci_status_with_icon(status, target = nil)
|
||||
content = ci_icon_for_status(status) + ' '.html_safe + ci_label_for_status(status)
|
||||
klass = "ci-status ci-#{status}"
|
||||
@@ -47,10 +39,13 @@ module CiStatusHelper
|
||||
end
|
||||
|
||||
def render_ci_status(ci_commit, tooltip_placement: 'auto left')
|
||||
link_to ci_status_icon(ci_commit),
|
||||
# TODO: split this method into
|
||||
# - render_commit_status
|
||||
# - render_pipeline_status
|
||||
link_to ci_icon_for_status(ci_commit.status),
|
||||
ci_status_path(ci_commit),
|
||||
class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
|
||||
title: "Build #{ci_status_label(ci_commit)}",
|
||||
title: "Build #{ci_label_for_status(ci_commit.status)}",
|
||||
data: { toggle: 'tooltip', placement: tooltip_placement }
|
||||
end
|
||||
|
||||
|
||||
@@ -9,7 +9,13 @@ module DiffHelper
|
||||
end
|
||||
|
||||
def diff_view
|
||||
params[:view] == 'parallel' ? 'parallel' : 'inline'
|
||||
diff_views = %w(inline parallel)
|
||||
|
||||
if diff_views.include?(cookies[:diff_view])
|
||||
cookies[:diff_view]
|
||||
else
|
||||
diff_views.first
|
||||
end
|
||||
end
|
||||
|
||||
def diff_hard_limit_enabled?
|
||||
|
||||
@@ -25,6 +25,10 @@ module GitlabRoutingHelper
|
||||
namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref)
|
||||
end
|
||||
|
||||
def project_pipelines_path(project, *args)
|
||||
namespace_project_pipelines_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
def project_builds_path(project, *args)
|
||||
namespace_project_builds_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
@@ -84,6 +84,14 @@ module PageLayoutHelper
|
||||
end
|
||||
end
|
||||
|
||||
def nav(name = nil)
|
||||
if name
|
||||
@nav = name
|
||||
else
|
||||
@nav
|
||||
end
|
||||
end
|
||||
|
||||
def fluid_layout(enabled = false)
|
||||
if @fluid_layout.nil?
|
||||
@fluid_layout = (current_user && current_user.layout == "fluid") || enabled
|
||||
|
||||
@@ -144,6 +144,10 @@ module ProjectsHelper
|
||||
nav_tabs << :settings
|
||||
end
|
||||
|
||||
if can?(current_user, :read_project_member, project)
|
||||
nav_tabs << :team
|
||||
end
|
||||
|
||||
if can?(current_user, :read_issue, project)
|
||||
nav_tabs << :issues
|
||||
end
|
||||
|
||||
@@ -110,4 +110,12 @@ module TabHelper
|
||||
'active'
|
||||
end
|
||||
end
|
||||
|
||||
def profile_tab_class
|
||||
if controller.controller_path =~ /\Aprofiles/
|
||||
return 'active'
|
||||
end
|
||||
|
||||
'active' if current_controller?('oauth/applications')
|
||||
end
|
||||
end
|
||||
|
||||
+8
-14
@@ -37,8 +37,6 @@
|
||||
|
||||
module Ci
|
||||
class Build < CommitStatus
|
||||
LAZY_ATTRIBUTES = ['trace']
|
||||
|
||||
belongs_to :runner, class_name: 'Ci::Runner'
|
||||
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
|
||||
belongs_to :erased_by, class_name: 'User'
|
||||
@@ -50,25 +48,17 @@ module Ci
|
||||
|
||||
scope :unstarted, ->() { where(runner_id: nil) }
|
||||
scope :ignore_failures, ->() { where(allow_failure: false) }
|
||||
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
|
||||
|
||||
mount_uploader :artifacts_file, ArtifactUploader
|
||||
mount_uploader :artifacts_metadata, ArtifactUploader
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
# To prevent db load megabytes of data from trace
|
||||
default_scope -> { select(Ci::Build.columns_without_lazy) }
|
||||
|
||||
before_destroy { project }
|
||||
|
||||
class << self
|
||||
def columns_without_lazy
|
||||
(column_names - LAZY_ATTRIBUTES).map do |column_name|
|
||||
"#{table_name}.#{column_name}"
|
||||
end
|
||||
end
|
||||
after_create :execute_hooks
|
||||
|
||||
class << self
|
||||
def last_month
|
||||
where('created_at > ?', Date.today - 1.month)
|
||||
end
|
||||
@@ -126,12 +116,16 @@ module Ci
|
||||
end
|
||||
|
||||
def retried?
|
||||
!self.commit.latest_statuses_for_ref(self.ref).include?(self)
|
||||
!self.commit.statuses.latest.include?(self)
|
||||
end
|
||||
|
||||
def retry
|
||||
Ci::Build.retry(self)
|
||||
end
|
||||
|
||||
def depends_on_builds
|
||||
# Get builds of the same type
|
||||
latest_builds = self.commit.builds.similar(self).latest
|
||||
latest_builds = self.commit.builds.latest
|
||||
|
||||
# Return builds from previous stages
|
||||
latest_builds.where('stage_idx < ?', stage_idx)
|
||||
|
||||
+53
-89
@@ -19,21 +19,28 @@
|
||||
module Ci
|
||||
class Commit < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
include Statuseable
|
||||
|
||||
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
|
||||
has_many :statuses, class_name: 'CommitStatus'
|
||||
has_many :builds, class_name: 'Ci::Build'
|
||||
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
|
||||
|
||||
delegate :stages, to: :statuses
|
||||
|
||||
validates_presence_of :sha
|
||||
validates_presence_of :status
|
||||
validate :valid_commit_sha
|
||||
|
||||
# Invalidate object and save if when touched
|
||||
after_touch :update_state
|
||||
|
||||
def self.truncate_sha(sha)
|
||||
sha[0...8]
|
||||
end
|
||||
|
||||
def to_param
|
||||
sha
|
||||
def self.stages
|
||||
CommitStatus.where(commit: all).stages
|
||||
end
|
||||
|
||||
def project_id
|
||||
@@ -68,15 +75,20 @@ module Ci
|
||||
nil
|
||||
end
|
||||
|
||||
def stage
|
||||
running_or_pending = statuses.latest.running_or_pending.ordered
|
||||
running_or_pending.first.try(:stage)
|
||||
def branch?
|
||||
!tag?
|
||||
end
|
||||
|
||||
def create_builds(ref, tag, user, trigger_request = nil)
|
||||
def retryable?
|
||||
builds.latest.any? do |build|
|
||||
build.failed? && build.retryable?
|
||||
end
|
||||
end
|
||||
|
||||
def create_builds(user, trigger_request = nil)
|
||||
return unless config_processor
|
||||
config_processor.stages.any? do |stage|
|
||||
CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present?
|
||||
CreateBuildsService.new(self).execute(stage, user, 'success', trigger_request).present?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -84,7 +96,7 @@ module Ci
|
||||
return unless config_processor
|
||||
|
||||
# don't create other builds if this one is retried
|
||||
latest_builds = builds.similar(build).latest
|
||||
latest_builds = builds.latest
|
||||
return unless latest_builds.exists?(build.id)
|
||||
|
||||
# get list of stages after this build
|
||||
@@ -92,88 +104,21 @@ module Ci
|
||||
next_stages.delete(build.stage)
|
||||
|
||||
# get status for all prior builds
|
||||
prior_builds = latest_builds.reject { |other_build| next_stages.include?(other_build.stage) }
|
||||
status = Ci::Status.get_status(prior_builds)
|
||||
prior_builds = latest_builds.where.not(stage: next_stages)
|
||||
prior_status = prior_builds.status
|
||||
|
||||
# create builds for next stages based
|
||||
next_stages.any? do |stage|
|
||||
CreateBuildsService.new.execute(self, stage, build.ref, build.tag, build.user, build.trigger_request, status).present?
|
||||
CreateBuildsService.new(self).execute(stage, build.user, prior_status, build.trigger_request).present?
|
||||
end
|
||||
end
|
||||
|
||||
def refs
|
||||
statuses.order(:ref).pluck(:ref).uniq
|
||||
end
|
||||
|
||||
def latest_statuses
|
||||
@latest_statuses ||= statuses.latest.to_a
|
||||
end
|
||||
|
||||
def latest_statuses_for_ref(ref)
|
||||
latest_statuses.select { |status| status.ref == ref }
|
||||
end
|
||||
|
||||
def matrix_builds(build = nil)
|
||||
matrix_builds = builds.latest.ordered
|
||||
matrix_builds = matrix_builds.similar(build) if build
|
||||
matrix_builds.to_a
|
||||
end
|
||||
|
||||
def retried
|
||||
@retried ||= (statuses.order(id: :desc) - statuses.latest)
|
||||
end
|
||||
|
||||
def status
|
||||
if yaml_errors.present?
|
||||
return 'failed'
|
||||
end
|
||||
|
||||
@status ||= Ci::Status.get_status(latest_statuses)
|
||||
end
|
||||
|
||||
def pending?
|
||||
status == 'pending'
|
||||
end
|
||||
|
||||
def running?
|
||||
status == 'running'
|
||||
end
|
||||
|
||||
def success?
|
||||
status == 'success'
|
||||
end
|
||||
|
||||
def failed?
|
||||
status == 'failed'
|
||||
end
|
||||
|
||||
def canceled?
|
||||
status == 'canceled'
|
||||
end
|
||||
|
||||
def active?
|
||||
running? || pending?
|
||||
end
|
||||
|
||||
def complete?
|
||||
canceled? || success? || failed?
|
||||
end
|
||||
|
||||
def duration
|
||||
duration_array = statuses.map(&:duration).compact
|
||||
duration_array.reduce(:+).to_i
|
||||
end
|
||||
|
||||
def started_at
|
||||
@started_at ||= statuses.order('started_at ASC').first.try(:started_at)
|
||||
end
|
||||
|
||||
def finished_at
|
||||
@finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
|
||||
end
|
||||
|
||||
def coverage
|
||||
coverage_array = latest_statuses.map(&:coverage).compact
|
||||
coverage_array = statuses.latest.map(&:coverage).compact
|
||||
if coverage_array.size >= 1
|
||||
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
|
||||
end
|
||||
@@ -181,23 +126,29 @@ module Ci
|
||||
|
||||
def config_processor
|
||||
return nil unless ci_yaml_file
|
||||
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
|
||||
save_yaml_error(e.message)
|
||||
nil
|
||||
rescue
|
||||
save_yaml_error("Undefined error")
|
||||
nil
|
||||
return @config_processor if defined?(@config_processor)
|
||||
|
||||
@config_processor ||= begin
|
||||
Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
|
||||
save_yaml_error(e.message)
|
||||
nil
|
||||
rescue
|
||||
save_yaml_error("Undefined error")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def ci_yaml_file
|
||||
return @ci_yaml_file if defined?(@ci_yaml_file)
|
||||
|
||||
@ci_yaml_file ||= begin
|
||||
blob = project.repository.blob_at(sha, '.gitlab-ci.yml')
|
||||
blob.load_all_data!(project.repository)
|
||||
blob.data
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def skip_ci?
|
||||
@@ -206,10 +157,23 @@ module Ci
|
||||
|
||||
private
|
||||
|
||||
def update_state
|
||||
statuses.reload
|
||||
self.status = if yaml_errors.blank?
|
||||
statuses.latest.status || 'skipped'
|
||||
else
|
||||
'failed'
|
||||
end
|
||||
self.started_at = statuses.started_at
|
||||
self.finished_at = statuses.finished_at
|
||||
self.duration = statuses.latest.duration
|
||||
save
|
||||
end
|
||||
|
||||
def save_yaml_error(error)
|
||||
return if self.yaml_errors?
|
||||
self.yaml_errors = error
|
||||
save
|
||||
update_state
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -207,12 +207,13 @@ class Commit
|
||||
@raw.short_id(7)
|
||||
end
|
||||
|
||||
def ci_commit
|
||||
project.ci_commit(sha)
|
||||
def ci_commits
|
||||
@ci_commits ||= project.ci_commits.where(sha: sha)
|
||||
end
|
||||
|
||||
def status
|
||||
ci_commit.try(:status) || :not_found
|
||||
return @status if defined?(@status)
|
||||
@status ||= ci_commits.status
|
||||
end
|
||||
|
||||
def revert_branch_name
|
||||
|
||||
+22
-34
@@ -33,30 +33,23 @@
|
||||
#
|
||||
|
||||
class CommitStatus < ActiveRecord::Base
|
||||
include Statuseable
|
||||
|
||||
self.table_name = 'ci_builds'
|
||||
|
||||
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
|
||||
belongs_to :commit, class_name: 'Ci::Commit'
|
||||
belongs_to :commit, class_name: 'Ci::Commit', touch: true
|
||||
belongs_to :user
|
||||
|
||||
validates :commit, presence: true
|
||||
validates :status, inclusion: { in: %w(pending running failed success canceled) }
|
||||
|
||||
validates_presence_of :name
|
||||
|
||||
alias_attribute :author, :user
|
||||
|
||||
scope :running, -> { where(status: 'running') }
|
||||
scope :pending, -> { where(status: 'pending') }
|
||||
scope :success, -> { where(status: 'success') }
|
||||
scope :failed, -> { where(status: 'failed') }
|
||||
scope :running_or_pending, -> { where(status: [:running, :pending]) }
|
||||
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, :commit_id)) }
|
||||
scope :ordered, -> { order(:ref, :stage_idx, :name) }
|
||||
scope :for_ref, ->(ref) { where(ref: ref) }
|
||||
|
||||
AVAILABLE_STATUSES = ['pending', 'running', 'success', 'failed', 'canceled']
|
||||
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
|
||||
|
||||
state_machine :status, initial: :pending do
|
||||
event :run do
|
||||
@@ -86,31 +79,24 @@ class CommitStatus < ActiveRecord::Base
|
||||
after_transition [:pending, :running] => :success do |commit_status|
|
||||
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status)
|
||||
end
|
||||
|
||||
state :pending, value: 'pending'
|
||||
state :running, value: 'running'
|
||||
state :failed, value: 'failed'
|
||||
state :success, value: 'success'
|
||||
state :canceled, value: 'canceled'
|
||||
end
|
||||
|
||||
delegate :sha, :short_sha, to: :commit, prefix: false
|
||||
delegate :sha, :short_sha, to: :commit
|
||||
|
||||
# TODO: this should be removed with all references
|
||||
def before_sha
|
||||
Gitlab::Git::BLANK_SHA
|
||||
commit.before_sha || Gitlab::Git::BLANK_SHA
|
||||
end
|
||||
|
||||
def started?
|
||||
!pending? && !canceled? && started_at
|
||||
def self.stages
|
||||
order_by = 'max(stage_idx)'
|
||||
group('stage').order(order_by).pluck(:stage, order_by).map(&:first).compact
|
||||
end
|
||||
|
||||
def active?
|
||||
running? || pending?
|
||||
end
|
||||
|
||||
def complete?
|
||||
canceled? || success? || failed?
|
||||
def self.stages_status
|
||||
all.stages.inject({}) do |h, stage|
|
||||
h[stage] = all.where(stage: stage).status
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
def ignored?
|
||||
@@ -118,11 +104,13 @@ class CommitStatus < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def duration
|
||||
if started_at && finished_at
|
||||
finished_at - started_at
|
||||
elsif started_at
|
||||
Time.now - started_at
|
||||
end
|
||||
duration =
|
||||
if started_at && finished_at
|
||||
finished_at - started_at
|
||||
elsif started_at
|
||||
Time.now - started_at
|
||||
end
|
||||
duration
|
||||
end
|
||||
|
||||
def stuck?
|
||||
|
||||
@@ -37,7 +37,6 @@ module Issuable
|
||||
scope :closed, -> { with_state(:closed) }
|
||||
scope :order_milestone_due_desc, -> { joins(:milestone).reorder('milestones.due_date DESC, milestones.id DESC') }
|
||||
scope :order_milestone_due_asc, -> { joins(:milestone).reorder('milestones.due_date ASC, milestones.id ASC') }
|
||||
scope :with_label, ->(title) { joins(:labels).where(labels: { title: title }) }
|
||||
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
|
||||
|
||||
scope :join_project, -> { joins(:project) }
|
||||
@@ -122,6 +121,14 @@ module Issuable
|
||||
|
||||
joins(join_clause).group(issuable_table[:id]).reorder("COUNT(notes.id) DESC")
|
||||
end
|
||||
|
||||
def with_label(title)
|
||||
if title.is_a?(Array) && title.count > 1
|
||||
joins(:labels).where(labels: { title: title }).group('issues.id').having("count(distinct labels.title) = #{title.count}")
|
||||
else
|
||||
joins(:labels).where(labels: { title: title })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def today?
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
module Statuseable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
AVAILABLE_STATUSES = %w(pending running success failed canceled skipped)
|
||||
|
||||
class_methods do
|
||||
def status_sql
|
||||
builds = all.select('count(*)').to_sql
|
||||
success = all.success.select('count(*)').to_sql
|
||||
ignored = all.ignored.select('count(*)').to_sql if all.respond_to?(:ignored)
|
||||
ignored ||= '0'
|
||||
pending = all.pending.select('count(*)').to_sql
|
||||
running = all.running.select('count(*)').to_sql
|
||||
canceled = all.canceled.select('count(*)').to_sql
|
||||
skipped = all.skipped.select('count(*)').to_sql
|
||||
|
||||
deduce_status = "(CASE
|
||||
WHEN (#{builds})=0 THEN NULL
|
||||
WHEN (#{builds})=(#{success})+(#{ignored}) THEN 'success'
|
||||
WHEN (#{builds})=(#{pending}) THEN 'pending'
|
||||
WHEN (#{builds})=(#{canceled}) THEN 'canceled'
|
||||
WHEN (#{builds})=(#{skipped}) THEN 'skipped'
|
||||
WHEN (#{running})+(#{pending})>0 THEN 'running'
|
||||
ELSE 'failed'
|
||||
END)"
|
||||
|
||||
deduce_status
|
||||
end
|
||||
|
||||
def status
|
||||
all.pluck(self.status_sql).first
|
||||
end
|
||||
|
||||
def duration
|
||||
duration_array = all.map(&:duration).compact
|
||||
duration_array.reduce(:+)
|
||||
end
|
||||
|
||||
def started_at
|
||||
all.minimum(:started_at)
|
||||
end
|
||||
|
||||
def finished_at
|
||||
all.maximum(:finished_at)
|
||||
end
|
||||
end
|
||||
|
||||
included do
|
||||
validates :status, inclusion: { in: AVAILABLE_STATUSES }
|
||||
|
||||
state_machine :status, initial: :pending do
|
||||
state :pending, value: 'pending'
|
||||
state :running, value: 'running'
|
||||
state :failed, value: 'failed'
|
||||
state :success, value: 'success'
|
||||
state :canceled, value: 'canceled'
|
||||
state :skipped, value: 'skipped'
|
||||
end
|
||||
|
||||
scope :running, -> { where(status: 'running') }
|
||||
scope :pending, -> { where(status: 'pending') }
|
||||
scope :success, -> { where(status: 'success') }
|
||||
scope :failed, -> { where(status: 'failed') }
|
||||
scope :canceled, -> { where(status: 'canceled') }
|
||||
scope :skipped, -> { where(status: 'skipped') }
|
||||
scope :running_or_pending, -> { where(status: [:running, :pending]) }
|
||||
scope :finished, -> { where(status: [:success, :failed, :canceled]) }
|
||||
end
|
||||
|
||||
def started?
|
||||
!pending? && !canceled? && started_at
|
||||
end
|
||||
|
||||
def active?
|
||||
running? || pending?
|
||||
end
|
||||
|
||||
def complete?
|
||||
canceled? || success? || failed?
|
||||
end
|
||||
end
|
||||
@@ -586,7 +586,7 @@ class MergeRequest < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def ci_commit
|
||||
@ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project
|
||||
@ci_commit ||= source_project.ci_commit(last_commit.id, source_branch) if last_commit && source_project
|
||||
end
|
||||
|
||||
def diff_refs
|
||||
|
||||
@@ -963,12 +963,12 @@ class Project < ActiveRecord::Base
|
||||
!namespace.share_with_group_lock
|
||||
end
|
||||
|
||||
def ci_commit(sha)
|
||||
ci_commits.find_by(sha: sha)
|
||||
def ci_commit(sha, ref)
|
||||
ci_commits.order(id: :desc).find_by(sha: sha, ref: ref)
|
||||
end
|
||||
|
||||
def ensure_ci_commit(sha)
|
||||
ci_commit(sha) || ci_commits.create(sha: sha)
|
||||
def ensure_ci_commit(sha, ref)
|
||||
ci_commit(sha, ref) || ci_commits.create(sha: sha, ref: ref)
|
||||
end
|
||||
|
||||
def enable_ci
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
module Ci
|
||||
class CreateBuildsService
|
||||
def execute(commit, stage, ref, tag, user, trigger_request, status)
|
||||
builds_attrs = commit.config_processor.builds_for_stage_and_ref(stage, ref, tag, trigger_request)
|
||||
def initialize(commit)
|
||||
@commit = commit
|
||||
end
|
||||
|
||||
def execute(stage, user, status, trigger_request = nil)
|
||||
builds_attrs = config_processor.builds_for_stage_and_ref(stage, @commit.ref, @commit.tag, trigger_request)
|
||||
|
||||
# check when to create next build
|
||||
builds_attrs = builds_attrs.select do |build_attrs|
|
||||
@@ -17,7 +21,8 @@ module Ci
|
||||
|
||||
builds_attrs.map do |build_attrs|
|
||||
# don't create the same build twice
|
||||
unless commit.builds.find_by(ref: ref, tag: tag, trigger_request: trigger_request, name: build_attrs[:name])
|
||||
unless @commit.builds.find_by(ref: @commit.ref, tag: @commit.tag,
|
||||
trigger_request: trigger_request, name: build_attrs[:name])
|
||||
build_attrs.slice!(:name,
|
||||
:commands,
|
||||
:tag_list,
|
||||
@@ -26,17 +31,21 @@ module Ci
|
||||
:stage,
|
||||
:stage_idx)
|
||||
|
||||
build_attrs.merge!(ref: ref,
|
||||
tag: tag,
|
||||
build_attrs.merge!(ref: @commit.ref,
|
||||
tag: @commit.tag,
|
||||
trigger_request: trigger_request,
|
||||
user: user,
|
||||
project: commit.project)
|
||||
project: @commit.project)
|
||||
|
||||
build = commit.builds.create!(build_attrs)
|
||||
build.execute_hooks
|
||||
build
|
||||
@commit.builds.create!(build_attrs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config_processor
|
||||
@config_processor ||= @commit.config_processor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,14 +7,14 @@ module Ci
|
||||
# check if ref is tag
|
||||
tag = project.repository.find_tag(ref).present?
|
||||
|
||||
ci_commit = project.ensure_ci_commit(commit.sha)
|
||||
ci_commit = project.ci_commits.create(sha: commit.sha, ref: ref, tag: tag)
|
||||
|
||||
trigger_request = trigger.trigger_requests.create!(
|
||||
variables: variables,
|
||||
commit: ci_commit,
|
||||
)
|
||||
|
||||
if ci_commit.create_builds(ref, tag, nil, trigger_request)
|
||||
if ci_commit.create_builds(nil, trigger_request)
|
||||
trigger_request
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,8 +3,9 @@ module Ci
|
||||
def execute(project, opts)
|
||||
sha = opts[:sha] || ref_sha(project, opts[:ref])
|
||||
|
||||
commit = project.ci_commits.find_by(sha: sha)
|
||||
image_name = image_for_commit(commit)
|
||||
ci_commits = project.ci_commits.where(sha: sha)
|
||||
ci_commits = ci_commits.where(ref: opts[:ref]) if opts[:ref]
|
||||
image_name = image_for_status(ci_commits.status)
|
||||
|
||||
image_path = Rails.root.join('public/ci', image_name)
|
||||
OpenStruct.new(path: image_path, name: image_name)
|
||||
@@ -16,9 +17,9 @@ module Ci
|
||||
project.commit(ref).try(:sha) if ref
|
||||
end
|
||||
|
||||
def image_for_commit(commit)
|
||||
return 'build-unknown.svg' unless commit
|
||||
'build-' + commit.status + ".svg"
|
||||
def image_for_status(status)
|
||||
status ||= 'unknown'
|
||||
'build-' + status + ".svg"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ class CreateCommitBuildsService
|
||||
def execute(project, user, params)
|
||||
return false unless project.builds_enabled?
|
||||
|
||||
before_sha = params[:checkout_sha] || params[:before]
|
||||
sha = params[:checkout_sha] || params[:after]
|
||||
origin_ref = params[:ref]
|
||||
|
||||
@@ -10,15 +11,16 @@ class CreateCommitBuildsService
|
||||
end
|
||||
|
||||
ref = Gitlab::Git.ref_name(origin_ref)
|
||||
tag = Gitlab::Git.tag_ref?(origin_ref)
|
||||
|
||||
# Skip branch removal
|
||||
if sha == Gitlab::Git::BLANK_SHA
|
||||
return false
|
||||
end
|
||||
|
||||
commit = project.ci_commit(sha)
|
||||
commit = project.ci_commit(sha, ref)
|
||||
unless commit
|
||||
commit = project.ci_commits.new(sha: sha)
|
||||
commit = project.ci_commits.new(sha: sha, ref: ref, before_sha: before_sha, tag: tag)
|
||||
|
||||
# Skip creating ci_commit when no gitlab-ci.yml is found
|
||||
unless commit.ci_yaml_file
|
||||
@@ -32,10 +34,10 @@ class CreateCommitBuildsService
|
||||
# Skip creating builds for commits that have [ci skip]
|
||||
unless commit.skip_ci?
|
||||
# Create builds for commit
|
||||
tag = Gitlab::Git.tag_ref?(origin_ref)
|
||||
commit.create_builds(ref, tag, user)
|
||||
commit.create_builds(user)
|
||||
end
|
||||
|
||||
commit.touch
|
||||
commit
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,8 +37,9 @@ class IssuableBaseService < BaseService
|
||||
end
|
||||
|
||||
def filter_params(issuable_ability_name = :issue)
|
||||
params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
|
||||
params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
|
||||
filter_assignee
|
||||
filter_milestone
|
||||
filter_labels
|
||||
|
||||
ability = :"admin_#{issuable_ability_name}"
|
||||
|
||||
@@ -49,6 +50,29 @@ class IssuableBaseService < BaseService
|
||||
end
|
||||
end
|
||||
|
||||
def filter_assignee
|
||||
if params[:assignee_id] == IssuableFinder::NONE
|
||||
params[:assignee_id] = ''
|
||||
end
|
||||
end
|
||||
|
||||
def filter_milestone
|
||||
milestone_id = params[:milestone_id]
|
||||
return unless milestone_id
|
||||
|
||||
if milestone_id == IssuableFinder::NONE ||
|
||||
project.milestones.find_by(id: milestone_id).nil?
|
||||
params[:milestone_id] = ''
|
||||
end
|
||||
end
|
||||
|
||||
def filter_labels
|
||||
return if params[:label_ids].to_a.empty?
|
||||
|
||||
params[:label_ids] =
|
||||
project.labels.where(id: params[:label_ids]).pluck(:id)
|
||||
end
|
||||
|
||||
def update(issuable)
|
||||
change_state(issuable)
|
||||
filter_params
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.well-confirmation.text-center
|
||||
%h1.prepend-top-0
|
||||
Almost there...
|
||||
%p.lead
|
||||
Please check your email to confirm your account
|
||||
%p.confirmation-content.text-center
|
||||
No confirmation email received? Please check your spam folder or
|
||||
.append-bottom-20.prepend-top-20.text-center
|
||||
%a.btn.btn-lg.btn-success{ href: new_user_confirmation_path }
|
||||
Request new confirmation email
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Applications"
|
||||
- header_title page_title, applications_profile_path
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
.content-wrapper
|
||||
= render "layouts/flash"
|
||||
= yield :flash_message
|
||||
- if defined?(nav) && nav
|
||||
.layout-nav
|
||||
%div{ class: container_class }
|
||||
= render "layouts/nav/#{nav}"
|
||||
%div{ class: (container_class unless @no_container) }
|
||||
.content
|
||||
.clearfix
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
= yield :scripts_body_top
|
||||
|
||||
= render "layouts/header/default", title: header_title
|
||||
= render 'layouts/page', sidebar: sidebar
|
||||
= render 'layouts/page', sidebar: sidebar, nav: nav
|
||||
|
||||
= yield :scripts_body
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
!!! 5
|
||||
%html{ lang: "en"}
|
||||
= render "layouts/head"
|
||||
%body.ui_charcoal.login-page.application.navless
|
||||
= render "layouts/header/empty"
|
||||
= render "layouts/broadcast"
|
||||
.container.navless-container
|
||||
.content
|
||||
= render "layouts/flash"
|
||||
= yield
|
||||
|
||||
%hr
|
||||
.container
|
||||
.footer-links
|
||||
= link_to "Explore", explore_root_path
|
||||
= link_to "Help", help_path
|
||||
= link_to "About GitLab", "https://about.gitlab.com/"
|
||||
@@ -48,8 +48,7 @@
|
||||
%span
|
||||
Help
|
||||
|
||||
%li.separate-item
|
||||
= nav_link(controller: :profile) do
|
||||
= nav_link(html_options: {class: profile_tab_class}) do
|
||||
= link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do
|
||||
= icon('user fw')
|
||||
%span
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
%ul.nav.nav-sidebar
|
||||
= nav_link do
|
||||
= link_to root_path, title: 'Go to dashboard', class: 'back-link' do
|
||||
= icon('caret-square-o-left fw')
|
||||
%span
|
||||
Go to dashboard
|
||||
|
||||
%li.separate-item
|
||||
|
||||
%ul.nav-links
|
||||
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
|
||||
= link_to profile_path, title: 'Profile Settings' do
|
||||
= icon('user fw')
|
||||
%span
|
||||
Profile Settings
|
||||
Profile
|
||||
= nav_link(controller: [:accounts, :two_factor_auths]) do
|
||||
= link_to profile_account_path, title: 'Account' do
|
||||
= icon('gear fw')
|
||||
@@ -27,7 +19,6 @@
|
||||
= icon('envelope-o fw')
|
||||
%span
|
||||
Emails
|
||||
%span.count= number_with_delimiter(current_user.emails.count + 1)
|
||||
- unless current_user.ldap_user?
|
||||
= nav_link(controller: :passwords) do
|
||||
= link_to edit_profile_password_path, title: 'Password' do
|
||||
@@ -45,7 +36,6 @@
|
||||
= icon('key fw')
|
||||
%span
|
||||
SSH Keys
|
||||
%span.count= number_with_delimiter(current_user.keys.count)
|
||||
= nav_link(controller: :preferences) do
|
||||
= link_to profile_preferences_path, title: 'Preferences' do
|
||||
-# TODO (rspeicher): Better icon?
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
Merge Requests
|
||||
%span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
|
||||
|
||||
- if project_nav_tab? :settings
|
||||
- if project_nav_tab? :team
|
||||
= nav_link(controller: [:project_members, :teams]) do
|
||||
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
|
||||
= icon('users fw')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
- page_title "Profile Settings"
|
||||
- header_title "Profile Settings", profile_path unless header_title
|
||||
- sidebar "profile"
|
||||
- sidebar "dashboard"
|
||||
- nav "profile"
|
||||
|
||||
= render template: "layouts/application"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Account"
|
||||
- header_title page_title, profile_account_path
|
||||
|
||||
- if current_user.ldap_user?
|
||||
.alert.alert-info
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Audit Log"
|
||||
- header_title page_title, audit_log_profile_path
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Emails"
|
||||
- header_title page_title, profile_emails_path
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "SSH Keys"
|
||||
- header_title page_title, profile_keys_path
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Notifications"
|
||||
- header_title page_title, profile_notifications_path
|
||||
|
||||
%div
|
||||
- if @user.errors.any?
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title "Password"
|
||||
- header_title page_title, edit_profile_password_path
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
- page_title 'Preferences'
|
||||
- header_title page_title, profile_preferences_path
|
||||
|
||||
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: {class: 'row prepend-top-default js-preferences-form'} do |f|
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
%li
|
||||
gcovr (C/C++) -
|
||||
%code ^TOTAL.*\s+(\d+\%)$
|
||||
%li
|
||||
tap --coverage-report=text-summary (Node.js) -
|
||||
%code ^Statements\s*:\s*([^%]+)
|
||||
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
.project-last-commit
|
||||
- ci_commit = project.ci_commit(commit.sha)
|
||||
- if ci_commit
|
||||
= link_to ci_status_path(ci_commit), class: "ci-status ci-#{ci_commit.status}" do
|
||||
= ci_status_icon(ci_commit)
|
||||
= ci_status_label(ci_commit)
|
||||
- if commit.status
|
||||
= link_to builds_namespace_project_commit_path(commit.project.namespace, commit.project, commit), class: "ci-status ci-#{commit.status}" do
|
||||
= ci_icon_for_status(commit.status)
|
||||
= ci_label_for_status(commit.status)
|
||||
|
||||
= 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), class: "commit-row-message"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
- if @lines.present?
|
||||
- if @form.unfold? && @form.since != 1 && !@form.bottom?
|
||||
%tr.line_holder{ id: @form.since }
|
||||
%tr.line_holder
|
||||
= render "projects/diffs/match_line", { line: @match_line,
|
||||
line_old: @form.since, line_new: @form.since, bottom: false, new_file: false }
|
||||
|
||||
- @lines.each_with_index do |line, index|
|
||||
- line_new = index + @form.since
|
||||
- line_old = line_new - @form.offset
|
||||
%tr.line_holder
|
||||
%tr.line_holder{ id: line_old }
|
||||
%td.old_line.diff-line-num{ data: { linenumber: line_old } }
|
||||
= link_to raw(line_old), "#"
|
||||
= link_to raw(line_old), "##{line_old}"
|
||||
%td.new_line.diff-line-num{ data: { linenumber: line_old } }
|
||||
= link_to raw(line_new) , "#"
|
||||
= link_to raw(line_new) , "##{line_old}"
|
||||
%td.line_content.noteable_line==#{' ' * @form.indent}#{line}
|
||||
|
||||
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
|
||||
|
||||
@@ -58,6 +58,6 @@
|
||||
%th Coverage
|
||||
%th
|
||||
|
||||
= render @builds, commit_sha: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
|
||||
= render @builds, commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
|
||||
|
||||
= paginate @builds, theme: 'gitlab'
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
= link_to "merge request #{merge_request.to_reference}", merge_request_path(merge_request)
|
||||
|
||||
#up-build-trace
|
||||
- builds = @build.commit.matrix_builds(@build)
|
||||
- builds = @build.commit.builds.latest.to_a
|
||||
- if builds.size > 1
|
||||
%ul.nav-links.no-top.no-bottom
|
||||
- builds.each do |build|
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
%td
|
||||
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace"
|
||||
|
||||
%td
|
||||
- if build.ref
|
||||
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref)
|
||||
- else
|
||||
.light none
|
||||
- if defined?(ref) && ref
|
||||
%td
|
||||
- if build.ref
|
||||
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref)
|
||||
- else
|
||||
.light none
|
||||
|
||||
- if defined?(runner) && runner
|
||||
%td
|
||||
@@ -48,6 +49,8 @@
|
||||
%span.label.label-info triggered
|
||||
- if build.try(:allow_failure)
|
||||
%span.label.label-danger allowed to fail
|
||||
- if defined?(retried) && retried
|
||||
%span.label.label-warning retried
|
||||
|
||||
%td.duration
|
||||
- if build.duration
|
||||
|
||||
@@ -1,67 +1,2 @@
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
- if can?(current_user, :update_build, @ci_commit.project)
|
||||
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
|
||||
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
|
||||
|
||||
- if @ci_commit.builds.running_or_pending.any?
|
||||
= link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
|
||||
|
||||
.oneline
|
||||
= pluralize @statuses.count(:id), "build"
|
||||
- if defined?(link_to_commit) && link_to_commit
|
||||
for commit
|
||||
= link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: "monospace"
|
||||
- if @ci_commit.duration > 0
|
||||
in
|
||||
= time_interval_in_words @ci_commit.duration
|
||||
|
||||
- if @ci_commit.yaml_errors.present?
|
||||
.bs-callout.bs-callout-danger
|
||||
%h4 Found errors in your .gitlab-ci.yml:
|
||||
%ul
|
||||
- @ci_commit.yaml_errors.split(",").each do |error|
|
||||
%li= error
|
||||
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
|
||||
|
||||
- if @ci_commit.project.builds_enabled? && !@ci_commit.ci_yaml_file
|
||||
.bs-callout.bs-callout-warning
|
||||
\.gitlab-ci.yml not found in this commit
|
||||
|
||||
.table-holder
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Ref
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @ci_commit.project.build_coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
- @ci_commit.refs.each do |ref|
|
||||
- builds = @ci_commit.statuses.for_ref(ref).latest.ordered
|
||||
= render builds, coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true
|
||||
|
||||
- if @ci_commit.retried.any?
|
||||
.gray-content-block.second-block
|
||||
Retried builds
|
||||
|
||||
.table-holder
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Ref
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @ci_commit.project.build_coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
= render @ci_commit.retried, coverage: @ci_commit.project.build_coverage_enabled?, stage: true
|
||||
- @ci_commits.each do |ci_commit|
|
||||
= render "ci_commit", ci_commit: ci_commit
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
- if can?(current_user, :update_build, @project)
|
||||
- if ci_commit.builds.latest.failed.any?(&:retryable?)
|
||||
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
|
||||
|
||||
- if ci_commit.builds.running_or_pending.any?
|
||||
= link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
|
||||
|
||||
.oneline
|
||||
= pluralize ci_commit.statuses.count(:id), "build"
|
||||
- if ci_commit.ref
|
||||
for
|
||||
%span.label.label-info
|
||||
= ci_commit.ref
|
||||
- if defined?(link_to_commit) && link_to_commit
|
||||
for commit
|
||||
= link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace"
|
||||
- if ci_commit.duration > 0
|
||||
in
|
||||
= time_interval_in_words ci_commit.duration
|
||||
|
||||
- if ci_commit.yaml_errors.present?
|
||||
.bs-callout.bs-callout-danger
|
||||
%h4 Found errors in your .gitlab-ci.yml:
|
||||
%ul
|
||||
- ci_commit.yaml_errors.split(",").each do |error|
|
||||
%li= error
|
||||
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
|
||||
|
||||
- if @project.builds_enabled? && !ci_commit.ci_yaml_file
|
||||
.bs-callout.bs-callout-warning
|
||||
\.gitlab-ci.yml not found in this commit
|
||||
|
||||
.table-holder
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @project.build_coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
- builds = ci_commit.statuses.latest.ordered
|
||||
= render builds, coverage: @project.build_coverage_enabled?, stage: true, ref: false, allow_retry: true
|
||||
|
||||
- if ci_commit.retried.any?
|
||||
.gray-content-block.second-block
|
||||
Retried builds
|
||||
|
||||
.table-holder
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Status
|
||||
%th Build ID
|
||||
%th Ref
|
||||
%th Stage
|
||||
%th Name
|
||||
%th Duration
|
||||
%th Finished at
|
||||
- if @project.build_coverage_enabled?
|
||||
%th Coverage
|
||||
%th
|
||||
= render ci_commit.retried, coverage: @project.build_coverage_enabled?, stage: true, ref: false
|
||||
@@ -43,12 +43,12 @@
|
||||
- @commit.parents.each do |parent|
|
||||
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
|
||||
|
||||
- if @ci_commit
|
||||
- if @commit.status
|
||||
.pull-right
|
||||
= link_to ci_status_path(@ci_commit), class: "ci-status ci-#{@ci_commit.status}" do
|
||||
= ci_status_icon(@ci_commit)
|
||||
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status ci-#{@commit.status}" do
|
||||
= ci_icon_for_status(@commit.status)
|
||||
build:
|
||||
= ci_status_label(@ci_commit)
|
||||
= ci_label_for_status(@commit.status)
|
||||
|
||||
.commit-info-row.branches
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.prepend-top-default
|
||||
= render "commit_box"
|
||||
- if @ci_commit
|
||||
- if @commit.status
|
||||
= render "ci_menu"
|
||||
- else
|
||||
%div.block-connector
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
- notes = commit.notes
|
||||
- note_count = notes.user.count
|
||||
|
||||
- ci_commit = project.ci_commit(commit.sha)
|
||||
- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count]
|
||||
- cache_key.push(ci_commit.status) if ci_commit
|
||||
- cache_key.push(commit.status) if commit.status
|
||||
|
||||
= cache(cache_key) do
|
||||
%li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" }
|
||||
@@ -17,8 +16,8 @@
|
||||
%a.text-expander.js-toggle-button ...
|
||||
|
||||
.pull-right
|
||||
- if ci_commit
|
||||
= render_ci_status(ci_commit)
|
||||
- if commit.status
|
||||
= render_ci_status(commit)
|
||||
= clipboard_button(clipboard_text: commit.id)
|
||||
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
|
||||
|
||||
|
||||
@@ -39,4 +39,4 @@
|
||||
= spinner
|
||||
|
||||
:javascript
|
||||
CommitsList.init("#{@ref}", #{@limit});
|
||||
CommitsList.init(#{@limit});
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
- if defined?(commit_sha) && commit_sha
|
||||
%td
|
||||
= link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace"
|
||||
|
||||
%td
|
||||
- if generic_commit_status.ref
|
||||
= link_to generic_commit_status.ref, namespace_project_commits_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.ref)
|
||||
- else
|
||||
.light none
|
||||
|
||||
- if defined?(ref) && ref
|
||||
%td
|
||||
- if generic_commit_status.ref
|
||||
= link_to generic_commit_status.ref, namespace_project_commits_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.ref)
|
||||
- else
|
||||
.light none
|
||||
|
||||
- if defined?(runner) && runner
|
||||
%td
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- @related_branches.each do |branch|
|
||||
%li
|
||||
- sha = @project.repository.find_branch(branch).target
|
||||
- ci_commit = @project.ci_commit(sha) if sha
|
||||
- ci_commit = @project.ci_commit(sha, branch) if sha
|
||||
- if ci_commit
|
||||
%span.related-branch-ci-status
|
||||
= render_ci_status(ci_commit)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
- page_card_attributes @merge_request.card_attributes
|
||||
- header_title project_title(@project, "Merge Requests", namespace_project_merge_requests_path(@project.namespace, @project))
|
||||
|
||||
- if params[:view] == 'parallel'
|
||||
- if diff_view == 'parallel'
|
||||
- fluid_layout true
|
||||
|
||||
.merge-request{'data-url' => merge_request_path(@merge_request)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- page_title "#{@merge_request.title} (#{merge_request.to_reference}", "Merge Requests"
|
||||
- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
|
||||
= render "header_title"
|
||||
|
||||
.merge-request
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
= render "projects/commit/builds", link_to_commit: true
|
||||
= render "projects/commit/ci_commit", ci_commit: @ci_commit, link_to_commit: true
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
group, members with
|
||||
%strong #{group_links.human_access}
|
||||
role (#{shared_group_users_count})
|
||||
- if current_user.can?(:admin_group, shared_group)
|
||||
- if can?(current_user, :admin_group, shared_group)
|
||||
.panel-head-actions
|
||||
= link_to group_group_members_path(shared_group), class: 'btn btn-sm' do
|
||||
%i.fa.fa-pencil-square-o
|
||||
|
||||
@@ -8,39 +8,7 @@
|
||||
= h(multi_label_name(params[:label_name], "Label"))
|
||||
= icon('chevron-down')
|
||||
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
|
||||
.dropdown-page-one
|
||||
= dropdown_title("Filter by label")
|
||||
= dropdown_filter("Search labels")
|
||||
= dropdown_content
|
||||
- if @project
|
||||
= dropdown_footer do
|
||||
%ul.dropdown-footer-list
|
||||
- if can? current_user, :admin_label, @project
|
||||
%li
|
||||
%a.dropdown-toggle-page{href: "#"}
|
||||
Create new
|
||||
%li
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project) do
|
||||
- if can? current_user, :admin_label, @project
|
||||
Manage labels
|
||||
- else
|
||||
View labels
|
||||
= render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label" }
|
||||
- if can? current_user, :admin_label, @project and @project
|
||||
.dropdown-page-two.dropdown-new-label
|
||||
= dropdown_title("Create new label", back: true)
|
||||
= dropdown_content do
|
||||
.dropdown-labels-error.js-label-error
|
||||
%input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"}
|
||||
.suggest-colors.suggest-colors-dropdown
|
||||
- suggested_colors.each do |color|
|
||||
= link_to '#', style: "background-color: #{color}", data: { color: color } do
|
||||
 
|
||||
.dropdown-label-color-input
|
||||
.dropdown-label-color-preview.js-dropdown-label-color-preview
|
||||
%input#new_label_color.dropdown-input-field{ type: "text" }
|
||||
.clearfix
|
||||
%button.btn.btn-primary.pull-left.js-new-label-btn{type: "button"}
|
||||
Create
|
||||
%button.btn.btn-default.pull-right.js-cancel-label-btn{type: "button"}
|
||||
Cancel
|
||||
= render partial: "shared/issuable/label_page_create"
|
||||
= dropdown_loading
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
.dropdown-page-two.dropdown-new-label
|
||||
= dropdown_title("Create new label", back: true)
|
||||
= dropdown_content do
|
||||
.dropdown-labels-error.js-label-error
|
||||
%input#new_label_name.default-dropdown-input{ type: "text", placeholder: "Name new label" }
|
||||
.suggest-colors.suggest-colors-dropdown
|
||||
- suggested_colors.each do |color|
|
||||
= link_to '#', style: "background-color: #{color}", data: { color: color } do
|
||||
 
|
||||
.dropdown-label-color-input
|
||||
.dropdown-label-color-preview.js-dropdown-label-color-preview
|
||||
%input#new_label_color.default-dropdown-input{ type: "text" }
|
||||
.clearfix
|
||||
%button.btn.btn-primary.pull-left.js-new-label-btn{ type: "button" }
|
||||
Create
|
||||
%button.btn.btn-default.pull-right.js-cancel-label-btn{ type: "button" }
|
||||
Cancel
|
||||
@@ -0,0 +1,20 @@
|
||||
- title = local_assigns.fetch(:title, 'Assign labels')
|
||||
- filter_placeholder = local_assigns.fetch(:filter_placeholder, 'Search labels')
|
||||
.dropdown-page-one
|
||||
= dropdown_title(title)
|
||||
= dropdown_filter(filter_placeholder)
|
||||
= dropdown_content
|
||||
- if @project
|
||||
= dropdown_footer do
|
||||
%ul.dropdown-footer-list
|
||||
- if can? current_user, :admin_label, @project
|
||||
%li
|
||||
%a.dropdown-toggle-page{href: "#"}
|
||||
Create new
|
||||
%li
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project), :"data-is-link" => true do
|
||||
- if can? current_user, :admin_label, @project
|
||||
Manage labels
|
||||
- else
|
||||
View labels
|
||||
= dropdown_loading
|
||||
@@ -20,7 +20,7 @@
|
||||
%a.btn.btn-default.issuable-pager.disabled{href: '#'}
|
||||
Next
|
||||
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
|
||||
.block.assignee
|
||||
.sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.to_reference if issuable.assignee)}
|
||||
- if issuable.assignee
|
||||
@@ -129,24 +129,9 @@
|
||||
Label
|
||||
= icon('chevron-down')
|
||||
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
|
||||
.dropdown-page-one
|
||||
= dropdown_title("Assign labels")
|
||||
= dropdown_filter("Search labels")
|
||||
= dropdown_content
|
||||
- if @project
|
||||
= dropdown_footer do
|
||||
%ul.dropdown-footer-list
|
||||
- if can? current_user, :admin_label, @project
|
||||
%li
|
||||
%a.dropdown-toggle-page{href: "#"}
|
||||
Create new
|
||||
%li
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project) do
|
||||
- if can? current_user, :admin_label, @project
|
||||
Manage labels
|
||||
- else
|
||||
View labels
|
||||
= dropdown_loading
|
||||
= render partial: "shared/issuable/label_page_default"
|
||||
- if can? current_user, :admin_label, @project and @project
|
||||
= render partial: "shared/issuable/label_page_create"
|
||||
|
||||
= render "shared/issuable/participants", participants: issuable.participants(current_user)
|
||||
- if current_user
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
- @sort ||= sort_value_recently_updated
|
||||
- personal = params[:personal]
|
||||
- archived = params[:archived]
|
||||
.dropdown.inline
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
@@ -10,7 +11,7 @@
|
||||
Sort by
|
||||
- projects_sort_options_hash.each do |value, title|
|
||||
%li
|
||||
= link_to filter_projects_path(sort: value, archived: archived), class: ("is-active" if @sort == value) do
|
||||
= link_to filter_projects_path(sort: value, archived: archived, personal: personal), class: ("is-active" if @sort == value) do
|
||||
= title
|
||||
|
||||
%li.divider
|
||||
@@ -20,3 +21,11 @@
|
||||
%li
|
||||
= link_to filter_projects_path(sort: @sort, archived: true), class: ("is-active" if params[:archived].present?) do
|
||||
Show archived projects
|
||||
- if current_user
|
||||
%li.divider
|
||||
%li
|
||||
= link_to filter_projects_path(sort: @sort, personal: nil), class: ("is-active" unless personal) do
|
||||
Owned by anyone
|
||||
%li
|
||||
= link_to filter_projects_path(sort: @sort, personal: true), class: ("is-active" if personal) do
|
||||
Owned by me
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
- css_class = '' unless local_assigns[:css_class]
|
||||
- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && project.commit
|
||||
- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description
|
||||
- ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit
|
||||
- cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.3']
|
||||
- cache_key.push(ci_commit.status) if ci_commit
|
||||
- cache_key.push(project.commit.status) if project.commit.try(:status)
|
||||
|
||||
%li.project-row{ class: css_class }
|
||||
= cache(cache_key) do
|
||||
@@ -16,9 +15,9 @@
|
||||
- if project.main_language
|
||||
%span
|
||||
= project.main_language
|
||||
- if ci_commit
|
||||
- if project.commit.try(:status)
|
||||
%span
|
||||
= render_ci_status(ci_commit)
|
||||
= render_ci_status(project.commit)
|
||||
- if forks
|
||||
%span
|
||||
= icon('code-fork')
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
end
|
||||
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
||||
require_relative '../config/boot'
|
||||
require 'rails/commands'
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
end
|
||||
require_relative '../config/boot'
|
||||
require 'rake'
|
||||
Rake.application.run
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path("../spring", __FILE__)
|
||||
rescue LoadError
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
end
|
||||
require 'bundler/setup'
|
||||
load Gem.bin_path('rspec-core', 'rspec')
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path("../spring", __FILE__)
|
||||
rescue LoadError
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
end
|
||||
require 'bundler/setup'
|
||||
load Gem.bin_path('spinach', 'spinach')
|
||||
|
||||
+6
-6
@@ -4,12 +4,12 @@
|
||||
# It gets overwritten when you run the `spring binstub` command.
|
||||
|
||||
unless defined?(Spring)
|
||||
require "rubygems"
|
||||
require "bundler"
|
||||
require 'rubygems'
|
||||
require 'bundler'
|
||||
|
||||
if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
|
||||
Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
|
||||
gem "spring", match[1]
|
||||
require "spring/binstub"
|
||||
if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
|
||||
Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
|
||||
gem 'spring', match[1]
|
||||
require 'spring/binstub'
|
||||
end
|
||||
end
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
end
|
||||
require 'bundler/setup'
|
||||
load Gem.bin_path('teaspoon', 'teaspoon')
|
||||
@@ -107,6 +107,10 @@ if Gitlab::Metrics.enabled?
|
||||
config.instrument_methods(const)
|
||||
config.instrument_instance_methods(const)
|
||||
end
|
||||
|
||||
# Instrument the classes used for checking if somebody has push access.
|
||||
config.instrument_instance_methods(Gitlab::GitAccess)
|
||||
config.instrument_instance_methods(Gitlab::GitAccessWiki)
|
||||
end
|
||||
|
||||
GC::Profiler.enable
|
||||
|
||||
@@ -418,6 +418,7 @@ Rails.application.routes.draw do
|
||||
|
||||
devise_scope :user do
|
||||
get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error
|
||||
get '/users/almost_there' => 'confirmations#almost_there'
|
||||
end
|
||||
|
||||
root to: "root#index"
|
||||
|
||||
@@ -19,7 +19,7 @@ class Gitlab::Seeder::Builds
|
||||
commits = @project.repository.commits('master', nil, 5)
|
||||
commits_sha = commits.map { |commit| commit.raw.id }
|
||||
commits_sha.map do |sha|
|
||||
@project.ensure_ci_commit(sha)
|
||||
@project.ensure_ci_commit(sha, 'master')
|
||||
end
|
||||
rescue
|
||||
[]
|
||||
|
||||
@@ -4,6 +4,8 @@ class AddTrigramIndexesForSearching < ActiveRecord::Migration
|
||||
def up
|
||||
return unless Gitlab::Database.postgresql?
|
||||
|
||||
create_trigrams_extension
|
||||
|
||||
unless trigrams_enabled?
|
||||
raise 'You must enable the pg_trgm extension. You can do so by running ' \
|
||||
'"CREATE EXTENSION pg_trgm;" as a PostgreSQL super user, this must be ' \
|
||||
@@ -37,6 +39,15 @@ class AddTrigramIndexesForSearching < ActiveRecord::Migration
|
||||
row && row['enabled'] == 't' ? true : false
|
||||
end
|
||||
|
||||
def create_trigrams_extension
|
||||
# This may not work if the user doesn't have permission. We attempt in
|
||||
# case we do have permission, particularly for test/dev environments.
|
||||
begin
|
||||
enable_extension 'pg_trgm'
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
def to_index
|
||||
{
|
||||
ci_runners: [:token, :description],
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class AddFieldsToCiCommit < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :ci_commits, :status, :string
|
||||
add_column :ci_commits, :started_at, :timestamp
|
||||
add_column :ci_commits, :finished_at, :timestamp
|
||||
add_column :ci_commits, :duration, :integer
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
class UpdateCiCommit < ActiveRecord::Migration
|
||||
# This migration can be run online, but needs to be executed for the second time after restarting Unicorn workers
|
||||
# Otherwise Offline migration should be used.
|
||||
def change
|
||||
execute("UPDATE ci_commits SET status=#{status}, ref=#{ref}, tag=#{tag} WHERE status IS NULL")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def status
|
||||
builds = '(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id)'
|
||||
success = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='success')"
|
||||
ignored = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND (status='failed' OR status='canceled') AND allow_failure)"
|
||||
pending = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='pending')"
|
||||
running = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='running')"
|
||||
canceled = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='canceled')"
|
||||
|
||||
"(CASE
|
||||
WHEN #{builds}=0 THEN 'skipped'
|
||||
WHEN #{builds}=#{success}+#{ignored} THEN 'success'
|
||||
WHEN #{builds}=#{pending} THEN 'pending'
|
||||
WHEN #{builds}=#{canceled} THEN 'canceled'
|
||||
WHEN #{running}+#{pending}>0 THEN 'running'
|
||||
ELSE 'failed'
|
||||
END)"
|
||||
end
|
||||
|
||||
def ref
|
||||
'(SELECT ref FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)'
|
||||
end
|
||||
|
||||
def tag
|
||||
'(SELECT tag FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)'
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
class AddCiCommitIndexes < ActiveRecord::Migration
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :ci_commits, [:gl_project_id, :sha], index_options
|
||||
add_index :ci_commits, [:gl_project_id, :status], index_options
|
||||
add_index :ci_commits, [:status], index_options
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def index_options
|
||||
if Gitlab::Database.postgresql?
|
||||
{ algorithm: :concurrently }
|
||||
else
|
||||
{ }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
class DisableRepositoryChecks < ActiveRecord::Migration
|
||||
def up
|
||||
change_column_default :application_settings, :repository_checks_enabled, false
|
||||
execute 'UPDATE application_settings SET repository_checks_enabled = false'
|
||||
end
|
||||
|
||||
def down
|
||||
change_column_default :application_settings, :repository_checks_enabled, true
|
||||
execute 'UPDATE application_settings SET repository_checks_enabled = true'
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user