Merge remote-tracking branch 'origin/master' into 2979-personal-access-tokens

This commit is contained in:
Timothy Andrew 2016-05-11 09:52:58 +05:30
commit 2e9742997d
446 changed files with 5141 additions and 4307 deletions

View File

@ -953,10 +953,9 @@ Performance/DoubleStartEndWith:
Performance/EndWith:
Enabled: false
# TODO: Enable LstripRstrip Cop.
# Use `strip` instead of `lstrip.rstrip`.
Performance/LstripRstrip:
Enabled: false
Enabled: true
# TODO: Enable RangeInclude Cop.
# Use `Range#cover?` instead of `Range#include?`.

View File

@ -244,11 +244,11 @@ linters:
# URLs should be valid and not contain protocols or domain names.
UrlFormat:
enabled: false
enabled: true
# URLs should always be enclosed within quotes.
UrlQuotes:
enabled: false
enabled: true
# Properties, like color and font, are easier to read and maintain
# when defined using variables rather than literals.

111
CHANGELOG
View File

@ -1,25 +1,74 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.0 (unreleased)
- Fix error when using link to uploads in global snippets
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Use a case-insensitive comparison in sanitizing URI schemes
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
- Updated gitlab_git to 10.1.0
- GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
- Reduce delay in destroying a project from 1-minute to immediately
- Make build status canceled if any of the jobs was canceled and none failed
- Allow authentication using personal acces tokens
- Upgrade Sidekiq to 4.1.2
- Sanitize repo paths in new project error message
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
- Remove future dates from contribution calendar graph.
- Support e-mail notifications for comments on project snippets
- Use ActionDispatch Remote IP for Akismet checking
- Fix error when visiting commit builds page before build was updated
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
- Update SVG sanitizer to conform to SVG 1.1
- Updated search UI
- Replace Devise Async with Devise ActiveJob integration. !3902 (Connor Shea)
- Display informative message when new milestone is created
- Sanitize milestones and labels titles
- Support multi-line tag messages. !3833 (Calin Seciu)
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
- Added button to toggle whitespaces changes on diff view
- Backport GitLab Enterprise support from EE
- Backport GitHub Enterprise import support from EE
- Create tags using Rugged for performance reasons. !3745
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
- Add eager load paths to help prevent dependency load issues in Sidekiq workers. !3724
- Added multiple colors for labels in dropdowns when dups happen.
- Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
- API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
- Expire repository exists? and has_visible_content? caches after a push if necessary
- Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
- Fix adding a todo for private group members (Ahmad Sherif)
- Bump ace-rails-ap gem version from 2.0.1 to 4.0.2 which upgrades Ace Editor from 1.1.2 to 1.2.3
v 8.7.1 (unreleased)
v 8.7.4
- Fix always showing build notification message when switching between merge requests
- Links for Redmine issue references are generated correctly again (Benedikt Huss)
- Fix an issue when filtering merge requests with more than one label. !3886
v 8.7.3
- Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
- Merge request widget displays TeamCity build state and code coverage correctly again.
- Fix the line code when importing PR review comments from GitHub. !4010
- Wikis are now initialized on legacy projects when checking repositories
v 8.7.2
- The "New Branch" button is now loaded asynchronously
- Fix error 500 when trying to create a wiki page
- Updated spacing between notification label and button
- Label titles in filters are now escaped properly
v 8.7.1
- Throttle the update of `project.last_activity_at` to 1 minute. !3848
- Fix .gitlab-ci.yml parsing issue when hidde job is a template without script definition. !3849
- Fix license detection to detect all license files, not only known licenses. !3878
- Use the `can?` helper instead of `current_user.can?`. !3882
- Prevent users from deleting Webhooks via API they do not own
- Fix Error 500 due to stale cache when projects are renamed or transferred
- Update width of search box to fix Safari bug. !3900 (Jedidiah)
- Use the `can?` helper instead of `current_user.can?`
v 8.7.0
- Gitlab::GitAccess and Gitlab::GitAccessWiki are now instrumented
@ -131,13 +180,25 @@ v 8.7.0
- 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
- Allow enable/disable push events for system hooks
- Fix GitHub project's link in the import page when provider has a custom URL
- Add RAW build trace output and button on build page
- Add incremental build trace update into CI API
v 8.6.8
- Prevent privilege escalation via "impersonate" feature
- Prevent privilege escalation via notes API
- Prevent privilege escalation via project webhook API
- Prevent XSS via Git branch and tag names
- Prevent XSS via custom issue tracker URL
- Prevent XSS via `window.opener`
- Prevent XSS via label drop-down
- Prevent information disclosure via milestone API
- Prevent information disclosure via snippet API
- Prevent information disclosure via project labels
- Prevent information disclosure via new merge request page
v 8.6.7
- Fix persistent XSS vulnerability in `commit_person_link` helper
- Fix persistent XSS vulnerability in Label and Milestone dropdowns
@ -279,6 +340,17 @@ v 8.6.0
- Trigger a todo for mentions on commits page
- Let project owners and admins soft delete issues and merge requests
v 8.5.12
- Prevent privilege escalation via "impersonate" feature
- Prevent privilege escalation via notes API
- Prevent privilege escalation via project webhook API
- Prevent XSS via Git branch and tag names
- Prevent XSS via custom issue tracker URL
- Prevent XSS via `window.opener`
- Prevent information disclosure via snippet API
- Prevent information disclosure via project labels
- Prevent information disclosure via new merge request page
v 8.5.11
- Fix persistent XSS vulnerability in `commit_person_link` helper
@ -429,6 +501,17 @@ v 8.5.0
- Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul)
- Add Todos
v 8.4.10
- Prevent privilege escalation via "impersonate" feature
- Prevent privilege escalation via notes API
- Prevent privilege escalation via project webhook API
- Prevent XSS via Git branch and tag names
- Prevent XSS via custom issue tracker URL
- Prevent XSS via `window.opener`
- Prevent information disclosure via snippet API
- Prevent information disclosure via project labels
- Prevent information disclosure via new merge request page
v 8.4.9
- Fix persistent XSS vulnerability in `commit_person_link` helper
@ -554,6 +637,15 @@ v 8.4.0
- Add IP check against DNSBLs at account sign-up
- Added cache:key to .gitlab-ci.yml allowing to fine tune the caching
v 8.3.9
- Prevent privilege escalation via "impersonate" feature
- Prevent privilege escalation via notes API
- Prevent privilege escalation via project webhook API
- Prevent XSS via custom issue tracker URL
- Prevent XSS via `window.opener`
- Prevent information disclosure via project labels
- Prevent information disclosure via new merge request page
v 8.3.8
- Fix persistent XSS vulnerability in `commit_person_link` helper
@ -663,6 +755,17 @@ v 8.3.0
- Expose Git's version in the admin area
- Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye)
v 8.2.5
- Prevent privilege escalation via "impersonate" feature
- Prevent privilege escalation via notes API
- Prevent privilege escalation via project webhook API
- Prevent XSS via `window.opener`
- Prevent information disclosure via project labels
- Prevent information disclosure via new merge request page
v 8.2.4
- Bump Git version requirement to 2.7.4
v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu)
- Fix Error 500s when creating global milestones with Unicode characters (Stan Hu)

View File

@ -142,6 +142,16 @@ code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
might be edited to make them small and simple.
You are encouraged to use the template below for feature proposals.
```
## Description including problem, use cases, benefits, and/or goals
## Proposal
## Links / references
```
For changes in the interface, it can be helpful to create a mockup first.
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
@ -349,7 +359,7 @@ on your merge request feel free to mention one of the Merge Marshalls in the
Please ensure that your merge request meets the contribution acceptance criteria.
When having your code reviewed and when reviewing merge requests please take the
[Thoughtbot code review guide] into account.
[code review guidelines](doc/development/code_review.md) into account.
### Merge request description format
@ -523,4 +533,3 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/
[Thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review

10
Gemfile
View File

@ -19,7 +19,8 @@ gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries
gem 'devise', '~> 3.5.4'
gem 'doorkeeper', '~> 2.2.0'
gem 'doorkeeper', '~> 3.1'
gem 'devise-async', '~> 0.9.0'
gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
@ -196,7 +197,7 @@ gem 'licensee', '~> 8.0.0'
gem "rack-attack", '~> 4.3.1'
# Ace editor
gem 'ace-rails-ap', '~> 2.0.1'
gem 'ace-rails-ap', '~> 4.0.2'
# Keyboard shortcuts
gem 'mousetrap-rails', '~> 1.4.6'
@ -241,7 +242,6 @@ group :development do
gem "foreman"
gem 'brakeman', '~> 3.2.0', require: false
gem "annotate", "~> 2.7.0"
gem 'letter_opener_web', '~> 1.3.0'
gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.11.0'
@ -269,7 +269,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.3.0'
gem 'rspec-rails', '~> 3.4.0'
gem 'rspec-retry'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
@ -319,7 +319,7 @@ gem "newrelic_rpm", '~> 3.14'
gem 'octokit', '~> 4.3.0'
gem "mail_room", "~> 0.6.1"
gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'

View File

@ -3,7 +3,7 @@ GEM
specs:
CFPropertyList (2.3.2)
RedCloth (4.2.9)
ace-rails-ap (2.0.1)
ace-rails-ap (4.0.2)
actionmailer (4.2.6)
actionpack (= 4.2.6)
actionview (= 4.2.6)
@ -51,9 +51,6 @@ GEM
activerecord (>= 3.0)
akismet (2.0.0)
allocations (1.0.4)
annotate (2.7.0)
activerecord (>= 3.2, < 6.0)
rake (~> 10.4)
arel (6.0.3)
asana (0.4.0)
faraday (~> 0.9)
@ -134,7 +131,7 @@ GEM
execjs
coffee-script-source (1.10.0)
colorize (0.7.7)
concurrent-ruby (1.0.1)
concurrent-ruby (1.0.2)
connection_pool (2.2.0)
coveralls (0.8.13)
json (~> 1.8)
@ -164,6 +161,8 @@ GEM
responders
thread_safe (~> 0.1)
warden (~> 1.2.3)
devise-async (0.9.0)
devise (~> 3.2)
devise-two-factor (2.0.1)
activesupport
attr_encrypted (~> 1.3.2)
@ -173,7 +172,7 @@ GEM
diff-lcs (1.2.5)
diffy (3.0.7)
docile (1.1.5)
doorkeeper (2.2.2)
doorkeeper (3.1.0)
railties (>= 3.2)
dropzonejs-rails (0.7.2)
rails (> 3.1)
@ -184,7 +183,7 @@ GEM
encryptor (1.3.0)
equalizer (0.0.11)
erubis (2.7.0)
escape_utils (1.1.0)
escape_utils (1.1.1)
eventmachine (1.0.8)
excon (0.45.4)
execjs (2.6.0)
@ -334,7 +333,7 @@ GEM
json
get_process_mem (0.2.0)
gherkin-ruby (0.3.2)
github-linguist (4.7.5)
github-linguist (4.7.6)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
@ -351,7 +350,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.3.1)
gemojione (~> 2.2, >= 2.2.1)
gitlab_git (10.0.0)
gitlab_git (10.1.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@ -465,7 +464,7 @@ GEM
systemu (~> 2.6.2)
mail (2.6.4)
mime-types (>= 1.16, < 4)
mail_room (0.6.1)
mail_room (0.7.0)
method_source (0.8.2)
mime-types (2.99.1)
mimemagic (0.3.0)
@ -662,29 +661,29 @@ GEM
chunky_png
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
rspec (3.3.0)
rspec-core (~> 3.3.0)
rspec-expectations (~> 3.3.0)
rspec-mocks (~> 3.3.0)
rspec-core (3.3.2)
rspec-support (~> 3.3.0)
rspec-expectations (3.3.1)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.4)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0)
rspec-mocks (3.3.2)
rspec-support (~> 3.4.0)
rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0)
rspec-rails (3.3.3)
rspec-support (~> 3.4.0)
rspec-rails (3.4.2)
actionpack (>= 3.0, < 4.3)
activesupport (>= 3.0, < 4.3)
railties (>= 3.0, < 4.3)
rspec-core (~> 3.3.0)
rspec-expectations (~> 3.3.0)
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-support (~> 3.4.0)
rspec-retry (0.4.5)
rspec-core
rspec-support (3.3.0)
rspec-support (3.4.1)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
powerpack (~> 0.1)
@ -738,7 +737,7 @@ GEM
rack
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
sidekiq (4.1.1)
sidekiq (4.1.2)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
redis (~> 3.2, >= 3.2.1)
@ -883,7 +882,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 2.0.1)
ace-rails-ap (~> 4.0.2)
activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0)
acts-as-taggable-on (~> 3.4)
@ -891,7 +890,6 @@ DEPENDENCIES
after_commit_queue
akismet (~> 2.0)
allocations (~> 1.0)
annotate (~> 2.7.0)
asana (~> 0.4.0)
asciidoctor (~> 1.5.2)
attr_encrypted (~> 1.3.4)
@ -920,9 +918,10 @@ DEPENDENCIES
database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0)
devise (~> 3.5.4)
devise-async (~> 0.9.0)
devise-two-factor (~> 2.0.0)
diffy (~> 3.0.3)
doorkeeper (~> 2.2.0)
doorkeeper (~> 3.1)
dropzonejs-rails (~> 0.7.1)
email_reply_parser (~> 0.5.8)
email_spec (~> 1.6.0)
@ -961,7 +960,7 @@ DEPENDENCIES
letter_opener_web (~> 1.3.0)
licensee (~> 8.0.0)
loofah (~> 2.0.3)
mail_room (~> 0.6.1)
mail_room (~> 0.7)
method_source (~> 0.8)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
@ -1011,7 +1010,7 @@ DEPENDENCIES
responders (~> 2.0)
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0)
rspec-rails (~> 3.4.0)
rspec-retry
rubocop (~> 0.38.0)
ruby-fogbugz (~> 0.2.1)
@ -1058,4 +1057,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.11.2
1.12.3

View File

@ -1,6 +1,6 @@
# GitLab
[![build status](https://ci.gitlab.com/projects/1/status.svg?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
@ -20,6 +20,10 @@ To see how GitLab looks please see the [features page on our website](https://ab
- Completely free and open source (MIT Expat license)
- Powered by [Ruby on Rails](https://github.com/rails/rails)
## Hiring
We're hiring developers, support people, and production engineers all the time, please see our [jobs page](https://about.gitlab.com/jobs/).
## Editions
There are two editions of GitLab:
@ -31,11 +35,11 @@ There are two editions of GitLab:
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
- [Subscriptions](https://about.gitlab.com/subscription/)
- [Subscriptions](https://about.gitlab.com/pricing/)
- [Consultancy](https://about.gitlab.com/consultancy/)
- [Community](https://about.gitlab.com/community/)
- [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service
- [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
- [GitLab Enterprise Edition](https://about.gitlab.com/features/#enterprise) with additional features aimed at larger organizations.
- [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
## Requirements
@ -80,7 +84,7 @@ There are a lot of [third-party applications integrating with GitLab](https://ab
## GitLab release cycle
For more information about the release process see the [release documentation](http://doc.gitlab.com/ce/release/).
For more information about the release process see the [release documentation](https://gitlab.com/gitlab-org/release-tools/blob/master/README.md).
## Upgrading

View File

@ -204,6 +204,7 @@ $ ->
$('.header-content .title').toggle()
$('.header-content .navbar-collapse').toggle()
$('.navbar-toggle').toggleClass('active')
$('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left")
# Show/hide comments on diff
$("body").on "click", ".js-toggle-diff-comments", (e) ->

View File

@ -1,58 +1,58 @@
class @AwardsHandler
constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @unicodes) ->
$(".js-add-award").on "click", (event) =>
constructor: (@getEmojisUrl, @postEmojiUrl, @noteableType, @noteableId, @unicodes) ->
$('.js-add-award').on 'click', (event) =>
event.stopPropagation()
event.preventDefault()
@showEmojiMenu()
$("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible")
$(".emoji-menu").removeClass "is-visible"
$('html').on 'click', (event) ->
if !$(event.target).closest('.emoji-menu').length
if $('.emoji-menu').is(':visible')
$('.emoji-menu').removeClass 'is-visible'
$(".awards")
.off "click"
.on "click", ".js-emoji-btn", @handleClick
$('.awards')
.off 'click'
.on 'click', '.js-emoji-btn', @handleClick
@renderFrequentlyUsedBlock()
handleClick: (e) ->
e.preventDefault()
emoji = $(this)
.find(".icon")
.data "emoji"
.find('.icon')
.data 'emoji'
if emoji is "thumbsup" and awards_handler.didUserClickEmoji $(this), "thumbsdown"
awards_handler.addAward "thumbsdown"
if emoji is 'thumbsup' and awardsHandler.didUserClickEmoji $(this), 'thumbsdown'
awardsHandler.addAward 'thumbsdown'
else if emoji is "thumbsdown" and awards_handler.didUserClickEmoji $(this), "thumbsup"
awards_handler.addAward "thumbsup"
else if emoji is 'thumbsdown' and awardsHandler.didUserClickEmoji $(this), 'thumbsup'
awardsHandler.addAward 'thumbsup'
awards_handler.addAward emoji
awardsHandler.addAward emoji
$(this).trigger 'blur'
didUserClickEmoji: (that, emoji) ->
if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title")
$(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1
if $(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title')
$(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title').indexOf('me') > -1
showEmojiMenu: ->
if $(".emoji-menu").length
if $(".emoji-menu").is ".is-visible"
$(".emoji-menu").removeClass "is-visible"
$("#emoji_search").blur()
if $('.emoji-menu').length
if $('.emoji-menu').is '.is-visible'
$('.emoji-menu').removeClass 'is-visible'
$('#emoji_search').blur()
else
$(".emoji-menu").addClass "is-visible"
$("#emoji_search").focus()
$('.emoji-menu').addClass 'is-visible'
$('#emoji_search').focus()
else
$('.js-add-award').addClass "is-loading"
$.get @get_emojis_url, (response) =>
$('.js-add-award').removeClass "is-loading"
$(".js-award-holder").append response
$('.js-add-award').addClass 'is-loading'
$.get @getEmojisUrl, (response) =>
$('.js-add-award').removeClass 'is-loading'
$('.js-award-holder').append response
setTimeout =>
$(".emoji-menu").addClass "is-visible"
$("#emoji_search").focus()
$('.emoji-menu').addClass 'is-visible'
$('#emoji_search').focus()
@setupSearch()
, 200
@ -60,7 +60,7 @@ class @AwardsHandler
@postEmoji emoji, =>
@addAwardToEmojiBar(emoji)
$(".emoji-menu").removeClass "is-visible"
$('.emoji-menu').removeClass 'is-visible'
addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji)
@ -69,9 +69,9 @@ class @AwardsHandler
if @isActive(emoji)
@decrementCounter(emoji)
else
counter = @findEmojiIcon(emoji).siblings(".js-counter")
counter = @findEmojiIcon(emoji).siblings('.js-counter')
counter.text(parseInt(counter.text()) + 1)
counter.parent().addClass("active")
counter.parent().addClass('active')
@addMeToAuthorList(emoji)
else
@createEmoji(emoji)
@ -80,47 +80,47 @@ class @AwardsHandler
@findEmojiIcon(emoji).length > 0
isActive: (emoji) ->
@findEmojiIcon(emoji).parent().hasClass("active")
@findEmojiIcon(emoji).parent().hasClass('active')
decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".js-counter")
counter = @findEmojiIcon(emoji).siblings('.js-counter')
emojiIcon = counter.parent()
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
emojiIcon.removeClass("active")
emojiIcon.removeClass('active')
@removeMeFromAuthorList(emoji)
else if emoji == "thumbsup" || emoji == "thumbsdown"
emojiIcon.tooltip("destroy")
else if emoji == 'thumbsup' || emoji == 'thumbsdown'
emojiIcon.tooltip('destroy')
counter.text(0)
emojiIcon.removeClass("active")
emojiIcon.removeClass('active')
@removeMeFromAuthorList(emoji)
else
emojiIcon.tooltip("destroy")
emojiIcon.tooltip('destroy')
emojiIcon.remove()
removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
authors = award_block
.attr("data-original-title")
.split(", ")
authors.splice(authors.indexOf("me"),1)
award_block
.closest(".js-emoji-btn")
.attr("data-original-title", authors.join(", "))
@resetTooltip(award_block)
awardBlock = @findEmojiIcon(emoji).parent()
authors = awardBlock
.attr('data-original-title')
.split(', ')
authors.splice(authors.indexOf('me'),1)
awardBlock
.closest('.js-emoji-btn')
.attr('data-original-title', authors.join(', '))
@resetTooltip(awardBlock)
addMeToAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
origTitle = award_block.attr("data-original-title").trim()
awardBlock = @findEmojiIcon(emoji).parent()
origTitle = awardBlock.attr('data-original-title').trim()
authors = []
if origTitle
authors = origTitle.split(', ')
authors.push("me")
award_block.attr("data-original-title", authors.join(", "))
@resetTooltip(award_block)
authors.push('me')
awardBlock.attr('data-original-title', authors.join(', '))
@resetTooltip(awardBlock)
resetTooltip: (award) ->
award.tooltip("destroy")
award.tooltip('destroy')
# "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout.
setTimeout (->
@ -139,20 +139,28 @@ class @AwardsHandler
"</button>"
)
emoji_node = $(nodes.join("\n"))
.insertBefore(".js-award-holder")
.find(".emoji-icon")
.data("emoji", emoji)
$(nodes.join("\n"))
.insertBefore('.js-award-holder')
.find('.emoji-icon')
.data('emoji', emoji)
$('.award-control').tooltip()
resolveNameToCssClass: (emoji) ->
"emoji-#{@unicodes[emoji]}"
emojiIcon = $(".emoji-menu-content [data-emoji='#{emoji}']")
if emojiIcon.length > 0
unicodeName = emojiIcon.data('unicode-name')
else
# Find by alias
unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data('unicode-name')
"emoji-#{unicodeName}"
postEmoji: (emoji, callback) ->
$.post @post_emoji_url, { note: {
$.post @postEmojiUrl, { note: {
note: ":#{emoji}:"
noteable_type: @noteable_type
noteable_id: @noteable_id
noteable_type: @noteableType
noteable_id: @noteableId
}},(data) ->
if data.ok
callback.call()
@ -166,42 +174,42 @@ class @AwardsHandler
}, 200)
addEmojiToFrequentlyUsedList: (emoji) ->
frequently_used_emojis = @getFrequentlyUsedEmojis()
frequently_used_emojis.push(emoji)
$.cookie('frequently_used_emojis', frequently_used_emojis.join(","), { expires: 365 })
frequentlyUsedEmojis = @getFrequentlyUsedEmojis()
frequentlyUsedEmojis.push(emoji)
$.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 })
getFrequentlyUsedEmojis: ->
frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",")
_.compact(_.uniq(frequently_used_emojis))
frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(',')
_.compact(_.uniq(frequentlyUsedEmojis))
renderFrequentlyUsedBlock: ->
if $.cookie('frequently_used_emojis')
frequently_used_emojis = @getFrequentlyUsedEmojis()
frequentlyUsedEmojis = @getFrequentlyUsedEmojis()
ul = $("<ul>")
ul = $('<ul>')
for emoji in frequently_used_emojis
for emoji in frequentlyUsedEmojis
do (emoji) ->
$(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul)
$(".emoji-menu-content [data-emoji='#{emoji}']").closest('li').clone().appendTo(ul)
$("input.emoji-search").after(ul).after($("<h5>").text("Frequently used"))
$('input.emoji-search').after(ul).after($('<h5>').text('Frequently used'))
setupSearch: ->
$("input.emoji-search").keyup (ev) =>
$('input.emoji-search').keyup (ev) =>
term = $(ev.target).val()
# Clean previous search results
$("ul.emoji-menu-search, h5.emoji-search").remove()
$('ul.emoji-menu-search, h5.emoji-search').remove()
if term
# Generate a search result block
h5 = $("<h5>").text("Search results").addClass("emoji-search")
found_emojis = @searchEmojis(term).show()
ul = $("<ul>").addClass("emoji-menu-list emoji-menu-search").append(found_emojis)
$(".emoji-menu-content ul, .emoji-menu-content h5").hide()
$(".emoji-menu-content").append(h5).append(ul)
h5 = $('<h5>').text('Search results').addClass('emoji-search')
foundEmojis = @searchEmojis(term).show()
ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis)
$('.emoji-menu-content ul, .emoji-menu-content h5').hide()
$('.emoji-menu-content').append(h5).append(ul)
else
$(".emoji-menu-content").children().show()
$('.emoji-menu-content').children().show()
searchEmojis: (term)->
$(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone()

View File

@ -1,34 +1,6 @@
# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.
#
# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
#
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
# WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
# GO AFTER THE REQUIRES BELOW.
#
#= require pager
#= require jquery_nested_form
#= require_tree .
#
$(document).on 'click', '.edit-runner-link', (event) ->
event.preventDefault()
descr = $(this).closest('.runner-description').first()
descr.addClass('hide')
form = descr.next('.runner-description-form')
descrInput = form.find('input.description')
originalValue = descrInput.val()
form.removeClass('hide')
form.find('.cancel').on 'click', (event) ->
event.preventDefault()
form.addClass('hide')
descrInput.val(originalValue)
descr.removeClass('hide')
$(document).on 'click', '.assign-all-runner', ->
$(this).replaceWith('<i class="fa fa-refresh fa-spin"></i> Assign in progress..')

View File

@ -12,6 +12,7 @@ class @Issue
@initMergeRequests()
@initRelatedBranches()
@initCanCreateBranch()
initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable')
@ -92,3 +93,25 @@ class @Issue
.success (data) ->
if 'html' of data
$container.html(data.html)
initCanCreateBranch: ->
$container = $('div#new-branch')
# If the user doesn't have the required permissions the container isn't
# rendered at all.
return unless $container
$.getJSON($container.data('path'))
.error ->
$container.find('.checking').hide()
$container.find('.unavailable').show()
new Flash('Failed to check if a new branch can be created.', 'alert')
.success (data) ->
if data.can_create_branch
$container.find('.checking').hide()
$container.find('.available').show()
$container.find('a').attr('disabled', false)
else
$container.find('.checking').hide()
$container.find('.unavailable').show()

View File

@ -163,6 +163,21 @@ class @LabelsSelect
$.ajax(
url: labelUrl
).done (data) ->
data = _.chain data
.groupBy (label) ->
label.title
.map (label) ->
color = _.map label, (dup) ->
dup.color
return {
id: label[0].id
title: label[0].title
color: color
duplicate: color.length > 1
}
.value()
if $dropdown.hasClass 'js-extra-options'
if showNo
data.unshift(
@ -178,6 +193,7 @@ class @LabelsSelect
if data.length > 2
data.splice 2, 0, 'divider'
callback data
renderRow: (label) ->
@ -192,11 +208,31 @@ class @LabelsSelect
if $dropdown.hasClass('js-multiselect') and removesAll
selectedClass.push 'dropdown-clear-active'
color = if label.color? then "<span class='dropdown-label-box' style='background-color: #{label.color}'></span>" else ""
if label.duplicate
spacing = 100 / label.color.length
# Reduce the colors to 4
label.color = label.color.filter (color, i) ->
i < 4
color = _.map(label.color, (color, i) ->
percentFirst = Math.floor(spacing * i)
percentSecond = Math.floor(spacing * (i + 1))
"#{color} #{percentFirst}%,#{color} #{percentSecond}% "
).join(',')
color = "linear-gradient(#{color})"
else
if label.color?
color = label.color[0]
if color
colorEl = "<span class='dropdown-label-box' style='background: #{color}'></span>"
else
colorEl = ''
"<li>
<a href='#' class='#{selectedClass.join(' ')}'>
#{color}
#{colorEl}
#{_.escape(label.title)}
</a>
</li>"

View File

@ -9,11 +9,12 @@ class @MergeRequestWidget
constructor: (@opts) ->
$('#modal_merge_info').modal(show: false)
@firstCICheck = true
@readyForCICheck = true
@readyForCICheck = false
clearInterval @fetchBuildStatusInterval
@clearEventListeners()
@addEventListeners()
@getCIStatus(false)
@pollCIStatus()
notifyPermissions()
@ -68,20 +69,18 @@ class @MergeRequestWidget
$.getJSON @opts.ci_status_url, (data) =>
@readyForCICheck = true
if @firstCICheck
@firstCICheck = false
@opts.ci_status = data.status
if @opts.ci_status is ''
@opts.ci_status = data.status
if data.status is ''
return
if data.status isnt @opts.ci_status and data.status?
if @firstCICheck || data.status isnt @opts.ci_status and data.status?
@opts.ci_status = data.status
@showCIStatus data.status
if data.coverage
@showCICoverage data.coverage
if showNotification
# The first check should only update the UI, a notification
# should only be displayed on status changes
if showNotification and not @firstCICheck
status = @ciLabelForStatus(data.status)
if status is "preparing"
@ -104,8 +103,7 @@ class @MergeRequestWidget
@close()
Turbolinks.visit _this.opts.builds_path
)
@opts.ci_status = data.status
@firstCICheck = false
showCIStatus: (state) ->
$('.ci_widget').hide()

View File

@ -167,8 +167,8 @@ class @Notes
return
if note.award
awards_handler.addAwardToEmojiBar(note.note)
awards_handler.scrollToAwards()
awardsHandler.addAwardToEmojiBar(note.note)
awardsHandler.scrollToAwards()
# render note if it not present in loaded list
# or skip if rendered
@ -373,11 +373,11 @@ class @Notes
new GLForm form
if scrollTo? and myLastNote?
# scroll to the bottom
# scroll to the bottom
# so the open of the last element doesn't make a jump
$('html, body').scrollTop($(document).height());
$('html, body').animate({
scrollTop: myLastNote.offset().top - 150
scrollTop: myLastNote.offset().top - 150
}, 500, ->
$noteText = form.find(".js-note-text")
$noteText.focus()

View File

@ -6,6 +6,10 @@ class @ShortcutsIssuable extends ShortcutsNavigation
super()
Mousetrap.bind('a', @openSidebarDropdown.bind(@, 'assignee'))
Mousetrap.bind('m', @openSidebarDropdown.bind(@, 'milestone'))
Mousetrap.bind('r', =>
@replyWithSelectedText()
return false
)
Mousetrap.bind('j', =>
@prevIssue()
return false

View File

@ -12,7 +12,7 @@ toggleSidebar = ->
niceScrollBars.updateScrollBar();
), 300
$(document).on("click", '.toggle-nav-collapse', (e) ->
$(document).on("click", '.toggle-nav-collapse, .side-nav-toggle', (e) ->
e.preventDefault()
toggleSidebar()

View File

@ -25,6 +25,7 @@
@import "framework/lists.scss";
@import "framework/markdown_area.scss";
@import "framework/mobile.scss";
@import "framework/modal.scss";
@import "framework/nav.scss";
@import "framework/pagination.scss";
@import "framework/progress.scss";

View File

@ -28,6 +28,7 @@
&.s46 { width: 46px; height: 46px; margin-right: 15px; }
&.s48 { width: 48px; height: 48px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; }
&.s70 { width: 70px; height: 70px; margin-right: 14px; }
&.s90 { width: 90px; height: 90px; margin-right: 15px; }
&.s110 { width: 110px; height: 110px; margin-right: 15px; }
&.s140 { width: 140px; height: 140px; margin-right: 20px; }

View File

@ -1,5 +1,5 @@
.light-well {
background-color: #f8fafc;
background-color: $background-color;
padding: 15px;
}
@ -18,7 +18,7 @@
line-height: 36px;
}
.gray-content-block {
.row-content-block {
margin-top: 0;
margin-bottom: -$gl-padding;
background-color: $background-color;
@ -81,6 +81,11 @@
margin-left: 10px;
}
}
&.build-content {
background-color: $white-light;
border-top: none;
}
}
.cover-block {
@ -113,7 +118,7 @@
line-height: 1.1;
h1 {
color: #313236;
color: $gl-gray-dark;
margin-bottom: 6px;
font-size: 23px;
}
@ -150,6 +155,41 @@
right: auto;
}
}
&.groups-cover-block {
background: $white-light;
border-bottom: 1px solid $border-color;
text-align: left;
padding: 24px 0;
.group-info {
.cover-title {
margin-top: 9px;
}
p {
margin-bottom: 0;
}
}
@media (max-width: $screen-xs-max) {
text-align: center;
.avatar {
float: none;
}
}
}
.group-info {
h1 {
display: inline;
font-weight: normal;
font-size: 24px;
color: $gl-title-color;
}
}
}
.block-connector {

View File

@ -59,7 +59,7 @@
}
@mixin btn-gray {
@include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236);
@include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, $gl-gray-dark);
}
@mixin btn-white {
@ -139,6 +139,10 @@
pointer-events: auto !important;
}
&[disabled] {
pointer-events: none !important;
}
.caret {
margin-left: 5px;
}
@ -247,3 +251,10 @@
.btn-file-option {
background: linear-gradient(180deg, $white-light 25%, $gray-light 100%);
}
.btn-build {
margin-left: 10px;
i {
color: $gl-icon-color;
}
}

View File

@ -24,6 +24,10 @@
background-color: $color-darker;
a {
color: #fff;
h3 {
color: #fff;
}
}
}
}

View File

@ -8,7 +8,7 @@ header {
&.navbar-empty {
height: 58px;
background: #fff;
border-bottom: 1px solid #eee;
border-bottom: 1px solid $btn-gray-hover;
.center-logo {
margin: 11px 0;
@ -22,14 +22,22 @@ header {
}
&.navbar-gitlab {
padding: 0 20px;
padding: 0 16px;
z-index: 100;
margin-bottom: 0;
min-height: $header-height;
height: $header-height;
background-color: $background-color;
border: none;
border-bottom: 1px solid $border-color;
@media (max-width: $screen-xs-min) {
padding: 0 16px;
}
&.with-horizontal-nav {
border-bottom: none;
}
.container-fluid {
width: 100% !important;
filter: none;
@ -56,16 +64,44 @@ header {
margin: 6px 0;
border-radius: 0;
position: absolute;
right: 2px;
right: -10px;
padding: 6px 10px;
&:hover {
background-color: #eee;
background-color: $btn-gray-hover;
}
&.active {
color: $gl-icon-color;
}
}
}
&.header-collapsed {
padding: 0 16px;
}
.side-nav-toggle {
display: none;
position: absolute;
left: -10px;
margin: 6px 0;
padding: 6px 10px;
border: none;
background-color: $background-color;
&:hover {
background-color: $btn-gray-hover;
}
&:focus {
outline: none;
}
@media (max-width: $screen-xs-min) {
display: block;
}
}
}
.header-content {
@ -73,6 +109,10 @@ header {
height: $header-height;
padding-right: 40px;
@media (max-width: $screen-xs-min) {
padding-left: 40px;
}
@media (min-width: $screen-sm-min) {
padding-right: 0;
}
@ -141,6 +181,10 @@ header {
@media (min-width: $screen-md-min) {
@include collapsed-header;
}
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
}
.header-expanded {
@ -149,6 +193,10 @@ header {
@media (min-width: $screen-md-min) {
margin-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
}
@media (max-width: $screen-xs-max) {

View File

@ -30,7 +30,7 @@
}
.rss-btn {
display: none !important;
display: none;
}
.project-home-links {

View File

@ -0,0 +1,22 @@
.modal-body {
position: relative;
overflow-y: auto;
padding: 15px;
.form-actions {
margin: -$gl-padding+1;
margin-top: 15px;
}
.text-danger {
font-weight: bold;
}
}
body.modal-open {
overflow: hidden;
}
.modal .modal-dialog {
width: 860px;
}

View File

@ -26,8 +26,8 @@
}
&.active a {
color: #000;
border-bottom: 2px solid #4688f1;
border-bottom: 2px solid $link-underline-blue;
color: $black;
}
.badge {
@ -140,6 +140,12 @@
}
}
.project-filter-form {
input {
background-color: $background-color;
}
}
@media (max-width: $screen-xs-max) {
padding-bottom: 0;
@ -187,13 +193,35 @@
}
.layout-nav {
position: fixed;
top: $header-height;
width: 100%;
z-index: 1;
background: $background-color;
border-bottom: 1px solid $border-color;
transition-duration: .3s;
.container-fluid {
position: relative;
}
.controls {
float: right;
position: relative;
top: 10px;
padding: 7px 0 0;
i {
color: $layout-link-gray;
}
.fa-rss,
.fa-cog {
font-size: 16px;
}
.fa-caret-down {
margin-left: 5px;
color: $gl-icon-color;
}
.dropdown {
margin-left: 7px;
@ -202,5 +230,34 @@
.nav-links {
border-bottom: none;
height: 51px;
white-space: nowrap;
overflow-x: auto;
li {
a {
padding-top: 10px;
}
a, i {
color: $layout-link-gray;
}
&.active {
a, i {
color: $black;
}
}
.badge {
color: $gl-icon-color;
}
}
}
}
.page-with-layout-nav {
margin-top: 50px;
}

View File

@ -3,6 +3,7 @@
position: absolute;
width: 58px;
cursor: pointer;
margin-top: 8px;
}
.page-with-sidebar {
@ -62,7 +63,7 @@
float: left;
height: $header-height;
width: 100%;
padding: 11px 0 11px 22px;
padding-left: 22px;
overflow: hidden;
outline: none;
transition-duration: .3s;
@ -85,7 +86,7 @@
margin: 0;
margin-left: 50px;
font-size: 19px;
line-height: 41px;
line-height: 50px;
font-weight: normal;
}
}
@ -97,7 +98,7 @@
}
.sidebar-user {
padding: 9px 22px;
padding: 7px 22px;
position: fixed;
bottom: 40px;
width: $sidebar_width;
@ -209,15 +210,33 @@
}
}
.sidebar-wrapper {
&.hidden-nav {
width: 0;
}
}
.page-sidebar-collapsed {
padding-left: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-left: 0;
}
.sidebar-wrapper {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
.header-logo {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
a {
padding-left: ($sidebar_collapsed_width - 36) / 2;
@ -243,17 +262,35 @@
.collapse-nav a {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
}
.sidebar-user {
padding-left: ($sidebar_collapsed_width - 36) / 2;
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
padding-left: 0;
padding-right: 0;
}
.username {
display: none;
}
}
}
.layout-nav {
padding-right: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
}
}
.page-sidebar-expanded {
@ -263,6 +300,10 @@
padding-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
padding-left: 0;
}
.sidebar-wrapper {
width: $sidebar_width;
@ -280,6 +321,20 @@
}
}
}
.layout-nav {
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
padding-right: 62px;
}
@media (min-width: $screen-md-min) {
padding-right: $sidebar_width;
}
}
}
.right-sidebar-collapsed {

View File

@ -32,13 +32,11 @@ table {
th {
background-color: $background-color;
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid $border-color;
border-bottom: none;
}
td {
border-color: $table-border-color;
border-bottom: 1px solid $border-color;
}
}
}

View File

@ -81,7 +81,7 @@
// Labels
.label {
padding: 2px 4px;
padding: 4px 5px;
font-size: 13px;
font-style: normal;
font-weight: normal;

View File

@ -153,8 +153,8 @@ $nav-link-padding: 13px $gl-padding;
//== Code
//
//##
$pre-bg: #f8fafc !default;
$pre-bg: $background-color !default;
$pre-color: $gl-gray !default;
$pre-border-color: #e7e9ed;
$pre-border-color: $border-color;
$table-bg-accent: $background-color;

View File

@ -42,14 +42,14 @@
margin: 24px 0 12px;
padding: 0 0 10px;
border-bottom: 1px solid #e7e9ed;
color: #313236;
color: $gl-gray-dark;
}
h2 {
font-size: 1.2em;
font-weight: 600;
margin: 24px 0 12px;
color: #313236;
color: $gl-gray-dark;
}
h3 {
@ -205,6 +205,10 @@ h1, h2, h3, h4, h5, h6 {
font-weight: 600;
}
.light-header {
font-weight: 600;
}
/** CODE **/
pre {
font-family: $monospace_font;
@ -259,3 +263,9 @@ h1, h2, h3, h4 {
color: $gl-gray;
}
}
.text-right-lg {
@media (min-width: $screen-lg-min) {
text-align: right;
}
}

View File

@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
$table-border-color: #eef0f2;
$table-border-color: #ececec;
$background-color: #fafafa;
/*
@ -20,7 +20,7 @@ $background-color: #fafafa;
*/
$gl-font-size: 15px;
$gl-title-color: #333;
$gl-text-color: #555;
$gl-text-color: #5c5c5c;
$gl-text-green: #4a2;
$gl-text-red: #d12f19;
$gl-text-orange: #d90;
@ -30,6 +30,7 @@ $gl-placeholder-color: #8f8f8f;
$gl-icon-color: $gl-placeholder-color;
$gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color;
$gl-gray-dark: #313236;
$gl-header-color: $gl-title-color;
/*
@ -65,7 +66,7 @@ $gl-padding-top: 10px;
$row-hover: #f4f8fe;
$progress-color: #c0392b;
$avatar_radius: 50%;
$header-height: 58px;
$header-height: 50px;
$fixed-layout-width: 1280px;
$gl-avatar-size: 40px;
$error-exclamation-point: #e62958;
@ -74,6 +75,9 @@ $btn-transparent-color: #8f8f8f;
$settings-icon-size: 18px;
$provider-btn-group-border: #e5e5e5;
$provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee;
$layout-link-gray: #7e7c7c;
$todo-alert-blue: #428bca;
/*
* Color schema
@ -108,6 +112,7 @@ $red-light: #e52c5a;
$red-normal: #d22852;
$red-dark: darken($red-normal, 5%);
$black: #000;
$black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: #f1f2f4;
@ -210,6 +215,7 @@ $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color;
$btn-active-gray: #ececec;
$btn-placeholder-gray: #c7c7c7;
$btn-white-active: #848484;
$btn-gray-hover: #eee;
/*
* Award emoji

View File

@ -83,3 +83,12 @@
}
}
}
table.builds {
.build-link {
a {
color: $gl-dark-link-color;
}
}
}

View File

@ -31,9 +31,23 @@
}
.commit-committer-link,
.commit-author-link {
color: #444;
color: $gl-gray;
font-weight: bold;
}
.time_ago {
margin-left: 8px;
}
.fa-clipboard {
color: $dropdown-title-btn-color;
}
.commit-info {
&.branches {
margin-left: 8px;
}
}
}
.commit-box {
@ -42,7 +56,7 @@
.commit-title {
margin: 0;
font-size: 23px;
color: #313236;
color: $gl-gray-dark;
}
.commit-description {
@ -83,6 +97,14 @@
}
}
.commit-action-buttons {
i {
color: $gl-icon-color;
font-size: 13px;
margin-right: 3px;
}
}
/*
* Commit message textarea for web editor and
* custom merge request message

View File

@ -22,7 +22,7 @@
.title {
margin: 0;
font-size: 23px;
color: #313236;
color: $gl-gray-dark;
}
.description {

View File

@ -55,25 +55,6 @@
}
}
.modal-body {
position: relative;
overflow-y: auto;
padding: 15px;
.form-actions {
margin: -$gl-padding+1;
margin-top: 15px;
}
}
body.modal-open {
overflow: hidden;
}
.modal .modal-dialog {
width: 860px;
}
.documentation {
padding: 7px;
}

View File

@ -104,7 +104,7 @@
font-weight: 600;
font-size: 17px;
margin: 5px 0;
color: #313236;
color: $gl-gray-dark;
}
p:last-child {
@ -136,7 +136,7 @@
}
.label-branch {
color: #313236;
color: $gl-gray-dark;
font-family: $monospace_font;
font-weight: bold;
overflow: hidden;
@ -272,3 +272,19 @@
display: inline-block;
width: 250px;
}
.table-holder {
.builds {
th {
background-color: $white-light;
color: $gl-placeholder-color;
}
th,
td {
padding: 16px;
}
}
}

View File

@ -28,7 +28,7 @@ li.milestone {
// Issue title
span a {
color: rgba(0,0,0,0.64);
color: $gl-text-color;
}
}
}
@ -51,7 +51,7 @@ li.milestone {
margin-top: 7px;
.issuable-number {
color: rgba(0,0,0,0.44);
color: $gl-placeholder-color;
margin-right: 5px;
}
.avatar {

View File

@ -114,10 +114,6 @@ ul.notes {
word-break: keep-all;
}
}
a {
word-break: break-all;
}
}
.note-header {
@ -172,6 +168,11 @@ ul.notes {
.notes {
background-color: $white-light;
}
a code {
top: 0;
margin-right: 0;
}
}
}
}

View File

@ -205,6 +205,7 @@
text-align: center;
}
}
.personal-access-tokens-revoked-label {
color: #bbb;
}
@ -215,4 +216,22 @@
.personal-access-tokens-token-column {
max-width: 500px
}
}
.user-profile {
@media (max-width: $screen-xs-max) {
.cover-block {
padding-top: 20px;
}
.cover-controls {
position: static;
margin-bottom: 20px;
.btn {
display: inline-block;
width: 46%;
}
}
}
}

View File

@ -178,7 +178,7 @@
.option-title {
font-weight: normal;
display: inline-block;
color: #313236;
color: $gl-gray-dark;
}
.option-descr {
@ -202,8 +202,31 @@
min-width: 200px;
}
.deploy-project-label {
margin: 1px;
.deploy-key-content {
@media (min-width: $screen-sm-min) {
float: left;
&:last-child {
float: right;
}
}
}
.deploy-key-projects {
@media (min-width: $screen-sm-min) {
line-height: 42px;
}
}
a.deploy-project-label {
padding: 5px;
margin-right: 5px;
color: $gl-gray;
background-color: $row-hover;
&:hover {
color: $gl-link-color;
}
}
.vs-public {
@ -256,12 +279,6 @@
}
}
table.table.protected-branches-list tr.no-border {
th, td {
border: 0;
}
}
.project-import .btn {
float: left;
margin-right: 10px;
@ -474,3 +491,14 @@ pre.light-well {
color: #fff;
}
}
.protected-branches-list {
a {
color: $gl-gray;
font-weight: 600;
&:hover {
color: $gl-link-color;
}
}
}

View File

@ -1,7 +1,7 @@
.container-fluid {
.ci-status {
padding: 2px 7px;
margin-right: 5px;
margin-right: 10px;
border: 1px solid #eee;
white-space: nowrap;
@include border-radius(4px);

View File

@ -6,9 +6,16 @@
.navbar-nav {
li {
.badge.todos-pending-count {
background-color: $gl-icon-color;
margin-top: -5px;
font-weight: normal;
background: $todo-alert-blue;
margin-left: -17px;
font-size: 11px;
color: white;
padding: 3px;
padding-top: 1px;
padding-bottom: 1px;
border-radius: 3px;
}
}
}

View File

@ -16,7 +16,7 @@
tr {
> td, > th {
line-height: 26px;
line-height: 23px;
}
&:hover {

View File

@ -6,12 +6,6 @@ class Admin::ApplicationController < ApplicationController
layout 'admin'
def authenticate_admin!
return render_404 unless current_user.is_admin?
end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
render_404 unless current_user.is_admin?
end
end

View File

@ -39,6 +39,12 @@ class Admin::HooksController < Admin::ApplicationController
end
def hook_params
params.require(:hook).permit(:url, :enable_ssl_verification, :push_events, :tag_push_events)
params.require(:hook).permit(
:enable_ssl_verification,
:push_events,
:tag_push_events,
:token,
:url
)
end
end

View File

@ -1,38 +0,0 @@
class Admin::ImpersonationController < Admin::ApplicationController
skip_before_action :authenticate_admin!, only: :destroy
before_action :user
before_action :authorize_impersonator!
def create
if @user.blocked?
flash[:alert] = "You cannot impersonate a blocked user"
redirect_to admin_user_path(@user)
else
session[:impersonator_id] = current_user.username
session[:impersonator_return_to] = admin_user_path(@user)
warden.set_user(user, scope: 'user')
flash[:alert] = "You are impersonating #{user.username}."
redirect_to root_path
end
end
def destroy
redirect = session[:impersonator_return_to]
warden.set_user(user, scope: 'user')
session[:impersonator_return_to] = nil
session[:impersonator_id] = nil
redirect_to redirect || root_path
end
def user
@user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
end
end

View File

@ -0,0 +1,26 @@
class Admin::ImpersonationsController < Admin::ApplicationController
skip_before_action :authenticate_admin!
before_action :authenticate_impersonator!
def destroy
original_user = current_user
warden.set_user(impersonator, scope: :user)
Gitlab::AppLogger.info("User #{original_user.username} has stopped impersonating #{impersonator.username}")
session[:impersonator_id] = nil
redirect_to admin_user_path(original_user)
end
private
def impersonator
@impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id]
end
def authenticate_impersonator!
render_404 unless impersonator && impersonator.is_admin? && !impersonator.blocked?
end
end

View File

@ -31,6 +31,24 @@ class Admin::UsersController < Admin::ApplicationController
user
end
def impersonate
if user.blocked?
flash[:alert] = "You cannot impersonate a blocked user"
redirect_to admin_user_path(user)
else
session[:impersonator_id] = current_user.id
warden.set_user(user, scope: :user)
Gitlab::AppLogger.info("User #{current_user.username} has started impersonating #{user.username}")
flash[:alert] = "You are now impersonating #{user.username}"
redirect_to root_path
end
end
def block
if user.block
redirect_back_or_admin_user(notice: "Successfully blocked")

View File

@ -126,7 +126,7 @@ class ApplicationController < ActionController::Base
end
def after_sign_out_path_for(resource)
current_application_settings.after_sign_out_path || new_user_session_path
current_application_settings.after_sign_out_path.presence || new_user_session_path
end
def abilities

View File

@ -1,6 +1,6 @@
class Dashboard::LabelsController < Dashboard::ApplicationController
def index
labels = Label.where(project_id: projects).select(:title, :color).uniq(:title)
labels = Label.where(project_id: projects).select(:id, :title, :color).uniq(:title)
respond_to do |format|
format.json { render json: labels }

View File

@ -15,7 +15,7 @@ class Projects::CommitsController < Projects::ApplicationController
if search.present?
@repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact
else
@repository.commits(@ref, @path, @limit, @offset)
@repository.commits(@ref, path: @path, limit: @limit, offset: @offset)
end
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).

View File

@ -7,31 +7,24 @@ class Projects::DeployKeysController < Projects::ApplicationController
layout "project_settings"
def index
@enabled_keys = @project.deploy_keys
@available_keys = accessible_keys - @enabled_keys
@available_project_keys = current_user.project_deploy_keys - @enabled_keys
@available_public_keys = DeployKey.are_public - @enabled_keys
# Public keys that are already used by another accessible project are already
# in @available_project_keys.
@available_public_keys -= @available_project_keys
@key = DeployKey.new
set_index_vars
end
def new
@key = @project.deploy_keys.new
respond_with(@key)
redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project)
end
def create
@key = DeployKey.new(deploy_key_params)
set_index_vars
if @key.valid? && @project.deploy_keys << @key
redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project)
else
render "new"
render "index"
end
end
@ -51,6 +44,18 @@ class Projects::DeployKeysController < Projects::ApplicationController
protected
def set_index_vars
@enabled_keys ||= @project.deploy_keys
@available_keys ||= accessible_keys - @enabled_keys
@available_project_keys ||= current_user.project_deploy_keys - @enabled_keys
@available_public_keys ||= DeployKey.are_public - @enabled_keys
# Public keys that are already used by another accessible project are already
# in @available_project_keys.
@available_public_keys -= @available_project_keys
end
def accessible_keys
@accessible_keys ||= current_user.accessible_deploy_keys
end

View File

@ -17,7 +17,7 @@ class Projects::GraphsController < Projects::ApplicationController
end
def commits
@commits = @project.repository.commits(@ref, nil, 2000, 0, true)
@commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true)
@commits_graph = Gitlab::Graphs::Commits.new(@commits)
@commits_per_week_days = @commits_graph.commits_per_week_days
@commits_per_time = @commits_graph.commits_per_time
@ -55,7 +55,7 @@ class Projects::GraphsController < Projects::ApplicationController
private
def fetch_graph
@commits = @project.repository.commits(@ref, nil, 6000, 0, true)
@commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true)
@log = []
@commits.each do |commit|

View File

@ -52,8 +52,16 @@ class Projects::HooksController < Projects::ApplicationController
end
def hook_params
params.require(:hook).permit(:url, :push_events, :issues_events,
:merge_requests_events, :tag_push_events, :note_events,
:build_events, :enable_ssl_verification)
params.require(:hook).permit(
:build_events,
:enable_ssl_verification,
:issues_events,
:merge_requests_events,
:note_events,
:push_events,
:tag_push_events,
:token,
:url
)
end
end

View File

@ -3,8 +3,8 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableActions
before_action :module_enabled
before_action :issue,
only: [:edit, :update, :show, :referenced_merge_requests, :related_branches]
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
:related_branches, :can_create_branch]
# Allow read any issue
before_action :authorize_read_issue!, only: [:show]
@ -96,6 +96,8 @@ class Projects::IssuesController < Projects::ApplicationController
if params[:move_to_project_id].to_i > 0
new_project = Project.find(params[:move_to_project_id])
return render_404 unless issue.can_move?(current_user, new_project)
move_service = Issues::MoveService.new(project, current_user)
@issue = move_service.execute(@issue, new_project)
end
@ -139,6 +141,18 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
def can_create_branch
can_create = current_user &&
can?(current_user, :push_code, @project) &&
@issue.can_be_worked_on?(current_user)
respond_to do |format|
format.json do
render json: { can_create_branch: can_create }
end
end
end
def bulk_update
result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
redirect_back_or_default(default: { action: 'index' }, options: { notice: "#{result[:count]} issues updated" })

View File

@ -40,10 +40,10 @@ class Projects::WikisController < Projects::ApplicationController
end
def update
@page = @project_wiki.find_page(params[:id])
return render('empty') unless can?(current_user, :create_wiki, @project)
@page = @project_wiki.find_page(params[:id])
if @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
redirect_to(
namespace_project_wiki_path(@project.namespace, @project, @page),

View File

@ -8,6 +8,13 @@ class RegistrationsController < Devise::RegistrationsController
def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
# To avoid duplicate form fields on the login page, the registration form
# names fields using `new_user`, but Devise still wants the params in
# `user`.
if params["new_#{resource_name}"].present? && params[resource_name].blank?
params[resource_name] = params.delete(:"new_#{resource_name}")
end
super
else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."

View File

@ -51,7 +51,7 @@ class SnippetsFinder
snippets = project.snippets.fresh
if current_user
if project.team.member?(current_user.id)
if project.team.member?(current_user.id) || current_user.admin?
snippets
else
snippets.public_and_internal

View File

@ -3,8 +3,8 @@ module BlobHelper
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
end
def highlight(blob_name, blob_content, nowrap: false)
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap)
def highlight(blob_name, blob_content, nowrap: false, plain: false)
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain)
end
def no_highlight_files
@ -131,7 +131,7 @@ module BlobHelper
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
def sanitize_svg(blob)
blob.data = Loofah.scrub_fragment(blob.data, :strip).to_xml
blob.data = Gitlab::Sanitizers::SVG.clean(blob.data)
blob
end

View File

@ -1,13 +0,0 @@
module CiBadgeHelper
def markdown_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
link = namespace_project_commits_path(project.namespace, project, ref)
"[![build status](#{url})](#{link})"
end
def html_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
link = namespace_project_commits_path(project.namespace, project, ref)
"<a href='#{link}'><img src='#{url}' /></a>"
end
end

View File

@ -16,31 +16,49 @@ module IssuesHelper
def url_for_project_issues(project = @project, options = {})
return '' if project.nil?
if options[:only_path]
project.issues_tracker.project_path
else
project.issues_tracker.project_url
end
url =
if options[:only_path]
project.issues_tracker.project_path
else
project.issues_tracker.project_url
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def url_for_new_issue(project = @project, options = {})
return '' if project.nil?
if options[:only_path]
project.issues_tracker.new_issue_path
else
project.issues_tracker.new_issue_url
end
url =
if options[:only_path]
project.issues_tracker.new_issue_path
else
project.issues_tracker.new_issue_url
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def url_for_issue(issue_iid, project = @project, options = {})
return '' if project.nil?
if options[:only_path]
project.issues_tracker.issue_path(issue_iid)
else
project.issues_tracker.issue_url(issue_iid)
end
url =
if options[:only_path]
project.issues_tracker.issue_path(issue_iid)
else
project.issues_tracker.issue_url(issue_iid)
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def bulk_update_milestone_options

View File

@ -34,10 +34,13 @@ module NavHelper
end
def nav_header_class
if nav_menu_collapsed?
"header-collapsed"
else
"header-expanded"
end
class_name =
if nav_menu_collapsed?
"header-collapsed"
else
"header-expanded"
end
class_name += " with-horizontal-nav" if defined?(nav) && nav
class_name
end
end

View File

@ -200,16 +200,13 @@ module ProjectsHelper
end
def repository_size(project = @project)
"#{project.repository_size} MB"
rescue
# In order to prevent 500 error
# when application cannot allocate memory
# to calculate repo size - just show 'Unknown'
'unknown'
size_in_bytes = project.repository_size * 1.megabyte
number_to_human_size(size_in_bytes, delimiter: ',', precision: 2)
end
def default_url_to_repo(project = @project)
if default_clone_protocol == "ssh"
case default_clone_protocol
when 'ssh'
project.ssh_url_to_repo
else
project.http_url_to_repo
@ -341,4 +338,10 @@ module ProjectsHelper
)
end
end
def sanitize_repo_path(message)
return '' unless message.present?
message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]")
end
end

View File

@ -28,6 +28,14 @@ module Emails
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
end
def note_snippet_email(recipient_id, note_id)
setup_note_mail(note_id, recipient_id)
@snippet = @note.noteable
@target_url = namespace_project_snippet_url(*note_target_url_options)
mail_answer_thread(@snippet, note_thread_options(recipient_id))
end
private
def note_target_url_options

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: abuse_reports
#
# id :integer not null, primary key
# reporter_id :integer
# user_id :integer
# message :text
# created_at :datetime
# updated_at :datetime
#
class AbuseReport < ActiveRecord::Base
belongs_to :reporter, class_name: 'User'
belongs_to :user

View File

@ -1,51 +1,3 @@
# == Schema Information
#
# Table name: application_settings
#
# id :integer not null, primary key
# default_projects_limit :integer
# signup_enabled :boolean
# signin_enabled :boolean
# gravatar_enabled :boolean
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
# home_page_url :string(255)
# default_branch_protection :integer default(2)
# restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null
# default_project_visibility :integer
# default_snippet_visibility :integer
# default_group_visibility :integer
# restricted_signup_domains :text
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# import_sources :text
# help_page_text :text
# admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
# runners_registration_token :string
# require_two_factor_authentication :boolean default(FALSE)
# two_factor_grace_period :integer default(48)
# metrics_enabled :boolean default(FALSE)
# metrics_host :string default("localhost")
# metrics_username :string
# metrics_password :string
# metrics_pool_size :integer default(16)
# metrics_timeout :integer default(10)
# metrics_method_call_threshold :integer default(10)
# recaptcha_enabled :boolean default(FALSE)
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
# email_author_in_body :boolean default(FALSE)
#
class ApplicationSetting < ActiveRecord::Base
include TokenAuthenticatable
add_authentication_token_field :runners_registration_token

View File

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: audit_events
#
# id :integer not null, primary key
# author_id :integer not null
# type :string(255) not null
# entity_id :integer not null
# entity_type :string(255) not null
# details :text
# created_at :datetime
# updated_at :datetime
#
class AuditEvent < ActiveRecord::Base
serialize :details, Hash

View File

@ -19,6 +19,14 @@ class Blob < SimpleDelegator
new(blob)
end
def no_highlighting?
size && size > 1.megabyte
end
def only_display_raw?
size && size > 5.megabytes
end
def svg?
text? && language && language.name == 'SVG'
end

View File

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: broadcast_messages
#
# id :integer not null, primary key
# message :text not null
# starts_at :datetime
# ends_at :datetime
# created_at :datetime
# updated_at :datetime
# color :string(255)
# font :string(255)
#
class BroadcastMessage < ActiveRecord::Base
include Sortable

View File

@ -1,40 +1,3 @@
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
# artifacts_metadata :text
# erased_by_id :integer
# erased_at :datetime
#
module Ci
class Build < CommitStatus
belongs_to :runner, class_name: 'Ci::Runner'

View File

@ -1,21 +1,3 @@
# == Schema Information
#
# Table name: ci_commits
#
# id :integer not null, primary key
# project_id :integer
# ref :string(255)
# sha :string(255)
# before_sha :string(255)
# push_data :text
# created_at :datetime
# updated_at :datetime
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
# gl_project_id :integer
#
module Ci
class Commit < ActiveRecord::Base
extend Ci::Model

View File

@ -1,22 +1,3 @@
# == Schema Information
#
# Table name: ci_runners
#
# id :integer not null, primary key
# token :string(255)
# created_at :datetime
# updated_at :datetime
# description :string(255)
# contacted_at :datetime
# active :boolean default(TRUE), not null
# is_shared :boolean default(FALSE)
# name :string(255)
# version :string(255)
# revision :string(255)
# platform :string(255)
# architecture :string(255)
#
module Ci
class Runner < ActiveRecord::Base
extend Ci::Model

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: ci_runner_projects
#
# id :integer not null, primary key
# runner_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
module Ci
class RunnerProject < ActiveRecord::Base
extend Ci::Model

View File

@ -1,16 +1,3 @@
# == Schema Information
#
# Table name: ci_triggers
#
# id :integer not null, primary key
# token :string(255)
# project_id :integer
# deleted_at :datetime
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
module Ci
class Trigger < ActiveRecord::Base
extend Ci::Model

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: ci_trigger_requests
#
# id :integer not null, primary key
# trigger_id :integer not null
# variables :text
# created_at :datetime
# updated_at :datetime
# commit_id :integer
#
module Ci
class TriggerRequest < ActiveRecord::Base
extend Ci::Model

View File

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: ci_variables
#
# id :integer not null, primary key
# project_id :integer
# key :string(255)
# value :text
# encrypted_value :text
# encrypted_value_salt :string(255)
# encrypted_value_iv :string(255)
# gl_project_id :integer
#
module Ci
class Variable < ActiveRecord::Base
extend Ci::Model

View File

@ -1,37 +1,3 @@
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
#
class CommitStatus < ActiveRecord::Base
include Statuseable

View File

@ -35,13 +35,14 @@ module Issuable
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
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 :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
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) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
scope :outer_join_milestone, -> { joins("LEFT OUTER JOIN milestones ON milestones.id = #{table_name}.milestone_id") }
delegate :name,
:email,
@ -123,8 +124,8 @@ module Issuable
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}")
if title.is_a?(Array) && title.size > 1
joins(:labels).where(labels: { title: title }).group(arel_table[:id]).having("COUNT(DISTINCT labels.title) = #{title.size}")
else
joins(:labels).where(labels: { title: title })
end
@ -159,6 +160,10 @@ module Issuable
notes.awards.where(note: "thumbsup").count
end
def user_notes_count
notes.user.count
end
def subscribed_without_subscriptions?(user)
participants(user).include?(user)
end

View File

@ -43,8 +43,8 @@ module Mentionable
self
end
def all_references(current_user = self.author, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, self.author)
def all_references(current_user = nil, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user || self.author, self.author)
if text
ext.analyze(text)

View File

@ -8,7 +8,7 @@ module Milestoneish
end
def complete?(user = nil)
total_items_count(user) == closed_items_count(user)
total_items_count(user) > 0 && total_items_count(user) == closed_items_count(user)
end
def percent_complete(user = nil)

View File

@ -1,18 +1,3 @@
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string(255)
# type :string(255)
# fingerprint :string(255)
# public :boolean default(FALSE), not null
#
class DeployKey < Key
has_many :deploy_keys_projects, dependent: :destroy
has_many :projects, through: :deploy_keys_projects

View File

@ -1,14 +1,3 @@
# == Schema Information
#
# Table name: deploy_keys_projects
#
# id :integer not null, primary key
# deploy_key_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class DeployKeysProject < ActiveRecord::Base
belongs_to :project
belongs_to :deploy_key

View File

@ -1,14 +1,3 @@
# == Schema Information
#
# Table name: emails
#
# id :integer not null, primary key
# user_id :integer not null
# email :string(255) not null
# created_at :datetime
# updated_at :datetime
#
class Email < ActiveRecord::Base
include Sortable

View File

@ -1,19 +1,3 @@
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# target_type :string(255)
# target_id :integer
# title :string(255)
# data :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
# action :integer
# author_id :integer
#
class Event < ActiveRecord::Base
include Sortable
default_scope { where.not(author_id: nil) }

View File

@ -1,14 +1,3 @@
# == Schema Information
#
# Table name: forked_project_links
#
# id :integer not null, primary key
# forked_to_project_id :integer not null
# forked_from_project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class ForkedProjectLink < ActiveRecord::Base
belongs_to :forked_to_project, class_name: Project
belongs_to :forked_from_project, class_name: Project

View File

@ -1,37 +1,3 @@
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
#
class GenericCommitStatus < CommitStatus
before_validation :set_default_values

View File

@ -1,19 +1,3 @@
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
# path :string(255) not null
# owner_id :integer
# visibility_level :integer default(20), not null
# created_at :datetime
# updated_at :datetime
# type :string(255)
# description :string(255) default(""), not null
# avatar :string(255)
#
require 'carrierwave/orm/activerecord'
class Group < Namespace

View File

@ -1,23 +1,3 @@
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
#
class ProjectHook < WebHook
belongs_to :project

View File

@ -1,23 +1,3 @@
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
#
class ServiceHook < WebHook
belongs_to :service

View File

@ -1,23 +1,3 @@
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
#
class SystemHook < WebHook
def async_execute(data, hook_name)
Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name)

View File

@ -1,23 +1,3 @@
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
#
class WebHook < ActiveRecord::Base
include Sortable
include HTTParty
@ -43,23 +23,17 @@ class WebHook < ActiveRecord::Base
if parsed_url.userinfo.blank?
response = WebHook.post(url,
body: data.to_json,
headers: {
"Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize
},
headers: build_headers(hook_name),
verify: enable_ssl_verification)
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
post_url = url.gsub("#{parsed_url.userinfo}@", '')
auth = {
username: CGI.unescape(parsed_url.user),
password: CGI.unescape(parsed_url.password),
}
response = WebHook.post(post_url,
body: data.to_json,
headers: {
"Content-Type" => "application/json",
"X-Gitlab-Event" => hook_name.singularize.titleize
},
headers: build_headers(hook_name),
verify: enable_ssl_verification,
basic_auth: auth)
end
@ -73,4 +47,15 @@ class WebHook < ActiveRecord::Base
def async_execute(data, hook_name)
Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data, hook_name)
end
private
def build_headers(hook_name)
headers = {
'Content-Type' => 'application/json',
'X-Gitlab-Event' => hook_name.singularize.titleize
}
headers['X-Gitlab-Token'] = token if token.present?
headers
end
end

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: identities
#
# id :integer not null, primary key
# extern_uid :string(255)
# provider :string(255)
# user_id :integer
# created_at :datetime
# updated_at :datetime
#
class Identity < ActiveRecord::Base
include Sortable
include CaseSensitivity

View File

@ -1,24 +1,3 @@
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# title :string(255)
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime
# updated_at :datetime
# position :integer default(0)
# branch_name :string(255)
# description :text
# milestone_id :integer
# state :string(255)
# iid :integer
# updated_by_id :integer
# moved_to_id :integer
#
require 'carrierwave/orm/activerecord'
class Issue < ActiveRecord::Base

View File

@ -1,18 +1,3 @@
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string(255)
# type :string(255)
# fingerprint :string(255)
# public :boolean default(FALSE), not null
#
require 'digest/md5'
class Key < ActiveRecord::Base

View File

@ -1,17 +1,3 @@
# == Schema Information
#
# Table name: labels
#
# id :integer not null, primary key
# title :string(255)
# color :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# template :boolean default(FALSE)
# description :string(255)
#
class Label < ActiveRecord::Base
include Referable
include Subscribable
@ -117,6 +103,10 @@ class Label < ActiveRecord::Base
LabelsHelper::text_color_for_bg(self.color)
end
def title=(value)
write_attribute(:title, Sanitize.clean(value.to_s)) if value.present?
end
private
def label_format_reference(format = :id)

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: label_links
#
# id :integer not null, primary key
# label_id :integer
# target_id :integer
# target_type :string(255)
# created_at :datetime
# updated_at :datetime
#
class LabelLink < ActiveRecord::Base
belongs_to :target, polymorphic: true
belongs_to :label

View File

@ -1,15 +1,3 @@
# == Schema Information
#
# Table name: lfs_objects
#
# id :integer not null, primary key
# oid :string(255) not null
# size :integer not null
# created_at :datetime
# updated_at :datetime
# file :string(255)
#
class LfsObject < ActiveRecord::Base
has_many :lfs_objects_projects, dependent: :destroy
has_many :projects, through: :lfs_objects_projects

View File

@ -1,14 +1,3 @@
# == Schema Information
#
# Table name: lfs_objects_projects
#
# id :integer not null, primary key
# lfs_object_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class LfsObjectsProject < ActiveRecord::Base
belongs_to :project
belongs_to :lfs_object

View File

@ -1,22 +1,3 @@
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string(255) not null
# user_id :integer
# notification_level :integer not null
# type :string(255)
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string(255)
# invite_token :string(255)
# invite_accepted_at :datetime
#
class Member < ActiveRecord::Base
include Sortable
include Gitlab::Access

View File

@ -1,22 +1,3 @@
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string(255) not null
# user_id :integer
# notification_level :integer not null
# type :string(255)
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string(255)
# invite_token :string(255)
# invite_accepted_at :datetime
#
class GroupMember < Member
SOURCE_TYPE = 'Namespace'

Some files were not shown because too many files have changed in this diff Show More