mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-15 23:56:09 +10:00
Merge branch 'ce-to-ee' into 'master'
CE to EE @rspeicher @douwe reference extraction / markdown parsing was refactored and improved again and again. And every time I merge CE into EE I has conflicts in this code. Can we have SAME code CE and EE responsible for reference extraction? Problem files: * lib/gitlab/markdown/external_issue_reference_filter.rb * lib/gitlab/reference_extractor.rb See merge request !411
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
before_script:
|
||||
- export PATH=$HOME/bin:/usr/local/bin:/usr/bin:/bin
|
||||
- ruby -v
|
||||
- which ruby
|
||||
- gem install bundler
|
||||
- which bundle
|
||||
- echo $PATH
|
||||
- cp config/database.yml.mysql config/database.yml
|
||||
- cp config/gitlab.yml.example config/gitlab.yml
|
||||
- ! 'sed "s/username\:.*$/username\: runner/" -i config/database.yml'
|
||||
- ! 'sed "s/password\:.*$/password\: ''password''/" -i config/database.yml'
|
||||
- sed "s/gitlabhq_test/gitlabhq_test_$((RANDOM/5000))/" -i config/database.yml
|
||||
- touch log/application.log
|
||||
- touch log/test.log
|
||||
- bundle install --without postgres production --jobs $(nproc)
|
||||
- bundle exec rake db:create RAILS_ENV=test
|
||||
jobs:
|
||||
- script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec
|
||||
name: Rspec
|
||||
runner: ruby,mysql
|
||||
- script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach
|
||||
name: Spinach
|
||||
runner: ruby,mysql
|
||||
- script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake jasmine:ci
|
||||
name: Jasmine
|
||||
runner: ruby,mysql
|
||||
- script:
|
||||
- bundle exec rubocop
|
||||
name: Rubocop
|
||||
runner: ruby,mysql
|
||||
- script:
|
||||
- bundle exec rake brakeman
|
||||
name: Brakeman
|
||||
runner: ruby,mysql
|
||||
deploy_jobs: []
|
||||
skip_refs: ''
|
||||
@@ -1,6 +1,73 @@
|
||||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 7.11.0 (unreleased)
|
||||
v 7.12.0 (unreleased)
|
||||
- Don't notify users mentioned in code blocks or blockquotes.
|
||||
- Omit link to generate labels if user does not have access to create them (Stan Hu)
|
||||
- Disable changing of the source branch in merge request update API (Stan Hu)
|
||||
- Shorten merge request WIP text.
|
||||
- Add option to disallow users from registering any application to use GitLab as an OAuth provider
|
||||
- Support editing target branch of merge request (Stan Hu)
|
||||
- Refactor permission checks with issues and merge requests project settings (Stan Hu)
|
||||
- Fix Markdown preview not working in Edit Milestone page (Stan Hu)
|
||||
- Fix Zen Mode not closing with ESC key (Stan Hu)
|
||||
- Allow HipChat API version to be blank and default to v2 (Stan Hu)
|
||||
- Add file attachment support in Milestone description (Stan Hu)
|
||||
- Fix milestone "Browse Issues" button.
|
||||
- Set milestone on new issue when creating issue from index with milestone filter active.
|
||||
- Make namespace API available to all users (Stan Hu)
|
||||
- Add web hook support for note events (Stan Hu)
|
||||
- Disable "New Issue" and "New Merge Request" buttons when features are disabled in project settings (Stan Hu)
|
||||
- Remove Rack Attack monkey patches and bump to version 4.3.0 (Stan Hu)
|
||||
- Fix clone URL losing selection after a single click in Safari and Chrome (Stan Hu)
|
||||
- Fix git blame syntax highlighting when different commits break up lines (Stan Hu)
|
||||
- Add "Resend confirmation e-mail" link in profile settings (Stan Hu)
|
||||
- Allow to configure location of the `.gitlab_shell_secret` file. (Jakub Jirutka)
|
||||
- Disabled expansion of top/bottom blobs for new file diffs
|
||||
- Update Asciidoctor gem to version 1.5.2. (Jakub Jirutka)
|
||||
- Fix resolving of relative links to repository files in AsciiDoc documents. (Jakub Jirutka)
|
||||
- Use the user list from the target project in a merge request (Stan Hu)
|
||||
- Default extention for wiki pages is now .md instead of .markdown (Jeroen van Baarsen)
|
||||
- Add validation to wiki page creation (only [a-zA-Z0-9/_-] are allowed) (Jeroen van Baarsen)
|
||||
- Fix new/empty milestones showing 100% completion value (Jonah Bishop)
|
||||
- Add a note when an Issue or Merge Request's title changes
|
||||
- Consistently refer to MRs as either Accepted or Rejected.
|
||||
- Add Accepted and Rejected tabs to MR lists.
|
||||
- Prefix EmailsOnPush email subject with `[Git]`.
|
||||
- Group project contributions by both name and email.
|
||||
- Clarify navigation labels for Project Settings and Group Settings.
|
||||
- Move user avatar and logout button to sidebar
|
||||
- You can not remove user if he/she is an only owner of group
|
||||
- User should be able to leave group. If not - show him proper message
|
||||
- User has ability to leave project
|
||||
- Add SAML support as an omniauth provider
|
||||
- Allow to configure a URL to show after sign out
|
||||
- Add an option to automatically sign-in with an Omniauth provider
|
||||
- Better performance for web editor (switched from satellites to rugged)
|
||||
- GitLab CI service sends .gitlab-ci.yaml in each push call
|
||||
- When remove project - move repository and schedule it removal
|
||||
- Improve group removing logic
|
||||
- Trigger create-hooks on backup restore task
|
||||
|
||||
v 7.11.4
|
||||
- Fix missing bullets when creating lists
|
||||
- Set rel="nofollow" on external links
|
||||
|
||||
v 7.11.3
|
||||
- no changes
|
||||
- Fix upgrader script (Martins Polakovs)
|
||||
|
||||
v 7.11.2
|
||||
- no changes
|
||||
|
||||
v 7.11.1
|
||||
- no changes
|
||||
|
||||
v 7.11.0
|
||||
- Fall back to Plaintext when Syntaxhighlighting doesn't work. Fixes some buggy lexers (Hannes Rosenögger)
|
||||
- Get editing comments to work in Chrome 43 again.
|
||||
- Allow special character in users bio. I.e.: I <3 GitLab
|
||||
|
||||
v 7.11.0
|
||||
- Fix broken view when viewing history of a file that includes a path that used to be another file (Stan Hu)
|
||||
- Don't show duplicate deploy keys
|
||||
- Fix commit time being displayed in the wrong timezone in some cases (Hannes Rosenögger)
|
||||
@@ -11,8 +78,6 @@ v 7.11.0 (unreleased)
|
||||
- Don't allow a merge request to be merged when its title starts with "WIP".
|
||||
- Add a page title to every page.
|
||||
- Allow primary email to be set to an email that you've already added.
|
||||
- Fix Error 500 when searching Wiki pages (Stan Hu)
|
||||
- Get Gitorious importer to work again.
|
||||
- Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
|
||||
- Ignore invalid lines in .gitmodules
|
||||
- Fix "Cannot move project" error message from popping up after a successful transfer (Stan Hu)
|
||||
@@ -21,7 +86,6 @@ v 7.11.0 (unreleased)
|
||||
- Fix "Revspec not found" errors when viewing diffs in a forked project with submodules (Stan Hu)
|
||||
- Improve project page UI
|
||||
- Fix broken file browsing with relative submodule in personal projects (Stan Hu)
|
||||
- Fix DB error when trying to tag a repository (Stan Hu)
|
||||
- Add "Reply quoting selected text" shortcut key (`r`)
|
||||
- Fix bug causing `@whatever` inside an issue's first code block to be picked up as a user mention.
|
||||
- Fix bug causing `@whatever` inside an inline code snippet (backtick-style) to be picked up as a user mention.
|
||||
@@ -32,20 +96,19 @@ v 7.11.0 (unreleased)
|
||||
- Show Atom feed buttons everywhere where applicable.
|
||||
- Add project activity atom feed.
|
||||
- Don't crash when an MR from a fork has a cross-reference comment from the target project on one of its commits.
|
||||
- Explain how to get a new password reset token in welcome emails
|
||||
- Include commit comments in MR from a forked project.
|
||||
- Fix adding new group members from admin area
|
||||
- Group milestones by title in the dashboard and all other issue views.
|
||||
- Query issues, merge requests and milestones with their IID through API (Julien Bianchi)
|
||||
- Add default project and snippet visibility settings to the admin web UI.
|
||||
- Show incompatible projects in Google Code import status (Stan Hu)
|
||||
- Fix bug where commit data would not appear in some subdirectories (Stan Hu)
|
||||
- Unescape branch names in compare commit (Stan Hu)
|
||||
- Task lists are now usable in comments, and will show up in Markdown previews.
|
||||
- Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu)
|
||||
- Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu)
|
||||
- Protect OmniAuth request phase against CSRF.
|
||||
-
|
||||
-
|
||||
- Don't send notifications to mentioned users that don't have access to the project in question.
|
||||
- Add search issues/MR by number
|
||||
- Move snippets UI to fluid layout
|
||||
- Improve UI for sidebar. Increase separation between navigation and content
|
||||
- Improve new project command options (Ben Bodenmiller)
|
||||
@@ -66,6 +129,17 @@ v 7.11.0 (unreleased)
|
||||
- Add style for <kbd> element in markdown
|
||||
- Spin spinner icon next to "Checking for CI status..." on MR page.
|
||||
- Fix reference links in dashboard activity and ATOM feeds.
|
||||
- Ensure that the first added admin performs repository imports
|
||||
|
||||
v 7.10.4
|
||||
- Fix migrations broken in 7.10.2
|
||||
- Make tags for GitLab installations running on MySQL case sensitive
|
||||
- Get Gitorious importer to work again.
|
||||
- Fix adding new group members from admin area
|
||||
- Fix DB error when trying to tag a repository (Stan Hu)
|
||||
- Fix Error 500 when searching Wiki pages (Stan Hu)
|
||||
- Unescape branch names in compare commit (Stan Hu)
|
||||
- Order commit comments chronologically in API.
|
||||
|
||||
v 7.10.2
|
||||
- Fix CI links on MR page
|
||||
@@ -150,12 +224,12 @@ v 7.9.0 (unreleased)
|
||||
- Ability to skip some items from backup (database, respositories or uploads)
|
||||
- Archive repositories in background worker.
|
||||
- Import GitHub, Bitbucket or GitLab.com projects owned by authenticated user into current namespace.
|
||||
- Project labels are now available over the API under the "tag_list" field (Cristian Medina)
|
||||
- Project labels are now available over the API under the "tag_list" field (Cristian Medina)
|
||||
- Fixed link paths for HTTP and SSH on the admin project view (Jeremy Maziarz)
|
||||
- Fix and improve help rendering (Sullivan Sénéchal)
|
||||
- Fix final line in EmailsOnPush email diff being rendered as error.
|
||||
- Prevent duplicate Buildkite service creation.
|
||||
- Fix git over ssh errors 'fatal: protocol error: bad line length character'
|
||||
- Fix git over ssh errors 'fatal: protocol error: bad line length character'
|
||||
- Automatically setup GitLab CI project for forks if origin project has GitLab CI enabled
|
||||
- Bust group page project list cache when namespace name or path changes.
|
||||
- Explicitly set image alt-attribute to prevent graphical glitches if gravatars could not be loaded
|
||||
@@ -164,7 +238,7 @@ v 7.9.0 (unreleased)
|
||||
- Fix stuck Merge Request merging events from old installations (Ben Bodenmiller)
|
||||
- Fix merge request comments on files with multiple commits
|
||||
- Fix Resource Owner Password Authentication Flow
|
||||
|
||||
|
||||
v 7.9.4
|
||||
- Security: Fix project import URL regex to prevent arbitary local repos from being imported
|
||||
- Fixed issue where only 25 commits would load in file listings
|
||||
@@ -470,6 +544,12 @@ v 7.5.0
|
||||
- Use secret token with GitLab internal API.
|
||||
- Add missing timestamps to 'members' table
|
||||
|
||||
v 7.4.5
|
||||
- Bump gitlab_git to 7.0.0.rc12 (includes Rugged 0.21.2)
|
||||
|
||||
v 7.4.4
|
||||
- No changes
|
||||
|
||||
v 7.4.3
|
||||
- Fix raw snippets view
|
||||
- Fix security issue for member api
|
||||
|
||||
+8
-7
@@ -29,11 +29,9 @@ You can also sign up on [CodeTriage](http://www.codetriage.com/gitlabhq/gitlabhq
|
||||
|
||||
## Issue tracker
|
||||
|
||||
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://about.gitlab.com/subscription/) and [consulting services](http://about.gitlab.com/consultancy/) are available from [GitLab.com](http://about.gitlab.com/).
|
||||
To get support for your particular problem please use the [getting help channels](https://about.gitlab.com/getting-help/).
|
||||
|
||||
The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
|
||||
|
||||
Issues can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues) or [github.com](https://github.com/gitlabhq/gitlabhq/issues).
|
||||
The [GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
|
||||
|
||||
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
|
||||
|
||||
@@ -86,7 +84,9 @@ If you can, please submit a merge request with the fix or improvements including
|
||||
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
|
||||
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
|
||||
|
||||
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
|
||||
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
|
||||
Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
|
||||
After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
|
||||
|
||||
Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? Can you do part of the refactor? The increased reviewability of small MR's that leads to higher code quality is more important to us than having a minimal commit log. The smaller a MR is the more likely it is it will be merged (quickly), after that you can send more MR's to enhance it.
|
||||
|
||||
@@ -160,8 +160,9 @@ If you add a dependency in GitLab (such as an operating system package) please c
|
||||
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
|
||||
1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
|
||||
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
|
||||
1. [Database Migrations](doc/development/migration_style_guide.md)
|
||||
1. [Documentation styleguide](doc_styleguide.md)
|
||||
1. Interface text should be written subjectively instead of objectively. It should be the gitlab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
|
||||
1. [Migrations](doc/development/migration_style_guide.md)
|
||||
|
||||
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
|
||||
|
||||
@@ -177,4 +178,4 @@ Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior can be
|
||||
reported by emailing contact@gitlab.com
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
||||
@@ -1,18 +1,7 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
def darwin_only(require_as)
|
||||
RUBY_PLATFORM.include?('darwin') && require_as
|
||||
end
|
||||
|
||||
def linux_only(require_as)
|
||||
RUBY_PLATFORM.include?('linux') && require_as
|
||||
end
|
||||
|
||||
gem "rails", "~> 4.1.0"
|
||||
|
||||
# Make links from text
|
||||
gem 'rails_autolink', '~> 1.1'
|
||||
|
||||
# Default values for AR models
|
||||
gem "default_value_for", "~> 3.0.0"
|
||||
|
||||
@@ -31,6 +20,7 @@ gem 'omniauth-shibboleth'
|
||||
gem 'omniauth-kerberos', group: :kerberos
|
||||
gem 'omniauth-gitlab'
|
||||
gem 'omniauth-bitbucket'
|
||||
gem 'omniauth-saml'
|
||||
gem 'doorkeeper', '2.1.3'
|
||||
gem "rack-oauth2", "~> 1.0.5"
|
||||
|
||||
@@ -44,12 +34,16 @@ gem "browser"
|
||||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
gem "gitlab_git", '~> 7.1.12'
|
||||
gem "gitlab_git", '~> 7.2.2'
|
||||
|
||||
# Ruby/Rack Git Smart-HTTP Server Handler
|
||||
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
|
||||
# For full list of changes see https://github.com/SaitoWu/grack/compare/master...gitlabhq:master
|
||||
gem 'gitlab-grack', '~> 2.0.2', require: 'grack'
|
||||
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
|
||||
gem 'gitlab_omniauth-ldap', '1.2.1', require: "omniauth-ldap"
|
||||
gem 'net-ldap'
|
||||
|
||||
@@ -57,6 +51,10 @@ gem 'net-ldap'
|
||||
gem 'gollum-lib', '~> 4.0.2'
|
||||
|
||||
# Language detection
|
||||
# GitLab fork of linguist does not require pygments/python dependency.
|
||||
# New version of original gem also dropped pygments support but it has strict
|
||||
# dependency to unstable rugged version. We have internal issue for replacing
|
||||
# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052.
|
||||
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
|
||||
|
||||
# API
|
||||
@@ -95,7 +93,7 @@ gem "seed-fu"
|
||||
|
||||
# Markdown and HTML processing
|
||||
gem 'html-pipeline', '~> 1.11.0'
|
||||
gem 'task_list', '~> 1.0.0', require: 'task_list/railtie'
|
||||
gem 'task_list', '1.0.2', require: 'task_list/railtie'
|
||||
gem 'github-markup'
|
||||
gem 'redcarpet', '~> 3.2.3'
|
||||
gem 'RedCloth'
|
||||
@@ -103,7 +101,7 @@ gem 'rdoc', '~>3.6'
|
||||
gem 'org-ruby', '= 0.9.12'
|
||||
gem 'creole', '~>0.3.6'
|
||||
gem 'wikicloth', '=0.8.1'
|
||||
gem 'asciidoctor', '= 0.1.4'
|
||||
gem 'asciidoctor', '~> 1.5.2'
|
||||
|
||||
# Diffs
|
||||
gem 'diffy', '~> 3.0.3'
|
||||
@@ -173,7 +171,7 @@ gem "underscore-rails", "~> 1.4.4"
|
||||
gem "sanitize", '~> 2.0'
|
||||
|
||||
# Protect against bruteforcing
|
||||
gem "rack-attack"
|
||||
gem "rack-attack", '~> 4.3.0'
|
||||
|
||||
# Ace editor
|
||||
gem 'ace-rails-ap'
|
||||
@@ -187,23 +185,23 @@ gem 'charlock_holmes'
|
||||
gem "sass-rails", '~> 4.0.2'
|
||||
gem "coffee-rails"
|
||||
gem "uglifier"
|
||||
gem 'turbolinks'
|
||||
gem 'turbolinks', '~> 2.5.0'
|
||||
gem 'jquery-turbolinks'
|
||||
|
||||
gem 'select2-rails'
|
||||
gem 'jquery-atwho-rails', '~> 1.0.0'
|
||||
gem "jquery-rails"
|
||||
gem "jquery-ui-rails"
|
||||
gem "jquery-scrollto-rails"
|
||||
gem "raphael-rails", "~> 2.1.2"
|
||||
gem 'bootstrap-sass', '~> 3.0'
|
||||
gem "font-awesome-rails", '~> 4.2'
|
||||
gem "gitlab_emoji", "~> 0.1"
|
||||
gem "gon", '~> 5.0.0'
|
||||
gem 'nprogress-rails'
|
||||
gem 'request_store'
|
||||
gem "virtus"
|
||||
gem 'addressable'
|
||||
gem 'bootstrap-sass', '~> 3.0'
|
||||
gem 'font-awesome-rails', '~> 4.2'
|
||||
gem 'gitlab_emoji', '~> 0.1'
|
||||
gem 'gon', '~> 5.0.0'
|
||||
gem 'jquery-atwho-rails', '~> 1.0.0'
|
||||
gem 'jquery-rails', '3.1.2'
|
||||
gem 'jquery-scrollto-rails'
|
||||
gem 'jquery-ui-rails'
|
||||
gem 'nprogress-rails'
|
||||
gem 'raphael-rails', '~> 2.1.2'
|
||||
gem 'request_store'
|
||||
gem 'select2-rails'
|
||||
gem 'virtus'
|
||||
|
||||
gem "gitlab-license", "~> 0.0.2"
|
||||
|
||||
@@ -242,25 +240,18 @@ group :development, :test do
|
||||
gem 'minitest', '~> 5.3.0'
|
||||
|
||||
# Generate Fake data
|
||||
gem "ffaker"
|
||||
|
||||
# Guard
|
||||
gem 'guard-rspec'
|
||||
gem 'guard-spinach'
|
||||
|
||||
# Notification
|
||||
gem 'rb-fsevent', require: darwin_only('rb-fsevent')
|
||||
gem 'growl', require: darwin_only('growl')
|
||||
gem 'rb-inotify', require: linux_only('rb-inotify')
|
||||
gem 'ffaker', '~> 2.0.0'
|
||||
|
||||
# PhantomJS driver for Capybara
|
||||
gem 'poltergeist', '~> 1.5.1'
|
||||
|
||||
gem 'jasmine-rails'
|
||||
gem 'teaspoon', '~> 1.0.0'
|
||||
gem 'teaspoon-jasmine'
|
||||
|
||||
gem "spring", '~> 1.3.1'
|
||||
gem "spring-commands-rspec", '1.0.4'
|
||||
gem "spring-commands-spinach", '1.0.0'
|
||||
gem 'spring', '~> 1.3.1'
|
||||
gem 'spring-commands-rspec', '~> 1.0.0'
|
||||
gem 'spring-commands-spinach', '~> 1.0.0'
|
||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||
|
||||
gem "byebug"
|
||||
end
|
||||
@@ -280,4 +271,4 @@ end
|
||||
gem "newrelic_rpm"
|
||||
|
||||
gem 'octokit', '3.7.0'
|
||||
gem "rugments"
|
||||
gem "rugments", "~> 1.0.0.beta7"
|
||||
|
||||
+50
-63
@@ -42,7 +42,7 @@ GEM
|
||||
arel (5.0.1.20140414130214)
|
||||
asana (0.0.6)
|
||||
activeresource (>= 3.2.3)
|
||||
asciidoctor (0.1.4)
|
||||
asciidoctor (1.5.2)
|
||||
ast (2.0.0)
|
||||
astrolabe (1.3.0)
|
||||
parser (>= 2.2.0.pre.3, < 3.0)
|
||||
@@ -101,13 +101,13 @@ GEM
|
||||
coderay (1.1.0)
|
||||
coercible (1.0.0)
|
||||
descendants_tracker (~> 0.0.1)
|
||||
coffee-rails (4.0.1)
|
||||
coffee-rails (4.1.0)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
coffee-script (2.2.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.6.3)
|
||||
coffee-script-source (1.9.1.1)
|
||||
colored (1.2)
|
||||
colorize (0.5.8)
|
||||
columnize (0.9.0)
|
||||
@@ -176,7 +176,7 @@ GEM
|
||||
faraday_middleware (0.9.0)
|
||||
faraday (>= 0.7.4, < 0.9)
|
||||
fastercsv (1.5.5)
|
||||
ffaker (1.22.1)
|
||||
ffaker (2.0.0)
|
||||
ffi (1.9.8)
|
||||
fog (1.21.0)
|
||||
fog-brightbox
|
||||
@@ -226,11 +226,11 @@ GEM
|
||||
mime-types (~> 1.19)
|
||||
gitlab_emoji (0.1.0)
|
||||
gemojione (~> 2.0)
|
||||
gitlab_git (7.1.12)
|
||||
gitlab_git (7.2.2)
|
||||
activesupport (~> 4.0)
|
||||
charlock_holmes (~> 0.6)
|
||||
gitlab-linguist (~> 3.0)
|
||||
rugged (~> 0.21.2)
|
||||
rugged (~> 0.22.2)
|
||||
gitlab_meta (7.0)
|
||||
gitlab_omniauth-ldap (1.2.1)
|
||||
net-ldap (~> 0.9)
|
||||
@@ -262,19 +262,6 @@ GEM
|
||||
grape-entity (0.4.2)
|
||||
activesupport
|
||||
multi_json (>= 1.3.2)
|
||||
growl (1.0.3)
|
||||
guard (2.2.4)
|
||||
formatador (>= 0.2.4)
|
||||
listen (~> 2.1)
|
||||
lumberjack (~> 1.0)
|
||||
pry (>= 0.9.12)
|
||||
thor (>= 0.18.1)
|
||||
guard-rspec (4.2.0)
|
||||
guard (>= 2.1.1)
|
||||
rspec (>= 2.14, < 4.0)
|
||||
guard-spinach (0.0.2)
|
||||
guard (>= 1.1)
|
||||
spinach
|
||||
haml (4.0.5)
|
||||
tilt
|
||||
haml-rails (0.5.3)
|
||||
@@ -301,14 +288,8 @@ GEM
|
||||
i18n (0.7.0)
|
||||
ice_cube (0.11.1)
|
||||
ice_nine (0.10.0)
|
||||
jasmine-core (2.2.0)
|
||||
jasmine-rails (0.10.8)
|
||||
jasmine-core (>= 1.3, < 3.0)
|
||||
phantomjs (>= 1.9)
|
||||
railties (>= 3.2.0)
|
||||
sprockets-rails
|
||||
jquery-atwho-rails (1.0.1)
|
||||
jquery-rails (3.1.0)
|
||||
jquery-rails (3.1.2)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-scrollto-rails (1.4.3)
|
||||
@@ -333,13 +314,14 @@ GEM
|
||||
celluloid (~> 0.16.0)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
lumberjack (1.0.4)
|
||||
macaddr (1.7.1)
|
||||
systemu (~> 2.6.2)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mimemagic (0.3.0)
|
||||
mini_portile (0.6.1)
|
||||
mini_portile (0.6.2)
|
||||
minitest (5.3.5)
|
||||
mousetrap-rails (1.4.6)
|
||||
multi_json (1.10.1)
|
||||
@@ -351,7 +333,7 @@ GEM
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.8.0)
|
||||
newrelic_rpm (3.9.4.245)
|
||||
nokogiri (1.6.5)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
nprogress-rails (0.1.2.3)
|
||||
oauth (0.4.7)
|
||||
@@ -390,6 +372,9 @@ GEM
|
||||
omniauth-oauth2 (1.1.1)
|
||||
oauth2 (~> 0.8.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-saml (1.3.1)
|
||||
omniauth (~> 1.1)
|
||||
ruby-saml (~> 0.8.1)
|
||||
omniauth-shibboleth (1.1.1)
|
||||
omniauth (>= 1.0.0)
|
||||
omniauth-twitter (1.0.1)
|
||||
@@ -401,7 +386,6 @@ GEM
|
||||
parser (2.2.0.2)
|
||||
ast (>= 1.1, < 3.0)
|
||||
pg (0.15.1)
|
||||
phantomjs (1.9.8.0)
|
||||
poltergeist (1.5.1)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
@@ -419,10 +403,10 @@ GEM
|
||||
quiet_assets (1.0.2)
|
||||
railties (>= 3.1, < 5.0)
|
||||
racc (1.4.10)
|
||||
rack (1.5.2)
|
||||
rack (1.5.3)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
rack-attack (4.2.0)
|
||||
rack-attack (4.3.0)
|
||||
rack
|
||||
rack-cors (0.2.9)
|
||||
rack-mini-profiler (0.9.0)
|
||||
@@ -451,8 +435,6 @@ GEM
|
||||
sprockets-rails (~> 2.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
rails_autolink (1.1.6)
|
||||
rails (> 3.1)
|
||||
railties (4.1.9)
|
||||
actionpack (= 4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
@@ -498,10 +480,6 @@ GEM
|
||||
rqrcode (0.4.2)
|
||||
rqrcode-rails3 (0.1.7)
|
||||
rqrcode (>= 0.4.2)
|
||||
rspec (2.99.0)
|
||||
rspec-core (~> 2.99.0)
|
||||
rspec-expectations (~> 2.99.0)
|
||||
rspec-mocks (~> 2.99.0)
|
||||
rspec-collection_matchers (1.1.2)
|
||||
rspec-expectations (>= 2.99.0.beta1)
|
||||
rspec-core (2.99.2)
|
||||
@@ -524,6 +502,9 @@ GEM
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
ruby-progressbar (1.7.1)
|
||||
ruby-saml (0.8.2)
|
||||
nokogiri (>= 1.5.0)
|
||||
uuid (~> 2.3)
|
||||
ruby2ruby (2.1.3)
|
||||
ruby_parser (~> 3.1)
|
||||
sexp_processor (~> 4.0)
|
||||
@@ -531,8 +512,8 @@ GEM
|
||||
sexp_processor (~> 4.1)
|
||||
rubyntlm (0.5.0)
|
||||
rubypants (0.2.0)
|
||||
rugged (0.21.4)
|
||||
rugments (1.0.0.beta6)
|
||||
rugged (0.22.2)
|
||||
rugments (1.0.0.beta7)
|
||||
safe_yaml (0.9.7)
|
||||
sanitize (2.1.0)
|
||||
nokogiri (>= 1.4.4)
|
||||
@@ -548,9 +529,9 @@ GEM
|
||||
sdoc (0.3.20)
|
||||
json (>= 1.1.3)
|
||||
rdoc (~> 3.10)
|
||||
seed-fu (2.3.1)
|
||||
activerecord (>= 3.1, < 4.2)
|
||||
activesupport (>= 3.1, < 4.2)
|
||||
seed-fu (2.3.5)
|
||||
activerecord (>= 3.1, < 4.3)
|
||||
activesupport (>= 3.1, < 4.3)
|
||||
select2-rails (3.5.2)
|
||||
thor (~> 0.14)
|
||||
settingslogic (2.0.9)
|
||||
@@ -590,11 +571,13 @@ GEM
|
||||
capybara (>= 2.0.0)
|
||||
railties (>= 3)
|
||||
spinach (>= 0.4)
|
||||
spring (1.3.3)
|
||||
spring (1.3.6)
|
||||
spring-commands-rspec (1.0.4)
|
||||
spring (>= 0.9.1)
|
||||
spring-commands-spinach (1.0.0)
|
||||
spring (>= 0.9.1)
|
||||
spring-commands-teaspoon (0.0.2)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (2.11.0)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
@@ -607,8 +590,13 @@ GEM
|
||||
stamp (0.5.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (2.5.2)
|
||||
systemu (2.6.5)
|
||||
task_list (1.0.2)
|
||||
html-pipeline
|
||||
teaspoon (1.0.2)
|
||||
railties (>= 3.2.5, < 5)
|
||||
teaspoon-jasmine (2.2.0)
|
||||
teaspoon (>= 1.0.0)
|
||||
temple (0.6.7)
|
||||
term-ansicolor (1.2.2)
|
||||
tins (~> 0.8)
|
||||
@@ -634,7 +622,7 @@ GEM
|
||||
multi_json (~> 1.7)
|
||||
twitter-stream (~> 0.1)
|
||||
tins (0.13.1)
|
||||
turbolinks (2.0.0)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
twitter-stream (0.1.16)
|
||||
eventmachine (>= 0.12.8)
|
||||
@@ -655,6 +643,8 @@ GEM
|
||||
raindrops (~> 0.7)
|
||||
unicorn-worker-killer (0.4.2)
|
||||
unicorn (~> 4)
|
||||
uuid (2.3.7)
|
||||
macaddr (~> 1.0)
|
||||
version_sorter (2.0.0)
|
||||
virtus (1.0.1)
|
||||
axiom-types (~> 0.0.5)
|
||||
@@ -684,7 +674,7 @@ DEPENDENCIES
|
||||
addressable
|
||||
annotate (~> 2.6.0.beta2)
|
||||
asana (~> 0.0.6)
|
||||
asciidoctor (= 0.1.4)
|
||||
asciidoctor (~> 1.5.2)
|
||||
attr_encrypted (= 1.3.4)
|
||||
awesome_print
|
||||
better_errors
|
||||
@@ -714,7 +704,7 @@ DEPENDENCIES
|
||||
email_spec
|
||||
enumerize
|
||||
factory_girl_rails
|
||||
ffaker
|
||||
ffaker (~> 2.0.0)
|
||||
fog (~> 1.14)
|
||||
font-awesome-rails (~> 4.2)
|
||||
foreman
|
||||
@@ -725,23 +715,19 @@ DEPENDENCIES
|
||||
gitlab-license (~> 0.0.2)
|
||||
gitlab-linguist (~> 3.0.1)
|
||||
gitlab_emoji (~> 0.1)
|
||||
gitlab_git (~> 7.1.12)
|
||||
gitlab_git (~> 7.2.2)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (= 1.2.1)
|
||||
gollum-lib (~> 4.0.2)
|
||||
gon (~> 5.0.0)
|
||||
grape (~> 0.6.1)
|
||||
grape-entity (~> 0.4.2)
|
||||
growl
|
||||
guard-rspec
|
||||
guard-spinach
|
||||
haml-rails
|
||||
hipchat (~> 1.5.0)
|
||||
html-pipeline (~> 1.11.0)
|
||||
httparty
|
||||
jasmine-rails
|
||||
jquery-atwho-rails (~> 1.0.0)
|
||||
jquery-rails
|
||||
jquery-rails (= 3.1.2)
|
||||
jquery-scrollto-rails
|
||||
jquery-turbolinks
|
||||
jquery-ui-rails
|
||||
@@ -760,6 +746,7 @@ DEPENDENCIES
|
||||
omniauth-gitlab
|
||||
omniauth-google-oauth2
|
||||
omniauth-kerberos
|
||||
omniauth-saml
|
||||
omniauth-shibboleth
|
||||
omniauth-twitter
|
||||
org-ruby (= 0.9.12)
|
||||
@@ -767,15 +754,12 @@ DEPENDENCIES
|
||||
poltergeist (~> 1.5.1)
|
||||
pry-rails
|
||||
quiet_assets (~> 1.0.1)
|
||||
rack-attack
|
||||
rack-attack (~> 4.3.0)
|
||||
rack-cors
|
||||
rack-mini-profiler
|
||||
rack-oauth2 (~> 1.0.5)
|
||||
rails (~> 4.1.0)
|
||||
rails_autolink (~> 1.1)
|
||||
raphael-rails (~> 2.1.2)
|
||||
rb-fsevent
|
||||
rb-inotify
|
||||
rdoc (~> 3.6)
|
||||
redcarpet (~> 3.2.3)
|
||||
redis-rails
|
||||
@@ -784,7 +768,7 @@ DEPENDENCIES
|
||||
rqrcode-rails3
|
||||
rspec-rails (= 2.99)
|
||||
rubocop (= 0.28.0)
|
||||
rugments
|
||||
rugments (~> 1.0.0.beta7)
|
||||
sanitize (~> 2.0)
|
||||
sass-rails (~> 4.0.2)
|
||||
sdoc
|
||||
@@ -801,15 +785,18 @@ DEPENDENCIES
|
||||
slim
|
||||
spinach-rails
|
||||
spring (~> 1.3.1)
|
||||
spring-commands-rspec (= 1.0.4)
|
||||
spring-commands-spinach (= 1.0.0)
|
||||
spring-commands-rspec (~> 1.0.0)
|
||||
spring-commands-spinach (~> 1.0.0)
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
stamp
|
||||
state_machine
|
||||
task_list (~> 1.0.0)
|
||||
task_list (= 1.0.2)
|
||||
teaspoon (~> 1.0.0)
|
||||
teaspoon-jasmine
|
||||
test_after_commit
|
||||
thin
|
||||
tinder (~> 1.9.2)
|
||||
turbolinks
|
||||
turbolinks (~> 2.5.0)
|
||||
uglifier
|
||||
underscore-rails (~> 1.4.4)
|
||||
unf
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# A sample Guardfile
|
||||
# More info at https://github.com/guard/guard#readme
|
||||
|
||||
guard 'rspec', cmd: "spring rspec", all_on_start: false, all_after_pass: false do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
|
||||
# Rails example
|
||||
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
||||
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
||||
watch('config/routes.rb') { "spec/routing" }
|
||||
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||
|
||||
# Capybara request specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
end
|
||||
|
||||
guard 'spinach', command_prefix: 'spring' do
|
||||
watch(%r|^features/(.*)\.feature|)
|
||||
watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m|
|
||||
"features/#{m[1]}#{m[2]}.feature"
|
||||
end
|
||||
end
|
||||
@@ -45,7 +45,7 @@ There are two editions of GitLab.
|
||||
*GitLab [Community Edition](https://about.gitlab.com/features/) (CE)* is available without any costs under an MIT license.
|
||||
|
||||
*GitLab Enterprise Edition (EE)* includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
|
||||
To get access to the EE and support please [become a subscriber](https://about.gitlab.com/pricing/).
|
||||
To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
|
||||
|
||||
## Code status
|
||||
|
||||
|
||||
@@ -49,8 +49,6 @@ window.slugify = (text) ->
|
||||
window.ajaxGet = (url) ->
|
||||
$.ajax({type: "GET", url: url, dataType: "script"})
|
||||
|
||||
window.showAndHide = (selector) ->
|
||||
|
||||
window.split = (val) ->
|
||||
return val.split( /,\s*/ )
|
||||
|
||||
@@ -92,15 +90,7 @@ window.disableButtonIfAnyEmptyField = (form, form_selector, button_selector) ->
|
||||
window.sanitize = (str) ->
|
||||
return str.replace(/<(?:.|\n)*?>/gm, '')
|
||||
|
||||
window.linkify = (str) ->
|
||||
exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
|
||||
return str.replace(exp,"<a href='$1'>$1</a>")
|
||||
|
||||
window.simpleFormat = (str) ->
|
||||
linkify(sanitize(str).replace(/\n/g, '<br />'))
|
||||
|
||||
window.unbindEvents = ->
|
||||
$(document).unbind('scroll')
|
||||
$(document).off('scroll')
|
||||
|
||||
window.shiftWindow = ->
|
||||
@@ -118,7 +108,10 @@ $.timeago.settings.allowFuture = true
|
||||
|
||||
$ ->
|
||||
# Click a .js-select-on-focus field, select the contents
|
||||
$(".js-select-on-focus").on "focusin", -> $(this).select()
|
||||
$(".js-select-on-focus").on "focusin", ->
|
||||
# Prevent a mouseup event from deselecting the input
|
||||
$(this).select().one 'mouseup', (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
$('.remove-row').bind 'ajax:success', ->
|
||||
$(this).closest('li').fadeOut()
|
||||
@@ -142,8 +135,8 @@ $ ->
|
||||
# Place the logo tooltip on the right when collapsed, bottom when expanded
|
||||
$el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom'
|
||||
else
|
||||
# Otherwise use the data-placement attribute like normal
|
||||
$el.data('placement')
|
||||
# Otherwise use the data-placement attribute, or 'bottom' if undefined
|
||||
$el.data('placement') or 'bottom'
|
||||
})
|
||||
|
||||
# Form submitter
|
||||
@@ -176,6 +169,10 @@ $ ->
|
||||
$(@).next('table').show()
|
||||
$(@).remove()
|
||||
|
||||
$('.navbar-toggle').on 'click', ->
|
||||
$('.header-content .title').toggle()
|
||||
$('.header-content .navbar-collapse').toggle()
|
||||
|
||||
# Show/hide comments on diff
|
||||
$("body").on "click", ".js-toggle-diff-comments", (e) ->
|
||||
$(@).toggleClass('active')
|
||||
@@ -191,14 +188,3 @@ $ ->
|
||||
new ConfirmDangerModal(form, text)
|
||||
|
||||
new Aside()
|
||||
|
||||
(($) ->
|
||||
# Disable an element and add the 'disabled' Bootstrap class
|
||||
$.fn.extend disable: ->
|
||||
$(@).attr('disabled', 'disabled').addClass('disabled')
|
||||
|
||||
# Enable an element and remove the 'disabled' Bootstrap class
|
||||
$.fn.extend enable: ->
|
||||
$(@).removeAttr('disabled').removeClass('disabled')
|
||||
|
||||
)(jQuery)
|
||||
|
||||
@@ -27,6 +27,7 @@ class Dispatcher
|
||||
new Milestone()
|
||||
when 'projects:milestones:new', 'projects:milestones:edit'
|
||||
new ZenMode()
|
||||
new DropzoneInput($('.milestone-form'))
|
||||
when 'projects:compare:show'
|
||||
new Diff()
|
||||
when 'projects:issues:new','projects:issues:edit'
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
$.fn.showAndHide = ->
|
||||
$(@).show().
|
||||
delay(3000).
|
||||
fadeOut()
|
||||
|
||||
$.fn.enableButton = ->
|
||||
$(@).removeAttr('disabled').
|
||||
removeClass('disabled')
|
||||
|
||||
$.fn.disableButton = ->
|
||||
$(@).attr('disabled', 'disabled').
|
||||
addClass('disabled')
|
||||
# Disable an element and add the 'disabled' Bootstrap class
|
||||
$.fn.extend disable: ->
|
||||
$(@)
|
||||
.attr('disabled', 'disabled')
|
||||
.addClass('disabled')
|
||||
|
||||
# Enable an element and remove the 'disabled' Bootstrap class
|
||||
$.fn.extend enable: ->
|
||||
$(@)
|
||||
.removeAttr('disabled')
|
||||
.removeClass('disabled')
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#= require jquery
|
||||
#= require jquery.waitforimages
|
||||
#= require task_list
|
||||
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
#= require jquery
|
||||
#= require bootstrap
|
||||
#= require jquery.waitforimages
|
||||
#= require task_list
|
||||
|
||||
class @MergeRequest
|
||||
# Initialize MergeRequest behavior
|
||||
#
|
||||
# Options:
|
||||
# action - String, current controller action
|
||||
# diffs_loaded - Boolean, have diffs been pre-rendered server-side?
|
||||
# (default: true if `action` is 'diffs', otherwise false)
|
||||
# commits_loaded - Boolean, have commits been pre-rendered server-side?
|
||||
# (default: false)
|
||||
#
|
||||
# check_enable - Boolean, whether to check automerge status
|
||||
# url_to_automerge_check - String, URL to use to check automerge status
|
||||
# current_status - String, current automerge status
|
||||
# ci_enable - Boolean, whether a CI service is enabled
|
||||
# url_to_ci_check - String, URL to use to check CI status
|
||||
#
|
||||
constructor: (@opts) ->
|
||||
@initContextWidget()
|
||||
this.$el = $('.merge-request')
|
||||
@diffs_loaded = if @opts.action == 'diffs' then true else false
|
||||
@commits_loaded = false
|
||||
|
||||
this.activateTab(@opts.action)
|
||||
@diffs_loaded = @opts.diffs_loaded or @opts.action == 'diffs'
|
||||
@commits_loaded = @opts.commits_loaded or false
|
||||
|
||||
this.bindEvents()
|
||||
this.activateTabFromPath()
|
||||
|
||||
this.initMergeWidget()
|
||||
this.$('.show-all-commits').on 'click', =>
|
||||
@@ -65,8 +79,18 @@ class @MergeRequest
|
||||
, 'json'
|
||||
|
||||
bindEvents: ->
|
||||
this.$('.merge-request-tabs').on 'click', 'li', (event) =>
|
||||
this.activateTab($(event.currentTarget).data('action'))
|
||||
this.$('.merge-request-tabs a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
|
||||
$target = $(e.target)
|
||||
tab_action = $target.data('action')
|
||||
|
||||
# Lazy-load diffs
|
||||
if tab_action == 'diffs'
|
||||
this.loadDiff() unless @diffs_loaded
|
||||
$('.diff-header').trigger('sticky_kit:recalc')
|
||||
|
||||
# Skip tab-persisting behavior on MergeRequests#new
|
||||
unless @opts.action == 'new'
|
||||
@setCurrentAction(tab_action)
|
||||
|
||||
this.$('.accept_merge_request').on 'click', ->
|
||||
$('.automerge_widget.can_be_merged').hide()
|
||||
@@ -84,21 +108,54 @@ class @MergeRequest
|
||||
this.$('.remove_source_branch_in_progress').hide()
|
||||
this.$('.remove_source_branch_widget.failed').show()
|
||||
|
||||
activateTab: (action) ->
|
||||
this.$('.merge-request-tabs li').removeClass 'active'
|
||||
this.$('.tab-content').hide()
|
||||
switch action
|
||||
when 'diffs'
|
||||
this.$('.merge-request-tabs .diffs-tab').addClass 'active'
|
||||
this.loadDiff() unless @diffs_loaded
|
||||
this.$('.diffs').show()
|
||||
$(".diff-header").trigger("sticky_kit:recalc")
|
||||
when 'commits'
|
||||
this.$('.merge-request-tabs .commits-tab').addClass 'active'
|
||||
this.$('.commits').show()
|
||||
else
|
||||
this.$('.merge-request-tabs .notes-tab').addClass 'active'
|
||||
this.$('.notes').show()
|
||||
# Activate a tab based on the current URL path
|
||||
#
|
||||
# If the current action is 'show' or 'new' (i.e., initial page load),
|
||||
# activates the first tab, otherwise activates the tab corresponding to the
|
||||
# current action (diffs, commits).
|
||||
activateTabFromPath: ->
|
||||
if @opts.action == 'show' || @opts.action == 'new'
|
||||
this.$('.merge-request-tabs a[data-toggle="tab"]:first').tab('show')
|
||||
else
|
||||
this.$(".merge-request-tabs a[data-action='#{@opts.action}']").tab('show')
|
||||
|
||||
# Replaces the current Merge Request-specific action in the URL with a new one
|
||||
#
|
||||
# If the action is "notes", the URL is reset to the standard
|
||||
# `MergeRequests#show` route.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# location.pathname # => "/namespace/project/merge_requests/1"
|
||||
# setCurrentAction('diffs')
|
||||
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
|
||||
#
|
||||
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
|
||||
# setCurrentAction('notes')
|
||||
# location.pathname # => "/namespace/project/merge_requests/1"
|
||||
#
|
||||
# location.pathname # => "/namespace/project/merge_requests/1/diffs"
|
||||
# setCurrentAction('commits')
|
||||
# location.pathname # => "/namespace/project/merge_requests/1/commits"
|
||||
setCurrentAction: (action) ->
|
||||
# Normalize action, just to be safe
|
||||
action = 'notes' if action == 'show'
|
||||
|
||||
# Remove a trailing '/commits' or '/diffs'
|
||||
new_state = location.pathname.replace(/\/(commits|diffs)\/?$/, '')
|
||||
|
||||
# Append the new action if we're on a tab other than 'notes'
|
||||
unless action == 'notes'
|
||||
new_state += "/#{action}"
|
||||
|
||||
# Ensure parameters and hash come along for the ride
|
||||
new_state += location.search + location.hash
|
||||
|
||||
# Replace the current history state with the new one without breaking
|
||||
# Turbolinks' history.
|
||||
#
|
||||
# See https://github.com/rails/turbolinks/issues/363
|
||||
history.replaceState {turbolinks: true, url: new_state}, '', new_state
|
||||
|
||||
showState: (state) ->
|
||||
$('.automerge_widget').hide()
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#= require jquery
|
||||
#= require autosave
|
||||
#= require bootstrap
|
||||
#= require dropzone
|
||||
#= require dropzone_input
|
||||
#= require gfm_auto_complete
|
||||
@@ -312,6 +310,14 @@ class @Notes
|
||||
form.show()
|
||||
textarea = form.find("textarea")
|
||||
textarea.focus()
|
||||
|
||||
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
|
||||
# The textarea has the correct value, Chrome just won't show it unless we
|
||||
# modify it, so let's clear it and re-set it!
|
||||
value = textarea.val()
|
||||
textarea.val ""
|
||||
textarea.val value
|
||||
|
||||
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
|
||||
|
||||
###
|
||||
|
||||
@@ -12,11 +12,11 @@ class @Profile
|
||||
$(this).find('.update-failed').hide()
|
||||
|
||||
$('.update-username form').on 'ajax:complete', ->
|
||||
$(this).find('.btn-save').enableButton()
|
||||
$(this).find('.btn-save').enable()
|
||||
$(this).find('.loading-gif').hide()
|
||||
|
||||
$('.update-notifications').on 'ajax:complete', ->
|
||||
$(this).find('.btn-save').enableButton()
|
||||
$(this).find('.btn-save').enable()
|
||||
|
||||
|
||||
$('.js-choose-user-avatar-button').bind "click", ->
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#= require jquery
|
||||
#= require mousetrap
|
||||
|
||||
#= require shortcuts_navigation
|
||||
|
||||
class @ShortcutsIssuable extends ShortcutsNavigation
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#= require d3
|
||||
#= require jquery
|
||||
#= require stat_graph_contributors_util
|
||||
|
||||
class @ContributorsStatGraph
|
||||
|
||||
@@ -2,11 +2,15 @@ window.ContributorsStatGraphUtil =
|
||||
parse_log: (log) ->
|
||||
total = {}
|
||||
by_author = {}
|
||||
by_email = {}
|
||||
for entry in log
|
||||
@add_date(entry.date, total) unless total[entry.date]?
|
||||
@add_author(entry, by_author) unless by_author[entry.author_name]?
|
||||
@add_date(entry.date, by_author[entry.author_name]) unless by_author[entry.author_name][entry.date]
|
||||
@store_data(entry, total[entry.date], by_author[entry.author_name][entry.date])
|
||||
|
||||
data = by_author[entry.author_name] #|| by_email[entry.author_email]
|
||||
data ?= @add_author(entry, by_author, by_email)
|
||||
|
||||
@add_date(entry.date, data) unless data[entry.date]
|
||||
@store_data(entry, total[entry.date], data[entry.date])
|
||||
total = _.toArray(total)
|
||||
by_author = _.toArray(by_author)
|
||||
total: total, by_author: by_author
|
||||
@@ -15,10 +19,12 @@ window.ContributorsStatGraphUtil =
|
||||
collection[date] = {}
|
||||
collection[date].date = date
|
||||
|
||||
add_author: (author, by_author) ->
|
||||
by_author[author.author_name] = {}
|
||||
by_author[author.author_name].author_name = author.author_name
|
||||
by_author[author.author_name].author_email = author.author_email
|
||||
add_author: (author, by_author, by_email) ->
|
||||
data = {}
|
||||
data.author_name = author.author_name
|
||||
data.author_email = author.author_email
|
||||
by_author[author.author_name] = data
|
||||
by_email[author.author_email] = data
|
||||
|
||||
store_data: (entry, total, by_author) ->
|
||||
@store_commits(total, by_author)
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
class @Wikis
|
||||
constructor: ->
|
||||
$('.build-new-wiki').bind "click", ->
|
||||
$('.build-new-wiki').bind "click", (e) ->
|
||||
$('[data-error~=slug]').addClass("hidden")
|
||||
$('p.hint').show()
|
||||
field = $('#new_wiki_path')
|
||||
slug = field.val()
|
||||
path = field.attr('data-wikis-path')
|
||||
valid_slug_pattern = /^[\w\/-]+$/
|
||||
|
||||
if(slug.length > 0)
|
||||
location.href = path + "/" + slug
|
||||
slug = field.val()
|
||||
if slug.match valid_slug_pattern
|
||||
path = field.attr('data-wikis-path')
|
||||
if(slug.length > 0)
|
||||
location.href = path + "/" + slug
|
||||
else
|
||||
e.preventDefault()
|
||||
$('p.hint').hide()
|
||||
$('[data-error~=slug]').removeClass("hidden")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class @ZenMode
|
||||
@fullscreen_prefix = 'fullscreen_'
|
||||
#= require dropzone
|
||||
#= require mousetrap
|
||||
#= require mousetrap/pause
|
||||
|
||||
class @ZenMode
|
||||
constructor: ->
|
||||
@active_zen_area = null
|
||||
@active_checkbox = null
|
||||
@@ -12,34 +14,31 @@ class @ZenMode
|
||||
|
||||
$('body').on 'click', '.zen-enter-link', (e) =>
|
||||
e.preventDefault()
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true)
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true).change()
|
||||
|
||||
$('body').on 'click', '.zen-leave-link', (e) =>
|
||||
e.preventDefault()
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false)
|
||||
$(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false).change()
|
||||
|
||||
$('body').on 'change', '.zen-toggle-comment', (e) =>
|
||||
checkbox = e.currentTarget
|
||||
if checkbox.checked
|
||||
# Disable other keyboard shortcuts in ZEN mode
|
||||
Mousetrap.pause()
|
||||
@udpateActiveZenArea(checkbox)
|
||||
@updateActiveZenArea(checkbox)
|
||||
else
|
||||
@exitZenMode()
|
||||
|
||||
$(document).on 'keydown', (e) =>
|
||||
if e.keyCode is $.ui.keyCode.ESCAPE
|
||||
if e.keyCode is 27 # Esc
|
||||
@exitZenMode()
|
||||
e.preventDefault()
|
||||
|
||||
$(window).on 'hashchange', @updateZenModeFromLocationHash
|
||||
|
||||
udpateActiveZenArea: (checkbox) =>
|
||||
updateActiveZenArea: (checkbox) =>
|
||||
@active_checkbox = $(checkbox)
|
||||
@active_checkbox.prop('checked', true)
|
||||
@active_zen_area = @active_checkbox.parent().find('textarea')
|
||||
@active_zen_area.focus()
|
||||
window.location.hash = ZenMode.fullscreen_prefix + @active_checkbox.prop('id')
|
||||
|
||||
exitZenMode: =>
|
||||
if @active_zen_area isnt null
|
||||
@@ -47,21 +46,9 @@ class @ZenMode
|
||||
@active_checkbox.prop('checked', false)
|
||||
@active_zen_area = null
|
||||
@active_checkbox = null
|
||||
window.location.hash = ''
|
||||
window.scrollTo(window.pageXOffset, @scroll_position)
|
||||
@restoreScroll(@scroll_position)
|
||||
# Enable dropzone when leaving ZEN mode
|
||||
Dropzone.forElement('.div-dropzone').enable()
|
||||
|
||||
checkboxFromLocationHash: (e) ->
|
||||
id = $.trim(window.location.hash.replace('#' + ZenMode.fullscreen_prefix, ''))
|
||||
if id
|
||||
return $('.zennable input[type=checkbox]#' + id)[0]
|
||||
else
|
||||
return null
|
||||
|
||||
updateZenModeFromLocationHash: (e) =>
|
||||
checkbox = @checkboxFromLocationHash()
|
||||
if checkbox
|
||||
@udpateActiveZenArea(checkbox)
|
||||
else
|
||||
@exitZenMode()
|
||||
restoreScroll: (y) ->
|
||||
window.scrollTo(window.pageXOffset, y)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
$style_color: #474D57;
|
||||
$hover: #FFF3EB;
|
||||
$hover: #FFFAF1;
|
||||
$gl-text-color: #222222;
|
||||
$gl-link-color: #446e9b;
|
||||
$nprogress-color: #c0392b;
|
||||
$gl-font-size: 14px;
|
||||
$list-font-size: 15px;
|
||||
$sidebar_collapsed_width: 52px;
|
||||
$sidebar_width: 230px;
|
||||
$avatar_radius: 50%;
|
||||
$code_font_size: 13px;
|
||||
|
||||
@@ -316,7 +316,7 @@ table {
|
||||
}
|
||||
|
||||
.btn-sign-in {
|
||||
margin-top: 5px;
|
||||
margin-top: 7px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@@ -351,9 +351,8 @@ table {
|
||||
}
|
||||
|
||||
#nprogress .spinner {
|
||||
top: auto !important;
|
||||
bottom: 20px !important;
|
||||
left: 20px !important;
|
||||
top: 15px !important;
|
||||
right: 10px !important;
|
||||
}
|
||||
|
||||
.header-with-avatar {
|
||||
|
||||
@@ -89,7 +89,6 @@ label {
|
||||
@include box-shadow(none);
|
||||
}
|
||||
|
||||
.issuable-description,
|
||||
.wiki-content {
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,14 @@
|
||||
* Application Header
|
||||
*
|
||||
*/
|
||||
$header-height: 46px;
|
||||
|
||||
header {
|
||||
&.navbar-empty {
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid #EEE;
|
||||
}
|
||||
|
||||
&.navbar-gitlab {
|
||||
z-index: 100;
|
||||
margin-bottom: 0;
|
||||
@@ -11,161 +18,104 @@ header {
|
||||
width: 100%;
|
||||
|
||||
.container {
|
||||
background: #FFF;
|
||||
width: 100% !important;
|
||||
padding: 0;
|
||||
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid #EEE;
|
||||
filter: none;
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 25px;
|
||||
font-size: 18px;
|
||||
line-height: 44px;
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
|
||||
@include str-truncated(37%);
|
||||
|
||||
a {
|
||||
color: #444;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app_logo {
|
||||
border-bottom: 1px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
|
||||
a {
|
||||
padding: 5px 8px;
|
||||
|
||||
img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
h3 {
|
||||
width: 158px;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 20px;
|
||||
font-size: 18px;
|
||||
line-height: 34px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav > li > a {
|
||||
color: #666;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
line-height: 32px;
|
||||
padding: 6px 10px;
|
||||
line-height: 19px;
|
||||
padding: 0;
|
||||
background-color: #f5f5f5;
|
||||
margin: 9px 0;
|
||||
margin-left: 10px;
|
||||
border-radius: 40px;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
background: none;
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
|
||||
/** NAV block with links and profile **/
|
||||
.nav {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
color: #666;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
|
||||
&:hover {
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.turbolink-spinner {
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
border-width: 0;
|
||||
font-size: 18px;
|
||||
|
||||
.title {
|
||||
@include str-truncated(70%);
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
margin-top: 47px;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
margin: 5px 0;
|
||||
|
||||
.visible-xs, .visable-sm {
|
||||
display: table-cell !important;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
display: table-cell;
|
||||
width: 1%;
|
||||
|
||||
a {
|
||||
text-align: center;
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Logo holder
|
||||
*
|
||||
*/
|
||||
.app_logo {
|
||||
.header-logo {
|
||||
border-bottom: 1px solid transparent;
|
||||
float: left;
|
||||
margin-right: 9px;
|
||||
height: $header-height;
|
||||
width: $sidebar_width;
|
||||
|
||||
a {
|
||||
float: left;
|
||||
height: 46px;
|
||||
height: $header-height;
|
||||
width: 100%;
|
||||
padding: 5px 8px;
|
||||
|
||||
h3 {
|
||||
width: 158px;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 20px;
|
||||
font-size: 18px;
|
||||
line-height: 34px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-pic {
|
||||
padding: 0px !important;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
margin-left: 5px;
|
||||
img {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
.header-content {
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-right: 35px;
|
||||
height: $header-height;
|
||||
|
||||
.title {
|
||||
position: relative;
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 35px;
|
||||
font-size: 18px;
|
||||
line-height: 44px;
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
|
||||
@include str-truncated(37%);
|
||||
|
||||
a {
|
||||
color: #444;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Search box
|
||||
*
|
||||
*/
|
||||
.search {
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
@@ -177,6 +127,7 @@ header {
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 220px;
|
||||
background-image: image-url("icon-search.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 10px;
|
||||
@@ -184,56 +135,74 @@ header {
|
||||
padding: 4px 6px;
|
||||
padding-left: 25px;
|
||||
font-size: 13px;
|
||||
@include border-radius(3px);
|
||||
border: 1px solid #DDD;
|
||||
box-shadow: none;
|
||||
@include transition(all 0.15s ease-in 0s);
|
||||
background-color: #f5f5f5;
|
||||
border-color: #f5f5f5;
|
||||
|
||||
&:focus {
|
||||
@include box-shadow(none);
|
||||
outline: none;
|
||||
border-color: #DDD;
|
||||
background-color: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search .search-input {
|
||||
width: 300px;
|
||||
&:focus {
|
||||
width: 330px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.search .search-input {
|
||||
width: 200px;
|
||||
&:focus {
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
#nprogress .spinner {
|
||||
right: 35px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
.header-collapsed, .header-expanded {
|
||||
width: 52px;
|
||||
@mixin collapsed-header {
|
||||
.header-logo {
|
||||
width: $sidebar_collapsed_width;
|
||||
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
.title {
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
header .container .title {
|
||||
max-width: 43%;
|
||||
}
|
||||
|
||||
.header-collapsed, .header-expanded {
|
||||
@include collapsed-header;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: $screen-md-max) {
|
||||
.header-collapsed {
|
||||
width: 52px;
|
||||
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
@include collapsed-header;
|
||||
}
|
||||
|
||||
.header-expanded {
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
header .container {
|
||||
font-size: 18px;
|
||||
|
||||
.title {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
margin: 0px;
|
||||
float: none !important;
|
||||
|
||||
.visible-xs, .visable-sm {
|
||||
display: table-cell !important;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
display: table-cell;
|
||||
width: 1%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
&:hover {
|
||||
background: $hover;
|
||||
border-bottom: 1px solid darken($hover, 10%);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
}
|
||||
|
||||
.container .title {
|
||||
margin-left: 6px !important;
|
||||
margin-left: 15px !important;
|
||||
max-width: 70% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
.page-with-sidebar {
|
||||
background: $background-color;
|
||||
|
||||
.sidebar-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -102,13 +100,13 @@
|
||||
padding-left: 50px;
|
||||
|
||||
.sidebar-wrapper {
|
||||
width: 52px;
|
||||
width: $sidebar_collapsed_width;
|
||||
|
||||
.nav-sidebar {
|
||||
margin-top: 29px;
|
||||
position: fixed;
|
||||
top: 45px;
|
||||
width: 52px;
|
||||
width: $sidebar_collapsed_width;
|
||||
|
||||
li a {
|
||||
padding-left: 18px;
|
||||
@@ -125,7 +123,21 @@
|
||||
|
||||
.collapse-nav a {
|
||||
left: 0px;
|
||||
width: 52px;
|
||||
width: $sidebar_collapsed_width;
|
||||
}
|
||||
|
||||
.sidebar-user {
|
||||
.username {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.logout-holder {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,3 +182,15 @@
|
||||
@include expanded-sidebar;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-user {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
|
||||
.avatar {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ pre {
|
||||
font-family: $monospace_font;
|
||||
}
|
||||
|
||||
code {
|
||||
&.key-fingerprint {
|
||||
background: $body-bg;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wiki typography
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.zennable {
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
.zen-toggle-comment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the Enter link when we're in Zen mode
|
||||
input:checked ~ .zen-backdrop .zen-enter-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Show the Leave link when we're in Zen mode
|
||||
input:checked ~ .zen-backdrop .zen-leave-link {
|
||||
display: block;
|
||||
position: absolute;
|
||||
@@ -62,6 +64,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Make the placeholder text in the standard textarea the same color as the
|
||||
// background, effectively hiding it
|
||||
|
||||
.zen-backdrop textarea::-webkit-input-placeholder {
|
||||
color: white;
|
||||
}
|
||||
@@ -78,6 +83,9 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
// Make the color of the placeholder text in the Zenned-out textarea darker,
|
||||
// so it becomes visible
|
||||
|
||||
input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@@ -123,38 +123,31 @@
|
||||
|
||||
.mr-state-widget {
|
||||
font-size: 13px;
|
||||
background: #F9F9F9;
|
||||
background: #FAFAFA;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
border: 1px solid #EEE;
|
||||
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
|
||||
border: 1px solid #e5e5e5;
|
||||
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
|
||||
@include border-radius(3px);
|
||||
|
||||
.ci_widget {
|
||||
padding: 10px 15px;
|
||||
font-size: 15px;
|
||||
border-bottom: 1px solid #BBB;
|
||||
color: #777;
|
||||
background-color: $background-color;
|
||||
border-bottom: 1px solid #EEE;
|
||||
|
||||
&.ci-success {
|
||||
color: $gl-success;
|
||||
border-color: $gl-success;
|
||||
background-color: #F1FAF1;
|
||||
}
|
||||
|
||||
&.ci-pending,
|
||||
&.ci-running {
|
||||
color: $gl-warning;
|
||||
border-color: $gl-warning;
|
||||
background-color: #FAF5F1;
|
||||
}
|
||||
|
||||
&.ci-failed,
|
||||
&.ci-canceled,
|
||||
&.ci-error {
|
||||
color: $gl-danger;
|
||||
border-color: $gl-danger;
|
||||
background-color: #FAF1F1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +155,8 @@
|
||||
padding: 10px 15px;
|
||||
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
font-weight: bold;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
|
||||
@@ -79,11 +79,11 @@ ul.notes {
|
||||
word-wrap: break-word;
|
||||
@include md-typography;
|
||||
|
||||
// Reduce left padding of first ul element
|
||||
// Reduce left padding of first task list ul element
|
||||
ul.task-list:first-child {
|
||||
padding-left: 10px;
|
||||
|
||||
// sub-lists should be padded normally
|
||||
// sub-tasks should be padded normally
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
@@ -84,8 +84,9 @@
|
||||
}
|
||||
|
||||
.btn {
|
||||
line-height: 36px;
|
||||
height: 56px;
|
||||
line-height: 40px;
|
||||
height: 42px;
|
||||
padding: 0px 12px;
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
@@ -93,3 +94,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Profile > Account > Two Factor Authentication
|
||||
.two-factor-new {
|
||||
.manual-instructions {
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
// Slightly increase the size of the details so they're easier to read
|
||||
dl {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,14 +48,16 @@
|
||||
}
|
||||
|
||||
.project-home-desc {
|
||||
color: $gray;
|
||||
float: left;
|
||||
font-size: 16px;
|
||||
line-height: 1.3;
|
||||
margin-right: 250px;
|
||||
}
|
||||
|
||||
.project-home-desc {
|
||||
float: left;
|
||||
color: $gray;
|
||||
// Render Markdown-generated HTML inline for this block
|
||||
p {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@
|
||||
}
|
||||
|
||||
.option-descr {
|
||||
margin-left: 24px;
|
||||
margin-left: 36px;
|
||||
color: $gray;
|
||||
}
|
||||
}
|
||||
@@ -209,13 +211,14 @@ ul.nav.nav-projects-tabs {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.well {
|
||||
padding: 14px;
|
||||
.panel {
|
||||
@include border-radius(3px);
|
||||
|
||||
h4 {
|
||||
.panel-heading, .panel-footer {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
color: #555;
|
||||
background-color: transparent;
|
||||
color: #666;
|
||||
border-color: #EEE;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@@ -224,12 +227,18 @@ ul.nav.nav-projects-tabs {
|
||||
|
||||
.nav-pills a {
|
||||
padding: 10px;
|
||||
font-weight: bold;
|
||||
color: $gl-link-color;
|
||||
}
|
||||
|
||||
.nav {
|
||||
margin: 10px 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.ci-status-image {
|
||||
max-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.transfer-project .select2-container {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
|
||||
header {
|
||||
&.navbar-gitlab {
|
||||
.app_logo {
|
||||
.header-logo {
|
||||
background-color: $color-darker;
|
||||
border-color: $color-darker;
|
||||
|
||||
a {
|
||||
color: $color-light;
|
||||
@@ -19,8 +20,6 @@
|
||||
}
|
||||
|
||||
.page-with-sidebar {
|
||||
background: $color-darker;
|
||||
|
||||
.collapse-nav a {
|
||||
color: #FFF;
|
||||
background: $color;
|
||||
@@ -29,6 +28,12 @@
|
||||
.sidebar-wrapper {
|
||||
background: $color-darker;
|
||||
border-right: 1px solid $color-darker;
|
||||
|
||||
.sidebar-user {
|
||||
a {
|
||||
color: $color-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-sidebar li {
|
||||
|
||||
@@ -39,11 +39,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
||||
:sign_in_text,
|
||||
:home_page_url,
|
||||
:help_text,
|
||||
:after_sign_out_path,
|
||||
:max_attachment_size,
|
||||
:default_project_visibility,
|
||||
:default_snippet_visibility,
|
||||
:restricted_signup_domains_raw,
|
||||
:version_check_enabled,
|
||||
:user_oauth_applications,
|
||||
restricted_visibility_levels: [],
|
||||
)
|
||||
end
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
class Admin::DeployKeysController < Admin::ApplicationController
|
||||
before_action :deploy_keys, only: [:index]
|
||||
before_action :deploy_key, only: [:show, :destroy]
|
||||
before_action :deploy_key, only: [:destroy]
|
||||
|
||||
def index
|
||||
|
||||
end
|
||||
|
||||
def show
|
||||
|
||||
end
|
||||
|
||||
def new
|
||||
|
||||
@@ -47,7 +47,7 @@ class Admin::GroupsController < Admin::ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@group.destroy
|
||||
DestroyGroupService.new(@group, current_user).execute
|
||||
|
||||
redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
|
||||
end
|
||||
|
||||
@@ -86,11 +86,7 @@ class Admin::UsersController < Admin::ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
# 1. Remove groups where user is the only owner
|
||||
user.solo_owned_groups.map(&:destroy)
|
||||
|
||||
# 2. Remove user with all authored content including personal projects
|
||||
user.destroy
|
||||
DeleteUserService.new.execute(user)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to admin_users_path }
|
||||
|
||||
@@ -89,7 +89,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def after_sign_out_path_for(resource)
|
||||
new_user_session_path
|
||||
current_application_settings.after_sign_out_path || new_user_session_path
|
||||
end
|
||||
|
||||
def abilities
|
||||
@@ -295,14 +295,14 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
def get_issues_collection
|
||||
set_filters_params
|
||||
issues = IssuesFinder.new.execute(current_user, @filter_params)
|
||||
issues
|
||||
@issuable_finder = IssuesFinder.new(current_user, @filter_params)
|
||||
@issuable_finder.execute
|
||||
end
|
||||
|
||||
def get_merge_requests_collection
|
||||
set_filters_params
|
||||
merge_requests = MergeRequestsFinder.new.execute(current_user, @filter_params)
|
||||
merge_requests
|
||||
@issuable_finder = MergeRequestsFinder.new(current_user, @filter_params)
|
||||
@issuable_finder.execute
|
||||
end
|
||||
|
||||
def github_import_enabled?
|
||||
|
||||
@@ -82,7 +82,11 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
|
||||
redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")
|
||||
else
|
||||
return render_403
|
||||
if @group.last_owner?(current_user)
|
||||
redirect_to(dashboard_groups_path, alert: "You can not leave #{group.name} group because you're the last owner. Transfer or delete the group.")
|
||||
else
|
||||
return render_403
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class GroupsController < Groups::ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@group.destroy
|
||||
DestroyGroupService.new(@group, current_user).execute
|
||||
|
||||
redirect_to root_path, notice: 'Group was removed.'
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
|
||||
include Gitlab::CurrentSettings
|
||||
include PageLayoutHelper
|
||||
|
||||
before_action :verify_user_oauth_applications_enabled
|
||||
before_action :authenticate_user!
|
||||
|
||||
layout 'profile'
|
||||
@@ -32,6 +34,12 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
|
||||
|
||||
private
|
||||
|
||||
def verify_user_oauth_applications_enabled
|
||||
return if current_application_settings.user_oauth_applications?
|
||||
|
||||
redirect_to applications_profile_url
|
||||
end
|
||||
|
||||
def set_application
|
||||
@application = current_user.oauth_applications.find(params[:id])
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
include AuthenticatesWithTwoFactor
|
||||
|
||||
protect_from_forgery except: :kerberos
|
||||
protect_from_forgery except: [:kerberos, :saml]
|
||||
|
||||
Gitlab.config.omniauth.providers.each do |provider|
|
||||
define_method provider['name'] do
|
||||
@@ -81,7 +81,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
end
|
||||
|
||||
flash[:notice] = message
|
||||
|
||||
|
||||
redirect_to new_user_session_path
|
||||
end
|
||||
|
||||
|
||||
@@ -36,4 +36,24 @@ class PasswordsController < Devise::PasswordsController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
super
|
||||
reset_password_token = Devise.token_generator.digest(
|
||||
User,
|
||||
:reset_password_token,
|
||||
resource.reset_password_token
|
||||
)
|
||||
|
||||
unless reset_password_token.nil?
|
||||
user = User.where(
|
||||
reset_password_token: reset_password_token
|
||||
).first_or_initialize
|
||||
|
||||
unless user.reset_password_period_valid?
|
||||
flash[:alert] = 'Your password reset token has expired.'
|
||||
redirect_to(new_user_password_url(user_email: user['email']))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
||||
def new
|
||||
unless current_user.otp_secret
|
||||
current_user.otp_secret = User.generate_otp_secret
|
||||
current_user.otp_secret = User.generate_otp_secret(32)
|
||||
current_user.save!
|
||||
end
|
||||
|
||||
@@ -18,6 +18,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
||||
else
|
||||
@error = 'Invalid pin code'
|
||||
@qr_code = build_qr_code
|
||||
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,10 +18,6 @@ class Projects::DeployKeysController < Projects::ApplicationController
|
||||
@available_public_keys -= @available_project_keys
|
||||
end
|
||||
|
||||
def show
|
||||
@key = @project.deploy_keys.find(params[:id])
|
||||
end
|
||||
|
||||
def new
|
||||
@key = @project.deploy_keys.new
|
||||
|
||||
|
||||
@@ -53,6 +53,6 @@ class Projects::HooksController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def hook_params
|
||||
params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events)
|
||||
params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,7 +19,15 @@ class Projects::IssuesController < Projects::ApplicationController
|
||||
def index
|
||||
terms = params['issue_search']
|
||||
@issues = get_issues_collection
|
||||
@issues = @issues.full_search(terms) if terms.present?
|
||||
|
||||
if terms.present?
|
||||
if terms =~ /\A#(\d+)\z/
|
||||
@issues = @issues.where(iid: $1)
|
||||
else
|
||||
@issues = @issues.full_search(terms)
|
||||
end
|
||||
end
|
||||
|
||||
@issues = @issues.page(params[:page]).per(PER_PAGE)
|
||||
|
||||
respond_to do |format|
|
||||
|
||||
@@ -2,10 +2,13 @@ require 'gitlab/satellite/satellite'
|
||||
|
||||
class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
before_action :module_enabled
|
||||
before_action :merge_request, only: [:edit, :update, :show, :diffs, :automerge, :automerge_check, :ci_status, :toggle_subscription]
|
||||
before_action :closes_issues, only: [:edit, :update, :show, :diffs]
|
||||
before_action :validates_merge_request, only: [:show, :diffs]
|
||||
before_action :define_show_vars, only: [:show, :diffs]
|
||||
before_action :merge_request, only: [
|
||||
:edit, :update, :show, :diffs, :commits, :automerge, :automerge_check,
|
||||
:ci_status, :toggle_subscription
|
||||
]
|
||||
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits]
|
||||
before_action :validates_merge_request, only: [:show, :diffs, :commits]
|
||||
before_action :define_show_vars, only: [:show, :diffs, :commits]
|
||||
|
||||
# Allow read any merge_request
|
||||
before_action :authorize_read_merge_request!
|
||||
@@ -19,7 +22,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
def index
|
||||
terms = params['issue_search']
|
||||
@merge_requests = get_merge_requests_collection
|
||||
@merge_requests = @merge_requests.full_search(terms) if terms.present?
|
||||
|
||||
if terms.present?
|
||||
if terms =~ /\A[#!](\d+)\z/
|
||||
@merge_requests = @merge_requests.where(iid: $1)
|
||||
else
|
||||
@merge_requests = @merge_requests.full_search(terms)
|
||||
end
|
||||
end
|
||||
|
||||
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
|
||||
|
||||
respond_to do |format|
|
||||
@@ -59,6 +70,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def commits
|
||||
render 'show'
|
||||
end
|
||||
|
||||
def new
|
||||
params[:merge_request] ||= ActionController::Parameters.new(source_project: @project)
|
||||
@merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute
|
||||
|
||||
@@ -84,12 +84,16 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def leave
|
||||
if @project.namespace == current_user.namespace
|
||||
return redirect_to(:back, alert: 'You can not leave your own project. Transfer or delete the project.')
|
||||
end
|
||||
|
||||
@project_member = @project.project_members.find_by(user_id: current_user)
|
||||
@project_member.destroy
|
||||
log_audit_event(@project_member, action: :destroy)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.html { redirect_to dashboard_path }
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,18 +97,15 @@ class ProjectsController < ApplicationController
|
||||
return access_denied! unless can?(current_user, :remove_project, @project)
|
||||
|
||||
::Projects::DestroyService.new(@project, current_user, {}).execute
|
||||
flash[:alert] = 'Project deleted.'
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
flash[:alert] = 'Project deleted.'
|
||||
|
||||
if request.referer.include?('/admin')
|
||||
redirect_to admin_namespaces_projects_path
|
||||
else
|
||||
redirect_to dashboard_path
|
||||
end
|
||||
end
|
||||
if request.referer.include?('/admin')
|
||||
redirect_to admin_namespaces_projects_path
|
||||
else
|
||||
redirect_to dashboard_path
|
||||
end
|
||||
rescue Projects::DestroyService::DestroyError => ex
|
||||
redirect_to edit_project_path(@project), alert: ex.message
|
||||
end
|
||||
|
||||
def autocomplete_sources
|
||||
|
||||
@@ -6,7 +6,7 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
end
|
||||
|
||||
def destroy
|
||||
current_user.destroy
|
||||
DeleteUserService.new.execute(current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to new_user_session_path, notice: "Account successfully removed." }
|
||||
|
||||
@@ -2,6 +2,7 @@ class SessionsController < Devise::SessionsController
|
||||
include AuthenticatesWithTwoFactor
|
||||
|
||||
prepend_before_action :authenticate_with_two_factor, only: [:create]
|
||||
before_action :auto_sign_in_with_provider, only: [:new]
|
||||
|
||||
def new
|
||||
redirect_path =
|
||||
@@ -75,6 +76,21 @@ class SessionsController < Devise::SessionsController
|
||||
end
|
||||
end
|
||||
|
||||
def auto_sign_in_with_provider
|
||||
provider = Gitlab.config.omniauth.auto_sign_in_with_provider
|
||||
return unless provider.present?
|
||||
|
||||
# Auto sign in with an Omniauth provider only if the standard "you need to sign-in" alert is
|
||||
# registered or no alert at all. In case of another alert (such as a blocked user), it is safer
|
||||
# to do nothing to prevent redirection loops with certain Omniauth providers.
|
||||
return unless flash[:alert].blank? || flash[:alert] == I18n.t('devise.failure.unauthenticated')
|
||||
|
||||
# Prevent alert from popping up on the first page shown after authentication.
|
||||
flash[:alert] = nil
|
||||
|
||||
redirect_to omniauth_authorize_path(:user, provider.to_sym)
|
||||
end
|
||||
|
||||
def valid_otp_attempt?(user)
|
||||
user.valid_otp?(user_params[:otp_attempt]) ||
|
||||
user.invalidate_otp_backup_code!(user_params[:otp_attempt])
|
||||
|
||||
@@ -16,7 +16,7 @@ issues = project.issues_for_user_filtered_by(user, params)
|
||||
Better use this:
|
||||
|
||||
```ruby
|
||||
issues = IssuesFinder.new.execute(project, user, filter)
|
||||
issues = IssuesFinder.new(project, user, filter).execute
|
||||
```
|
||||
|
||||
It will help keep models thiner.
|
||||
|
||||
@@ -23,10 +23,12 @@ class IssuableFinder
|
||||
|
||||
attr_accessor :current_user, :params
|
||||
|
||||
def execute(current_user, params)
|
||||
def initialize(current_user, params)
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def execute
|
||||
items = init_collection
|
||||
items = by_scope(items)
|
||||
items = by_state(items)
|
||||
@@ -40,6 +42,77 @@ class IssuableFinder
|
||||
items = sort(items)
|
||||
end
|
||||
|
||||
def group
|
||||
return @group if defined?(@group)
|
||||
|
||||
@group =
|
||||
if params[:group_id].present?
|
||||
Group.find(params[:group_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def project
|
||||
return @project if defined?(@project)
|
||||
|
||||
@project =
|
||||
if params[:project_id].present?
|
||||
Project.find(params[:project_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def search
|
||||
params[:search].presence
|
||||
end
|
||||
|
||||
def milestones?
|
||||
params[:milestone_title].present?
|
||||
end
|
||||
|
||||
def milestones
|
||||
return @milestones if defined?(@milestones)
|
||||
|
||||
@milestones =
|
||||
if milestones? && params[:milestone_title] != NONE
|
||||
Milestone.where(title: params[:milestone_title])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def assignee?
|
||||
params[:assignee_id].present?
|
||||
end
|
||||
|
||||
def assignee
|
||||
return @assignee if defined?(@assignee)
|
||||
|
||||
@assignee =
|
||||
if assignee? && params[:assignee_id] != NONE
|
||||
User.find(params[:assignee_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def author?
|
||||
params[:author_id].present?
|
||||
end
|
||||
|
||||
def author
|
||||
return @author if defined?(@author)
|
||||
|
||||
@author =
|
||||
if author? && params[:author_id] != NONE
|
||||
User.find(params[:author_id])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def init_collection
|
||||
@@ -75,6 +148,10 @@ class IssuableFinder
|
||||
case params[:state]
|
||||
when 'closed'
|
||||
items.closed
|
||||
when 'rejected'
|
||||
items.respond_to?(:rejected) ? items.rejected : items.closed
|
||||
when 'merged'
|
||||
items.respond_to?(:merged) ? items.merged : items.closed
|
||||
when 'all'
|
||||
items
|
||||
when 'opened'
|
||||
@@ -85,25 +162,19 @@ class IssuableFinder
|
||||
end
|
||||
|
||||
def by_group(items)
|
||||
if params[:group_id].present?
|
||||
items = items.of_group(Group.find(params[:group_id]))
|
||||
end
|
||||
items = items.of_group(group) if group
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def by_project(items)
|
||||
if params[:project_id].present?
|
||||
items = items.of_projects(params[:project_id])
|
||||
end
|
||||
items = items.of_projects(project.id) if project
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def by_search(items)
|
||||
if params[:search].present?
|
||||
items = items.search(params[:search])
|
||||
end
|
||||
items = items.search(search) if search
|
||||
|
||||
items
|
||||
end
|
||||
@@ -113,25 +184,24 @@ class IssuableFinder
|
||||
end
|
||||
|
||||
def by_milestone(items)
|
||||
if params[:milestone_title].present?
|
||||
milestone_ids = (params[:milestone_title] == NONE ? nil : Milestone.where(title: params[:milestone_title]).pluck(:id))
|
||||
items = items.where(milestone_id: milestone_ids)
|
||||
if milestones?
|
||||
items = items.where(milestone_id: milestones.try(:pluck, :id))
|
||||
end
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def by_assignee(items)
|
||||
if params[:assignee_id].present?
|
||||
items = items.where(assignee_id: (params[:assignee_id] == NONE ? nil : params[:assignee_id]))
|
||||
if assignee?
|
||||
items = items.where(assignee_id: assignee.try(:id))
|
||||
end
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def by_author(items)
|
||||
if params[:author_id].present?
|
||||
items = items.where(author_id: (params[:author_id] == NONE ? nil : params[:author_id]))
|
||||
if author?
|
||||
items = items.where(author_id: author.try(:id))
|
||||
end
|
||||
|
||||
items
|
||||
@@ -151,10 +221,6 @@ class IssuableFinder
|
||||
items
|
||||
end
|
||||
|
||||
def project
|
||||
Project.where(id: params[:project_id]).first if params[:project_id].present?
|
||||
end
|
||||
|
||||
def current_user_related?
|
||||
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
|
||||
end
|
||||
|
||||
@@ -228,18 +228,28 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def render_markup(file_name, file_content)
|
||||
GitHub::Markup.render(file_name, file_content).
|
||||
force_encoding(file_content.encoding).html_safe
|
||||
if gitlab_markdown?(file_name)
|
||||
Haml::Helpers.preserve(markdown(file_content))
|
||||
elsif asciidoc?(file_name)
|
||||
asciidoc(file_content)
|
||||
else
|
||||
GitHub::Markup.render(file_name, file_content).
|
||||
force_encoding(file_content.encoding).html_safe
|
||||
end
|
||||
rescue RuntimeError
|
||||
simple_format(file_content)
|
||||
end
|
||||
|
||||
def markup?(filename)
|
||||
Gitlab::MarkdownHelper.markup?(filename)
|
||||
Gitlab::MarkupHelper.markup?(filename)
|
||||
end
|
||||
|
||||
def gitlab_markdown?(filename)
|
||||
Gitlab::MarkdownHelper.gitlab_markdown?(filename)
|
||||
Gitlab::MarkupHelper.gitlab_markdown?(filename)
|
||||
end
|
||||
|
||||
def asciidoc?(filename)
|
||||
Gitlab::MarkupHelper.asciidoc?(filename)
|
||||
end
|
||||
|
||||
# Overrides ActionView::Helpers::UrlHelper#link_to to add `rel="nofollow"` to
|
||||
@@ -275,10 +285,6 @@ module ApplicationHelper
|
||||
html_options
|
||||
end
|
||||
|
||||
def escaped_autolink(text)
|
||||
auto_link ERB::Util.html_escape(text), link: :urls
|
||||
end
|
||||
|
||||
def promo_host
|
||||
'about.gitlab.com'
|
||||
end
|
||||
@@ -326,7 +332,12 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def state_filters_text_for(entity, project)
|
||||
entity_title = entity.to_s.humanize
|
||||
titles = {
|
||||
opened: "Open",
|
||||
merged: "Accepted"
|
||||
}
|
||||
|
||||
entity_title = titles[entity] || entity.to_s.humanize
|
||||
|
||||
count =
|
||||
if project.nil?
|
||||
|
||||
@@ -23,6 +23,10 @@ module ApplicationSettingsHelper
|
||||
current_application_settings.help_text
|
||||
end
|
||||
|
||||
def user_oauth_applications?
|
||||
current_application_settings.user_oauth_applications
|
||||
end
|
||||
|
||||
# Return a group of checkboxes that use Bootstrap's button plugin for a
|
||||
# toggle button effect.
|
||||
def restricted_level_checkboxes(help_block_id)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module BlobHelper
|
||||
def highlight(blob_name, blob_content, nowrap = false)
|
||||
formatter = Rugments::Formatters::HTML.new(
|
||||
def highlight(blob_name, blob_content, nowrap: false, continue: false)
|
||||
@formatter ||= Rugments::Formatters::HTML.new(
|
||||
nowrap: nowrap,
|
||||
cssclass: 'code highlight',
|
||||
lineanchors: true,
|
||||
@@ -8,12 +8,14 @@ module BlobHelper
|
||||
)
|
||||
|
||||
begin
|
||||
lexer = Rugments::Lexer.guess(filename: blob_name, source: blob_content)
|
||||
rescue Rugments::Lexer::AmbiguousGuess
|
||||
@lexer ||= Rugments::Lexer.guess(filename: blob_name, source: blob_content).new
|
||||
result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
|
||||
rescue
|
||||
lexer = Rugments::Lexers::PlainText
|
||||
result = @formatter.format(lexer.lex(blob_content)).html_safe
|
||||
end
|
||||
|
||||
formatter.format(lexer.lex(blob_content)).html_safe
|
||||
result
|
||||
end
|
||||
|
||||
def no_highlight_files
|
||||
@@ -55,7 +57,7 @@ module BlobHelper
|
||||
end
|
||||
|
||||
def editing_preview_title(filename)
|
||||
if Gitlab::MarkdownHelper.previewable?(filename)
|
||||
if Gitlab::MarkupHelper.previewable?(filename)
|
||||
'Preview'
|
||||
else
|
||||
'Preview changes'
|
||||
|
||||
@@ -101,6 +101,10 @@ module DiffHelper
|
||||
(bottom) ? 'js-unfold-bottom' : ''
|
||||
end
|
||||
|
||||
def unfold_class(unfold)
|
||||
(unfold) ? 'unfold js-unfold' : ''
|
||||
end
|
||||
|
||||
def diff_line_content(line)
|
||||
if line.blank?
|
||||
" "
|
||||
|
||||
@@ -35,4 +35,23 @@ module EmailsHelper
|
||||
lexer = Rugments::Lexers::Diff.new
|
||||
raw formatter.format(lexer.lex(diffcontent))
|
||||
end
|
||||
|
||||
def password_reset_token_valid_time
|
||||
valid_hours = Devise.reset_password_within / 60 / 60
|
||||
if valid_hours >= 24
|
||||
unit = 'day'
|
||||
valid_length = (valid_hours / 24).floor
|
||||
else
|
||||
unit = 'hour'
|
||||
valid_length = valid_hours.floor
|
||||
end
|
||||
|
||||
pluralize(valid_length, unit)
|
||||
end
|
||||
|
||||
def reset_token_expire_message
|
||||
link_tag = link_to('request a new one', new_user_password_url(user_email: @user.email))
|
||||
msg = "This link is valid for #{password_reset_token_valid_time}. "
|
||||
msg << "After it expires, you can #{link_tag}."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'nokogiri'
|
||||
|
||||
module GitlabMarkdownHelper
|
||||
include Gitlab::Markdown
|
||||
|
||||
@@ -21,41 +23,59 @@ module GitlabMarkdownHelper
|
||||
|
||||
gfm_body = gfm(escaped_body, {}, html_options)
|
||||
|
||||
gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match|
|
||||
"</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1
|
||||
fragment = Nokogiri::XML::DocumentFragment.parse(gfm_body)
|
||||
if fragment.children.size == 1 && fragment.children[0].name == 'a'
|
||||
# Fragment has only one node, and it's a link generated by `gfm`.
|
||||
# Replace it with our requested link.
|
||||
text = fragment.children[0].text
|
||||
fragment.children[0].replace(link_to(text, url, html_options))
|
||||
else
|
||||
# Traverse the fragment's first generation of children looking for pure
|
||||
# text, wrapping anything found in the requested link
|
||||
fragment.children.each do |node|
|
||||
next unless node.text?
|
||||
node.replace(link_to(node.text, url, html_options))
|
||||
end
|
||||
end
|
||||
|
||||
link_to(gfm_body.html_safe, url, html_options)
|
||||
fragment.to_html.html_safe
|
||||
end
|
||||
|
||||
MARKDOWN_OPTIONS = {
|
||||
no_intra_emphasis: true,
|
||||
tables: true,
|
||||
fenced_code_blocks: true,
|
||||
strikethrough: true,
|
||||
lax_spacing: true,
|
||||
space_after_headers: true,
|
||||
superscript: true,
|
||||
footnotes: true
|
||||
}.freeze
|
||||
|
||||
def markdown(text, options={})
|
||||
unless @markdown && options == @options
|
||||
@options = options
|
||||
|
||||
options.merge!(
|
||||
# Handled further down the line by Gitlab::Markdown::SanitizationFilter
|
||||
escape_html: false
|
||||
)
|
||||
|
||||
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
|
||||
rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options)
|
||||
|
||||
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
|
||||
@markdown = Redcarpet::Markdown.new(rend,
|
||||
no_intra_emphasis: true,
|
||||
tables: true,
|
||||
fenced_code_blocks: true,
|
||||
strikethrough: true,
|
||||
lax_spacing: true,
|
||||
space_after_headers: true,
|
||||
superscript: true,
|
||||
footnotes: true
|
||||
)
|
||||
@markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS)
|
||||
end
|
||||
|
||||
@markdown.render(text).html_safe
|
||||
end
|
||||
|
||||
def asciidoc(text)
|
||||
Gitlab::Asciidoc.render(text, {
|
||||
commit: @commit,
|
||||
project: @project,
|
||||
project_wiki: @project_wiki,
|
||||
requested_path: @path,
|
||||
ref: @ref
|
||||
})
|
||||
end
|
||||
|
||||
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
||||
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||
@@ -67,8 +87,11 @@ module GitlabMarkdownHelper
|
||||
end
|
||||
|
||||
def render_wiki_content(wiki_page)
|
||||
if wiki_page.format == :markdown
|
||||
case wiki_page.format
|
||||
when :markdown
|
||||
markdown(wiki_page.content)
|
||||
when :asciidoc
|
||||
asciidoc(wiki_page.content)
|
||||
else
|
||||
wiki_page.formatted_content.html_safe
|
||||
end
|
||||
@@ -122,15 +145,25 @@ module GitlabMarkdownHelper
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the text necessary to reference `entity` across projects
|
||||
#
|
||||
# project - Project to reference
|
||||
# entity - Object that responds to `to_reference`
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# cross_project_reference(project, project.issues.first)
|
||||
# # => 'namespace1/project1#123'
|
||||
#
|
||||
# cross_project_reference(project, project.merge_requests.first)
|
||||
# # => 'namespace1/project1!345'
|
||||
#
|
||||
# Returns a String
|
||||
def cross_project_reference(project, entity)
|
||||
path = project.path_with_namespace
|
||||
|
||||
if entity.kind_of?(Issue)
|
||||
[path, entity.iid].join('#')
|
||||
elsif entity.kind_of?(MergeRequest)
|
||||
[path, entity.iid].join('!')
|
||||
if entity.respond_to?(:to_reference)
|
||||
"#{project.to_reference}#{entity.to_reference}"
|
||||
else
|
||||
raise 'Not supported type'
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,44 @@
|
||||
module LabelsHelper
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
# Link to a Label
|
||||
#
|
||||
# label - Label object to link to
|
||||
# project - Project object which will be used as the context for the label's
|
||||
# link. If omitted, defaults to `@project`, or the label's own
|
||||
# project.
|
||||
# block - An optional block that will be passed to `link_to`, forming the
|
||||
# body of the link element. If omitted, defaults to
|
||||
# `render_colored_label`.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# # Allow the generated link to use the label's own project
|
||||
# link_to_label(label)
|
||||
#
|
||||
# # Force the generated link to use @project
|
||||
# @project = Project.first
|
||||
# link_to_label(label)
|
||||
#
|
||||
# # Force the generated link to use a provided project
|
||||
# link_to_label(label, project: Project.last)
|
||||
#
|
||||
# # Customize link body with a block
|
||||
# link_to_label(label) { "My Custom Label Text" }
|
||||
#
|
||||
# Returns a String
|
||||
def link_to_label(label, project: nil, &block)
|
||||
project ||= @project || label.project
|
||||
link = namespace_project_issues_path(project.namespace, project,
|
||||
label_name: label.name)
|
||||
|
||||
if block_given?
|
||||
link_to link, &block
|
||||
else
|
||||
link_to render_colored_label(label), link
|
||||
end
|
||||
end
|
||||
|
||||
def project_label_names
|
||||
@project.labels.pluck(:title)
|
||||
end
|
||||
|
||||
@@ -148,7 +148,7 @@ module ProjectsHelper
|
||||
nav_tabs << [:files, :commits, :network, :graphs]
|
||||
end
|
||||
|
||||
if project.repo_exists? && project.merge_requests_enabled
|
||||
if project.repo_exists? && can?(current_user, :read_merge_request, project)
|
||||
nav_tabs << :merge_requests
|
||||
end
|
||||
|
||||
@@ -156,11 +156,19 @@ module ProjectsHelper
|
||||
nav_tabs << :settings
|
||||
end
|
||||
|
||||
[:issues, :wiki, :snippets].each do |feature|
|
||||
nav_tabs << feature if project.send :"#{feature}_enabled"
|
||||
if can?(current_user, :read_issue, project)
|
||||
nav_tabs << :issues
|
||||
end
|
||||
|
||||
if project.issues_enabled || project.merge_requests_enabled
|
||||
if can?(current_user, :read_wiki, project)
|
||||
nav_tabs << :wiki
|
||||
end
|
||||
|
||||
if can?(current_user, :read_project_snippet, project)
|
||||
nav_tabs << :snippets
|
||||
end
|
||||
|
||||
if can?(current_user, :read_milestone, project)
|
||||
nav_tabs << [:milestones, :labels]
|
||||
end
|
||||
|
||||
@@ -302,4 +310,16 @@ module ProjectsHelper
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def user_max_access_in_project(user, project)
|
||||
level = project.team.max_member_access(user)
|
||||
|
||||
if level
|
||||
Gitlab::Access.options_with_owner.key(level)
|
||||
end
|
||||
end
|
||||
|
||||
def leave_project_message(project)
|
||||
"Are you sure you want to leave \"#{project.name}\" project?"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,6 +11,7 @@ module SelectsHelper
|
||||
any_user = opts[:any_user] || false
|
||||
email_user = opts[:email_user] || false
|
||||
first_user = opts[:first_user] && current_user ? current_user.username : false
|
||||
project = opts[:project] || @project
|
||||
|
||||
html = {
|
||||
class: css_class,
|
||||
@@ -22,8 +23,8 @@ module SelectsHelper
|
||||
}
|
||||
|
||||
unless opts[:scope] == :all
|
||||
if @project
|
||||
html['data-project-id'] = @project.id
|
||||
if project
|
||||
html['data-project-id'] = project.id
|
||||
elsif @group
|
||||
html['data-group-id'] = @group.id
|
||||
end
|
||||
|
||||
@@ -25,13 +25,7 @@ module TreeHelper
|
||||
end
|
||||
|
||||
def render_readme(readme)
|
||||
if gitlab_markdown?(readme.name)
|
||||
preserve(markdown(readme.data))
|
||||
elsif markup?(readme.name)
|
||||
render_markup(readme.name, readme.data)
|
||||
else
|
||||
simple_format(readme.data)
|
||||
end
|
||||
render_markup(readme.name, readme.data)
|
||||
end
|
||||
|
||||
# Return an image icon depending on the file type and mode
|
||||
|
||||
@@ -93,7 +93,8 @@ module Emails
|
||||
"pushed to"
|
||||
end
|
||||
|
||||
@subject = "[#{@project.path_with_namespace}]"
|
||||
@subject = "[Git]"
|
||||
@subject << "[#{@project.path_with_namespace}]"
|
||||
@subject << "[#{@ref_name}]" if action == :push
|
||||
@subject << " "
|
||||
|
||||
|
||||
@@ -117,6 +117,27 @@ class Ability
|
||||
rules -= project_archived_rules
|
||||
end
|
||||
|
||||
unless project.issues_enabled
|
||||
rules -= named_abilities('issue')
|
||||
end
|
||||
|
||||
unless project.merge_requests_enabled
|
||||
rules -= named_abilities('merge_request')
|
||||
end
|
||||
|
||||
unless project.issues_enabled or project.merge_requests_enabled
|
||||
rules -= named_abilities('label')
|
||||
rules -= named_abilities('milestone')
|
||||
end
|
||||
|
||||
unless project.snippets_enabled
|
||||
rules -= named_abilities('project_snippet')
|
||||
end
|
||||
|
||||
unless project.wiki_enabled
|
||||
rules -= named_abilities('wiki')
|
||||
end
|
||||
|
||||
rules
|
||||
end
|
||||
end
|
||||
@@ -288,5 +309,16 @@ class Ability
|
||||
abilities
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def named_abilities(name)
|
||||
[
|
||||
:"read_#{name}",
|
||||
:"write_#{name}",
|
||||
:"modify_#{name}",
|
||||
:"admin_#{name}"
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
# default_project_visibility :integer
|
||||
# default_snippet_visibility :integer
|
||||
# restricted_signup_domains :text
|
||||
# user_oauth_applications :bool default(TRUE)
|
||||
# after_sign_out_path :string(255)
|
||||
#
|
||||
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
@@ -31,6 +33,10 @@ class ApplicationSetting < ActiveRecord::Base
|
||||
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" },
|
||||
if: :home_page_url_column_exist
|
||||
|
||||
validates :after_sign_out_path,
|
||||
allow_blank: true,
|
||||
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }
|
||||
|
||||
validates_each :restricted_visibility_levels do |record, attr, value|
|
||||
unless value.nil?
|
||||
value.each do |level|
|
||||
|
||||
+32
-7
@@ -1,9 +1,11 @@
|
||||
class Commit
|
||||
include ActiveModel::Conversion
|
||||
include StaticModel
|
||||
extend ActiveModel::Naming
|
||||
|
||||
include ActiveModel::Conversion
|
||||
include Mentionable
|
||||
include Participable
|
||||
include Referable
|
||||
include StaticModel
|
||||
|
||||
attr_mentionable :safe_message
|
||||
participant :author, :committer, :notes, :mentioned_users
|
||||
@@ -56,6 +58,34 @@ class Commit
|
||||
@raw.id
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
(self.class === other) && (raw == other.raw)
|
||||
end
|
||||
|
||||
def self.reference_prefix
|
||||
'@'
|
||||
end
|
||||
|
||||
# Pattern used to extract commit references from text
|
||||
#
|
||||
# The SHA can be between 6 and 40 hex characters.
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
(?:#{Project.reference_pattern}#{reference_prefix})?
|
||||
(?<commit>\h{6,40})
|
||||
}x
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
if cross_project_reference?(from_project)
|
||||
"#{project.to_reference}@#{id}"
|
||||
else
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
def diff_line_count
|
||||
@diff_line_count ||= Commit::diff_line_count(self.diffs)
|
||||
@diff_line_count
|
||||
@@ -126,11 +156,6 @@ class Commit
|
||||
Gitlab::ClosingIssueExtractor.new(project, current_user).closed_by_message(safe_message)
|
||||
end
|
||||
|
||||
# Mentionable override.
|
||||
def gfm_reference
|
||||
"commit #{id}"
|
||||
end
|
||||
|
||||
def author
|
||||
User.find_for_commit(author_email, author_name)
|
||||
end
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#
|
||||
class CommitRange
|
||||
include ActiveModel::Conversion
|
||||
include Referable
|
||||
|
||||
attr_reader :sha_from, :notation, :sha_to
|
||||
|
||||
@@ -28,10 +29,24 @@ class CommitRange
|
||||
# See `exclude_start?`
|
||||
attr_reader :exclude_start
|
||||
|
||||
# The beginning and ending SHA sums can be between 6 and 40 hex characters,
|
||||
# and the range selection can be double- or triple-dot.
|
||||
# The beginning and ending SHAs can be between 6 and 40 hex characters, and
|
||||
# the range notation can be double- or triple-dot.
|
||||
PATTERN = /\h{6,40}\.{2,3}\h{6,40}/
|
||||
|
||||
def self.reference_prefix
|
||||
'@'
|
||||
end
|
||||
|
||||
# Pattern used to extract commit range references from text
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
(?:#{Project.reference_pattern}#{reference_prefix})?
|
||||
(?<commit_range>#{PATTERN})
|
||||
}x
|
||||
end
|
||||
|
||||
# Initialize a CommitRange
|
||||
#
|
||||
# range_string - The String commit range.
|
||||
@@ -59,6 +74,17 @@ class CommitRange
|
||||
"#{sha_from[0..7]}#{notation}#{sha_to[0..7]}"
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
# Not using to_s because we want the full SHAs
|
||||
reference = sha_from + notation + sha_to
|
||||
|
||||
if cross_project_reference?(from_project)
|
||||
reference = project.to_reference + '@' + reference
|
||||
end
|
||||
|
||||
reference
|
||||
end
|
||||
|
||||
# Returns a String for use in a link's title attribute
|
||||
def reference_title
|
||||
"Commits #{suffixed_sha_from} through #{sha_to}"
|
||||
|
||||
@@ -20,10 +20,15 @@ module Mentionable
|
||||
end
|
||||
end
|
||||
|
||||
# Generate a GFM back-reference that will construct a link back to this Mentionable when rendered. Must
|
||||
# be overridden if this model object can be referenced directly by GFM notation.
|
||||
def gfm_reference
|
||||
raise NotImplementedError.new("#{self.class} does not implement #gfm_reference")
|
||||
# Returns the text used as the body of a Note when this object is referenced
|
||||
#
|
||||
# By default this will be the class name and the result of calling
|
||||
# `to_reference` on the object.
|
||||
def gfm_reference(from_project = nil)
|
||||
# "MergeRequest" > "merge_request" > "Merge request" > "merge request"
|
||||
friendly_name = self.class.to_s.underscore.humanize.downcase
|
||||
|
||||
"#{friendly_name} #{to_reference(from_project)}"
|
||||
end
|
||||
|
||||
# Construct a String that contains possible GFM references.
|
||||
|
||||
@@ -35,8 +35,8 @@ module Participable
|
||||
end
|
||||
end
|
||||
|
||||
def participants(current_user = self.author)
|
||||
self.class.participant_attrs.flat_map do |attr|
|
||||
def participants(current_user = self.author, project = self.project)
|
||||
participants = self.class.participant_attrs.flat_map do |attr|
|
||||
meth = method(attr)
|
||||
|
||||
value =
|
||||
@@ -46,20 +46,28 @@ module Participable
|
||||
meth.call
|
||||
end
|
||||
|
||||
participants_for(value, current_user)
|
||||
participants_for(value, current_user, project)
|
||||
end.compact.uniq
|
||||
|
||||
if project
|
||||
participants.select! do |user|
|
||||
user.can?(:read_project, project)
|
||||
end
|
||||
end
|
||||
|
||||
participants
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def participants_for(value, current_user = nil)
|
||||
def participants_for(value, current_user = nil, project = nil)
|
||||
case value
|
||||
when User
|
||||
[value]
|
||||
when Enumerable, ActiveRecord::Relation
|
||||
value.flat_map { |v| participants_for(v, current_user) }
|
||||
value.flat_map { |v| participants_for(v, current_user, project) }
|
||||
when Participable
|
||||
value.participants(current_user)
|
||||
value.participants(current_user, project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# == Referable concern
|
||||
#
|
||||
# Contains functionality related to making a model referable in Markdown, such
|
||||
# as "#1", "!2", "~3", etc.
|
||||
module Referable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Returns the String necessary to reference this object in Markdown
|
||||
#
|
||||
# from_project - Refering Project object
|
||||
#
|
||||
# This should be overridden by the including class.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# Issue.first.to_reference # => "#1"
|
||||
# Issue.last.to_reference(other_project) # => "cross-project#1"
|
||||
#
|
||||
# Returns a String
|
||||
def to_reference(_from_project = nil)
|
||||
''
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# The character that prefixes the actual reference identifier
|
||||
#
|
||||
# This should be overridden by the including class.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# Issue.reference_prefix # => '#'
|
||||
# MergeRequest.reference_prefix # => '!'
|
||||
#
|
||||
# Returns a String
|
||||
def reference_prefix
|
||||
''
|
||||
end
|
||||
|
||||
# Regexp pattern used to match references to this object
|
||||
#
|
||||
# This must be overridden by the including class.
|
||||
#
|
||||
# Returns a Regexp
|
||||
def reference_pattern
|
||||
raise NotImplementedError, "#{self} does not implement #{__method__}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Check if a reference is being done cross-project
|
||||
#
|
||||
# from_project - Refering Project object
|
||||
def cross_project_reference?(from_project)
|
||||
if self.is_a?(Project)
|
||||
self != from_project
|
||||
else
|
||||
from_project && self.project && self.project != from_project
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,6 @@
|
||||
class ExternalIssue
|
||||
include Referable
|
||||
|
||||
def initialize(issue_identifier, project)
|
||||
@issue_identifier, @project = issue_identifier, project
|
||||
end
|
||||
@@ -26,4 +28,13 @@ class ExternalIssue
|
||||
def project
|
||||
@project
|
||||
end
|
||||
|
||||
# Pattern used to extract `JIRA-123` issue references from text
|
||||
def self.reference_pattern
|
||||
%r{(?<issue>([A-Z\-]+-)\d+)}
|
||||
end
|
||||
|
||||
def to_reference(_from_project = nil)
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,6 +17,8 @@ require 'carrierwave/orm/activerecord'
|
||||
require 'file_size_validator'
|
||||
|
||||
class Group < Namespace
|
||||
include Referable
|
||||
|
||||
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
|
||||
has_many :users, through: :group_members
|
||||
has_many :project_group_links, dependent: :destroy
|
||||
@@ -40,6 +42,18 @@ class Group < Namespace
|
||||
def sort(method)
|
||||
order_by(method)
|
||||
end
|
||||
|
||||
def reference_prefix
|
||||
User.reference_prefix
|
||||
end
|
||||
|
||||
def reference_pattern
|
||||
User.reference_pattern
|
||||
end
|
||||
end
|
||||
|
||||
def to_reference(_from_project = nil)
|
||||
"#{self.class.reference_prefix}#{name}"
|
||||
end
|
||||
|
||||
def human_name
|
||||
@@ -108,10 +122,14 @@ class Group < Namespace
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
Gitlab::AppLogger.info("Group \"#{name}\" was created")
|
||||
|
||||
system_hook_service.execute_hooks_for(self, :create)
|
||||
end
|
||||
|
||||
def post_destroy_hook
|
||||
Gitlab::AppLogger.info("Group \"#{name}\" was removed")
|
||||
|
||||
system_hook_service.execute_hooks_for(self, :destroy)
|
||||
end
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class GroupMilestone
|
||||
def percent_complete
|
||||
((closed_items_count * 100) / total_items_count).abs
|
||||
rescue ZeroDivisionError
|
||||
100
|
||||
0
|
||||
end
|
||||
|
||||
def state
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# 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
|
||||
#
|
||||
|
||||
class ProjectHook < WebHook
|
||||
@@ -21,5 +22,6 @@ class ProjectHook < WebHook
|
||||
scope :push_hooks, -> { where(push_events: true) }
|
||||
scope :tag_push_hooks, -> { where(tag_push_events: true) }
|
||||
scope :issue_hooks, -> { where(issues_events: true) }
|
||||
scope :note_hooks, -> { where(note_events: true) }
|
||||
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
|
||||
end
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# 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
|
||||
#
|
||||
|
||||
class ServiceHook < WebHook
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# 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
|
||||
#
|
||||
|
||||
class SystemHook < WebHook
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# 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
|
||||
#
|
||||
|
||||
class WebHook < ActiveRecord::Base
|
||||
@@ -21,6 +22,7 @@ class WebHook < ActiveRecord::Base
|
||||
|
||||
default_value_for :push_events, true
|
||||
default_value_for :issues_events, false
|
||||
default_value_for :note_events, false
|
||||
default_value_for :merge_requests_events, false
|
||||
default_value_for :tag_push_events, false
|
||||
|
||||
|
||||
+24
-5
@@ -21,10 +21,11 @@ require 'carrierwave/orm/activerecord'
|
||||
require 'file_size_validator'
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
include Issuable
|
||||
include InternalId
|
||||
include Taskable
|
||||
include Issuable
|
||||
include Referable
|
||||
include Sortable
|
||||
include Taskable
|
||||
|
||||
ActsAsTaggableOn.strict_case_match = true
|
||||
|
||||
@@ -53,10 +54,28 @@ class Issue < ActiveRecord::Base
|
||||
attributes
|
||||
end
|
||||
|
||||
# Mentionable overrides.
|
||||
def self.reference_prefix
|
||||
'#'
|
||||
end
|
||||
|
||||
def gfm_reference
|
||||
"issue ##{iid}"
|
||||
# Pattern used to extract `#123` issue references from text
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
(#{Project.reference_pattern})?
|
||||
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
|
||||
}x
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{iid}"
|
||||
|
||||
if cross_project_reference?(from_project)
|
||||
reference = project.to_reference + reference
|
||||
end
|
||||
|
||||
reference
|
||||
end
|
||||
|
||||
# Reset issue events cache
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#
|
||||
|
||||
class Label < ActiveRecord::Base
|
||||
include Referable
|
||||
|
||||
DEFAULT_COLOR = '#428BCA'
|
||||
|
||||
default_value_for :color, DEFAULT_COLOR
|
||||
@@ -34,6 +36,45 @@ class Label < ActiveRecord::Base
|
||||
|
||||
alias_attribute :name, :title
|
||||
|
||||
def self.reference_prefix
|
||||
'~'
|
||||
end
|
||||
|
||||
# Pattern used to extract label references from text
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
#{reference_prefix}
|
||||
(?:
|
||||
(?<label_id>\d+) | # Integer-based label ID, or
|
||||
(?<label_name>
|
||||
[A-Za-z0-9_-]+ | # String-based single-word label title, or
|
||||
"[^&\?,]+" # String-based multi-word label surrounded in quotes
|
||||
)
|
||||
)
|
||||
}x
|
||||
end
|
||||
|
||||
# Returns the String necessary to reference this Label in Markdown
|
||||
#
|
||||
# format - Symbol format to use (default: :id, optional: :name)
|
||||
#
|
||||
# Note that its argument differs from other objects implementing Referable. If
|
||||
# a non-Symbol argument is given (such as a Project), it will default to :id.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# Label.first.to_reference # => "~1"
|
||||
# Label.first.to_reference(:name) # => "~\"bug\""
|
||||
#
|
||||
# Returns a String
|
||||
def to_reference(format = :id)
|
||||
if format == :name && !name.include?('"')
|
||||
%(#{self.class.reference_prefix}"#{name}")
|
||||
else
|
||||
"#{self.class.reference_prefix}#{id}"
|
||||
end
|
||||
end
|
||||
|
||||
def open_issues_count
|
||||
issues.opened.count
|
||||
end
|
||||
|
||||
@@ -25,10 +25,11 @@ require Rails.root.join("app/models/commit")
|
||||
require Rails.root.join("lib/static_model")
|
||||
|
||||
class MergeRequest < ActiveRecord::Base
|
||||
include Issuable
|
||||
include Taskable
|
||||
include InternalId
|
||||
include Issuable
|
||||
include Referable
|
||||
include Sortable
|
||||
include Taskable
|
||||
|
||||
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
|
||||
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
|
||||
@@ -136,7 +137,31 @@ class MergeRequest < ActiveRecord::Base
|
||||
# Closed scope for merge request should return
|
||||
# both merged and closed mr's
|
||||
scope :closed, -> { with_states(:closed, :merged) }
|
||||
scope :declined, -> { with_states(:closed) }
|
||||
scope :rejected, -> { with_states(:closed) }
|
||||
|
||||
def self.reference_prefix
|
||||
'!'
|
||||
end
|
||||
|
||||
# Pattern used to extract `!123` merge request references from text
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
(#{Project.reference_pattern})?
|
||||
#{Regexp.escape(reference_prefix)}(?<merge_request>\d+)
|
||||
}x
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{iid}"
|
||||
|
||||
if cross_project_reference?(from_project)
|
||||
reference = project.to_reference + reference
|
||||
end
|
||||
|
||||
reference
|
||||
end
|
||||
|
||||
def validate_branches
|
||||
if target_project == source_project && target_branch == source_branch
|
||||
@@ -175,7 +200,6 @@ class MergeRequest < ActiveRecord::Base
|
||||
def update_merge_request_diff
|
||||
if source_branch_changed? || target_branch_changed?
|
||||
reload_code
|
||||
mark_as_unchecked
|
||||
end
|
||||
end
|
||||
|
||||
@@ -292,11 +316,6 @@ class MergeRequest < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# Mentionable override.
|
||||
def gfm_reference
|
||||
"merge request !#{iid}"
|
||||
end
|
||||
|
||||
def target_project_path
|
||||
if target_project
|
||||
target_project.path_with_namespace
|
||||
|
||||
@@ -66,7 +66,7 @@ class Milestone < ActiveRecord::Base
|
||||
def percent_complete
|
||||
((closed_items_count * 100) / total_items_count).abs
|
||||
rescue ZeroDivisionError
|
||||
100
|
||||
0
|
||||
end
|
||||
|
||||
def expires_at
|
||||
|
||||
+13
-2
@@ -72,7 +72,7 @@ class Namespace < ActiveRecord::Base
|
||||
path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
|
||||
|
||||
# Users with the great usernames of "." or ".." would end up with a blank username.
|
||||
# Work around that by setting their username to "blank", followed by a counter.
|
||||
# Work around that by setting their username to "blank", followed by a counter.
|
||||
path = "blank" if path.blank?
|
||||
|
||||
counter = 0
|
||||
@@ -99,7 +99,18 @@ class Namespace < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def rm_dir
|
||||
gitlab_shell.rm_namespace(path)
|
||||
# Move namespace directory into trash.
|
||||
# We will remove it later async
|
||||
new_path = "#{path}+#{id}+deleted"
|
||||
|
||||
if gitlab_shell.mv_namespace(path, new_path)
|
||||
message = "Namespace directory \"#{path}\" moved to \"#{new_path}\""
|
||||
Gitlab::AppLogger.info message
|
||||
|
||||
# Remove namespace directroy async with delay so
|
||||
# GitLab has time to remove all projects first
|
||||
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, new_path)
|
||||
end
|
||||
end
|
||||
|
||||
def move_dir
|
||||
|
||||
+2
-2
@@ -326,8 +326,8 @@ class Note < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# Mentionable override.
|
||||
def gfm_reference
|
||||
noteable.gfm_reference
|
||||
def gfm_reference(from_project = nil)
|
||||
noteable.gfm_reference(from_project)
|
||||
end
|
||||
|
||||
# Mentionable override.
|
||||
|
||||
+12
-2
@@ -33,11 +33,12 @@ require 'carrierwave/orm/activerecord'
|
||||
require 'file_size_validator'
|
||||
|
||||
class Project < ActiveRecord::Base
|
||||
include Sortable
|
||||
include Gitlab::ConfigHelper
|
||||
include Gitlab::ShellAdapter
|
||||
include Gitlab::VisibilityLevel
|
||||
include Gitlab::ConfigHelper
|
||||
include Rails.application.routes.url_helpers
|
||||
include Referable
|
||||
include Sortable
|
||||
|
||||
extend Gitlab::ConfigHelper
|
||||
extend Enumerize
|
||||
@@ -252,6 +253,11 @@ class Project < ActiveRecord::Base
|
||||
order_by(method)
|
||||
end
|
||||
end
|
||||
|
||||
def reference_pattern
|
||||
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
|
||||
%r{(?<project>#{name_pattern}/#{name_pattern})}
|
||||
end
|
||||
end
|
||||
|
||||
def team
|
||||
@@ -310,6 +316,10 @@ class Project < ActiveRecord::Base
|
||||
path
|
||||
end
|
||||
|
||||
def to_reference(_from_project = nil)
|
||||
path_with_namespace
|
||||
end
|
||||
|
||||
def web_url
|
||||
[gitlab_config.url, path_with_namespace].join('/')
|
||||
end
|
||||
|
||||
@@ -40,6 +40,12 @@ class GitlabCiService < CiService
|
||||
def execute(data)
|
||||
return unless supported_events.include?(data[:object_kind])
|
||||
|
||||
ci_yaml_file = ci_yaml_file(data)
|
||||
|
||||
if ci_yaml_file
|
||||
data.merge!(ci_yaml_file: ci_yaml_file)
|
||||
end
|
||||
|
||||
service_hook.execute(data)
|
||||
end
|
||||
|
||||
@@ -123,6 +129,14 @@ class GitlabCiService < CiService
|
||||
|
||||
private
|
||||
|
||||
def ci_yaml_file(data)
|
||||
ref = data[:checkout_sha]
|
||||
repo = project.repository
|
||||
commit = repo.commit(ref)
|
||||
blob = Gitlab::Git::Blob.find(repo, commit.id, ".gitlab-ci.yml")
|
||||
blob && blob.data
|
||||
end
|
||||
|
||||
def fork_registration_path
|
||||
project_url.sub(/projects\/\d*/, "#{API_PREFIX}/forks")
|
||||
end
|
||||
|
||||
@@ -63,7 +63,7 @@ class HipchatService < Service
|
||||
private
|
||||
|
||||
def gate
|
||||
options = { api_version: api_version || 'v2' }
|
||||
options = { api_version: api_version.present? ? api_version : 'v2' }
|
||||
options[:server_url] = server unless server.blank?
|
||||
@gate ||= HipChat::Client.new(token, options)
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ class ProjectWiki
|
||||
include Gitlab::ShellAdapter
|
||||
|
||||
MARKUPS = {
|
||||
'Markdown' => :markdown,
|
||||
'Markdown' => :md,
|
||||
'RDoc' => :rdoc,
|
||||
'AsciiDoc' => :asciidoc
|
||||
} unless defined?(MARKUPS)
|
||||
|
||||
@@ -370,8 +370,55 @@ class Repository
|
||||
@root_ref ||= raw_repository.root_ref
|
||||
end
|
||||
|
||||
def commit_file(user, path, content, message, ref)
|
||||
path[0] = '' if path[0] == '/'
|
||||
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
content: content,
|
||||
path: path
|
||||
}
|
||||
|
||||
Gitlab::Git::Blob.commit(raw_repository, options)
|
||||
end
|
||||
|
||||
def remove_file(user, path, message, ref)
|
||||
path[0] = '' if path[0] == '/'
|
||||
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
path: path
|
||||
}
|
||||
|
||||
Gitlab::Git::Blob.remove(raw_repository, options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_to_comitter(user)
|
||||
{
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
time: Time.now
|
||||
}
|
||||
end
|
||||
|
||||
def cache
|
||||
@cache ||= RepositoryCache.new(path_with_namespace)
|
||||
end
|
||||
|
||||
+29
-3
@@ -16,14 +16,16 @@
|
||||
#
|
||||
|
||||
class Snippet < ActiveRecord::Base
|
||||
include Sortable
|
||||
include Linguist::BlobHelper
|
||||
include Gitlab::VisibilityLevel
|
||||
include Linguist::BlobHelper
|
||||
include Participable
|
||||
include Referable
|
||||
include Sortable
|
||||
|
||||
default_value_for :visibility_level, Snippet::PRIVATE
|
||||
|
||||
belongs_to :author, class_name: "User"
|
||||
belongs_to :author, class_name: 'User'
|
||||
belongs_to :project
|
||||
|
||||
has_many :notes, as: :noteable, dependent: :destroy
|
||||
|
||||
@@ -50,6 +52,30 @@ class Snippet < ActiveRecord::Base
|
||||
|
||||
participant :author, :notes
|
||||
|
||||
def self.reference_prefix
|
||||
'$'
|
||||
end
|
||||
|
||||
# Pattern used to extract `$123` snippet references from text
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
def self.reference_pattern
|
||||
%r{
|
||||
(#{Project.reference_pattern})?
|
||||
#{Regexp.escape(reference_prefix)}(?<snippet>\d+)
|
||||
}x
|
||||
end
|
||||
|
||||
def to_reference(from_project = nil)
|
||||
reference = "#{self.class.reference_prefix}#{id}"
|
||||
|
||||
if cross_project_reference?(from_project)
|
||||
reference = project.to_reference + reference
|
||||
end
|
||||
|
||||
reference
|
||||
end
|
||||
|
||||
def self.content_types
|
||||
[
|
||||
".rb", ".py", ".pl", ".scala", ".c", ".cpp", ".java",
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
class Tree
|
||||
include Gitlab::MarkdownHelper
|
||||
include Gitlab::MarkupHelper
|
||||
|
||||
attr_accessor :repository, :sha, :path, :entries
|
||||
|
||||
def initialize(repository, sha, path = '/')
|
||||
path = '/' if path.blank?
|
||||
|
||||
|
||||
@repository = repository
|
||||
@sha = sha
|
||||
@path = path
|
||||
@@ -20,7 +20,7 @@ class Tree
|
||||
available_readmes = blobs.select(&:readme?)
|
||||
|
||||
if available_readmes.count == 0
|
||||
return @readme = nil
|
||||
return @readme = nil
|
||||
end
|
||||
|
||||
# Take the first previewable readme, or the first available readme, if we
|
||||
|
||||
+32
-4
@@ -62,11 +62,13 @@ require 'carrierwave/orm/activerecord'
|
||||
require 'file_size_validator'
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
include Sortable
|
||||
include Gitlab::ConfigHelper
|
||||
include TokenAuthenticatable
|
||||
extend Gitlab::ConfigHelper
|
||||
|
||||
include Gitlab::ConfigHelper
|
||||
include Gitlab::CurrentSettings
|
||||
include Referable
|
||||
include Sortable
|
||||
include TokenAuthenticatable
|
||||
|
||||
default_value_for :admin, false
|
||||
default_value_for :can_create_group, gitlab_config.default_can_create_group
|
||||
@@ -274,6 +276,18 @@ class User < ActiveRecord::Base
|
||||
|
||||
username
|
||||
end
|
||||
|
||||
def reference_prefix
|
||||
'@'
|
||||
end
|
||||
|
||||
# Pattern used to extract `@user` user references from text
|
||||
def reference_pattern
|
||||
%r{
|
||||
#{Regexp.escape(reference_prefix)}
|
||||
(?<user>#{Gitlab::Regex::NAMESPACE_REGEX_STR})
|
||||
}x
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
@@ -284,6 +298,10 @@ class User < ActiveRecord::Base
|
||||
username
|
||||
end
|
||||
|
||||
def to_reference(_from_project = nil)
|
||||
"#{self.class.reference_prefix}#{username}"
|
||||
end
|
||||
|
||||
def notification
|
||||
@notification ||= Notification.new(self)
|
||||
end
|
||||
@@ -493,7 +511,7 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def sanitize_attrs
|
||||
%w(name username skype linkedin twitter bio).each do |attr|
|
||||
%w(name username skype linkedin twitter).each do |attr|
|
||||
value = self.send(attr)
|
||||
self.send("#{attr}=", Sanitize.clean(value)) if value.present?
|
||||
end
|
||||
@@ -669,6 +687,12 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def namespaces
|
||||
namespace_ids = groups.pluck(:id)
|
||||
namespace_ids.push(namespace.id)
|
||||
Namespace.where(id: namespace_ids)
|
||||
end
|
||||
|
||||
def oauth_authorized_tokens
|
||||
Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
|
||||
end
|
||||
@@ -703,4 +727,8 @@ class User < ActiveRecord::Base
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def can_be_removed?
|
||||
!solo_owned_groups.present?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
class DeleteUserService
|
||||
def execute(user)
|
||||
if user.solo_owned_groups.present?
|
||||
user.errors[:base] << 'You must transfer ownership or delete groups before you can remove user'
|
||||
user
|
||||
else
|
||||
user.personal_projects.each do |project|
|
||||
# Skip repository removal because we remove directory with namespace
|
||||
# that contain all this repositories
|
||||
::Projects::DestroyService.new(project, current_user, skip_repo: true).execute
|
||||
end
|
||||
|
||||
user.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
class DestroyGroupService
|
||||
attr_accessor :group, :current_user
|
||||
|
||||
def initialize(group, user)
|
||||
@group, @current_user = group, user
|
||||
end
|
||||
|
||||
def execute
|
||||
@group.projects.each do |project|
|
||||
# Skip repository removal because we remove directory with namespace
|
||||
# that contain all this repositories
|
||||
::Projects::DestroyService.new(project, current_user, skip_repo: true).execute
|
||||
end
|
||||
|
||||
@group.destroy
|
||||
end
|
||||
end
|
||||
@@ -17,5 +17,12 @@ module Files
|
||||
def git_hook
|
||||
project.git_hook
|
||||
end
|
||||
|
||||
def after_commit(sha)
|
||||
commit = repository.commit(sha)
|
||||
full_ref = 'refs/heads/' + (params[:new_branch] || ref)
|
||||
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
|
||||
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require_relative "base_service"
|
||||
|
||||
module Files
|
||||
class CreateService < BaseService
|
||||
class CreateService < Files::BaseService
|
||||
def execute
|
||||
allowed = Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref)
|
||||
|
||||
@@ -37,16 +37,24 @@ module Files
|
||||
end
|
||||
end
|
||||
|
||||
content =
|
||||
if params[:encoding] == 'base64'
|
||||
Base64.decode64(params[:content])
|
||||
else
|
||||
params[:content]
|
||||
end
|
||||
|
||||
new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
|
||||
created_successfully = new_file_action.commit!(
|
||||
params[:content],
|
||||
sha = repository.commit_file(
|
||||
current_user,
|
||||
file_path,
|
||||
content,
|
||||
params[:commit_message],
|
||||
params[:encoding],
|
||||
params[:new_branch]
|
||||
params[:new_branch] || ref
|
||||
)
|
||||
|
||||
if created_successfully
|
||||
|
||||
if sha
|
||||
after_commit(sha)
|
||||
success
|
||||
else
|
||||
error("Your changes could not be committed, because the file has been changed")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require_relative "base_service"
|
||||
|
||||
module Files
|
||||
class DeleteService < BaseService
|
||||
class DeleteService < Files::BaseService
|
||||
def execute
|
||||
allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref)
|
||||
|
||||
@@ -23,14 +23,15 @@ module Files
|
||||
return error("You can only edit text files")
|
||||
end
|
||||
|
||||
delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path)
|
||||
|
||||
deleted_successfully = delete_file_action.commit!(
|
||||
nil,
|
||||
params[:commit_message]
|
||||
sha = repository.remove_file(
|
||||
current_user,
|
||||
path,
|
||||
params[:commit_message],
|
||||
ref
|
||||
)
|
||||
|
||||
if deleted_successfully
|
||||
if sha
|
||||
after_commit(sha)
|
||||
success
|
||||
else
|
||||
error("Your changes could not be committed, because the file has been changed")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require_relative "base_service"
|
||||
|
||||
module Files
|
||||
class UpdateService < BaseService
|
||||
class UpdateService < Files::BaseService
|
||||
def execute
|
||||
allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref)
|
||||
|
||||
@@ -23,14 +23,22 @@ module Files
|
||||
return error("You can only edit text files")
|
||||
end
|
||||
|
||||
edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path)
|
||||
edit_file_action.commit!(
|
||||
params[:content],
|
||||
content =
|
||||
if params[:encoding] == 'base64'
|
||||
Base64.decode64(params[:content])
|
||||
else
|
||||
params[:content]
|
||||
end
|
||||
|
||||
sha = repository.commit_file(
|
||||
current_user,
|
||||
path,
|
||||
content,
|
||||
params[:commit_message],
|
||||
params[:encoding],
|
||||
params[:new_branch]
|
||||
params[:new_branch] || ref
|
||||
)
|
||||
|
||||
after_commit(sha)
|
||||
success
|
||||
rescue Gitlab::Satellite::CheckoutFailed => ex
|
||||
error("Your changes could not be committed because ref '#{ref}' could not be checked out", 400)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user