Commit 31a87ef8 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'ce_upstream' into 'master'

CE upstream

@timothyandrew Please resolve:

```
spec/lib/gitlab/git_access_spec.rb
lib/gitlab/checks/change_access.rb
lib/gitlab/git_access.rb
lib/gitlab/git_access_wiki.rb
```

See merge request !568
parents 150250fc 704825ba
Please view this file on the master branch, on stable branches it's out of date.
v 8.10.0 (unreleased)
- Fix profile activity heatmap to show correct day name (eanplatter)
- Expose {should,force}_remove_source_branch (Ben Boeckel)
- Disable PostgreSQL statement timeout during migrations
- Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho)
......@@ -16,6 +17,7 @@ v 8.10.0 (unreleased)
- Align flash messages with left side of page content !4959 (winniehell)
- Display tooltip for "Copy to Clipboard" button !5164 (winniehell)
- Use default cursor for table header of project files !5165 (winniehell)
- Store when and yaml variables in builds table
- Display last commit of deleted branch in push events !4699 (winniehell)
- Escape file extension when parsing search results !5141 (winniehell)
- Apply the trusted_proxies config to the rack request object for use with rack_attack
......@@ -23,13 +25,18 @@ v 8.10.0 (unreleased)
- Add Sidekiq queue duration to transaction metrics.
- Add a new column `artifacts_size` to table `ci_builds` !4964
- Let Workhorse serve format-patch diffs
- Display tooltip for mentioned users and groups !5261 (winniehell)
- Allow build email service to be tested
- Added day name to contribution calendar tooltips
- Make images fit to the size of the viewport !4810
- Fixed misplaced mirror repository button on tags page
- Fix check for New Branch button on Issue page !4630 (winniehell)
- Fix MR-auto-close text added to description. !4836
- Support U2F devices in Firefox. !5177
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
- Add Spring EmojiOne updates.
- Fix fetching LFS objects for private CI projects
- Add the new 2016 Emoji! Adds 72 new emoji including bacon, facepalm, and selfie. !5237
- Add syntax for multiline blockquote using `>>>` fence !3954
- Fix viewing notification settings when a project is pending deletion
- Updated compare dropdown menus to use GL dropdown
......@@ -46,6 +53,7 @@ v 8.10.0 (unreleased)
- Render inline diffs for multiple changed lines following eachother
- Wildcards for protected branches. !4665
- Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Expose `due_date` for issues (Robert Schilling)
- API: Todos !3188 (Robert Schilling)
- API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
- Add "Enabled Git access protocols" to Application Settings
......@@ -55,12 +63,17 @@ v 8.10.0 (unreleased)
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- Only show New Snippet button to users that can create snippets.
- PipelinesFinder uses git cache data
- Track a user who created a pipeline
- Actually render old and new sections of parallel diff next to each other
- Throttle the update of `project.pushes_since_gc` to 1 minute.
- Allow expanding and collapsing files in diff view (!4990)
- Collapse large diffs by default (!4990)
- Fix mentioned users list on diff notes
- Fix creation of deployment on build that is retried, redeployed or rollback
- Don't parse Rinku returned value to DocFragment when it didn't change the original html string.
- Check for conflicts with existing Project's wiki path when creating a new project.
- Show last push widget in upstream after push to fork
- Fix stage status shown for pipelines
- Cache todos pending/done dashboard query counts.
- Don't instantiate a git tree on Projects show default view
- Bump Rinku to 2.0.0
......@@ -81,8 +94,11 @@ v 8.10.0 (unreleased)
- Add basic system information like memory and disk usage to the admin panel
- Don't garbage collect commits that have related DB records like comments
- More descriptive message for git hooks and file locks
- Aliases of award emoji should be stored as original name. !5060 (dixpac)
- Handle custom Git hook result in GitLab UI
- Allow to access Container Registry for Public and Internal projects
- Allow '?', or '&' for label names
- Support redirected blobs for Container Registry integration
- Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests
- Add date when user joined the team on the member page
- Fix 404 redirect after validation fails importing a GitLab project
......@@ -90,6 +106,7 @@ v 8.10.0 (unreleased)
- Add min value for project limit field on user's form !3622 (jastkand)
- Reset project pushes_since_gc when we enqueue the git gc call
- Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt)
- Collapsed diffs lines/size don't acumulate to overflow diffs.
- Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel)
- Style of import project buttons were fixed in the new project page. !5183 (rdemirbay)
- Fix GitHub client requests when rate limit is disabled
......@@ -97,7 +114,16 @@ v 8.10.0 (unreleased)
- Redesign Builds and Pipelines pages
- Change status color and icon for running builds
- Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.`
- Project export filename now includes the project and namespace path
- Fix last update timestamp on issues not preserved on gitlab.com and project imports
- Fix issues importing projects from EE to CE
- Fix creating group with space in group path
- Improve cron_jobs loading error messages !5318
- Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska)
- Limit the number of retries on error to 3 for exporting projects
- Allow empty repositories on project import/export
- Render only commit message title in builds (Katarzyna Kobierska Ula Budziszewska)
- Allow bulk (un)subscription from issues in issue index
v 8.9.6
- Fix importing of events under notes for GitLab projects. !5154
......@@ -106,6 +132,7 @@ v 8.9.6
- Fix broken migration in MySQL. !5005
- Overwrite Host and X-Forwarded-Host headers in NGINX !5213
- Keeps issue number when importing from Gitlab.com
- Add Pending tab for Builds (Katarzyna Kobierska, Urszula Budziszewska)
v 8.9.7 (unreleased)
- Fix import_data wrongly saved as a result of an invalid import_url
......
......@@ -56,7 +56,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.2'
gem 'gitlab_git', '~> 10.3.2'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -66,7 +66,7 @@ gem 'net-ldap'
# Git Wiki
# Required manually in config/initializers/gollum.rb to control load order
gem 'gollum-lib', '~> 4.1.0', require: false
gem 'gollum-lib', '~> 4.2', require: false
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
# Language detection
......@@ -115,7 +115,7 @@ gem 'gitlab-elasticsearch-git', '~> 0.0.15', require: "elasticsearch/git"
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
gem 'github-markup', '~> 1.3.1'
gem 'github-markup', '~> 1.4'
gem 'redcarpet', '~> 3.3.3'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~>3.6'
......@@ -123,7 +123,7 @@ gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.11'
gem 'rouge', '~> 2.0'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
......@@ -233,7 +233,7 @@ gem 'jquery-turbolinks', '~> 2.1.0'
gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.6.1'
gem 'gemojione', '~> 2.6'
gem 'gemojione', '~> 3.0'
gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0'
......@@ -360,3 +360,6 @@ gem 'health_check', '~> 2.1.0'
# System information
gem 'vmstat', '~> 2.1.0'
gem 'sys-filesystem', '~> 1.1.6'
# Secure headers for Content Security Policy
gem 'secure_headers', '~> 3.3'
......@@ -267,8 +267,8 @@ GEM
rspec (~> 3.0)
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.24.0b13)
gemojione (2.6.1)
rugged (~> 0.21)
gemojione (3.0.1)
json
get_process_mem (0.2.0)
gherkin-ruby (0.3.2)
......@@ -276,8 +276,8 @@ GEM
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
rugged (>= 0.24.0b13)
github-markup (1.3.3)
rugged (>= 0.23.0b)
github-markup (1.4.0)
gitlab-elasticsearch-git (0.0.15)
activemodel (~> 4.2)
activesupport (~> 4.2)
......@@ -296,7 +296,7 @@ GEM
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
gitlab-license (1.0.0)
gitlab_git (10.2.3)
gitlab_git (10.3.2)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -309,13 +309,13 @@ GEM
rubyntlm (~> 0.3)
globalid (0.3.6)
activesupport (>= 4.1.0)
gollum-grit_adapter (1.0.0)
gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1)
gollum-lib (4.1.0)
github-markup (~> 1.3.3)
gollum-lib (4.2.1)
github-markup (~> 1.4.0)
gollum-grit_adapter (~> 1.0)
nokogiri (~> 1.6.4)
rouge (~> 1.9)
rouge (~> 2.0)
sanitize (~> 2.1.0)
stringex (~> 2.5.1)
gollum-rugged_adapter (0.4.2)
......@@ -602,7 +602,7 @@ GEM
railties (>= 4.2.0, < 5.1)
rinku (2.0.0)
rotp (2.1.2)
rouge (1.11.0)
rouge (2.0.3)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
......@@ -669,6 +669,8 @@ GEM
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
secure_headers (3.3.2)
useragent
seed-fu (2.3.6)
activerecord (>= 3.1)
activesupport (>= 3.1)
......@@ -791,6 +793,7 @@ GEM
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uniform_notifier (1.9.0)
useragent (0.16.7)
uuid (2.3.8)
macaddr (~> 1.0)
validates_hostname (1.0.5)
......@@ -886,16 +889,16 @@ DEPENDENCIES
foreman (~> 0.78.0)
fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 2.6)
gemojione (~> 3.0)
github-linguist (~> 4.7.0)
github-markup (~> 1.3.1)
github-markup (~> 1.4)
gitlab-elasticsearch-git (~> 0.0.15)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0)
gitlab_git (~> 10.2)
gitlab_git (~> 10.3.2)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.0.1)
grape (~> 0.13.0)
......@@ -966,7 +969,7 @@ DEPENDENCIES
request_store (~> 1.3.0)
rerun (~> 0.11.0)
responders (~> 2.0)
rouge (~> 1.11)
rouge (~> 2.0)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5)
......@@ -977,6 +980,7 @@ DEPENDENCIES
sass-rails (~> 5.0.0)
scss_lint (~> 0.47.0)
sdoc (~> 0.3.20)
secure_headers (~> 3.3)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven (~> 1.1.0)
......
app/assets/images/emoji.png

1000 KB | W: | H:

app/assets/images/emoji.png

1.04 MB | W: | H:

app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/emoji@2x.png

2.38 MB | W: | H:

app/assets/images/emoji@2x.png

2.53 MB | W: | H:

app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -54,7 +54,6 @@
#= require_directory ./u2f
#= require_directory .
#= require fuzzaldrin-plus
#= require u2f
window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
......
......@@ -39,8 +39,6 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
new GLForm($('.issue-form'))
new IssuableForm($('.issue-form'))
new LabelsSelect()
new MilestoneSelect()
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
new Diff()
shortcut_handler = new ShortcutsNavigation()
......
......@@ -250,6 +250,8 @@ class GitLabDropdown
if self.options.clicked
self.options.clicked(selected, $el, e)
$el.trigger('blur')
# Finds an element inside wrapper element
getElement: (selector) ->
@dropdown.find selector
......
......@@ -85,12 +85,13 @@ class @IssuableBulkActions
getFormDataAsObject: ->
formData =
update:
state_event : @form.find('input[name="update[state_event]"]').val()
assignee_id : @form.find('input[name="update[assignee_id]"]').val()
milestone_id : @form.find('input[name="update[milestone_id]"]').val()
issues_ids : @form.find('input[name="update[issues_ids]"]').val()
add_label_ids : []
remove_label_ids : []
state_event : @form.find('input[name="update[state_event]"]').val()
assignee_id : @form.find('input[name="update[assignee_id]"]').val()
milestone_id : @form.find('input[name="update[milestone_id]"]').val()
issues_ids : @form.find('input[name="update[issues_ids]"]').val()
subscription_event : @form.find('input[name="update[subscription_event]"]').val()
add_label_ids : []
remove_label_ids : []
if @willUpdateLabels
@getLabelsToApply().map (id) ->
......
......@@ -184,22 +184,20 @@ class @LabelsSelect
.value()
if $dropdown.hasClass 'js-extra-options'
extraData = []
if showAny
extraData.push(
isAny: true
title: 'Any Label'
)
if showNo
extraData.push(
data.unshift(
id: 0
title: 'No Label'
)
if extraData.length
extraData.push 'divider'
data = extraData.concat(data)
if showAny
data.unshift(
isAny: true
title: 'Any Label'
)
if data.length > 2
data.splice 2, 0, 'divider'
callback data
......@@ -289,12 +287,6 @@ class @LabelsSelect
defaultLabel
fieldName: $dropdown.data('field-name')
id: (label) ->
if $dropdown.hasClass('js-issuable-form-dropdown')
if label.id is 0
return
else
return label.id
if $dropdown.hasClass("js-filter-submit") and not label.isAny?
label.title
else
......@@ -308,9 +300,6 @@ class @LabelsSelect
$selectbox.hide()
# display:block overrides the hide-collapse rule
$value.removeAttr('style')
return if $dropdown.hasClass('js-issuable-form-dropdown')
if $dropdown.hasClass 'js-multiselect'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
selectedLabels = $dropdown
......@@ -332,7 +321,7 @@ class @LabelsSelect
clicked: (label) ->
_this.enableBulkLabelDropdown()
if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
if $dropdown.hasClass('js-filter-bulk-update')
return
page = $('body').data 'page'
......
......@@ -2,7 +2,7 @@
w.gl ?= {}
w.gl.utils ?= {}
w.gl.utils.days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
w.gl.utils.formatDate = (datetime) ->
dateFormat(datetime, 'mmm d, yyyy h:MMtt Z')
......
......@@ -62,7 +62,7 @@ class @MilestoneSelect
title: 'Upcoming'
)
if extraOptions.length > 0
if extraOptions.length > 2
extraOptions.push 'divider'
callback(extraOptions.concat(data))
......
class @SubscriptionSelect
constructor: ->
$('.js-subscription-event').each (i, el) ->
fieldName = $(el).data("field-name")
$(el).glDropdown(
selectable: true
fieldName: fieldName
toggleLabel: (selected, el, instance) =>
label = 'Subscription'
$item = instance.dropdown.find('.is-active')
label = $item.text() if $item.length
label
clicked: (item, $el, e)->
e.preventDefault()
id: (obj, el) ->
$(el).data("id")
)
......@@ -6,8 +6,20 @@
class @U2FAuthenticate
constructor: (@container, u2fParams) ->
@appId = u2fParams.app_id
@challenges = u2fParams.challenges
@signRequests = u2fParams.sign_requests
@challenge = u2fParams.challenge
# The U2F Javascript API v1.1 requires a single challenge, with
# _no challenges per-request_. The U2F Javascript API v1.0 requires a
# challenge per-request, which is done by copying the single challenge
# into every request.
#
# In either case, we don't need the per-request challenges that the server
# has generated, so we can remove them.
#
# Note: The server library fixes this behaviour in (unreleased) version 1.0.0.
# This can be removed once we upgrade.
# https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4
@signRequests = u2fParams.sign_requests.map (request) -> _(request).omit('challenge')
start: () =>
if U2FUtil.isU2FSupported()
......@@ -16,7 +28,7 @@ class @U2FAuthenticate
@renderNotSupported()
authenticate: () =>
u2f.sign(@appId, @challenges, @signRequests, (response) =>
u2f.sign(@appId, @challenge, @signRequests, (response) =>
if response.errorCode
error = new U2FError(response.errorCode)
@renderError(error);
......
class @U2FUtil
@isU2FSupported: ->
window.u2f
# Helper class for U2F (universal 2nd factor) device registration and authentication.
class @U2FUtil
@isU2FSupported: ->
if @testMode
true
else
gon.u2f.browser_supports_u2f
@enableTestMode: ->
@testMode = true
<% if Rails.env.test? %>
U2FUtil.enableTestMode();
<% end %>
......@@ -155,13 +155,11 @@ class @UsersSelect
# display:block overrides the hide-collapse rule
$value.css('display', '')
clicked: (user, $el, e) ->
clicked: (user) ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
e.preventDefault()
selectedId = user.id
if $dropdown.hasClass('js-filter-bulk-update')
return
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
......@@ -174,8 +172,7 @@ class @UsersSelect
.closest('.selectbox')
.find("input[name='#{$dropdown.data('field-name')}']").val()
assignTo(selected)
id: (user) ->
user.id
renderRow: (user) ->
username = if user.username then "@#{user.username}" else ""
avatar = if user.avatar_url then user.avatar_url else false
......
......@@ -56,7 +56,7 @@
position: absolute;
top: 50%;
right: 6px;
margin-top: -6px;
margin-top: -4px;
color: $dropdown-toggle-icon-color;
font-size: 10px;
}
......
......@@ -70,7 +70,7 @@
}
&.wiki {
padding: $gl-padding;
padding: 30px $gl-padding;
.highlight {
margin-bottom: 9px;
......
......@@ -37,39 +37,41 @@
}
h1 {
font-size: 1.3em;
font-size: 2em;
font-weight: 600;
margin: 24px 0 12px;
padding: 0 0 10px;
border-bottom: 1px solid #e7e9ed;
margin: 1em 0 10px;
padding: 0 0 0.3em;
border-bottom: 1px solid $btn-default-border;
color: $gl-gray-dark;
}
h2 {
font-size: 1.2em;
font-size: 1.6em;
font-weight: 600;
margin: 24px 0 12px;
margin: 1em 0 10px;
padding-bottom: 0.3em;
border-bottom: 1px solid $btn-default-border;
color: $gl-gray-dark;
}
h3 {
margin: 24px 0 12px;
font-size: 1.1em;
margin: 1em 0 10px;
font-size: 1.4em;
}
h4 {
margin: 24px 0 12px;
font-size: 0.98em;
margin: 1em 0 10px;
font-size: 1.25em;
}
h5 {
margin: 24px 0 12px;
font-size: 0.95em;
margin: 1em 0 10px;
font-size: 1em;
}
h6 {
margin: 24px 0 12px;
font-size: 0.90em;
margin: 1em 0 10px;
font-size: 0.95em;
}
blockquote {
......@@ -115,7 +117,7 @@
ul, ol {
padding: 0;
margin: 6px 0 6px 28px !important;
margin: 3px 0 3px 28px !important;
}
li {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -270,7 +270,7 @@
.item-title {
@media (min-width: $screen-sm-min) {
width: 49%;
width: 45%;
}
}
......@@ -324,10 +324,6 @@
.issuable-form-select-holder {
display: inline-block;
width: 250px;
.dropdown-menu-toggle {
width: 100%;
}
}
.table-holder {
......
......@@ -129,6 +129,8 @@
}
.cancel-retry-btns {
vertical-align: middle;
.btn:not(:first-child) {
margin-left: 8px;
}
......
......@@ -5,8 +5,10 @@ class Admin::BuildsController < Admin::ApplicationController
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'pending'
@builds.pending.reverse_order
when 'running'
@builds.running_or_pending.reverse_order
@builds.running.reverse_order
when 'finished'
@builds.finished
else
......
......@@ -354,10 +354,6 @@ class ApplicationController < ActionController::Base
session[:skip_tfa] && session[:skip_tfa] > Time.current
end
def browser_supports_u2f?
browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
end
def redirect_to_home_page_url?
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
......
......@@ -57,7 +57,7 @@ module AuthenticatesWithTwoFactor
# Authenticate using the response from a U2F (universal 2nd factor) device
def authenticate_with_two_factor_via_u2f(user)
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenges])
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
# Remove any lingering user data from login
session.delete(:otp_user_id)
session.delete(:challenges)
......@@ -77,11 +77,9 @@ module AuthenticatesWithTwoFactor
if key_handles.present?
sign_requests = u2f.authentication_requests(key_handles)
challenges = sign_requests.map(&:challenge)
session[:challenges] = challenges
gon.push(u2f: { challenges: challenges, app_id: u2f_app_id,
sign_requests: sign_requests,
browser_supports_u2f: browser_supports_u2f? })
session[:challenge] ||= u2f.challenge
gon.push(u2f: { challenge: session[:challenge], app_id: u2f_app_id,
sign_requests: sign_requests })
end
end
end
......@@ -10,7 +10,6 @@ module DiffForPath
diff_commit = commit_for_diff(diff_file)
blob = diff_file.blob(diff_commit)
@expand_all_diffs = true
locals = {
diff_file: diff_file,
......
......@@ -100,7 +100,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id,
register_requests: registration_requests,
sign_requests: sign_requests,
browser_supports_u2f: browser_supports_u2f? })
sign_requests: sign_requests })
end
end
......@@ -10,8 +10,10 @@ class Projects::BuildsController < Projects::ApplicationController
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'pending'
@builds.pending.reverse_order
when 'running'
@builds.running_or_pending.reverse_order
@builds.running.reverse_order
when 'finished'
@builds.finished
else
......
......@@ -232,6 +232,7 @@ class Projects::IssuesController < Projects::ApplicationController
:assignee_id,
:milestone_id,
:state_event,
:subscription_event,
label_ids: [],
add_label_ids: [],
remove_label_ids: []
......
......@@ -46,8 +46,9 @@ class Projects::ServicesController < Projects::ApplicationController
end
def test
data = Gitlab::PushDataBuilder.build_sample(project, current_user)
data = @service.test_data(project, current_user)
outcome = @service.test(data)
if outcome[:success]
message = { notice: 'We sent a request to the provided URL' }
else
......
......@@ -5,7 +5,7 @@ class ProjectsController < Projects::ApplicationController
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
before_action :assign_ref_vars, only: [:show], if: :repo_exists?
before_action :tree, only: [:show], if: :project_view_files?
before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
# Authorize
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
......
module BlobHelper
def highlighter(blob_name, blob_content, repository: nil, nowrap: false)
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap, repository: repository)
end
def highlight(blob_name, blob_content, repository: nil, nowrap: false, plain: false)
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain, repository: repository)
def highlight(blob_name, blob_content, repository: nil, plain: false)
highlighted = Gitlab::Highlight.highlight(blob_name, blob_content, plain: plain, repository: repository)
raw %(<pre class="code highlight"><code>#{highlighted}</code></pre>)
end
def no_highlight_files
......
......@@ -9,7 +9,7 @@ module DiffHelper
end
def expand_all_diffs?
@expand_all_diffs || params[:expand_all_diffs].present?
params[:expand_all_diffs].present?
end
def diff_view
......@@ -23,13 +23,14 @@ module DiffHelper
end
def diff_options
default_options = Commit.max_diff_options
options = { ignore_whitespace_change: hide_whitespace?, no_collapse: expand_all_diffs? }
if action_name == 'diff_for_path'
default_options[:paths] = params.values_at(:old_path, :new_path)
options[:no_collapse] = true
options[:paths] = params.values_at(:old_path, :new_path)
end
default_options.merge(ignore_whitespace_change: hide_whitespace?)
Commit.max_diff_options.merge(options)
end
def safe_diff_files(diffs, diff_refs: nil, repository: nil)
......
......@@ -9,7 +9,7 @@ module IssuablesHelper
def multi_label_name(current_labels, default_label)
# current_labels may be a string from before
if current_labels.is_a?(Array) && current_labels.any?
if current_labels.is_a?(Array)
if current_labels.count > 1
"#{current_labels[0]} +#{current_labels.count - 1} more"
else
......
module U2fHelper
def inject_u2f_api?
browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
end
end
......@@ -6,6 +6,7 @@ module Emails
add_project_headers
add_build_headers('failed')
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
end
......
......@@ -218,7 +218,8 @@ class Ability
:download_code,
:fork_project,
:read_commit_status,
:read_pipeline
:read_pipeline,
:read_container_image
]
end
......
......@@ -5,6 +5,7 @@ module Ci
belongs_to :erased_by, class_name: 'User'
serialize :options
serialize :yaml_variables
validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref
......@@ -52,7 +53,10 @@ module Ci
new_build.stage = build.stage
new_build.stage_idx = build.stage_idx
new_build.trigger_request = build.trigger_request
new_build.yaml_variables = build.yaml_variables
new_build.when = build.when
new_build.user = user
new_build.environment = build.environment
new_build.save
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
new_build
......@@ -117,7 +121,12 @@ module Ci
end
def variables
predefined_variables + yaml_variables + project_variables + trigger_variables
variables = []
variables += predefined_variables
variables += yaml_variables if yaml_variables
variables += project_variables
variables += trigger_variables
variables
end
def merge_request
......@@ -395,30 +404,6 @@ module Ci
self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil)
end
def yaml_variables
global_yaml_variables + job_yaml_variables
end
def global_yaml_variables
if pipeline.config_processor
pipeline.config_processor.global_variables.map do |key, value|
{ key: key, value: value, public: true }
end
else
[]
end
end
def job_yaml_variables
if pipeline.config_processor
pipeline.config_processor.job_variables(name).map do |key, value|
{ key: key, value: value, public: true }
end
else
[]
end
end
def project_variables
project.variables.map do |variable|
{ key: variable.key, value: variable.value, public: false }
......
......@@ -6,6 +6,8 @@ module Ci
self.table_name = 'ci_commits'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :user
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id
......@@ -49,6 +51,10 @@ module Ci
commit.try(:message)
end
def git_commit_title
commit.try(:title)
end
def short_sha
Ci::Pipeline.truncate_sha(sha)
end
......@@ -215,6 +221,8 @@ module Ci
end
def keep_around_commits
return unless project
project.repository.keep_around(self.sha)
project.repository.keep_around(self.before_sha)
end
......
......@@ -65,8 +65,7 @@ module Awardable
def create_award_emoji(name, current_user)
return unless emoji_awardable?
award_emoji.create(name: name, user: current_user)
award_emoji.create(name: normalize_name(name), user: current_user)
end
def remove_award_emoji(name, current_user)
......@@ -80,4 +79,10 @@ module Awardable
create_award_emoji(emoji_name, current_user)
end
end
private
def normalize_name(name)
Gitlab::AwardEmoji.normalize_emoji_name(name)
end
end
......@@ -14,14 +14,14 @@ module Mentionable
attr = attr.to_s
mentionable_attrs << [attr, options]
end
end
included do
# Accessor for attributes marked mentionable.
def mentionable_attrs
@mentionable_attrs ||= []
cattr_accessor :mentionable_attrs, instance_accessor: false do
[]
end
end
included do
if self < Participable
participant -> (user, ext) { all_references(user, extractor: ext) }
end
......
......@@ -41,9 +41,12 @@ module Participable
def participant(attr)
participant_attrs << attr
end
end
def participant_attrs
@participant_attrs ||= []
included do
# Accessor for participant attributes.
cattr_accessor :participant_attrs, instance_accessor: false do
[]
end
end
......
......@@ -38,7 +38,7 @@ class LegacyDiffNote < Note
end
def diff_line
@diff_line ||= diff_file.line_for_line_code(self.line_code)
@diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file
end
def for_line?(line)
......@@ -55,7 +55,7 @@ class LegacyDiffNote < Note
def active?
return @active if defined?(@active)
return true if for_commit?
return true unless self.diff
return true unless diff_line
return false unless noteable
noteable_diff = find_noteable_diff
......
......@@ -235,8 +235,7 @@ class Note < ActiveRecord::Base
end
def award_emoji_name
original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
Gitlab::AwardEmoji.normalize_emoji_name(original_name)
note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
end
private
......
......@@ -169,10 +169,7 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
validates :import_url, addressable_url: true, if: :external_import?
validates :import_url, presence: true, if: :mirror?
validate :import_url_availability, if: :import_url_changed?
validates :mirror_user, presence: true, if: :mirror?
validates :import_url, addressable_url: true, if: :import_url
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
validate :avatar_type,
......@@ -516,7 +513,7 @@ class Project < ActiveRecord::Base
end
def create_or_update_import_data(data: nil, credentials: nil)
return unless valid_import_url?
return unless import_url.present? && valid_import_url?
project_import_data = import_data || build_import_data
if data
......@@ -1175,8 +1172,8 @@ class Project < ActiveRecord::Base
pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end
def ensure_pipeline(sha, ref)
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref)
def ensure_pipeline(sha, ref, current_user = nil)
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref, user: current_user)
end
def enable_ci
......
......@@ -42,6 +42,19 @@ class BuildsEmailService < Service
end
end
def can_test?
project.builds.count > 0
end
def disabled_title
"Please setup a build on your repository."
end
def test_data(project = nil, user = nil)
build = project.builds.last
Gitlab::BuildDataBuilder.build(build)
end
def fields
[
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' },
......@@ -50,6 +63,20 @@ class BuildsEmailService < Service
]
end
def test(data)
begin
# bypass build status verification when testing
data[:build_status] = "failed"
data[:build_allow_failure] = false
result = execute(data)
rescue StandardError => error
return { success: false, result: error }
end
{ success: true, result: result }
end
def should_build_be_notified?(data)
case data[:build_status]
when 'success'
......
......@@ -76,6 +76,10 @@ class Service < ActiveRecord::Base
[]
end
def test_data(project, user)
Gitlab::PushDataBuilder.build_sample(project, user)
end
def supported_events
%w(push tag_push issue merge_request wiki_page)
end
......@@ -94,6 +98,11 @@ class Service < ActiveRecord::Base
!project.empty_repo?
end
# reason why service cannot be tested
def disabled_title
"Please setup a project repository."
end
# Provide convenient accessor methods
# for each serialized property.
# Also keep track of updated properties in a similar way as ActiveModel::Dirty
......
......@@ -87,6 +87,7 @@ class User < ActiveRecord::Base
has_one :abuse_report, dependent: :destroy
has_many :spam_logs, dependent: :destroy
has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline'
has_many :todos, dependent: :destroy
has_many :notification_settings, dependent: :destroy
has_many :award_emoji, dependent: :destroy
......
......@@ -36,7 +36,9 @@ module Ci
:allow_failure,
:stage,
:stage_idx,
:environment)
:environment,
:when,
:yaml_variables)
build_attrs.merge!(pipeline: @pipeline,
ref: @pipeline.ref,
......
......@@ -2,6 +2,7 @@ module Ci
class CreatePipelineService < BaseService
def execute
pipeline = project.pipelines.new(params)
pipeline.user = current_user
unless ref_names.include?(params[:ref])
pipeline.errors.add(:base, 'Reference not found')
......
......@@ -17,7 +17,13 @@ class CreateCommitBuildsService
return false
end
@pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
@pipeline = Ci::Pipeline.new(
project: project,
sha: sha,
ref: ref,
before_sha: before_sha,
tag: tag,
user: user)
##
# Skip creating pipeline if no gitlab-ci.yml is found
......
......@@ -101,6 +101,7 @@ class IssuableBaseService < BaseService
def update(issuable)
change_state(issuable)
change_subscription(issuable)
filter_params
old_labels = issuable.labels.to_a
......@@ -124,6 +125,15 @@ class IssuableBaseService < BaseService
end
end
def change_subscription(issuable)
case params.delete(:subscription_event)
when 'subscribe'
issuable.subscribe(current_user)
when 'unsubscribe'
issuable.unsubscribe(current_user)
end
end
def has_changes?(issuable, old_labels: [])
valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch]
......
......@@ -4,7 +4,7 @@ module Issues
issues_ids = params.delete(:issues_ids).split(",")
issue_params = params
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids).each do |key|
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids subscription_event).each do |key|
issue_params.delete(key) unless issue_params[key].present?
end
......
......@@ -8,7 +8,6 @@ module Notes
if note.award_emoji?
noteable = note.noteable
todo_service.new_award_emoji(noteable, current_user)
return noteable.create_award_emoji(note.award_emoji_name, current_user)
end
......
......@@ -10,7 +10,7 @@ module Projects
def save_all
if [version_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver].all?(&:save)
Gitlab::ImportExport::Saver.save(shared: @shared)
Gitlab::ImportExport::Saver.save(project: project, shared: @shared)
notify_success
else
cleanup_and_notify
......
......@@ -207,7 +207,7 @@ class TodoService
end
def create_assignment_todo(issuable, author)
if issuable.assignee && issuable.assignee != author
if issuable.assignee
attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED)
create_todos(issuable.assignee, attributes)
end
......@@ -257,7 +257,6 @@ class TodoService
def filter_mentioned_users(project, target, author)
mentioned_users = target.mentioned_users(author)
mentioned_users = reject_users_without_access(mentioned_users, project, target)
mentioned_users.delete(author)
mentioned_users.uniq
end
......
......@@ -10,15 +10,20 @@
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
%li{class: ('active' if @scope == 'pending')}
= link_to admin_builds_path(scope: :pending) do
Pending
%span.badge= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to admin_builds_path(scope: :running) do
Running
%span.badge.js-running-count= number_with_delimiter(@all_builds.running_or_pending.count(:id))
%span.badge= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to admin_builds_path(scope: :finished) do
Finished
%span.badge.js-running-count= number_with_delimiter(@all_builds.finished.count(:id))
%span.badge= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls
- if @all_builds.running_or_pending.any?
......
- if inject_u2f_api?
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('u2f.js')
%div
.login-box
.login-heading
......
.emoji-menu
= text_field_tag :emoji_search, "", class: "emoji-search search-input form-control", placeholder: "Seach emojis"
= text_field_tag :emoji_search, "", class: "emoji-search search-input form-control", placeholder: "Search emoji"
.emoji-menu-content
- Gitlab::AwardEmoji.emoji_by_category.each do |category, emojis|
%h5.emoji-menu-title
......
......@@ -44,7 +44,7 @@
name: "#{j(@project.name)}"
};
- if @group and @group.path
- if @group && @group.persisted? && @group.path
:javascript
gl.groupOptions = gl.groupOptions || {};
gl.groupOptions["#{j(@group.path)}"] = {
......
- if @note.diff_note?
- if @note.diff_note? && @note.diff_file
%p.details
New comment on diff for
= link_to @note.diff_file.file_path, @target_url
......
......@@ -2,6 +2,10 @@
- header_title "Two-Factor Authentication", profile_two_factor_auth_path
= render 'profiles/head'
- if inject_u2f_api?
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('u2f.js')
.row.prepend-top-default
.col-lg-3
%h4.prepend-top-0
......
......@@ -94,9 +94,9 @@
.block
.title
Commit message
Commit title
%p.build-light-text.append-bottom-0
#{@build.pipeline.git_commit_message}
#{@build.pipeline.git_commit_title}
- if @build.tags.any?
.block
......
......@@ -11,17 +11,22 @@
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'pending')}
= link_to project_builds_path(@project, scope: :pending) do
Pending
%span.badge
= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@all_builds.running_or_pending.count(:id))
%span.badge
= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to project_builds_path(@project, scope: :finished) do
Finished
%span.badge.js-running-count
%span.badge
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls
......
......@@ -32,7 +32,7 @@
Cant find HEAD commit for this branch
- stages_status = pipeline.statuses.stages_status
- stages_status = pipeline.statuses.latest.stages_status
- stages.each do |stage|
%td
- status = stages_status[stage]
......@@ -58,16 +58,7 @@
.controls.hidden-xs.pull-right
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
- if artifacts.present?
.btn-group.inline
.btn-group
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
= icon("play")
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to '#' do
= icon("play")
%span Deploy to production
.inline
.btn-group
%a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'}
= icon("download")
......@@ -80,7 +71,7 @@
%span Download '#{build.name}' artifacts
- if can?(current_user, :update_pipeline, @project)
.cancel-retry-btns
.cancel-retry-btns.inline
- if pipeline.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat")
......
......@@ -8,12 +8,12 @@
- elsif blob_text_viewable?(blob)
- if !project.repository.diffable?(blob)
.nothing-here-block This diff was suppressed by a .gitattributes entry.
- elsif diff_file.collapsed?
- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path))
.nothing-here-block.diff-collapsed{data: { diff_for_path: url } }
This diff is collapsed. Click to expand it.
- elsif diff_file.diff_lines.length > 0
- if diff_file.collapsed_by_default? && !expand_all_diffs?
- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path))
.nothing-here-block.diff-collapsed{data: { diff_for_path: url } }
This diff is collapsed. Click to expand it.
- elsif diff_view == 'parallel'
- if diff_view == 'parallel'
= render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob
- else
= render "projects/diffs/text_file", diff_file: diff_file
......
......@@ -6,7 +6,7 @@
.content-block.oneline-block.files-changed
.inline-parallel-buttons
- unless expand_all_diffs?
- if !expand_all_diffs? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: 'html')), class: 'btn btn-default'
- if show_whitespace_toggle
- if current_controller?(:commit)
......
......@@ -12,5 +12,5 @@
&nbsp;
- if @service.valid? && @service.activated?
- disabled = @service.can_test? ? '':'disabled'
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service.to_param), class: "btn #{disabled}"
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service), class: "btn #{disabled}", title: @service.disabled_title
= link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel"
......@@ -21,10 +21,10 @@
placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
.filter-item.inline.milestone-filter
= render "shared/issuable/milestone_dropdown", selected: params[:milestone_title], name: :milestone_title, show_any: true, show_upcoming: true
= render "shared/issuable/milestone_dropdown"
.filter-item.inline.labels-filter
= render "shared/issuable/label_dropdown", selected: params[:label_name], data_options: { field_name: "label_name[]" }
= render "shared/issuable/label_dropdown"
- if local_assigns[:type] == :issues
.filter-item.inline.weight-filter
......@@ -56,9 +56,15 @@
placeholder: "Search authors", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: @project.id, field_name: "update[assignee_id]" } })
.filter-item.inline
= dropdown_tag("Milestone", options: { title: "Assign milestone", toggle_class: 'js-milestone-select js-extra-options js-filter-submit js-filter-bulk-update', filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", placeholder: "Search milestones", data: { show_no: true, field_name: "update[milestone_id]", project_id: @project.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :json), use_id: true } })
.filter-item.inline.labels-filter
= render "shared/issuable/label_dropdown", classes: ['js-filter-bulk-update', 'js-multiselect'], show_create: false, show_footer: false, extra_options: false, filter_submit: false, show_footer: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true }
.filter-item.inline
= dropdown_tag("Subscription", options: { toggle_class: "js-subscription-event", title: "Change subscription", dropdown_class: "dropdown-menu-selectable", data: { field_name: "update[subscription_event]" } } ) do
%ul
%li
%a{href: "#", data: {id: "subscribe"}} Subscribe
%li
%a{href: "#", data: {id: "unsubscribe"}} Unsubscribe
= hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag :state_event, params[:state_event]
......@@ -76,6 +82,7 @@
new MilestoneSelect();
new IssueStatusSelect();
new WeightSelect();
new SubscriptionSelect();
$('form.filter-form').on('submit', function (event) {
event.preventDefault();
Turbolinks.visit(this.action + '&' + $(this).serialize());
......
......@@ -52,24 +52,38 @@
= f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder
- project = @target_project || @project
- if issuable.assignee_id
= hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id)
= dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-issuable-form-dropdown js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit",
placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (project.id if project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } })
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
selected: issuable.assignee_id, project: @target_project || @project,
first_user: true, current_user: true, include_blank: true)
%div
= link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
.form-group.issue-milestone
= f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone_id, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false
- if milestone_options(issuable).present?
.issuable-form-select-holder
= f.select(:milestone_id, milestone_options(issuable),
{ include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
- else
.prepend-top-10
%span.light No open milestones available.
- if can? current_user, :admin_milestone, issuable.project
%div
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
.form-group
- has_labels = issuable.project.labels.any?
- selected_labels = issuable.label_ids.any? ? issuable.label_ids : nil
- label_dropdown_toggle = issuable.labels.map { |label| label.title }
= f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
.issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: selected_labels, selected_toggle: label_dropdown_toggle, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: "false" }
- if has_labels
.issuable-form-select-holder
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
- else
%span.light No labels yet.
- if can? current_user, :admin_label, issuable.project
%div
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
- if issuable.respond_to?(:weight)
.form-group
......
......@@ -4,21 +4,19 @@
- show_footer = local_assigns.fetch(:show_footer, true)
- data_options = local_assigns.fetch(:data_options, {})
- classes = local_assigns.fetch(:classes, [])
- selected = local_assigns.fetch(:selected, nil)
- selected_toggle = local_assigns.fetch(:selected_toggle, nil)
- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", selected: selected, project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}
- dropdown_data = {toggle: 'dropdown', field_name: 'label_name[]', show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}
- dropdown_data.merge!(data_options)
- classes << 'js-extra-options' if extra_options
- classes << 'js-filter-submit' if filter_submit
- if selected.present?
- if selected.respond_to?('any?')
- selected.each do |label|
= hidden_field_tag data_options[:field_name], label, id: nil
- if params[:label_name].present?
- if params[:label_name].respond_to?('any?')
- params[:label_name].each do |label|
= hidden_field_tag "label_name[]", label, id: nil
.dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data}
%span.dropdown-toggle-text
= h(multi_label_name(selected_toggle || selected, "Label"))
= h(multi_label_name(params[:label_name], "Label"))
= icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create }
......
- if selected.present?
= hidden_field_tag(name, selected)
= dropdown_tag(milestone_dropdown_label(selected), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected, project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
- if params[:milestone_title].present?
= hidden_field_tag(:milestone_title, params[:milestone_title])
= dropdown_tag(milestone_dropdown_label(params[:milestone_title]), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, show_upcoming: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
- if @project
%ul.dropdown-footer-list
- if can? current_user, :admin_milestone, @project
......
class ProjectExportWorker
include Sidekiq::Worker
sidekiq_options queue: :gitlab_shell, retry: true
sidekiq_options queue: :gitlab_shell, retry: 3
def perform(current_user_id, project_id)
current_user = User.find(current_user_id)
......
......@@ -79,7 +79,7 @@ module Gitlab
# Enable the asset pipeline
config.assets.enabled = true
config.assets.paths << Gemojione.index.images_path
config.assets.paths << Gemojione.images_path
config.assets.precompile << "*.png"
config.assets.precompile << "print.css"
config.assets.precompile << "notify.css"
......@@ -90,6 +90,7 @@ module Gitlab
config.assets.precompile << "profile/application.js"
config.assets.precompile << "lib/utils/*.js"
config.assets.precompile << "lib/*.js"
config.assets.precompile << "u2f.js"
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
......
# CSP headers have to have single quotes, so failures relating to quotes
# inside Ruby string arrays are irrelevant.
# rubocop:disable Lint/PercentStringArray
require 'gitlab/current_settings'
include Gitlab::CurrentSettings
# If Sentry is enabled and the Rails app is running in production mode,
# this will construct the Report URI for Sentry.
if Rails.env.production? && current_application_settings.sentry_enabled
uri = URI.parse(current_application_settings.sentry_dsn)
CSP_REPORT_URI = "#{uri.scheme}://#{uri.host}/api#{uri.path}/csp-report/?sentry_key=#{uri.user}"
else
CSP_REPORT_URI = ''
end
# Content Security Policy Headers
# For more information on CSP see:
# - https://gitlab.com/gitlab-org/gitlab-ce/issues/18231
# - https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives
SecureHeaders::Configuration.default do |config|
# Mark all cookies as "Secure", "HttpOnly", and "SameSite=Strict".
config.cookies = {
secure: true,
httponly: true,
samesite: {
strict: true
}
}
config.x_content_type_options = "nosniff"
config.x_xss_protection = "1; mode=block"
config.x_download_options = "noopen"
config.x_permitted_cross_domain_policies = "none"
config.referrer_policy = "origin-when-cross-origin"
config.csp = {
# "Meta" values.
report_only: true,
preserve_schemes: true,
# "Directive" values.
# Default source allows nothing, more permissive values are set per-policy.
default_src: %w('none'),
# (Deprecated) Don't allow iframes.
frame_src: %w('none'),
# Only allow XMLHTTPRequests from the GitLab instance itself.
connect_src: %w('self'),
# Only load local fonts.
font_src: %w('self'),
# Load local images, any external image available over HTTPS.
img_src: %w(* 'self' data:),
# Audio and video can't be played on GitLab currently, so it's disabled.
media_src: %w('none'),
# Don't allow <object>, <embed>, or <applet> elements.
object_src: %w('none'),
# Allow local scripts and inline scripts.
script_src: %w('unsafe-inline' 'unsafe-eval' 'self'),
# Allow local stylesheets and inline styles.
style_src: %w('unsafe-inline' 'self'),
# The URIs that a user agent may use as the document base URL.
base_uri: %w('self'),
# Only allow local iframes and service workers
child_src: %w('self'),
# Only submit form information to the GitLab instance.
form_action: %w('self'),
# Disallow any parents from embedding a page in an iframe.
frame_ancestors: %w('none'),
# Don't allow any plugins (Flash, Shockwave, etc.)
plugin_types: %w(),
# Blocks all mixed (HTTP) content.
block_all_mixed_content: true,
# Upgrades insecure requests to HTTPS when possible.
upgrade_insecure_requests: true
}
# Reports are sent to Sentry if it's enabled.
if current_application_settings.sentry_enabled
config.csp[:report_uri] = %W(#{CSP_REPORT_URI})
end
# Allow Bootstrap Linter in development mode.
if Rails.env.development?
config.csp[:script_src] << "maxcdn.bootstrapcdn.com"
end
# reCAPTCHA
if current_application_settings.recaptcha_enabled
config.csp[:script_src] << "https://www.google.com/recaptcha/"
config.csp[:script_src] << "https://www.gstatic.com/recaptcha/"
config.csp[:frame_src] << "https://www.google.com/recaptcha/"
config.x_frame_options = "SAMEORIGIN"
end
# Gravatar
if current_application_settings.gravatar_enabled?
config.csp[:img_src] << "www.gravatar.com"
config.csp[:img_src] << "secure.gravatar.com"
config.csp[:img_src] << Gitlab.config.gravatar.host
end
# Piwik
if Gitlab.config.extra.has_key?('piwik_url') && Gitlab.config.extra.has_key?('piwik_site_id')
config.csp[:script_src] << Gitlab.config.extra.piwik_url
config.csp[:img_src] << Gitlab.config.extra.piwik_url
end
# Google Analytics
if Gitlab.config.extra.has_key?('google_analytics_id')
config.csp[:script_src] << "https://www.google-analytics.com"
end
end
......@@ -13,7 +13,14 @@ Sidekiq.configure_server do |config|
# UGLY Hack to get nested hash from settingslogic
cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json)
# UGLY hack: Settingslogic doesn't allow 'class' key
cron_jobs.each { |k, v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') }
cron_jobs_required_keys = %w(job_class cron)
cron_jobs.each do |k, v|
if cron_jobs[k] && cron_jobs_required_keys.all? { |s| cron_jobs[k].key?(s) }
cron_jobs[k]['class'] = cron_jobs[k].delete('job_class')
else
raise("Invalid cron_jobs config key: '#{k}'. Check your gitlab config file.")
end
end
Sidekiq::Cron::Job.load_from_hash! cron_jobs
# Gitlab Geo: enable bulk notify job only on primary node
......
class AddUserIdToPipeline < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_column :ci_commits, :user_id, :integer
end
end
class AddIndexForPipelineUserId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def change
add_concurrent_index :ci_commits, :user_id
end
end
class AddWhenAndYamlVariablesToCiBuilds < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_column :ci_builds, :when, :string
add_column :ci_builds, :yaml_variables, :text
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160713222618) do
ActiveRecord::Schema.define(version: 20160716115710) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -194,6 +194,8 @@ ActiveRecord::Schema.define(version: 20160713222618) do
t.string "environment"
t.datetime "artifacts_expire_at"
t.integer "artifacts_size"
t.string "when"
t.text "yaml_variables"
end
add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
......@@ -225,6 +227,7 @@ ActiveRecord::Schema.define(version: 20160713222618) do
t.datetime "started_at"
t.datetime "finished_at"
t.integer "duration"
t.integer "user_id"
end
add_index "ci_commits", ["gl_project_id", "sha"], name: "index_ci_commits_on_gl_project_id_and_sha", using: :btree
......@@ -236,6 +239,7 @@ ActiveRecord::Schema.define(version: 20160713222618) do
add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree
add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree
add_index "ci_commits", ["status"], name: "index_ci_commits_on_status", using: :btree
add_index "ci_commits", ["user_id"], name: "index_ci_commits_on_user_id", using: :btree
create_table "ci_events", force: :cascade do |t|
t.integer "project_id"
......
......@@ -78,7 +78,8 @@ Example response:
"iid" : 6,
"labels" : [],
"subscribed" : false,
"user_notes_count": 1
"user_notes_count": 1,
"due_date": "2016-07-22"
}
]
```
......@@ -154,7 +155,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false,
"user_notes_count": 1
"user_notes_count": 1,
"due_date": null
}
]
```
......@@ -232,7 +234,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false,
"user_notes_count": 1
"user_notes_count": 1,
"due_date": "2016-07-22"
}
]
```
......@@ -295,7 +298,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
"subscribed": false,
"user_notes_count": 1
"user_notes_count": 1,
"due_date": null
}
```
......@@ -320,6 +324,7 @@ POST /projects/:id/issues
| `milestone_id` | integer | no | The ID of a milestone to assign issue |
| `labels` | string | no | Comma-separated label names for an issue |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
```bash
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
......@@ -351,7 +356,8 @@ Example response:
"updated_at" : "2016-01-07T12:44:33.959Z",
"milestone" : null,
"subscribed" : true,
"user_notes_count": 0
"user_notes_count": 0,
"due_date": null
}
```
......@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id
| `labels` | string | no | Comma-separated label names for an issue |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
```bash
curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
......@@ -410,7 +417,8 @@ Example response:
"assignee" : null,
"milestone" : null,
"subscribed" : true,
"user_notes_count": 0
"user_notes_count": 0,
"due_date": "2016-07-22"
}
```
......@@ -487,7 +495,8 @@ Example response:
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin"
}
},
"due_date": null
}
```
......@@ -541,7 +550,8 @@ Example response:
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin"
}
},
"due_date": null
}
```
......@@ -596,7 +606,8 @@ Example response:
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/orville"
},
"subscribed": false
"subscribed": false,
"due_date": null
}
```
......
......@@ -985,11 +985,11 @@ directive defined in `.postgres_services` and `.mysql_services` respectively:
- ruby
test:postgres:
<< *job_definition
<<: *job_definition
services: *postgres_definition
test:mysql:
<< *job_definition
<<: *job_definition
services: *mysql_definition
```
......
......@@ -44,7 +44,7 @@ it organized and easy to find.
- When introducing a new document, be careful for the headings to be
grammatically and syntactically correct. It is advised to mention one or all
of the following GitLab members for a review: `@axil`, `@rspeicher`,
`@dblessing`, `@ashleys`, `@nearlythere`. This is to ensure that no document
`@dblessing`, `@ashleys`. This is to ensure that no document
with wrong heading is going live without an audit, thus preventing dead links
and redirection issues when corrected
- Leave exactly one newline after a heading
......
......@@ -53,3 +53,8 @@ Generating a sprite file containing all the Emoji can be done by running:
```
bundle exec rake gemojione:sprite
```
If new emoji are added, the spritesheet may change size. To compensate for
such changes, first generate the `emoji.png` spritesheet with the above Rake
task, then check the dimensions of the new spritesheet and update the
`SPRITESHEET_WIDTH` and `SPRITESHEET_HEIGHT` constants accordingly.
......@@ -37,7 +37,6 @@ Feature: Project Issues
And I submit new issue "500 error on profile"
Then I should see issue "500 error on profile"
@javascript
Scenario: I submit new unassigned issue with labels
Given project "Shop" has labels: "bug", "feature", "enhancement"
And I click link "New Issue"
......
......@@ -135,17 +135,19 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end
step 'I click "Assign to" dropdown"' do
click_button 'Assignee'
first('.ajax-users-select').click
end
step 'I should see the target project ID in the input selector' do
expect(find('.js-assignee-search')["data-project-id"]).to eq "#{@project.id}"
expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]")
end
step 'I should see the users from the target project ID' do
expect(page).to have_content 'Unassigned'
expect(page).to have_content current_user.name
expect(page).to have_content @project.users.first.name
expect(page).to have_selector('.user-result', visible: true, count: 3)
users = page.all('.user-name')
expect(users[0].text).to eq 'Unassigned'
expect(users[1].text).to eq current_user.name
expect(users[2].text).to eq @project.users.first.name
end
# Verify a link is generated against the correct project
......
......@@ -82,8 +82,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
step 'I submit new issue "500 error on profile" with label \'bug\'' do
fill_in "issue_title", with: "500 error on profile"
click_button "Label"
click_link "bug"
select 'bug', from: "Labels"
click_button "Submit issue"
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -56,9 +56,9 @@ module API
not_found!('Award Emoji') unless can_read_awardable?
award = awardable.award_emoji.new(name: params[:name], user: current_user)
award = awardable.create_award_emoji(params[:name], current_user)
if award.save
if award.persisted?
present award, with: Entities::AwardEmoji
else
not_found!("Award Emoji #{award.errors.messages}")
......
......@@ -64,7 +64,7 @@ module API
ref = branches.first
end
pipeline = @project.ensure_pipeline(commit.sha, ref)
pipeline = @project.ensure_pipeline(commit.sha, ref, current_user)
name = params[:name] || params[:context]
status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref])
......
......@@ -202,6 +202,7 @@ module API
end
expose :user_notes_count
expose :upvotes, :downvotes
expose :due_date
end
class ExternalIssue < Grape::Entity
......
......@@ -63,7 +63,12 @@ module API
if access_status.status
# Return the repository full path so that gitlab-shell has it when
# handling ssh commands
response[:repository_path] = project.repository.path_to_repo
response[:repository_path] =
if wiki?
project.wiki.repository.path_to_repo
else
project.repository.path_to_repo
end
end
response
......
......@@ -152,12 +152,13 @@ module API
# milestone_id (optional) - The ID of a milestone to assign issue
# labels (optional) - The labels of an issue
# created_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request:
# POST /projects/:id/issues
post ":id/issues" do
post ':id/issues' do
required_attributes! [:title]
keys = [:title, :description, :assignee_id, :milestone_id]
keys = [:title, :description, :assignee_id, :milestone_id, :due_date]
keys << :created_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys)
......@@ -201,12 +202,13 @@ module API
# labels (optional) - The labels of an issue
# state_event (optional) - The state event of an issue (close|reopen)
# updated_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request:
# PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do
put ':id/issues/:issue_id' do
issue = user_project.issues.find(params[:issue_id])
authorize! :update_issue, issue
keys = [:title, :description, :assignee_id, :milestone_id, :state_event]
keys = [:title, :description, :assignee_id, :milestone_id, :state_event, :due_date]
keys << :updated_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys)
......
......@@ -56,6 +56,8 @@ module Banzai
# period (e.g., http://localhost:3000/)
rinku = Rinku.auto_link(html, :urls, options, IGNORE_PARENTS.to_a, 1)
return if rinku == html
# Rinku returns a String, so parse it back to a Nokogiri::XML::Document
# for further processing.
@doc = parse_html(rinku)
......
......@@ -19,14 +19,22 @@ module Banzai
language = node.attr('class')
code = node.text
css_classes = "code highlight"
lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText
formatter = Rouge::Formatters::HTML.new
begin
highlighted = block_code(code, language)
code = formatter.format(lexer.lex(code))
css_classes << " js-syntax-highlight #{lexer.tag}"
rescue
# Gracefully handle syntax highlighter bugs/errors to ensure
# users can still access an issue/comment/etc.
highlighted = "<pre>#{code}</pre>"
end
highlighted = %(<pre class="#{css_classes}"><code>#{code}</code></pre>)
# Extracted to a method to measure it
replace_parent_pre_element(node, highlighted)
end
......@@ -40,8 +48,7 @@ module Banzai
# Override Rouge::Plugins::Redcarpet#rouge_formatter
def rouge_formatter(lexer)
Rouge::Formatters::HTMLGitlab.new(
cssclass: "code highlight js-syntax-highlight #{lexer.tag}")
Rouge::Formatters::HTML.new
end
end
end
......
......@@ -112,7 +112,7 @@ module Banzai
data = data_attribute(project: project.id, author: author.try(:id))
text = link_text || User.reference_prefix + 'all'
link_tag(url, data, text)
link_tag(url, data, text, 'All Project and Group Members')
end
def link_to_namespace(namespace, link_text: nil)
......@@ -128,7 +128,7 @@ module Banzai
data = data_attribute(group: namespace.id)
text = link_text || Group.reference_prefix + group
link_tag(url, data, text)
link_tag(url, data, text, namespace.name)
end
def link_to_user(user, namespace, link_text: nil)
......@@ -136,11 +136,11 @@ module Banzai
data = data_attribute(user: namespace.owner_id)
text = link_text || User.reference_prefix + user
link_tag(url, data, text)
link_tag(url, data, text, namespace.owner_name)
end
def link_tag(url, data, text)
%(<a href="#{url}" #{data} class="#{link_class}">#{escape_once(text)}</a>)
def link_tag(url, data, text, title)
%(<a href="#{url}" #{data} class="#{link_class}" title="#{escape_once(title)}">#{escape_once(text)}</a>)
end
end
end
......
......@@ -31,28 +31,34 @@ module Ci
raise ValidationError, e.message
end
def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
builds.select do |build|
build[:stage] == stage &&
process?(build[:only], build[:except], ref, tag, trigger_request)
def jobs_for_ref(ref, tag = false, trigger_request = nil)
@jobs.select do |_, job|
process?(job[:only], job[:except], ref, tag, trigger_request)
end
end
def builds
@jobs.map do |name, job|
build_job(name, job)
def jobs_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
jobs_for_ref(ref, tag, trigger_request).select do |_, job|
job[:stage] == stage
end
end
def global_variables
@variables
def builds_for_ref(ref, tag = false, trigger_request = nil)
jobs_for_ref(ref, tag, trigger_request).map do |name, job|
build_job(name, job)
end
end
def job_variables(name)
job = @jobs[name.to_sym]
return [] unless job
def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
jobs_for_stage_and_ref(stage, ref, tag, trigger_request).map do |name, job|
build_job(name, job)
end
end
job[:variables] || []
def builds
@jobs.map do |name, job|
build_job(name, job)
end
end
private
......@@ -95,11 +101,10 @@ module Ci
commands: [job[:before_script] || @before_script, job[:script]].flatten.compact.join("\n"),
tag_list: job[:tags] || [],
name: name,
only: job[:only],
except: job[:except],
allow_failure: job[:allow_failure] || false,
when: job[:when] || 'on_success',
environment: job[:environment],
yaml_variables: yaml_variables(name),
options: {
image: job[:image] || @image,
services: job[:services] || @services,
......@@ -111,6 +116,24 @@ module Ci
}
end
def yaml_variables(name)
variables = global_variables.merge(job_variables(name))
variables.map do |key, value|
{ key: key, value: value, public: true }
end
end
def global_variables
@variables || {}
end
def job_variables(name)
job = @jobs[name.to_sym]
return {} unless job
job[:variables] || {}
end
def validate!
@jobs.each do |name, job|
validate_job!(name, job)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment