Commit 539de0dd authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into rs-redactor-filter

parents b093cb35 0b9273a2
Please view this file on the master branch, on stable branches it's out of date.
v 8.1.0 (unreleased)
- Make diff file view easier to use on mobile screens (Stan Hu)
- Add support for creating directories from Files page (Stan Hu)
- Allow removing of project without confirmation when JavaScript is disabled (Stan Hu)
- Support filtering by "Any" milestone or issue and fix "No Milestone" and "No Label" filters (Stan Hu)
- Improved performance of the trending projects page
- Improved performance of finding projects by their namespace
- Fix bug where transferring a project would result in stale commit links (Stan Hu)
- Include full path of source and target branch names in New Merge Request page (Stan Hu)
- Add user preference to view activities as default dashboard (Stan Hu)
......@@ -10,6 +16,7 @@ v 8.1.0 (unreleased)
- Move CI charts to project graphs area
- Fix cases where Markdown did not render links in activity feed (Stan Hu)
- Add first and last to pagination (Zeger-Jan van de Weg)
- Added Commit Status API
- Show CI status on commit page
- Show CI status on Your projects page and Starred projects page
- Remove "Continuous Integration" page from dashboard
......@@ -33,6 +40,20 @@ v 8.1.0 (unreleased)
- Add user preference to change layout width (Peter Göbel)
- Use commit status in merge request widget as preffered source of CI status
- Integrate CI commit and build pages into project pages
- Move CI services page to project settings area
- Add "Quick Submit" behavior to input fields throughout the application. Use
Cmd+Enter on Mac and Ctrl+Enter on Windows/Linux.
- Fix position of hamburger in header for smaller screens (Han Loong Liauw)
- Fix bug where Emojis in Markdown would truncate remaining text (Sakata Sinji)
- Persist filters when sorting on admin user page (Jerry Lukins)
- Add spellcheck=false to certain input fields
- Invalidate stored service password if the endpoint URL is changed
- Project names are not fully shown if group name is too big, even on group page view
- Apply new design for Files page
- Add "New Page" button to Wiki Pages tab (Stan Hu)
- Only render 404 page from /public
- Hide passwords from services API (Alex Lossent)
- Fix: Images cannot show when projects' path was changed
v 8.0.4
- Fix Message-ID header to be RFC 2111-compliant to prevent e-mails being dropped (Stan Hu)
......@@ -41,11 +62,13 @@ v 8.0.4
- Remove CI token from build traces
- Fix "Assign All" button on Runner admin page
- Fix search in Files
- Add full project namespace to payload of system webhooks (Ricardo Band)
v 8.0.3
- Fix URL shown in Slack notifications
- Fix bug where projects would appear to be stuck in the forked import state (Stan Hu)
- Fix Error 500 in creating merge requests with > 1000 diffs (Stan Hu)
- Add work_in_progress key to MR web hooks (Ben Boeckel)
v 8.0.2
- Fix default avatar not rendering in network graph (Stan Hu)
......
......@@ -22,20 +22,20 @@ gem "mysql2", '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries
gem "devise", '~> 3.5.2'
gem "devise-async", '~> 0.9.0'
gem 'omniauth', "~> 1.2.2"
gem 'omniauth-google-oauth2', '~> 0.2.5'
gem 'omniauth-twitter', '~> 1.0.1'
gem 'devise', '~> 3.5.2'
gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-shibboleth', '~> 1.1.1'
gem 'omniauth-kerberos', '~> 0.2.0', group: :kerberos
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-google-oauth2', '~> 0.2.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-saml', '~> 1.4.0'
gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd'
gem "rack-oauth2", "~> 1.0.5"
gem 'rack-oauth2', '~> 1.0.5'
# Two-factor authentication
gem 'devise-two-factor', '~> 2.0.0'
......@@ -47,7 +47,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.17'
gem "gitlab_git", '~> 7.2.18'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -65,9 +65,9 @@ gem 'gollum-lib', '~> 4.0.2'
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
# API
gem "grape", "~> 0.6.1"
gem "grape-entity", "~> 0.4.2"
gem 'rack-cors', '~> 0.2.9', require: 'rack/cors'
gem 'grape', '~> 0.6.1'
gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times
# based on human-friendly examples
......@@ -80,7 +80,7 @@ gem 'enumerize', '~> 0.7.0'
gem "kaminari", "~> 0.16.3"
# HAML
gem "haml-rails", '~> 0.5.3'
gem "haml-rails", '~> 0.9.0'
# Files attachments
gem "carrierwave", '~> 0.9.0'
......@@ -128,7 +128,6 @@ gem 'after_commit_queue'
gem 'acts-as-taggable-on', '~> 3.4'
# Background jobs
gem 'slim', '~> 2.0.2'
gem 'sinatra', '~> 1.4.4', require: nil
gem 'sidekiq', '3.3.0'
gem 'sidetiq', '~> 0.6.3'
......@@ -151,7 +150,7 @@ gem 'version_sorter', '~> 2.0.0'
gem "redis-rails", '~> 4.0.0'
# Campfire integration
gem 'tinder', '~> 1.9.2'
gem 'tinder', '~> 1.10.0'
# HipChat integration
gem 'hipchat', '~> 1.5.0'
......@@ -163,7 +162,7 @@ gem "gitlab-flowdock-git-hook", "~> 1.0.1"
gem "gemnasium-gitlab-service", "~> 0.2"
# Slack integration
gem "slack-notifier", "~> 1.0.0"
gem "slack-notifier", "~> 1.2.0"
# Asana integration
gem 'asana', '~> 0.0.6'
......@@ -291,7 +290,7 @@ gem 'newrelic-grape'
gem 'octokit', '~> 3.7.0'
gem "mail_room", "~> 0.5.2"
gem "mail_room", "~> 0.6.0"
gem 'email_reply_parser', '~> 0.5.8'
......@@ -300,9 +299,6 @@ gem 'activerecord-deprecated_finders', '~> 1.0.3'
gem 'activerecord-session_store', '~> 0.1.0'
gem "nested_form", '~> 0.3.2'
# Scheduled
gem 'whenever', '~> 0.8.4', require: false
# OAuth
gem 'oauth2', '~> 1.0.0'
......
......@@ -105,7 +105,6 @@ GEM
celluloid (0.16.0)
timers (~> 4.0.0)
charlock_holmes (0.6.9.4)
chronic (0.10.2)
chunky_png (1.3.4)
cliver (0.3.2)
coderay (1.1.0)
......@@ -182,8 +181,8 @@ GEM
factory_girl_rails (4.3.0)
factory_girl (~> 4.3.0)
railties (>= 3.0.0)
faraday (0.8.10)
multipart-post (~> 1.2.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.10.0)
faraday (>= 0.7.4, < 0.10)
fastercsv (1.5.5)
......@@ -279,7 +278,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.1.1)
gemojione (~> 2.0)
gitlab_git (7.2.17)
gitlab_git (7.2.18)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
......@@ -330,12 +329,13 @@ GEM
rspec (>= 2.14, < 4.0)
haml (4.0.7)
tilt
haml-rails (0.5.3)
haml-rails (0.9.0)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
haml (>= 3.1, < 5.0)
haml (>= 4.0.6, < 5.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashie (2.1.2)
hashie (3.4.2)
highline (1.6.21)
hike (1.2.3)
hipchat (1.5.2)
......@@ -345,6 +345,11 @@ GEM
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
html2haml (2.0.0)
erubis (~> 2.7.0)
haml (~> 4.0.0)
nokogiri (~> 1.6.0)
ruby_parser (~> 3.5)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.5.3)
......@@ -387,7 +392,7 @@ GEM
systemu (~> 2.6.2)
mail (2.6.3)
mime-types (>= 1.16, < 3)
mail_room (0.5.2)
mail_room (0.6.0)
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
......@@ -396,7 +401,7 @@ GEM
mousetrap-rails (1.4.6)
multi_json (1.11.2)
multi_xml (0.5.5)
multipart-post (1.2.0)
multipart-post (2.0.0)
mysql2 (0.3.20)
nenv (0.2.0)
nested_form (0.3.2)
......@@ -440,7 +445,7 @@ GEM
omniauth-google-oauth2 (0.2.6)
omniauth (> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-kerberos (0.2.0)
omniauth-kerberos (0.3.0)
omniauth-multipassword
timfel-krb5-auth (~> 0.8)
omniauth-multipassword (0.4.2)
......@@ -454,11 +459,11 @@ GEM
omniauth-saml (1.4.1)
omniauth (~> 1.1)
ruby-saml (~> 1.0.0)
omniauth-shibboleth (1.1.2)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
omniauth-twitter (1.2.1)
json (~> 1.3)
omniauth-oauth (~> 1.1)
omniauth_crowd (2.2.3)
activesupport
nokogiri (>= 1.4.4)
......@@ -496,7 +501,7 @@ GEM
rack (>= 0.4)
rack-attack (4.3.0)
rack
rack-cors (0.2.9)
rack-cors (0.4.0)
rack-mini-profiler (0.9.7)
rack (>= 1.1.3)
rack-mount (0.8.3)
......@@ -666,10 +671,7 @@ GEM
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
six (0.2.0)
slack-notifier (1.0.0)
slim (2.0.3)
temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1)
slack-notifier (1.2.1)
slop (3.6.0)
spinach (0.8.10)
colorize
......@@ -705,7 +707,6 @@ GEM
railties (>= 3.2.5, < 5)
teaspoon-jasmine (2.2.0)
teaspoon (>= 1.0.0)
temple (0.6.10)
term-ansicolor (1.3.2)
tins (~> 1.0)
terminal-table (1.5.2)
......@@ -721,13 +722,13 @@ GEM
timers (4.0.4)
hitimes
timfel-krb5-auth (0.8.3)
tinder (1.9.4)
tinder (1.10.1)
eventmachine (~> 1.0)
faraday (~> 0.8.9)
faraday (~> 0.9.0)
faraday_middleware (~> 0.9)
hashie (>= 1.0, < 3)
hashie (>= 1.0)
json (~> 1.8.0)
mime-types (~> 1.19)
mime-types
multi_json (~> 1.7)
twitter-stream (~> 0.1)
tins (1.6.0)
......@@ -770,9 +771,6 @@ GEM
websocket-driver (0.6.2)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
whenever (0.8.4)
activesupport (>= 2.3.4)
chronic (>= 0.6.3)
wikicloth (0.8.1)
builder
expression_parser
......@@ -836,7 +834,7 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.17)
gitlab_git (~> 7.2.18)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.0.2)
......@@ -845,7 +843,7 @@ DEPENDENCIES
grape-entity (~> 0.4.2)
growl
guard-rspec (~> 4.2.0)
haml-rails (~> 0.5.3)
haml-rails (~> 0.9.0)
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
......@@ -856,7 +854,7 @@ DEPENDENCIES
jquery-ui-rails (~> 4.2.1)
kaminari (~> 0.16.3)
letter_opener (~> 1.1.2)
mail_room (~> 0.5.2)
mail_room (~> 0.6.0)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.3.16)
......@@ -870,11 +868,11 @@ DEPENDENCIES
omniauth-bitbucket (~> 0.0.2)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.5)
omniauth-kerberos (~> 0.2.0)
omniauth-google-oauth2 (~> 0.2.0)
omniauth-kerberos (~> 0.3.0)
omniauth-saml (~> 1.4.0)
omniauth-shibboleth (~> 1.1.1)
omniauth-twitter (~> 1.0.1)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)
omniauth_crowd
org-ruby (~> 0.9.12)
paranoia (~> 2.0)
......@@ -883,7 +881,7 @@ DEPENDENCIES
pry-rails
quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.0)
rack-cors (~> 0.2.9)
rack-cors (~> 0.4.0)
rack-mini-profiler (~> 0.9.0)
rack-oauth2 (~> 1.0.5)
rails (= 4.1.12)
......@@ -912,8 +910,7 @@ DEPENDENCIES
simplecov (~> 0.10.0)
sinatra (~> 1.4.4)
six (~> 0.2.0)
slack-notifier (~> 1.0.0)
slim (~> 2.0.2)
slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1)
spring (~> 1.3.6)
spring-commands-rspec (~> 1.0.4)
......@@ -927,7 +924,7 @@ DEPENDENCIES
teaspoon-jasmine (~> 2.2.0)
test_after_commit (~> 0.2.2)
thin (~> 1.6.1)
tinder (~> 1.9.2)
tinder (~> 1.10.0)
turbolinks (~> 2.5.0)
uglifier (~> 2.3.2)
underscore-rails (~> 1.4.4)
......@@ -937,7 +934,6 @@ DEPENDENCIES
version_sorter (~> 2.0.0)
virtus (~> 1.0.1)
webmock (~> 1.21.0)
whenever (~> 0.8.4)
wikicloth (= 0.8.1)
BUNDLED WITH
......
......@@ -79,7 +79,11 @@ Thanks for the issue report but we only support issues for the latest stable ver
### Support requests and configuration questions
Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://about.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
Thanks for your interest in GitLab. We don't use the issue tracker for support
requests and configuration questions. Please check our
\[getting help\]\(https://about.gitlab.com/getting-help/) page to see all of the available
support options. Also, have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md)
for more information.
### Code format
......
......@@ -71,7 +71,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1
- Git 1.7.10+
- Redis 2.0+
- Redis 2.4+
- MySQL or PostgreSQL
For more information please see the [architecture documentation](http://doc.gitlab.com/ce/development/architecture.html).
......
......@@ -180,6 +180,7 @@ $ ->
$('.navbar-toggle').on 'click', ->
$('.header-content .title').toggle()
$('.header-content .navbar-collapse').toggle()
$('.navbar-toggle').toggleClass('active')
# Show/hide comments on diff
$("body").on "click", ".js-toggle-diff-comments", (e) ->
......
# Quick Submit behavior
#
# When an input field with the `js-quick-submit` class receives a "Meta+Enter"
# (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, its parent form is
# submitted.
#
#= require extensions/jquery
#
# ### Example Markup
#
# <form action="/foo">
# <input type="text" class="js-quick-submit" />
# <textarea class="js-quick-submit"></textarea>
# </form>
#
$(document).on 'keydown.quick_submit', '.js-quick-submit', (e) ->
return if (e.originalEvent && e.originalEvent.repeat) || e.repeat
return unless e.keyCode == 13 # Enter
if navigator.userAgent.match(/Macintosh/)
return unless (e.metaKey && !e.altKey && !e.ctrlKey && !e.shiftKey)
else
return unless (e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey)
e.preventDefault()
$form = $(e.target).closest('form')
$form.find('input[type=submit], button[type=submit]').disable()
$form.submit()
......@@ -34,6 +34,5 @@ $.fn.requiresInput = ->
$form.on 'change input', fieldSelector, requireInput
# Triggered on standard document `ready` and on Turbolinks `page:load` events
$(document).on 'ready page:load', ->
$ ->
$('form.js-requires-input').requiresInput()
......@@ -47,6 +47,7 @@ class @BlobFileDropzone
return
this.on 'sending', (file, xhr, formData) ->
formData.append('new_branch', form.find('#new_branch').val())
formData.append('commit_message', form.find('#commit_message').val())
return
......
This diff is collapsed.
$(document).on 'click', '.badge-codes-toggle', ->
$('.badge-codes-block').toggleClass("hide")
return false
$(document).on 'click', '.sync-now', ->
$(this).find('i').addClass('fa-spin')
......@@ -6,7 +6,7 @@
#
# ### Example Markup
#
# <div id="tree-content-holder">
# <div id="blob-content-holder">
# <div class="file-content">
# <div class="line-numbers">
# <a href="#L1" id="L1" data-line-number="1">1</a>
......@@ -53,7 +53,7 @@ class @LineHighlighter
$.scrollTo("#L#{range[0]}", offset: -150)
bindEvents: ->
$('#tree-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
$('#blob-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
# While it may seem odd to bind to the mousedown event and then throw away
# the click event, there is a method to our madness.
......@@ -62,7 +62,7 @@ class @LineHighlighter
# active state even when the event is cancelled, resulting in an ugly border
# around the link and/or a persisted underline text decoration.
$('#tree-content-holder').on 'click', 'a[data-line-number]', (event) ->
$('#blob-content-holder').on 'click', 'a[data-line-number]', (event) ->
event.preventDefault()
clickHandler: (event) =>
......
......@@ -69,7 +69,7 @@ class @MergeRequestTabs
scrollToElement: (container) ->
if window.location.hash
top = $(container + " " + window.location.hash).offset().top
$('body').scrollTo(top);
$('body').scrollTo(top)
# Activate a tab based on the current action
activateTab: (action) ->
......@@ -139,13 +139,16 @@ class @MergeRequestTabs
@diffsLoaded = true
@scrollToElement(".diffs")
toggleLoading: ->
$('.mr-loading-status .loading').toggle()
# Show or hide the loading spinner
#
# status - Boolean, true to show, false to hide
toggleLoading: (status) ->
$('.mr-loading-status .loading').toggle(status)
_get: (options) ->
defaults = {
beforeSend: @toggleLoading
complete: @toggleLoading
beforeSend: => @toggleLoading(true)
complete: => @toggleLoading(false)
dataType: 'json'
type: 'GET'
}
......
......@@ -63,12 +63,6 @@ class @Notes
# fetch notes when tab becomes visible
$(document).on "visibilitychange", @visibilityChange
# Chrome doesn't fire keypress or keyup for Command+Enter, so we need keydown.
$(document).on 'keydown', '.js-note-text', (e) ->
return if e.originalEvent.repeat
if e.keyCode == 10 || ((e.metaKey || e.ctrlKey) && e.keyCode == 13)
$(@).closest('form').submit()
cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form"
......@@ -82,7 +76,6 @@ class @Notes
$(document).off "click", ".js-discussion-reply-button"
$(document).off "click", ".js-add-diff-note-button"
$(document).off "visibilitychange"
$(document).off "keydown", ".js-note-text"
$(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close"
......
......@@ -11,59 +11,41 @@
*= require cal-heatmap
*/
/*
* Welcome to GitLab css!
* If you need to add or modify UI component that is common for many pages
* like a table or typography then make changes in the framework/ directory.
* If you need to add unique style that should affect only one page - use pages/
* directory.
*/
@import "base/fonts";
@import "base/variables";
@import "base/mixins";
@import "base/layout";
/**
* Customized Twitter bootstrap
/*
* GitLab UI framework
*/
@import 'base/gl_variables';
@import 'base/gl_bootstrap';
@import "framework";
/**
/*
* NProgress load bar css
*/
@import 'nprogress';
@import 'nprogress-bootstrap';
/**
/*
* Font icons
*
*/
@import "font-awesome";
/**
* UI themes:
*/
@import "themes/**/*";
/**
* Generic css (forms, nav etc):
*/
@import "generic/**/*";
/**
/*
* Page specific styles (issues, projects etc):
*/
@import "pages/**/*";
/**
/*
* Code highlight
*/
@import "highlight/**/*";
/**
/*
* Styles for JS behaviors.
*/
@import "behaviors.scss";
\ No newline at end of file
/**
* CI specific styles:
*/
@import "ci/**/*";
@import "framework/fonts";
@import "framework/variables";
@import "framework/mixins";
@import "framework/layout";
@import 'framework/tw_bootstrap_variables';
@import 'framework/tw_bootstrap';
@import "framework/avatar.scss";
@import "framework/blocks.scss";
@import "framework/buttons.scss";
@import "framework/calendar.scss";
@import "framework/callout.scss";
@import "framework/common.scss";
@import "framework/files.scss";
@import "framework/filters.scss";
@import "framework/flash.scss";
@import "framework/forms.scss";
@import "framework/gfm.scss";
@import "framework/gitlab-theme.scss";
@import "framework/header.scss";
@import "framework/highlight.scss";
@import "framework/issue_box.scss";
@import "framework/jquery.scss";
@import "framework/lists.scss";
@import "framework/markdown_area.scss";
@import "framework/mobile.scss";
@import "framework/pagination.scss";
@import "framework/selects.scss";
@import "framework/sidebar.scss";
@import "framework/tables.scss";
@import "framework/timeline.scss";
@import "framework/typography.scss";
@import "framework/zen.scss";
body {
text-rendering: geometricPrecision;
@mixin btn-default {
@include border-radius(2px);
border-width: 1px;
border-style: solid;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
line-height: 18px;
padding: 11px $gl-padding;
letter-spacing: .4px;
&:focus,
&:active {
outline: none;
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
}
}
@mixin btn-middle {
@include btn-default;
@include border-radius(2px);
padding: 11px 24px;
}
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
background-color: $light;
border-color: $border-light;
color: $color;
&:hover,
&:focus {
background-color: $normal;
border-color: $border-normal;
color: $color;
}
&:active {
@include box-shadow (inset 0 0 4px rgba(0, 0, 0, 0.12));
background-color: $dark;
border-color: $border-dark;
color: $color;
}
}
@mixin btn-green {
@include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #FFFFFF);
}
@mixin btn-blue {
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
}
@mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
}
@mixin btn-red {
@include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #FFFFFF);
}
@mixin btn-gray {
@include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, #313236);
}
@mixin btn-white {
@include btn-color($white-light, $border-white-light, $white-normal, $border-white-normal, $white-dark, $border-white-dark, #313236);
}
.btn {
@extend .btn-default;
@include btn-default;
@include btn-white;
&.btn-sm {
padding: 5px 10px;
}
&.btn-new {
@extend .btn-success;
&.btn-xs {
padding: 1px 5px;
}
&.btn-create {
@extend .btn-success;
&.btn-success,
&.btn-new,
&.btn-create,
&.btn-save,
&.btn-green {
@include btn-green;
}
&.btn-save {
@extend .btn-success;
&.btn-gray {
@include btn-gray;
}
&.btn-remove {
@extend .btn-danger;
&.btn-primary,
&.btn-info {
@include btn-blue;
}
&.btn-warning {
@include btn-orange;
}
&.btn-danger,
&.btn-remove,
&.btn-red {
@include btn-red;
}
&.btn-cancel {
......@@ -47,14 +133,6 @@ body {
margin-right: 0px;
}
}
&.btn-save {
@extend .btn-primary;
}
&.btn-new, &.btn-create {
@extend .btn-success;
}
}
.btn-block {
......@@ -91,138 +169,3 @@ body {
}
}
}
@mixin btn-info {
@include border-radius(2px);
border-width: 1px;
border-style: solid;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
line-height: 18px;
padding: 11px 16px;
letter-spacing: .4px;
&:hover {
border-width: 1px;
border-style: solid;
}
&:focus {
border-width: 1px;
border-style: solid;
}
&:active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
border-width: 1px;
border-style: solid;
}
}
@mixin btn-middle {
@include border-radius(2px);
border-width: 1px;
border-style: solid;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
line-height: 18px;
padding: 11px 24px;
letter-spacing: .4px;
&:hover {
border-width: 1px;
border-style: solid;
}
&:focus {
border-width: 1px;
border-style: solid;
}
&:active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
border-width: 1px;
border-style: solid;
}
}
@mixin btn-green {
background-color: #28b061;
border: 1px solid #26a65c;
color: #fff;
&:hover {
background-color: #26ab5d;
border: 1px solid #229954;
color: #fff;
}
&:focus {
background-color: #26ab5d;
border: 1px solid #229954;
color: #fff;
}
&:active {
@include box-shadow (inset 0 0 4px rgba(0, 0, 0, 0.12));
background-color: #23a158 !important;
border: 1px solid #229954 !important;
color: #fff !important;
}
}
/*Butons*/
@mixin bnt-project {
background-color: #f0f2f5;
border-color: #dce0e5;
color: #313236;
&:hover {
border-color:#dce0e5;
background-color: #ebeef2;
color: #313236;
}
&:focus {
border-color: #dce0e5;
background-color: #ebeef2;
color: #313236;
}
&:active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
color: #313236 !important;
border-color: #c6cacf !important;
background-color: #e4e7ed !important;
}
}
@mixin btn-remove {
background-color: #f72e60;
border-color: #ee295a;
&:hover {
background-color: #e82757;
border-color: #e32555;
}
&:focus {
background-color: #e82757;
border-color: #e32555;
}
&:active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
background-color: #d42450 !important;
border-color: #e12554 !important;
}
}
\ No newline at end of file
......@@ -394,3 +394,7 @@ table {
.dropzone .dz-preview .dz-progress .dz-upload {
background: $gl-success !important;
}
.space-right {
margin-right: 10px;
}
......@@ -29,12 +29,6 @@ input[type='text'].danger {
border-top: 1px solid $border-color;
}
@media (min-width: $screen-sm-min) {
.form-actions {
padding-left: 17%;
}
}
label {
&.control-label {
@extend .col-sm-2;
......@@ -84,3 +78,17 @@ label {
.wiki-content {
margin-top: 35px;
}
.form-group .control-label {
font-weight: normal;
}
.form-control::-webkit-input-placeholder {
color: #7f8fa4;
}
.input-group {
.input-group-addon {
background-color: #f7f8fa;
}
}
......@@ -22,4 +22,5 @@
.gfm-commit, .gfm-commit_range {
font-family: $monospace_font;
font-size: 90%;
}
......@@ -50,15 +50,17 @@ header {
.navbar-toggle {
color: #666;
margin: 0;
margin: 6px 0;
border-radius: 0;
position: absolute;
right: 2px;
top: 15px;
&:hover {
background-color: #EEE;
}
&.active {
color: #7f8fa4;
}
}
}
}
......@@ -87,6 +89,7 @@ header {
.navbar-collapse {
float: right;
border-top: none;
}
}
......
......@@ -5,7 +5,7 @@
*/
.issue-box {
@include border-radius(3px);
@include border-radius(2px);
display: inline-block;
padding: 10px $gl-padding;
......
......@@ -5,6 +5,7 @@ html {
body {
padding-top: $header-height;
text-rendering: geometricPrecision;
}
}
......
......@@ -117,8 +117,12 @@ ul.content-list {
}
.controls {
padding-top: 10px;
padding-top: 4px;
float: right;
.btn {
padding: 10px 14px;
}
}
}
}
......
......@@ -54,147 +54,6 @@
@include box-shadow(0 0 0 3px #f1f1f1);
}
@mixin md-typography {
color: $md-text-color;
a {
color: $md-link-color;
}
img {
max-width: 100%;
}
*:first-child {
margin-top: 0;
}
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 1px 2px;
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #FCFCFC;
border-width: 1px;
border-style: solid;
border-color: #CCC #CCC #BBB;
border-image: none;
border-radius: 3px;
box-shadow: 0px -1px 0px #BBB inset;
}
h1 {
font-size: 1.3em;
font-weight: 600;
margin: 24px 0 12px 0;
padding: 0 0 10px 0;
border-bottom: 1px solid #e7e9ed;
color: #313236;
}
h2 {
font-size: 1.2em;
font-weight: 600;
margin: 24px 0 12px 0;
color: #313236;
}
h3 {
margin: 24px 0 12px 0;
font-size: 1.25em;
}
h4 {
margin: 24px 0 12px 0;
font-size: 1.1em;
}
h5 {
margin: 24px 0 12px 0;
font-size: 1em;
}
h6 {
margin: 24px 0 12px 0;
font-size: 0.90em;
}
blockquote {
padding: 8px 21px;
margin: 12px 0 12px;
border-left: 3px solid #e7e9ed;
}
blockquote p {
color: #7f8fa4 !important;
font-size: 15px;
line-height: 1.5;
}
p {
color:#5c5d5e;
margin:6px 0 0 0;
}
table {
@extend .table;
@extend .table-bordered;
margin: 12px 0 12px 0;
color: #5c5d5e;
th {
background: #f8fafc;
}
}
pre {
margin: 12px 0 12px 0 !important;
background-color: #f8fafc !important;
font-size: 13px !important;
color: #5b6169 !important;
line-height: 1.6em !important;
@include border-radius(2px);
}
p > code {
font-weight: inherit;
}
ul {
color: #5c5d5e;
}
li {
line-height: 1.6em;
}
a[href*="/uploads/"], a[href*="storage.googleapis.com/google-code-attachments/"] {
&:before {
margin-right: 4px;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: "\f0c6";
}
&:hover:before {
text-decoration: none;
}
}
}
@mixin str-truncated($max_width: 82%) {
display: inline-block;
overflow: hidden;
......
......@@ -23,7 +23,7 @@
margin-right: 0;
}
.issues-filters,
.issues-details-filters,
.dash-projects-filters,
.check-all-holder {
display: none;
......@@ -83,6 +83,7 @@
.center-top-menu {
height: 45px;
margin-bottom: 30px;
li a {
font-size: 14px;
......@@ -90,9 +91,11 @@
}
}
.projects-search-form {
margin: 0 -5px !important;
.activity-filter-block {
display: none;
}
.projects-search-form {
.btn {
display: none;
}
......@@ -100,6 +103,11 @@
}
@media (max-width: $screen-sm-max) {
.page-with-sidebar .content-wrapper {
padding: 0;
padding-top: 1px;
}
.issues-filters {
.milestone-filter, .labels-filter {
display: none;
......
......@@ -8,7 +8,7 @@
font-size: $gl-font-size;
line-height: 1.42857143;
@include border-radius(4px);
@include border-radius(2px);
.select2-arrow {
background: #FFF;
......@@ -18,8 +18,39 @@
}
}
.select2-container .select2-choice, .select2-container.select2-drop-above .select2-choice{
color: #7f8fa4;
border: 1px solid #e7e9ed;
}
.select2-drop {
@include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px);
@include border-radius (0px);
padding: 16px;
border: none !important;
}
.select2-results .select2-result-label {
padding: 16px;
}
.select2-drop{
color: #7f8fa4;
}
.select2-highlighted {
background: #3084bb !important;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: 600;
color: #313236;
}
.select2-container-multi .select2-choices {
@include border-radius(4px);
@include border-radius(2px);
border-color: #CCC;
}
......@@ -63,7 +94,7 @@
.ajax-users-dropdown, .ajax-project-users-dropdown {
.select2-search {
padding-top: 4px;
padding-top: 2px;
}
}
......@@ -97,9 +128,6 @@
}
.user-name {
}
.user-username {
color: #999;
}
}
.namespace-result {
......@@ -114,5 +142,5 @@
}
.ajax-users-dropdown {
min-width: 225px !important;
min-width: 250px !important;
}
table {
&.table {
.dropdown-menu a {
text-decoration: none;
}
.success,
.warning,
.danger,
.info {
color: #fff;
a:not(.btn) {
text-decoration: underline;
color: #fff;
}
}
tr {
td, th {
padding: 8px 10px;
......@@ -12,7 +28,7 @@ table {
border-bottom: 1px solid $border-color !important;
}
td {
border-color: #F1F1F1 !important;
border-color: $table-border-color !important;
border-bottom: 1px solid;
}
}
......
......@@ -10,8 +10,8 @@
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
border-bottom: 1px solid #f1f2f4;
border-right: 1px solid #f1f2f4;
border-bottom: 1px solid #ECEEF1;
border-right: 1px solid #ECEEF1;
&:last-child {
border-bottom: none;
......
......@@ -32,8 +32,6 @@
@import "bootstrap/pager";
@import "bootstrap/labels";
@import "bootstrap/badges";
@import "bootstrap/jumbotron";
@import "bootstrap/thumbnails";
@import "bootstrap/alerts";
@import "bootstrap/progress-bars";
@import "bootstrap/list-group";
......@@ -251,23 +249,3 @@
.text-info:hover {
color: $brand-info;
}
// Tables =====================================================================
table.table {
.dropdown-menu a {
text-decoration: none;
}
.success,
.warning,
.danger,
.info {
color: #fff;
a:not(.btn) {
text-decoration: underline;
color: #fff;
}
}
}
......@@ -22,8 +22,8 @@ $brand-info: $gl-info;
$brand-warning: $gl-warning;
$brand-danger: $gl-danger;
$border-radius-base: 3px !default;
$border-radius-large: 5px !default;
$border-radius-base: 2px !default;
$border-radius-large: 2px !default;
$border-radius-small: 2px !default;
......@@ -156,3 +156,5 @@ $nav-link-padding: 13px $gl-padding;
$pre-bg: #f8fafc !default;
$pre-color: $gl-gray !default;
$pre-border-color: #e7e9ed;
$table-bg-accent: $background-color;
@mixin md-typography {
color: $md-text-color;
a {
color: $md-link-color;
}
img {
max-width: 100%;
}
*:first-child {
margin-top: 0;
}
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 1px 2px;
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #FCFCFC;
border-width: 1px;
border-style: solid;
border-color: #CCC #CCC #BBB;
border-image: none;
border-radius: 3px;
box-shadow: 0px -1px 0px #BBB inset;
}
h1 {
font-size: 1.3em;
font-weight: 600;
margin: 24px 0 12px 0;
padding: 0 0 10px 0;
border-bottom: 1px solid #e7e9ed;
color: #313236;
}
h2 {
font-size: 1.2em;
font-weight: 600;
margin: 24px 0 12px 0;
color: #313236;
}
h3 {
margin: 24px 0 12px 0;
font-size: 1.25em;
}
h4 {
margin: 24px 0 12px 0;
font-size: 1.1em;
}
h5 {
margin: 24px 0 12px 0;
font-size: 1em;
}
h6 {
margin: 24px 0 12px 0;
font-size: 0.90em;
}
blockquote {
padding: 8px 21px;
margin: 12px 0 12px;
border-left: 3px solid #e7e9ed;
}
blockquote p {
color: #7f8fa4 !important;
font-size: 15px;
line-height: 1.5;
}
p {
color:#5c5d5e;
margin:6px 0 0 0;
}
table {
@extend .table;
@extend .table-bordered;
margin: 12px 0 12px 0;
color: #5c5d5e;
th {
background: #f8fafc;
}
}
pre {
margin: 12px 0 12px 0 !important;
background-color: #f8fafc !important;
font-size: 13px !important;
color: #5b6169 !important;
line-height: 1.6em !important;
@include border-radius(2px);
}
p > code {
font-weight: inherit;
}
ul {
color: #5c5d5e;
}
li {
line-height: 1.6em;
}
a[href*="/uploads/"], a[href*="storage.googleapis.com/google-code-attachments/"] {
&:before {
margin-right: 4px;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: "\f0c6";
}
&:hover:before {
text-decoration: none;
}
}
}
/**
* Headers
*
......
......@@ -16,6 +16,7 @@ $avatar_radius: 50%;
$code_font_size: 13px;
$code_line_height: 1.5;
$border-color: #dce0e6;
$table-border-color: #eef0f2;
$background-color: #F7F8FA;
$header-height: 58px;
$fixed-layout-width: 1200px;
......@@ -23,15 +24,67 @@ $gl-gray: #7f8fa4;
$gl-padding: 16px;
$gl-avatar-size: 46px;
/*
* Color schema
*/
$white-light: #FFFFFF;
$white-normal: #DCE0E5;
$white-dark: #E4E7ED;
$gray-light: #F0F2F5;
$gray-normal: #DCE0E5;
$gray-dark: #E4E7ED;
$green-light: #31AF64;
$green-normal: #2FAA60;
$green-dark: #2CA05B;
$blue-light: #2EA8E5;
$blue-normal: #2D9FD8;
$blue-dark: #2897CE;
$orange-light: #FC6443;
$orange-normal: #E75E40;
$orange-dark: #CE5237;
$red-light: #F43263;
$red-normal: #E52C5A;
$red-dark: #D22852;
$border-white-light: #E3E7EC;
$border-white-normal: #D6DAE2;
$border-white-dark: #C6CACF;
$border-gray-light: #DCE0E5;
$border-gray-normal: #D6DAE2;
$border-gray-dark: #C6CACF;
$border-green-light: #2FAA60;
$border-green-normal: #2CA05B;
$border-green-dark: #279654;
$border-blue-light: #2D9FD8;
$border-blue-normal: #2897CE;
$border-blue-dark: #258DC1;
$border-orange-light: #ED5C3D;
$border-orange-normal: #CE5237;
$border-orange-dark: #C14E35;
$border-red-light: #E52C5A;
$border-red-normal: #D22852;
$border-red-dark: #CA264F;
/*
* State colors:
*/
$gl-primary: #446e9b;
$gl-success: #44c679;
$gl-info: #00aaff;
$gl-warning: #EB9532;
$gl-danger: #d9534f;
$gl-primary: $blue-normal;
$gl-success: $green-normal;
$gl-info: $blue-normal;
$gl-warning: $orange-normal;
$gl-danger: $red-normal;
/*
* Commit Diff Colors
......
.commits-compare-switch{
@extend .btn;
@include btn-default;
@include btn-white;
background: image-url("switch_icon.png") no-repeat center center;
text-indent: -9999px;
float: left;
......
// Common
.diff-file {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
......@@ -12,24 +13,17 @@
color: #555;
z-index: 10;
> span {
.diff-title {
font-family: $monospace_font;
word-break: break-all;
margin-right: 200px;
display: block;
.file-mode {
margin-left: 10px;
color: #777;
}
}
.diff-btn-group {
float: right;
position: absolute;
top: 5px;
right: 15px;
.diff-controls {
.btn {
padding: 0px 10px;
font-size: 13px;
......@@ -90,12 +84,12 @@
}
}
tr.line_holder.parallel{
tr.line_holder.parallel {
.old_line, .new_line, .diff_line {
min-width: 50px;
}
td.line_content.parallel{
td.line_content.parallel {
width: 50%;
}
}
......@@ -105,7 +99,7 @@
padding: 0px;
border: none;
background: $background-color;
color: rgba(0,0,0,0.3);
color: rgba(0, 0, 0, 0.3);
padding: 0px 5px;
border-right: 1px solid $border-color;
text-align: right;
......@@ -117,7 +111,7 @@
float: left;
width: 35px;
font-weight: normal;
color: rgba(0,0,0,0.3);
color: rgba(0, 0, 0, 0.3);
&:hover {
text-decoration: underline;
}
......@@ -168,7 +162,7 @@
background: #ddd;
text-align: center;
padding: 30px;
.wrap{
.wrap {
display: inline-block;
}
......@@ -176,7 +170,7 @@
display: inline-block;
background-color: #fff;
line-height: 0;
img{
img {
border: 1px solid #FFF;
background: image-url('trans_bg.gif');
max-width: 100%;
......@@ -189,21 +183,21 @@
border: 1px solid $added;
}
}
.image-info{
.image-info {
font-size: 12px;
margin: 5px 0 0 0;
color: grey;
}
.view.swipe{
.view.swipe {
position: relative;
.swipe-frame{
.swipe-frame {
display: block;
margin: auto;
position: relative;
}
.swipe-wrap{
.swipe-wrap {
overflow: hidden;
border-left: 1px solid #999;
position: absolute;
......@@ -211,33 +205,33 @@
top: 13px;
right: 7px;
}
.frame{
.frame {
top: 0;
right: 0;
position: absolute;
&.deleted{
&.deleted {
margin: 0;
display: block;
top: 13px;
right: 7px;
}
}
.swipe-bar{
.swipe-bar {
display: block;
height: 100%;
width: 15px;
z-index: 100;
position: absolute;
cursor: pointer;
&:hover{
.top-handle{
&:hover {
.top-handle {
background-position: -15px 3px;
}
.bottom-handle{
.bottom-handle {
background-position: -15px -11px;
}
};
.top-handle{
}
.top-handle {
display: block;
height: 14px;
width: 15px;
......@@ -245,7 +239,7 @@
top: 0px;
background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
}
.bottom-handle{
.bottom-handle {
display: block;
height: 14px;
width: 15px;
......@@ -254,9 +248,10 @@
background: image-url('swipemode_sprites.gif') 0 -11px no-repeat;
}
}
} //.view.swipe
.view.onion-skin{
.onion-skin-frame{
}
//.view.swipe
.view.onion-skin {
.onion-skin-frame {
display: block;
margin: auto;
position: relative;
......@@ -267,7 +262,7 @@
top: 0px;
left: 0px;
}
.controls{
.controls {
display: block;
height: 14px;
width: 300px;
......@@ -277,7 +272,7 @@
left: 50%;
margin-left: -150px;
.drag-track{
.drag-track {
display: block;
position: absolute;
left: 12px;
......@@ -317,39 +312,40 @@
background: image-url('onion_skin_sprites.gif') -2px -10px no-repeat;
}
}
} //.view.onion-skin
}
.view-modes{
//.view.onion-skin
}
.view-modes {
padding: 10px;
text-align: center;
background: #EEE;
ul, li{
ul, li {
list-style: none;
margin: 0;
padding: 0;
display: inline-block;
}
li{
li {
color: grey;
border-left: 1px solid #c1c1c1;
padding: 0 12px 0 16px;
cursor: pointer;
&:first-child{
&:first-child {
border-left: none;
}
&:hover{
&:hover {
text-decoration: underline;
}
&.active{
&:hover{
&.active {
&:hover {
text-decoration: none;
}
cursor: default;
color: #333;
}
&.disabled{
&.disabled {
display: none;
}
}
......@@ -373,3 +369,37 @@
float: right;
margin-top: -5px;
}
// Mobile
@media (max-width: 480px) {
.diff-title {
margin: 0;
.file-mode {
display: none;
}
}
.diff-controls {
position: static;
text-align: center;
}
}
// Bigger screens
@media (min-width: 481px) {
.diff-title {
margin-right: 200px;
.file-mode {
margin-left: 10px;
}
}
.diff-controls {
float: right;
position: absolute;
top: 5px;
right: 15px;
}
}
......@@ -54,21 +54,22 @@
margin-top: -15px;
padding: 10px 0;
margin-bottom: 0;
color: $gl-gray;
color: #5c5d5e;
font-size: 16px;
.author {
color: $gl-gray;
color: #5c5d5e;
}
.issue-id {
font-size: 19px;
color: $gl-text-color;
color: #5c5d5e;
}
}
.issue-title {
margin: 0;
font-size: 23px;
color: #313236;
}
.description {
......
......@@ -3,12 +3,11 @@
*
*/
.mr-state-widget {
background: #f8fafc;
background: #F7F8FA;
margin-bottom: 20px;
color: $gl-gray;
border: 1px solid #eef0f2;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
@include border-radius(3px);
border: 1px solid #dce0e6;
@include border-radius(2px);
form {
margin-bottom: 0;
......@@ -77,10 +76,16 @@
padding: 15px;
}
.normal {
color: #5c5d5e;
}
.mr-widget-body {
h4 {
font-weight: bold;
font-weight: 600;
font-size: 17px;
margin: 5px 0;
color: #313236;
}
p:last-child {
......@@ -97,14 +102,26 @@
}
}
.merge-request .merge-request-tabs{
.merge-request .merge-request-tabs {
@include nav-menu;
margin: -$gl-padding;
padding: $gl-padding;
text-align: center;
border-top: 1px solid #e7e9ed;
margin-top: 18px;
margin-bottom: 3px;
margin-bottom: 1px;
}
// Mobile
@media (max-width: 480px) {
.merge-request .merge-request-tabs {
margin: 0;
padding: 0;
li {
a {
padding: 0;
}
}
}
}
.mr_source_commit,
......@@ -120,10 +137,12 @@
}
.label-branch {
color: #222;
color: #313236;
font-family: $monospace_font;
font-weight: bold;
overflow: hidden;
font-size: 14px;
margin: 0 3px;
}
.mr-list {
......
......@@ -65,19 +65,18 @@
.note-image-attach {
@extend .col-md-4;
@extend .thumbnail;
margin-left: 45px;
float: none;
}
.common-note-form {
margin: 0;
background: #f8fafc;
background: #F7F8FA;
padding: $gl-padding;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border-right: 1px solid #f1f2f4;
border-top: 1px solid #f1f2f4;
border-right: 1px solid #ECEEF1;
border-top: 1px solid #ECEEF1;
margin-bottom: -$gl-padding;
}
......@@ -168,7 +167,7 @@
.comment-hints {
color: #999;
background: #FFF;
padding: 5px;
padding: 7px;
margin-top: -11px;
border: 1px solid $border-color;
font-size: 13px;
......
......@@ -18,7 +18,7 @@ ul.notes {
font-size: 14px;
padding-top: 10px;
padding-bottom: 10px;
background: #f8fafc;
background: #FDFDFD;
.timeline-icon {
.avatar {
......
......@@ -13,11 +13,15 @@
.edit_project {
fieldset.features {
.control-label {
font-weight: bold;
font-weight: normal;
}
}
}
.project-edit-content {
padding: 7px;
}
.project-name-holder {
.help-inline {
vertical-align: top;
......@@ -59,6 +63,7 @@
}
p {
padding: 0 $gl-padding;
color: #5c5d5e;
}
}
......@@ -92,8 +97,7 @@
margin-bottom: 0px;
.btn {
@include bnt-project;
@include btn-info;
@include btn-gray;
.count {
display: inline-block;
......@@ -149,7 +153,7 @@
.input-group-btn {
.btn {
@include bnt-project;
@include btn-gray;
@include btn-middle;
&:hover {
......@@ -183,8 +187,8 @@
margin: 0 12px 0 12px;
.btn{
@include bnt-project;
@include btn-info;
@include btn-gray;
@include btn-default;
}
.dropdown-toggle {
......@@ -251,18 +255,19 @@
margin-bottom: 10px;
i {
margin: 0 3px;
margin: 2px 0;
font-size: 20px;
}
.option-title {
font-weight: bold;
font-weight: normal;
display: inline-block;
color: #313236;
}
.option-descr {
margin-left: 36px;
color: $gray;
margin-left: 29px;
color: #54565b;
}
}
}
......@@ -376,8 +381,8 @@ table.table.protected-branches-list tr.no-border {
}
.nav > li > a {
@include btn-info;
@include bnt-project;
@include btn-default;
@include btn-gray;
background-color: transparent;
border: 1px solid #f7f8fa;
......@@ -437,7 +442,7 @@ pre.light-well {
.btn-remove {
@include btn-middle;
@include btn-remove;
@include btn-red;
float: left !important;
}
......@@ -506,8 +511,3 @@ pre.light-well {
margin-top: -1px;
}
}
.inline-form {
display: inline-block;
}
.tree-holder {
.tree-content-holder {
float: left;
width: 100%;
.tree-table-holder {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
}
.tree_progress {
......@@ -13,10 +13,15 @@
}
.tree-table {
@extend .table;
@include border-radius(0);
margin-bottom: 0;
tr {
> td, > th {
padding: 10px $gl-padding;
line-height: 32px;
border-color: $table-border-color !important;
}
&:hover {
td {
background: $hover;
......@@ -27,9 +32,9 @@
}
&.selected {
td {
background: $background-color;
border-top: 1px solid #EEE;
border-bottom: 1px solid #EEE;
background: $gray-dark;
border-top: 1px solid $border-gray-dark;
border-bottom: 1px solid $border-gray-dark;
}
}
}
......@@ -85,19 +90,6 @@
margin-right: 15px;
}
.readme-holder {
margin: 0 auto;
.readme-file-title {
font-size: 14px;
font-weight: bold;
margin-bottom: 20px;
color: #777;
border-bottom: 1px solid #DDD;
padding: 10px 0;
}
}
.blob-commit-info {
list-style: none;
margin: 0;
......
.ci-body {
.build-page {
// color codes are based on http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
// see also: https://gist.github.com/jasonm23/2868981
......
......@@ -30,7 +30,7 @@ class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do |exception|
log_exception(exception)
render "errors/not_found", layout: "errors", status: 404
render_404
end
protected
......@@ -149,10 +149,6 @@ class ApplicationController < ActionController::Base
render "errors/access_denied", layout: "errors", status: 404
end
def not_found!
render "errors/not_found", layout: "errors", status: 404
end
def git_not_found!
render "errors/git_not_found", layout: "errors", status: 404
end
......
module Ci
class BuildsController < Ci::ApplicationController
before_action :authenticate_user!, except: [:status]
before_action :project
before_action :authorize_access_project!, except: [:status]
before_action :authorize_manage_project!, except: [:status, :retry, :cancel]
before_action :authorize_manage_builds!, only: [:retry, :cancel]
before_action :build
def retry
if @build.commands.blank?
return page_404
end
build = Ci::Build.retry(@build)
if params[:return_to]
redirect_to URI.parse(params[:return_to]).path
else
redirect_to build_path(build)
end
end
def status
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
end
def cancel
@build.cancel
redirect_to build_path(@build)
end
protected
def project
@project = Ci::Project.find(params[:project_id])
end
def build
@build ||= project.builds.unscoped.find_by!(id: params[:id])
end
def commit_by_sha
@project.commits.find_by(sha: params[:id])
end
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
end
end
module Ci
class CommitsController < Ci::ApplicationController
before_action :authenticate_user!, except: [:status, :show]
before_action :authenticate_public_page!, only: :show
before_action :project
before_action :authorize_access_project!, except: [:status, :show, :cancel]
before_action :authorize_manage_builds!, only: [:cancel]
def status
commit = Ci::Project.find(params[:project_id]).commits.find_by_sha!(params[:id])
render json: commit.to_json(only: [:id, :sha], methods: [:status, :coverage])
rescue ActiveRecord::RecordNotFound
render json: { status: "not_found" }
end
def cancel
commit.builds.running_or_pending.each(&:cancel)
redirect_to namespace_project_commit_path(commit.gl_project.namespace, commit.gl_project, commit.sha)
end
private
def project
@project ||= Ci::Project.find(params[:project_id])
end
def commit
@commit ||= Ci::Project.find(params[:project_id]).commits.find_by_sha!(params[:id])
end
end
end
module Ci
class ProjectsController < Ci::ApplicationController
before_action :authenticate_user!, except: [:build, :badge, :show]
before_action :authenticate_public_page!, only: :show
before_action :project, only: [:build, :show, :badge, :toggle_shared_runners, :dumped_yaml]
before_action :authorize_access_project!, except: [:build, :badge, :show, :new]
before_action :project
before_action :authenticate_user!, except: [:build, :badge]
before_action :authorize_access_project!, except: [:badge]
before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml]
before_action :authenticate_token!, only: [:build]
before_action :no_cache, only: [:badge]
protect_from_forgery except: :build
layout 'ci/project', except: [:index]
def show
@ref = params[:ref]
@commits = @project.commits.reverse_order
if @ref
# unscope is required, because of default_scope defined in Ci::Build
builds = @project.builds.unscope(:select, :order).where(ref: @ref).select(:commit_id).distinct
@commits = @commits.where(id: builds)
end
@commits = @commits.page(params[:page]).per(20)
end
protect_from_forgery
# Project status badge
# Image with build status for sha or ref
......
module Ci
class ServicesController < Ci::ApplicationController
before_action :authenticate_user!
before_action :project
before_action :authorize_access_project!
before_action :authorize_manage_project!
before_action :service, only: [:edit, :update, :test]
respond_to :html
layout 'ci/project'
def index
@project.build_missing_services
@services = @project.services.reload
end
def edit
end
def update
if @service.update_attributes(service_params)
redirect_to edit_ci_project_service_path(@project, @service.to_param)
else
render 'edit'
end
end
def test
last_build = @project.builds.last
if @service.execute(last_build)
message = { notice: 'We successfully tested the service' }
else
message = { alert: 'We tried to test the service but error occurred' }
end
redirect_to :back, message
end
private
def project
@project = Ci::Project.find(params[:project_id])
end
def service
@service ||= @project.services.find { |service| service.to_param == params[:id] }
end
def service_params
params.require(:service).permit(
:type, :active, :webhook, :notify_only_broken_builds,
:email_recipients, :email_only_broken_builds, :email_add_pusher,
:hipchat_token, :hipchat_room, :hipchat_server
)
end
end
end
......@@ -88,7 +88,7 @@ class GroupsController < Groups::ApplicationController
def destroy
DestroyGroupService.new(@group, current_user).execute
redirect_to root_path, alert: "Group '#{@group.name} was deleted."
redirect_to root_path, alert: "Group '#{@group.name}' was successfully deleted."
end
protected
......
......@@ -62,7 +62,7 @@ class Import::BitbucketController < Import::BaseController
end
def verify_bitbucket_import_enabled
not_found! unless bitbucket_import_enabled?
render_404 unless bitbucket_import_enabled?
end
def bitbucket_auth
......
......@@ -99,6 +99,6 @@ class Import::FogbugzController < Import::BaseController
end
def verify_fogbugz_import_enabled
not_found! unless fogbugz_import_enabled?
render_404 unless fogbugz_import_enabled?
end
end
......@@ -47,7 +47,7 @@ class Import::GithubController < Import::BaseController
end
def verify_github_import_enabled
not_found! unless github_import_enabled?
render_404 unless github_import_enabled?
end
def github_auth
......
......@@ -44,7 +44,7 @@ class Import::GitlabController < Import::BaseController
end
def verify_gitlab_import_enabled
not_found! unless gitlab_import_enabled?
render_404 unless gitlab_import_enabled?
end
def gitlab_auth
......
......@@ -42,7 +42,7 @@ class Import::GitoriousController < Import::BaseController
end
def verify_gitorious_import_enabled
not_found! unless gitorious_import_enabled?
render_404 unless gitorious_import_enabled?
end
end
......@@ -106,7 +106,7 @@ class Import::GoogleCodeController < Import::BaseController
end
def verify_google_code_import_enabled
not_found! unless google_code_import_enabled?
render_404 unless google_code_import_enabled?
end
def user_map
......
......@@ -12,7 +12,7 @@ class Projects::AvatarsController < Projects::ApplicationController
filename: @blob.name
)
else
not_found!
render_404
end
end
......
......@@ -8,7 +8,7 @@ class Projects::BlobController < Projects::ApplicationController
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:destroy]
before_action :authorize_push_code!, only: [:destroy, :create]
before_action :assign_blob_vars
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
......@@ -25,7 +25,7 @@ class Projects::BlobController < Projects::ApplicationController
result = Files::CreateService.new(@project, current_user, @commit_params).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
flash[:notice] = "The changes have been successfully committed"
respond_to do |format|
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) }
format.json { render json: { message: "success", filePath: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) } }
......@@ -34,7 +34,7 @@ class Projects::BlobController < Projects::ApplicationController
flash[:alert] = result[:message]
respond_to do |format|
format.html { render :new }
format.json { render json: { message: "failed", filePath: namespace_project_new_blob_path(@project.namespace, @project, @id) } }
format.json { render json: { message: "failed", filePath: namespace_project_blob_path(@project.namespace, @project, @id) } }
end
end
end
......@@ -113,14 +113,14 @@ class Projects::BlobController < Projects::ApplicationController
end
end
return not_found!
return render_404
end
end
def commit
@commit = @repository.commit(@ref)
return not_found! unless @commit
return render_404 unless @commit
end
def assign_blob_vars
......@@ -128,7 +128,7 @@ class Projects::BlobController < Projects::ApplicationController
@ref, @path = extract_ref(@id)
rescue InvalidPathError
not_found!
render_404
end
def after_edit_path
......@@ -154,7 +154,7 @@ class Projects::BlobController < Projects::ApplicationController
def editor_variables
@current_branch = @ref
@target_branch = (sanitized_new_branch_name || @ref)
@target_branch = params[:new_branch].present? ? sanitized_new_branch_name : @ref
@file_path =
if action_name.to_s == 'create'
......
......@@ -2,6 +2,8 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :ci_project
before_action :build
before_action :authorize_admin_project!, except: [:show, :status]
layout "project"
def show
......@@ -17,9 +19,37 @@ class Projects::BuildsController < Projects::ApplicationController
end
end
def retry
if @build.commands.blank?
return page_404
end
build = Ci::Build.retry(@build)
if params[:return_to]
redirect_to URI.parse(params[:return_to]).path
else
redirect_to build_path(build)
end
end
def status
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
end
def cancel
@build.cancel
redirect_to build_path(@build)
end
private
def build
@build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
end
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
end
class Projects::CiServicesController < Projects::ApplicationController
before_action :ci_project
before_action :authorize_admin_project!
layout "project_settings"
def index
@ci_project.build_missing_services
@services = @ci_project.services.reload
end
def edit
service
end
def update
if @service.update_attributes(service_params)
redirect_to edit_namespace_project_ci_service_path(@project, @project.namespace, @service.to_param)
else
render 'edit'
end
end
def test
last_build = @project.builds.last
if @service.execute(last_build)
message = { notice: 'We successfully tested the service' }
else
message = { alert: 'We tried to test the service but error occurred' }
end
redirect_to :back, message
end
private
def service
@service ||= @ci_project.services.find { |service| service.to_param == params[:id] }
end
def service_params
params.require(:service).permit(
:type, :active, :webhook, :notify_only_broken_builds,
:email_recipients, :email_only_broken_builds, :email_add_pusher,
:hipchat_token, :hipchat_room, :hipchat_server
)
end
end
......@@ -38,6 +38,14 @@ class Projects::CommitController < Projects::ApplicationController
@ci_project = @project.gitlab_ci_project
end
def cancel_builds
@ci_commit = @project.ci_commit(@commit.sha)
@ci_commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def branches
@branches = @project.repository.branch_names_contains(commit.id)
@tags = @project.repository.tag_names_contains(commit.id)
......
......@@ -20,7 +20,7 @@ class Projects::RawController < Projects::ApplicationController
disposition: 'inline'
)
else
not_found!
render_404
end
end
......
# Controller for viewing a repository's file structure
class Projects::TreeController < Projects::ApplicationController
include ExtractsPath
include ActionView::Helpers::SanitizeHelper
before_action :require_non_empty_project, except: [:new, :create]
before_action :assign_ref_vars
before_action :assign_dir_vars, only: [:create_dir]
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:create_dir]
def show
return not_found! unless @repository.commit(@ref)
return render_404 unless @repository.commit(@ref)
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
......@@ -16,7 +19,7 @@ class Projects::TreeController < Projects::ApplicationController
File.join(@ref, @path))
) and return
elsif @path.present?
return not_found!
return render_404
end
end
......@@ -26,4 +29,38 @@ class Projects::TreeController < Projects::ApplicationController
format.js { no_cache_headers }
end
end
def create_dir
return render_404 unless @commit_params.values.all?
begin
result = Files::CreateDirService.new(@project, current_user, @commit_params).execute
message = result[:message]
rescue => e
message = e.to_s
end
if result && result[:status] == :success
flash[:notice] = "The directory has been successfully created"
respond_to do |format|
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@new_branch, @dir_name)) }
end
else
flash[:alert] = message
respond_to do |format|
format.html { redirect_to namespace_project_blob_path(@project.namespace, @project, @new_branch) }
end
end
end
def assign_dir_vars
@new_branch = params[:new_branch].present? ? sanitize(strip_tags(params[:new_branch])) : @ref
@dir_name = File.join(@path, params[:dir_name])
@commit_params = {
file_path: @dir_name,
current_branch: @ref,
target_branch: @new_branch,
commit_message: params[:commit_message],
}
end
end
......@@ -20,7 +20,7 @@ class Projects::UploadsController < Projects::ApplicationController
end
def show
return not_found! if uploader.nil? || !uploader.file.exists?
return render_404 if uploader.nil? || !uploader.file.exists?
disposition = uploader.image? ? 'inline' : 'attachment'
send_file uploader.file.path, disposition: disposition
......
......@@ -10,7 +10,7 @@ class UploadsController < ApplicationController
end
unless uploader.file && uploader.file.exists?
return not_found!
return render_404
end
disposition = uploader.image? ? 'inline' : 'attachment'
......@@ -21,7 +21,7 @@ class UploadsController < ApplicationController
def find_model
unless upload_model && upload_mount
return not_found!
return render_404
end
@model = upload_model.find(params[:id])
......@@ -44,7 +44,7 @@ class UploadsController < ApplicationController
return if authorized
if current_user
not_found!
render_404
else
authenticate_user!
end
......
......@@ -72,11 +72,15 @@ class IssuableFinder
params[:milestone_title].present?
end
def no_milestones?
milestones? && params[:milestone_title] == Milestone::None.title
end
def milestones
return @milestones if defined?(@milestones)
@milestones =
if milestones? && params[:milestone_title] != Milestone::None.title
if milestones?
Milestone.where(title: params[:milestone_title])
else
nil
......@@ -183,8 +187,12 @@ class IssuableFinder
def by_milestone(items)
if milestones?
if no_milestones?
items = items.where(milestone_id: [-1, nil])
else
items = items.where(milestone_id: milestones.try(:pluck, :id))
end
end
items
end
......@@ -207,6 +215,11 @@ class IssuableFinder
def by_label(items)
if params[:label_name].present?
if params[:label_name] == Label::None.title
item_ids = LabelLink.where(target_type: klass.name).pluck(:target_id)
items = items.where('id NOT IN (?)', item_ids)
else
label_names = params[:label_name].split(",")
item_ids = LabelLink.joins(:label).
......@@ -215,6 +228,7 @@ class IssuableFinder
items = items.where(id: item_ids)
end
end
items
end
......
class TrendingProjectsFinder
def execute(current_user, start_date = nil)
start_date ||= Date.today - 1.month
projects = projects_for(current_user)
# Determine trending projects based on comments count
# for period of time - ex. month
projects.joins(:notes).where('notes.created_at > ?', start_date).
group("projects.id").reorder("count(notes.id) DESC")
def execute(current_user, start_date = 1.month.ago)
projects_for(current_user).trending(start_date)
end
private
......
......@@ -93,7 +93,10 @@ module LabelsHelper
end
def project_labels_options(project)
options_from_collection_for_select(project.labels, 'name', 'name', params[:label_name])
labels = project.labels.to_a
labels.unshift(Label::None)
labels.unshift(Label::Any)
options_from_collection_for_select(labels, 'name', 'title', params[:label_name])
end
# Required for Gitlab::Markdown::LabelReferenceFilter
......
......@@ -30,7 +30,8 @@ module MilestonesHelper
grouped_milestones = Milestones::GroupService.new(milestones).execute
grouped_milestones.unshift(Milestone::None)
grouped_milestones.unshift(Milestone::Any)
options_from_collection_for_select(grouped_milestones, 'title', 'title', params[:milestone_title])
options_from_collection_for_select(grouped_milestones, 'name', 'title', params[:milestone_title])
end
end
......@@ -135,6 +135,8 @@ class Ability
def project_report_rules
project_guest_rules + [
:create_commit_status,
:read_commit_statuses,
:download_code,
:fork_project,
:create_project_snippet,
......
......@@ -24,32 +24,19 @@
#
module Ci
class Build < ActiveRecord::Base
extend Ci::Model
class Build < CommitStatus
LAZY_ATTRIBUTES = ['trace']
belongs_to :commit, class_name: 'Ci::Commit'
belongs_to :runner, class_name: 'Ci::Runner'
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
belongs_to :user
serialize :options
validates :commit, presence: true
validates :status, presence: true
validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref
scope :running, ->() { where(status: "running") }
scope :pending, ->() { where(status: "pending") }
scope :success, ->() { where(status: "success") }
scope :failed, ->() { where(status: "failed") }
scope :unstarted, ->() { where(runner_id: nil) }
scope :running_or_pending, ->() { where(status:[:running, :pending]) }
scope :latest, ->() { where(id: unscope(:select).select('max(id)').group(:name, :ref)).order(stage_idx: :asc) }
scope :ignore_failures, ->() { where(allow_failure: false) }
scope :for_ref, ->(ref) { where(ref: ref) }
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
acts_as_taggable
......@@ -74,13 +61,14 @@ module Ci
def create_from(build)
new_build = build.dup
new_build.status = :pending
new_build.status = 'pending'
new_build.runner_id = nil
new_build.trigger_request_id = nil
new_build.save
end
def retry(build)
new_build = Ci::Build.new(status: :pending)
new_build = Ci::Build.new(status: 'pending')
new_build.ref = build.ref
new_build.tag = build.tag
new_build.options = build.options
......@@ -98,28 +86,7 @@ module Ci
end
state_machine :status, initial: :pending do
event :run do
transition pending: :running
end
event :drop do
transition running: :failed
end
event :success do
transition running: :success
end
event :cancel do
transition [:pending, :running] => :canceled
end
after_transition pending: :running do |build, transition|
build.update_attributes started_at: Time.now
end
after_transition any => [:success, :failed, :canceled] do |build, transition|
build.update_attributes finished_at: Time.now
project = build.project
if project.web_hooks?
......@@ -136,19 +103,10 @@ module Ci
build.update_coverage
end
end
state :pending, value: 'pending'
state :running, value: 'running'
state :failed, value: 'failed'
state :success, value: 'success'
state :canceled, value: 'canceled'
end
delegate :sha, :short_sha, :project, :gl_project,
to: :commit, prefix: false
def before_sha
Gitlab::Git::BLANK_SHA
def ignored?
failed? && allow_failure?
end
def trace_html
......@@ -156,22 +114,6 @@ module Ci
html || ''
end
def started?
!pending? && !canceled? && started_at
end
def active?
running? || pending?
end
def complete?
canceled? || success? || failed?
end
def ignored?
failed? && allow_failure?
end
def timeout
project.timeout
end
......@@ -180,14 +122,6 @@ module Ci
yaml_variables + project_variables + trigger_variables
end
def duration
if started_at && finished_at
finished_at - started_at
elsif started_at
Time.now - started_at
end
end
def project
commit.project
end
......@@ -278,6 +212,25 @@ module Ci
"#{dir_to_trace}/#{id}.log"
end
def target_url
Gitlab::Application.routes.url_helpers.
namespace_project_build_url(gl_project.namespace, gl_project, self)
end
def cancel_url
if active?
Gitlab::Application.routes.url_helpers.
cancel_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
end
def retry_url
if commands.present?
Gitlab::Application.routes.url_helpers.
retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
end
private
def yaml_variables
......
......@@ -20,7 +20,8 @@ module Ci
extend Ci::Model
belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id
has_many :builds, dependent: :destroy, class_name: 'Ci::Build'
has_many :statuses, dependent: :destroy, class_name: 'CommitStatus'
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
validates_presence_of :sha
......@@ -47,7 +48,7 @@ module Ci
end
def retry
builds_without_retry.each do |build|
latest_builds.each do |build|
Ci::Build.retry(build)
end
end
......@@ -81,12 +82,11 @@ module Ci
end
def stage
running_or_pending = builds_without_retry.running_or_pending
running_or_pending.limit(1).pluck(:stage).first
running_or_pending = statuses.latest.running_or_pending.ordered
running_or_pending.first.try(:stage)
end
def create_builds(ref, tag, user, trigger_request = nil)
return if skip_ci? && trigger_request.blank?
return unless config_processor
config_processor.stages.any? do |stage|
CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
......@@ -94,7 +94,6 @@ module Ci
end
def create_next_builds(ref, tag, user, trigger_request)
return if skip_ci? && trigger_request.blank?
return unless config_processor
stages = builds.where(ref: ref, tag: tag, trigger_request: trigger_request).group_by(&:stage)
......@@ -107,61 +106,60 @@ module Ci
end
def refs
builds.group(:ref).pluck(:ref)
statuses.order(:ref).pluck(:ref).uniq
end
def last_ref
builds.latest.first.try(:ref)
def latest_statuses
@latest_statuses ||= statuses.latest.to_a
end
def builds_without_retry
builds.latest
def latest_builds
@latest_builds ||= builds.latest.to_a
end
def builds_without_retry_for_ref(ref)
builds.for_ref(ref).latest
def latest_builds_for_ref(ref)
latest_builds.select { |build| build.ref == ref }
end
def retried_builds
@retried_builds ||= (builds.order(id: :desc) - builds_without_retry)
def retried
@retried ||= (statuses.order(id: :desc) - statuses.latest)
end
def status
if skip_ci?
return 'skipped'
elsif yaml_errors.present?
if yaml_errors.present?
return 'failed'
elsif builds.none?
return 'skipped'
elsif success?
end
@status ||= begin
latest = latest_statuses
latest.reject! { |status| status.try(&:allow_failure?) }
if latest.none?
'skipped'
elsif latest.all?(&:success?)
'success'
elsif pending?
elsif latest.all?(&:pending?)
'pending'
elsif running?
elsif latest.any?(&:running?) || latest.any?(&:pending?)
'running'
elsif canceled?
elsif latest.all?(&:canceled?)
'canceled'
else
'failed'
end
end
end
def pending?
builds_without_retry.all? do |build|
build.pending?
end
status == 'pending'
end
def running?
builds_without_retry.any? do |build|
build.running? || build.pending?
end
status == 'running'
end
def success?
builds_without_retry.all? do |build|
build.success? || build.ignored?
end
status == 'success'
end
def failed?
......@@ -169,26 +167,21 @@ module Ci
end
def canceled?
builds_without_retry.all? do |build|
build.canceled?
end
status == 'canceled'
end
def duration
@duration ||= builds_without_retry.select(&:duration).sum(&:duration).to_i
end
def duration_for_ref(ref)
builds_without_retry_for_ref(ref).select(&:duration).sum(&:duration).to_i
duration_array = latest_statuses.map(&:duration).compact
duration_array.reduce(:+).to_i
end
def finished_at
@finished_at ||= builds.order('finished_at DESC').first.try(:finished_at)
@finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
end
def coverage
if project.coverage_enabled?
coverage_array = builds_without_retry.map(&:coverage).compact
coverage_array = latest_builds.map(&:coverage).compact
if coverage_array.size >= 1
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
end
......@@ -196,7 +189,7 @@ module Ci
end
def matrix_for_ref?(ref)
builds_without_retry_for_ref(ref).pluck(:id).size > 1
latest_builds_for_ref(ref).size > 1
end
def config_processor
......@@ -217,7 +210,6 @@ module Ci
end
def skip_ci?
return false if builds.any?
git_commit_message =~ /(\[ci skip\])/ if git_commit_message
end
......
......@@ -184,4 +184,12 @@ class Commit
def parents
@parents ||= Commit.decorate(super, project)
end
def ci_commit
project.ci_commit(sha)
end
def status
ci_commit.try(:status) || :not_found
end
end
class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds'
belongs_to :commit, class_name: 'Ci::Commit'
belongs_to :user
validates :commit, presence: true
validates :status, inclusion: { in: %w(pending running failed success canceled) }
validates_presence_of :name
alias_attribute :author, :user
scope :running, -> { where(status: 'running') }
scope :pending, -> { where(status: 'pending') }
scope :success, -> { where(status: 'success') }
scope :failed, -> { where(status: 'failed') }
scope :running_or_pending, -> { where(status:[:running, :pending]) }
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) }
scope :running_or_pending, -> { where(status: [:running, :pending]) }
state_machine :status, initial: :pending do
event :run do
transition pending: :running
end
event :drop do
transition running: :failed
end
event :success do
transition [:pending, :running] => :success
end
event :cancel do
transition [:pending, :running] => :canceled
end
after_transition pending: :running do |build, transition|
build.update_attributes started_at: Time.now
end
after_transition any => [:success, :failed, :canceled] do |build, transition|
build.update_attributes finished_at: Time.now
end
state :pending, value: 'pending'
state :running, value: 'running'
state :failed, value: 'failed'
state :success, value: 'success'
state :canceled, value: 'canceled'
end
delegate :sha, :short_sha, :gl_project,
to: :commit, prefix: false
# TODO: this should be removed with all references
def before_sha
Gitlab::Git::BLANK_SHA
end
def started?
!pending? && !canceled? && started_at
end
def active?
running? || pending?
end
def complete?
canceled? || success? || failed?
end
def duration
if started_at && finished_at
finished_at - started_at
elsif started_at
Time.now - started_at
end
end
def cancel_url
nil
end
def retry_url
nil
end
end
# Concern for querying columns with specific case sensitivity handling.
module CaseSensitivity
extend ActiveSupport::Concern
module ClassMethods
# Queries the given columns regardless of the casing used.
#
# Unlike other ActiveRecord methods this method only operates on a Hash.
def iwhere(params)
criteria = self
cast_lower = Gitlab::Database.postgresql?
params.each do |key, value|
column = ActiveRecord::Base.connection.quote_table_name(key)
if cast_lower
condition = "LOWER(#{column}) = LOWER(:value)"
else
condition = "#{column} = :value"
end
criteria = criteria.where(condition, value: value)
end
criteria
end
end
end
class GenericCommitStatus < CommitStatus
before_validation :set_default_values
# GitHub compatible API
alias_attribute :context, :name
def set_default_values
self.context ||= 'default'
self.stage ||= 'external'
end
def tags
[:external]
end
end
class GroupMilestone
alias_attribute :name, :title
def initialize(title, milestones)
@title = title
@milestones = milestones
......
......@@ -12,6 +12,11 @@
class Label < ActiveRecord::Base
include Referable
# Represents a "No Label" state used for filtering Issues and Merge
# Requests that have no label assigned.
LabelStruct = Struct.new(:title, :name)
None = LabelStruct.new('No Label', 'No Label')
Any = LabelStruct.new('Any', '')
DEFAULT_COLOR = '#428BCA'
......
......@@ -227,7 +227,7 @@ class MergeRequest < ActiveRecord::Base
end
def work_in_progress?
title =~ /\A\[?WIP\]?:? /i
!!(title =~ /\A\[?WIP\]?:? /i)
end
def mergeable?
......@@ -275,7 +275,8 @@ class MergeRequest < ActiveRecord::Base
attrs = {
source: source_project.hook_attrs,
target: target_project.hook_attrs,
last_commit: nil
last_commit: nil,
work_in_progress: work_in_progress?
}
unless last_commit.nil?
......
......@@ -16,7 +16,9 @@
class Milestone < ActiveRecord::Base
# Represents a "No Milestone" state used for filtering Issues and Merge
# Requests that have no milestone assigned.
None = Struct.new(:title).new('No Milestone')
MilestoneStruct = Struct.new(:title, :name)
None = MilestoneStruct.new('No Milestone', 'No Milestone')
Any = MilestoneStruct.new('Any', '')
include InternalId
include Sortable
......@@ -47,6 +49,8 @@ class Milestone < ActiveRecord::Base
state :active
end
alias_attribute :name, :title
class << self
def search(query)
query = "%#{query}%"
......
......@@ -118,6 +118,8 @@ class Namespace < ActiveRecord::Base
gitlab_shell.add_namespace(path_was)
if gitlab_shell.mv_namespace(path_was, path)
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
......
......@@ -40,6 +40,7 @@ class Project < ActiveRecord::Base
include Referable
include Sortable
include AfterCommitQueue
include CaseSensitivity
extend Gitlab::ConfigHelper
extend Enumerize
......@@ -235,13 +236,18 @@ class Project < ActiveRecord::Base
end
def find_with_namespace(id)
return nil unless id.include?('/')
namespace_path, project_path = id.split('/')
id = id.split('/')
namespace = Namespace.by_path(id.first)
return nil unless namespace
return nil if !namespace_path || !project_path
where(namespace_id: namespace.id).where("LOWER(projects.path) = :path", path: id.second.downcase).first
# Use of unscoped ensures we're not secretly adding any ORDER BYs, which
# have a negative impact on performance (and aren't needed for this
# query).
unscoped.
joins(:namespace).
iwhere('namespaces.path' => namespace_path).
iwhere('projects.path' => project_path).
take
end
def visibility_levels
......@@ -260,6 +266,20 @@ class Project < ActiveRecord::Base
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
%r{(?<project>#{name_pattern}/#{name_pattern})}
end
def trending(since = 1.month.ago)
# By counting in the JOIN we don't expose the GROUP BY to the outer query.
# This means that calls such as "any?" and "count" just return a number of
# the total count, instead of the counts grouped per project as a Hash.
join_body = "INNER JOIN (
SELECT project_id, COUNT(*) AS amount
FROM notes
WHERE created_at >= #{sanitize(since)}
GROUP BY project_id
) join_note_counts ON projects.id = join_note_counts.project_id"
joins(join_body).reorder('join_note_counts.amount DESC')
end
end
def team
......@@ -636,6 +656,8 @@ class Project < ActiveRecord::Base
# db changes in order to prevent out of sync between db and fs
raise Exception.new('repository cannot be renamed')
end
Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path)
end
def hook_attrs
......
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.
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.
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