Commit 2eab1fd2 authored by James Lopez's avatar James Lopez

Merge branch 'master' into 'latest-security-to-master-21-03-18'

# Conflicts:
#   Gemfile
#   Gemfile.lock
parents 4d0ec5b1 d68ddc83
...@@ -2,6 +2,198 @@ ...@@ -2,6 +2,198 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.6.0 (2018-03-22)
### Security (4 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Ensure that OTP backup codes are always invalidated.
- Add verification for GitLab Pages custom domains.
- Fix GitLab Auth0 integration signing in the wrong user.
### Fixed (75 changes, 17 of them are from the community)
- Ensure users cannot create environments with leading or trailing slashes (Fixes #39885). !15273
- Fix new project path input overlapping. !16755 (George Tsiolis)
- Respect description and visibility when creating project from template. !16820 (George Tsiolis)
- Remove user notification settings for groups and projects when user leaves. !16906 (Jacopo Beschi @jacopo-beschi)
- Fix Teleporting Emoji. !16963 (Jared Deckard <jared.deckard@gmail.com>)
- Fix duplicate system notes when merging a merge request. !17035
- Fix breadcrumb on labels page for groups. !17045 (Onuwa Nnachi Isaac)
- Fix user avatar's vertical align on the issues and merge requests pages. !17072 (Laszlo Karpati)
- Fix settings panels not expanding when fragment hash linked. !17074
- Fix 404 when listing archived projects in a group where all projects have been archived. !17077 (Ashley Dumaine)
- Allow to call PUT /projects/:id API with only ci_config_path specified. !17105 (Laszlo Karpati)
- Fix long list of recipients on group request membership email. !17121 (Jacopo Beschi @jacopo-beschi)
- Remove duplicated error message on duplicate variable validation. !17135
- Keep "Import project" tab/form active when validation fails trying to import "Repo by URL". !17136
- Fixed bug with unauthenticated requests through git ssh. !17149
- Allows project rename after validation error. !17150
- Fix "Remove source branch" button in Merge request widget during merge when pipeline succeeds state. !17192
- Add missing pagination on the commit diff endpoint. !17203 (Maxime Roussin-Bélanger)
- Fix get a single pages domain when project path contains a period. !17206 (Travis Miller)
- remove avater underline. !17219 (Ken Ding)
- Allows the usage of /milestone quick action for group milestones. !17239 (Jacopo Beschi @jacopo-beschi)
- Encode branch name as binary before creating a RPC request to copy attributes. !17291
- Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed. !17293
- Do not persist Google Project verification flash errors after a page reload. !17299
- Ensure group issues and merge requests pages show results from subgroups when there are no results from the current group. !17312
- Prevent trace artifact migration to incur data loss. !17313
- Fixes gpg popover layout. !17323
- Return a 404 instead of 403 if the repository does not exist on disk. !17341
- Fix Slack/Mattermost notifications not respecting `notify_only_default_branch` setting for pushes. !17345
- Fix Group labels load failure when there are duplicate labels present. !17353
- Allow Prometheus application to be installed from Cluster applications. !17372
- Fixes Prometheus admin configuration page. !17377
- Enable filtering MR list based on clicked label in MR sidebar. !17390
- Fix code and wiki search results pages when non-ASCII text is displayed. !17413
- Count comments on diffs and discussions as contributions for the contributions calendar. !17418 (Riccardo Padovani)
- Add Assignees vue component missing data container. !17426 (George Tsiolis)
- Update tooltip on pipeline cancel to Stop (#42946). !17444
- Removing the two factor check when the user sets a new password. !17457
- Fix quick actions for users who cannot update issues and merge requests. !17482
- Stop loading spinner on error of milestone update on issue. !17507 (Takuya Noguchi)
- Set margins around dropdown dividers to 4px. !17517
- Fix pages flaky failure by reloading stale object. !17522
- Remove extra breadcrumb on tags. !17562 (Takuya Noguchi)
- Fix missing uploads after group transfer. !17658
- Fix markdown table showing extra column. !17669
- Ensure the API returns https links when https is configured. !17681
- Sanitize extra blank spaces used when uploading a SSH key. !40552
- Render htmlentities correctly for links not supported by Rinku.
- Keep link when redacting unauthorized object links.
- Handle empty state in Pipelines page.
- Revert Project.public_or_visible_to_user changes and only apply to snippets.
- Release libgit2 cache and open file descriptors after `git gc` run.
- Fix project dashboard showing the wrong timestamps.
- Fix "Can't modify frozen hash" error when project is destroyed.
- Fix Error 500 when viewing a commit with a GPG signature in Geo.
- Don't error out in system hook if user has `nil` datetime columns.
- Remove double caching of Repository#empty?.
- Don't delete todos or unassign issues and MRs when a user leaves a project.
- Don't cache a nil repository root ref to prevent caching issues.
- Escape HTML entities in commit messages.
- Verify project import status again before marking as failed.
- [GitHub Import] Create an empty wiki if wiki import failed.
- Create empty wiki when import from GitLab and wiki is not there.
- Make sure wiki exists when it's enabled.
- Fix broken loading state for close issue button.
- Fix code and wiki search results when filename is non-ASCII.
- Fix file upload on project show page.
- Fix squashing when a file is renamed.
- Show loading button inline in refresh button in MR widget.
- Fix close button on issues not working on mobile.
- Adds tooltip in environment names to increase readability.
- Fixed issue edit shortcut not opening edit form.
- Fix 500 error being shown when diff has context marker with invalid encoding.
- Render modified icon for moved file in changes dropdown.
- Remember assignee when moving an issue.
### Changed (16 changes, 9 of them are from the community)
- Allow including custom attributes in API responses. !16526 (Markus Koller)
- Apply new default and inline label design. !16956 (George Tsiolis)
- Remove whitespace from the username/email sign in form field. !17020 (Peter lauck)
- CI charts now include the current day. !17032 (Dakkaron)
- Hide CI secret variable values after saving. !17044
- Add new modal Vue component. !17108
- Asciidoc now support inter-document cross references between files in repository. !17125 (Turo Soisenniemi)
- Update issue closing pattern to allow variations in punctuation. !17198 (Vicky Chijwani)
- Add a button to deploy a runner to a Kubernetes cluster in the settings page. !17278
- Pages custom domain: allow update of key/certificate. !17376 (rfwatson)
- Clear the Labels dropdown search filter after a selection is made. !17393 (Andrew Torres)
- Hook data for pipelines includes detailed_status. !17607
- Avoid showing unnecessary Trigger checkboxes for project Integrations with only one event. !17607
- Display a link to external issue tracker when enabled.
- Allow token authentication on go-get request.
- Update SSH key link to include existing keys. (Brendan O'Leary)
### Performance (24 changes, 5 of them are from the community)
- Add catch-up background migration to migrate pipeline stages. !15741
- Move BoardNewIssue vue component. !16947 (George Tsiolis)
- Move IssuableTimeTracker vue component. !16948 (George Tsiolis)
- Move RecentSearchesDropdownContent vue component. !16951 (George Tsiolis)
- Move Assignees vue component. !16952 (George Tsiolis)
- Improve performance of pipeline page by reducing DB queries. !17168
- Store sha256 checksum to job artifacts. !17354
- Move SidebarAssignees vue component. !17398 (George Tsiolis)
- Improve database response time for user activity listing. !17454
- Use persisted/memoized value for MRs shas instead of doing git lookups. !17555
- Cache MergeRequests can_be_resolved_in_ui? git operations. !17589
- Prevent the graphs page from generating unnecessary Gitaly requests. !37602
- Use a user object in ApplicationHelper#avatar_icon where possible to avoid N+1 queries. !42800
- Submit a single batch blob RPC to Gitaly per HTTP request when viewing diffs.
- Avoid re-fetching merge-base SHA from Gitaly unnecessarily.
- Don't use ProjectsFinder in TodosFinder.
- Adding missing indexes on taggings table.
- Add index on section_name_id on ci_build_trace_sections table.
- Cache column_exists? for application settings.
- Cache table_exists?('application_settings') to reduce repeated schema reloads.
- Make --prune a configurable parameter in fetching a git remote.
- Fix timeouts loading /admin/projects page.
- Add partial indexes on todos to handle users with many todos.
- Optimize search queries on the search page by setting a limit for matching records in project scope.
### Added (30 changes, 9 of them are from the community)
- Add CommonMark markdown engine (experimental). !14835 (blackst0ne)
- API: Get references a commit is pushed to. !15026 (Robert Schilling)
- Add overview of branches and a filter for active/stale branches. !15402 (Takuya Noguchi)
- Add project export API. !15860 (Travis Miller)
- expose more metrics in merge requests api. !16589 (haseebeqx)
- #28481: Display time tracking totals on milestone page. !16753 (Riccardo Padovani)
- Add a button on the project page to set up a Kubernetes cluster and enable Auto DevOps. !16900
- Include cycle time in usage ping data. !16973
- Add ability to use external plugins as an alternative to system hooks. !17003
- Add search param to Branches API. !17005 (bunufi)
- API endpoint for importing a project export. !17025
- Display ingress IP address in the Kubernetes page. !17052
- Implemented badge API endpoints. !17082
- Allow installation of GitLab Runner with a single click. !17134
- Allow commits endpoint to work over all commits of a repository. !17182
- Display Runner IP Address. !17286
- Add archive feature to trace. !17314
- Allow maintainers to push to forks of their projects when a merge request is open. !17395
- Foreground verification of uploads and LFS objects. !17402
- Adds updated_at filter to issues and merge_requests API. !17417 (Jacopo Beschi @jacopo-beschi)
- Port /wip quick action command to Merge Request creation (on description). !17463 (Adam Pahlevi)
- Add a paragraph about security implications on Cluster's page. !17486
- Add plugins list to the system hooks page. !17518
- Enable privileged mode for GitLab Runner. !17528
- Expose GITLAB_FEATURES as CI/CD variable (fixes #40994).
- Upgrade GitLab Workhorse to 4.0.0.
- Allow CI/CD Jobs being grouped on version strings.
- Add discussions API for Issues and Snippets.
- Add one group board to Libre.
- Add support for filtering by source and target branch to merge requests API.
### Other (14 changes, 3 of them are from the community)
- Update vue component naming guidelines. !17018 (George Tsiolis)
- Added new design for promotion modals. !17197
- Update to github-linguist 5.3.x. !17241 (Ken Ding)
- update toml-rb to 1.0.0. !17259 (Ken Ding)
- Keep track of projects a user interacted with. !17327
- Enables eslint in codeclimate job. !17392
- Port Labels Select dropdown to Vue. !17411
- Add NOT NULL constraint to projects.namespace_id. !17448
- Ensure foreign keys on clusters applications. !17488
- Started translation into Turkish, Indonesian and Filipino. !17526
- Add documentation for displayed K8s Ingress IP address (#44330). !17836
- Move Ruby endpoints to OPT_OUT.
- Upgrade Workhorse to version 3.8.0 to support structured logging.
- Use host URL to build JIRA remote link icon.
## 10.5.6 (2018-03-16)
### Security (2 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.5.5 (2018-03-15) ## 10.5.5 (2018-03-15)
### Fixed (3 changes) ### Fixed (3 changes)
...@@ -261,6 +453,14 @@ entry. ...@@ -261,6 +453,14 @@ entry.
- Adds empty state illustration for pending job. - Adds empty state illustration for pending job.
## 10.4.6 (2018-03-16)
### Security (2 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.4.5 (2018-03-01) ## 10.4.5 (2018-03-01)
### Security (1 change) ### Security (1 change)
...@@ -492,6 +692,15 @@ entry. ...@@ -492,6 +692,15 @@ entry.
- Use a background migration for issues.closed_at. - Use a background migration for issues.closed_at.
## 10.3.9 (2018-03-16)
### Security (3 changes)
- Fixed some SSRF vulnerabilities in services, hooks and integrations. !2337
- Update nokogiri to 1.8.2. !16807
- Fix GitLab Auth0 integration signing in the wrong user.
## 10.3.8 (2018-03-01) ## 10.3.8 (2018-03-01)
### Security (1 change) ### Security (1 change)
......
# --- Special code for migrating to Rails 5.0 ---
def rails5?
%w[1 true].include?(ENV["RAILS5"])
end
gem_versions = {}
gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2'
gem_versions['default_value_for'] = rails5? ? '~> 3.0.5' : '~> 3.0.0'
gem_versions['html-pipeline'] = rails5? ? '~> 2.6.0' : '~> 1.11.0'
gem_versions['rails'] = rails5? ? '5.0.6' : '4.2.10'
gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9'
# --- The end of special code for migrating to Rails 5.0 ---
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rails', '4.2.10' gem 'rails', gem_versions['rails']
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
...@@ -9,7 +22,7 @@ gem 'responders', '~> 2.0' ...@@ -9,7 +22,7 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0' gem 'sprockets', '~> 3.7.0'
# Default values for AR models # Default values for AR models
gem 'default_value_for', '~> 3.0.0' gem 'default_value_for', gem_versions['default_value_for']
# Supported DBs # Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql gem 'mysql2', '~> 0.4.10', group: :mysql
...@@ -24,7 +37,7 @@ gem 'faraday', '~> 0.12' ...@@ -24,7 +37,7 @@ gem 'faraday', '~> 0.12'
gem 'devise', '~> 4.2' gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.3' gem 'doorkeeper', '~> 4.3'
gem 'doorkeeper-openid_connect', '~> 1.3' gem 'doorkeeper-openid_connect', '~> 1.3'
gem 'omniauth', '~> 1.4.2' gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 2.0.0' gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-oauth2', '~> 0.0.9' gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-cas3', '~> 1.1.4'
...@@ -122,7 +135,7 @@ gem 'unf', '~> 0.1.4' ...@@ -122,7 +135,7 @@ gem 'unf', '~> 0.1.4'
gem 'seed-fu', '~> 2.3.7' gem 'seed-fu', '~> 2.3.7'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0' gem 'html-pipeline', gem_versions['html-pipeline']
gem 'deckar01-task_list', '2.0.0' gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2' gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4' gem 'redcarpet', '~> 3.4'
...@@ -266,7 +279,7 @@ gem 'premailer-rails', '~> 1.9.7' ...@@ -266,7 +279,7 @@ gem 'premailer-rails', '~> 1.9.7'
# I18n # I18n
gem 'ruby_parser', '~> 3.8', require: false gem 'ruby_parser', '~> 3.8', require: false
gem 'rails-i18n', '~> 4.0.9' gem 'rails-i18n', gem_versions['rails-i18n']
gem 'gettext_i18n_rails', '~> 1.8.0' gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3' gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.2.2', require: false, group: :development gem 'gettext', '~> 3.2.2', require: false, group: :development
...@@ -357,7 +370,7 @@ group :development, :test do ...@@ -357,7 +370,7 @@ group :development, :test do
gem 'license_finder', '~> 3.1', require: false gem 'license_finder', '~> 3.1', require: false
gem 'knapsack', '~> 1.16' gem 'knapsack', '~> 1.16'
gem 'activerecord_sane_schema_dumper', '0.2' gem 'activerecord_sane_schema_dumper', gem_versions['activerecord_sane_schema_dumper']
gem 'stackprof', '~> 0.2.10', require: false gem 'stackprof', '~> 0.2.10', require: false
......
...@@ -524,8 +524,8 @@ GEM ...@@ -524,8 +524,8 @@ GEM
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.8.0) octokit (4.8.0)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.4.3) omniauth (1.8.1)
hashie (>= 1.2, < 4) hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3) rack (>= 1.6.2, < 3)
omniauth-auth0 (2.0.0) omniauth-auth0 (2.0.0)
omniauth-oauth2 (~> 1.4) omniauth-oauth2 (~> 1.4)
...@@ -1104,7 +1104,7 @@ DEPENDENCIES ...@@ -1104,7 +1104,7 @@ DEPENDENCIES
nokogiri (~> 1.8.2) nokogiri (~> 1.8.2)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.8) octokit (~> 4.8)
omniauth (~> 1.4.2) omniauth (~> 1.8)
omniauth-auth0 (~> 2.0.0) omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.1) omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9) omniauth-azure-oauth2 (~> 0.0.9)
......
# BUNDLE_GEMFILE=Gemfile.rails5 bundle install
ENV["RAILS5"] = "true"
gemfile = File.expand_path("../Gemfile", __FILE__)
eval(File.read(gemfile), nil, gemfile)
GEM
remote: https://rubygems.org/
specs:
RedCloth (4.3.2)
abstract_type (0.0.7)
ace-rails-ap (4.1.4)
actioncable (5.0.6)
actionpack (= 5.0.6)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1)
actionmailer (5.0.6)
actionpack (= 5.0.6)
actionview (= 5.0.6)
activejob (= 5.0.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.0.6)
actionview (= 5.0.6)
activesupport (= 5.0.6)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.6)
activesupport (= 5.0.6)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.6)
activesupport (= 5.0.6)
globalid (>= 0.3.6)
activemodel (5.0.6)
activesupport (= 5.0.6)
activerecord (5.0.6)
activemodel (= 5.0.6)
activesupport (= 5.0.6)
arel (~> 7.0)
activerecord_sane_schema_dumper (1.0)
rails (>= 5, < 6)
activesupport (5.0.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
acts-as-taggable-on (4.0.0)
activerecord (>= 4.0)
adamantium (0.2.0)
ice_nine (~> 0.11.0)
memoizable (~> 0.4.0)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
aes_key_wrap (1.0.1)
akismet (2.0.0)
allocations (1.0.5)
arel (7.1.4)
asana (0.6.3)
faraday (~> 0.9)
faraday_middleware (~> 0.9)
faraday_middleware-multi_json (~> 0.0)
oauth2 (~> 1.0)
asciidoctor (1.5.6.1)
asciidoctor-plantuml (0.0.7)
asciidoctor (~> 1.5)
asset_sync (2.2.0)
activemodel (>= 4.1.0)
fog-core
mime-types (>= 2.99)
unf
ast (2.4.0)
atomic (1.1.100)
attr_encrypted (3.0.3)
encryptor (~> 3.0.0)
attr_required (1.0.1)
autoprefixer-rails (8.1.0.1)
execjs
awesome_print (1.2.0)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
babosa (1.0.2)
base32 (0.3.2)
batch-loader (1.2.1)
bcrypt (3.1.11)
bcrypt_pbkdf (1.0.0)
benchmark-ips (2.3.0)
better_errors (2.1.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
rack (>= 0.9.0)
bindata (2.4.3)
binding_of_caller (0.7.3)
debug_inspector (>= 0.0.1)
blankslate (2.1.2.4)
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
bootstrap_form (2.7.0)
brakeman (3.6.2)
browser (2.5.3)
builder (3.2.3)
bullet (5.5.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
bundler-audit (0.5.0)
bundler (~> 1.2)
thor (~> 0.18)
byebug (9.0.6)
capybara (2.18.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (>= 2.0, < 4.0)
capybara-screenshot (1.0.18)
capybara (>= 1.0, < 3)
launchy
carrierwave (1.2.2)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
charlock_holmes (0.7.5)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2)
chronic_duration (0.10.6)
numerizer (~> 0.1.1)
chunky_png (1.3.10)
citrus (3.0.2)
coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
colorize (0.8.1)
commonmarker (0.17.9)
ruby-enum (~> 0.5)
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
concurrent-ruby (1.0.5)
concurrent-ruby-ext (1.0.5)
concurrent-ruby (= 1.0.5)
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
creole (0.5.0)
css_parser (1.6.0)
addressable
d3_rails (3.5.17)
railties (>= 3.1.0)
daemons (1.2.6)
database_cleaner (1.5.3)
debug_inspector (0.0.3)
debugger-ruby_core_source (1.3.8)
deckar01-task_list (2.0.0)
html-pipeline
declarative (0.0.10)
declarative-option (0.1.0)
default_value_for (3.0.5)
activerecord (>= 3.2.0, < 5.2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.4.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.2)
responders
warden (~> 1.2.3)
devise-two-factor (3.0.2)
activesupport (< 5.2)
attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 4.0)
railties (< 5.2)
rotp (~> 2.0)
diff-lcs (1.3)
diffy (3.1.0)
docile (1.1.5)
domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.2.6)
railties (>= 4.2)
doorkeeper-openid_connect (1.2.0)
doorkeeper (~> 4.0)
json-jwt (~> 1.6)
dropzonejs-rails (0.7.4)
rails (> 3.1)
email_reply_trimmer (0.1.10)
email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
encryptor (3.0.0)
equalizer (0.0.11)
erubis (2.7.0)
escape_utils (1.1.1)
et-orbi (1.0.9)
tzinfo
eventmachine (1.2.5)
excon (0.60.0)
execjs (2.7.0)
expression_parser (0.9.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0)
faraday_middleware-multi_json (0.0.6)
faraday_middleware
multi_json
fast_blank (1.0.0)
fast_gettext (1.6.0)
ffaker (2.8.1)
ffi (1.9.23)
flay (2.10.0)
erubis (~> 2.7.0)
path_expander (~> 1.0)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
flipper (0.11.0)
flipper-active_record (0.11.0)
activerecord (>= 3.2, < 6)
flipper (~> 0.11.0)
flipper-active_support_cache_store (0.11.0)
activesupport (>= 3.2, < 6)
flipper (~> 0.11.0)
flowdock (0.7.1)
httparty (~> 0.7)
multi_json
fog-aliyun (0.2.0)
fog-core (~> 1.27)
fog-json (~> 1.0)
ipaddress (~> 0.8)
xml-simple (~> 1.1)
fog-aws (1.4.1)
fog-core (~> 1.38)
fog-json (~> 1.0)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
fog-core (1.45.0)
builder
excon (~> 0.58)
formatador (~> 0.2)
fog-google (0.6.0)
fog-core
fog-json
fog-xml
fog-json (1.0.2)
fog-core (~> 1.0)
multi_json (~> 1.10)
fog-local (0.5.0)
fog-core (>= 1.27, < 3.0)
fog-openstack (0.1.24)
fog-core (~> 1.40)
fog-json (>= 1.0)
ipaddress (>= 0.8)
fog-rackspace (0.1.5)
fog-core (>= 1.35)
fog-json (>= 1.0)
fog-xml (>= 0.1)
ipaddress (>= 0.8)
fog-xml (0.1.3)
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
font-awesome-rails (4.7.0.3)
railties (>= 3.2, < 5.2)
foreman (0.78.0)
thor (~> 0.19.1)
formatador (0.2.5)
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (3.3.0)
json
get_process_mem (0.2.1)
gettext (3.2.9)
locale (>= 2.0.5)
text (>= 1.3.0)
gettext_i18n_rails (1.8.0)
fast_gettext (>= 0.9.0)
gettext_i18n_rails_js (1.2.0)
gettext (>= 3.0.2)
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.88.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (5.3.3)
charlock_holmes (~> 0.7.5)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
rugged (>= 0.25.1)
github-markup (1.7.0)
gitlab-flowdock-git-hook (1.0.1)
flowdock (~> 0.7)
gitlab-grit (>= 2.4.1)
multi_json
gitlab-grit (2.8.2)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (>= 1.16)
posix-spawn (~> 0.3)
gitlab-markup (1.6.3)
gitlab-styles (2.3.2)
rubocop (~> 0.51)
rubocop-gitlab-security (~> 0.1.0)
rubocop-rspec (~> 1.19)
gitlab_omniauth-ldap (2.0.4)
net-ldap (~> 0.16)
omniauth (~> 1.3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
globalid (0.4.1)
activesupport (>= 4.2.0)
gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1)
gollum-lib (4.2.7)
gemojione (~> 3.2)
github-markup (~> 1.6)
gollum-grit_adapter (~> 1.0)
nokogiri (>= 1.6.1, < 2.0)
rouge (~> 2.1)
sanitize (~> 2.1)
stringex (~> 2.6)
gollum-rugged_adapter (0.4.4)
mime-types (>= 1.15)
rugged (~> 0.25)
gon (6.1.0)
actionpack (>= 3.0)
json
multi_json
request_store (>= 1.0)
google-api-client (0.13.6)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.5)
httpclient (>= 2.8.1, < 3.0)
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.5.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
googleauth (0.6.2)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
logging (~> 2.0)
memoist (~> 0.12)
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
gpgme (2.0.16)
mini_portile2 (~> 2.3)
grape (1.0.2)
activesupport
builder
mustermann-grape (~> 1.0.0)
rack (>= 1.3.0)
rack-accept
virtus (>= 1.0.0)
grape-entity (0.6.1)
activesupport (>= 5.0.0)
multi_json (>= 1.3.2)
grape-route-helpers (2.1.0)
activesupport
grape (>= 0.16.0)
rake
grape_logging (1.7.0)
grape
grpc (1.10.0)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (>= 0.5.1, < 0.7)
haml (4.0.7)
tilt
haml_lint (0.26.0)
haml (>= 4.0, < 5.1)
rainbow
rake (>= 10, < 13)
rubocop (>= 0.49.0)
sysexits (~> 1.1)
hamlit (2.6.2)
temple (~> 0.7.6)
thor
tilt
hashdiff (0.3.7)
hashie (3.5.7)
hashie-forbidden_attributes (0.1.1)
hashie (>= 3.0)
health_check (2.6.0)
rails (>= 4.0)
hipchat (1.5.4)
httparty
mimemagic
html-pipeline (2.6.0)
activesupport (>= 2)
nokogiri (>= 1.4)
html2text (0.2.1)
nokogiri (~> 1.6)
htmlentities (4.3.4)
http (0.9.8)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
http_parser.rb (~> 0.6.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (1.0.3)
http_parser.rb (0.6.0)
httparty (0.13.7)
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
influxdb (0.5.3)
ipaddress (0.8.3)
jira-ruby (1.5.0)
activesupport
multipart-post
oauth (~> 0.5, >= 0.5.0)
jquery-atwho-rails (1.3.2)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.6)
json-jwt (1.9.2)
activesupport
aes_key_wrap
bindata
securecompare
url_safe_base64
json-schema (2.8.0)
addressable (>= 2.4)
jwt (1.5.6)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
kgio (2.11.2)
knapsack (1.11.1)
rake
timecop (>= 0.1.0)
kubeclient (2.2.0)
http (= 0.9.8)
recursive-open-struct (= 1.0.0)
rest-client
launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.6.0)
launchy (~> 2.2)
letter_opener_web (1.3.3)
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
license_finder (3.1.1)
bundler
httparty
rubyzip
thor
toml (= 0.1.2)
with_env (> 1.0)
xml-simple
licensee (8.7.0)
rugged (~> 0.24)
little-plugger (1.1.4)
locale (2.1.2)
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
lograge (0.9.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (1.0.2)
mustermann-grape (1.0.0)
mustermann (~> 1.0.0)
mysql2 (0.4.10)
net-ldap (0.16.1)
net-ssh (4.1.0)
netrc (0.11.0)
nio4r (2.2.0)
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
numerizer (0.1.1)
oauth (0.5.4)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
octokit (4.6.2)
sawyer (~> 0.8.0, >= 0.5.3)
oj (2.17.5)
omniauth (1.4.3)
hashie (>= 1.2, < 4)
rack (>= 1.6.2, < 3)
omniauth-auth0 (1.4.2)
omniauth-oauth2 (~> 1.1)
omniauth-authentiq (0.3.1)
omniauth-oauth2 (~> 1.3, >= 1.3.1)
omniauth-azure-oauth2 (0.0.9)
jwt (~> 1.0)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.4)
omniauth-cas3 (1.1.4)
addressable (~> 2.3)
nokogiri (~> 1.7, >= 1.7.1)
omniauth (~> 1.2)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-gitlab (1.0.3)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
omniauth-google-oauth2 (0.5.3)
jwt (>= 1.5)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.5)
omniauth-kerberos (0.3.0)
omniauth-multipassword
timfel-krb5-auth (~> 0.8)
omniauth-multipassword (0.4.2)
omniauth (~> 1.0)
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.5.0)
oauth2 (~> 1.1)
omniauth (~> 1.2)
omniauth-oauth2-generic (0.2.4)
omniauth-oauth2 (~> 1.0)
omniauth-saml (1.7.0)
omniauth (~> 1.3)
ruby-saml (~> 1.4)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
omniauth-twitter (1.2.1)
json (~> 1.3)
omniauth-oauth (~> 1.1)
omniauth_crowd (2.2.3)
activesupport
nokogiri (>= 1.4.4)
omniauth (~> 1.0)
org-ruby (0.9.12)
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (0.9.6)
parallel (1.12.1)
parser (2.5.0.4)
ast (~> 2.4.0)
parslet (1.5.0)
blankslate (~> 2.0)
path_expander (1.0.2)
peek (1.0.1)
concurrent-ruby (>= 0.9.0)
concurrent-ruby-ext (>= 0.9.0)
railties (>= 4.0.0)
peek-gc (0.0.2)
peek
peek-host (1.0.0)
peek
peek-mysql2 (1.1.0)
atomic (>= 1.0.0)
mysql2
peek
peek-performance_bar (1.3.1)
peek (>= 0.1.0)
peek-pg (1.3.0)
concurrent-ruby
concurrent-ruby-ext
peek
pg
peek-rblineprof (0.2.0)
peek
rblineprof
peek-redis (1.2.0)
atomic (>= 1.0.0)
peek
redis
peek-sidekiq (1.0.3)
atomic (>= 1.0.0)
peek
sidekiq
pg (0.18.4)
po_to_json (1.0.1)
json (>= 1.6.0)
posix-spawn (0.3.13)
powerpack (0.1.1)
premailer (1.11.1)
addressable
css_parser (>= 1.6.0)
htmlentities (>= 4.0.0)
premailer-rails (1.9.7)
actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9)
proc_to_ast (0.1.0)
coderay
parser
unparser
procto (0.0.3)
prometheus-client-mmap (0.9.1)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.4.3)
byebug (>= 9.0, < 9.1)
pry (~> 0.10)
pry-rails (0.3.6)
pry (>= 0.10.4)
public_suffix (3.0.2)
pyu-ruby-sasl (0.0.3.3)
rack (2.0.4)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.4.1)
rack
rack-cors (1.0.2)
rack-oauth2 (1.2.3)
activesupport (>= 2.3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
multi_json (>= 1.3.6)
rack (>= 1.1)
rack-protection (2.0.1)
rack
rack-proxy (0.6.4)
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (5.0.6)
actioncable (= 5.0.6)
actionmailer (= 5.0.6)
actionpack (= 5.0.6)
actionview (= 5.0.6)
activejob (= 5.0.6)
activemodel (= 5.0.6)
activerecord (= 5.0.6)
activesupport (= 5.0.6)
bundler (>= 1.3.0)
railties (= 5.0.6)
sprockets-rails (>= 2.0.0)
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails-i18n (5.1.1)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
railties (5.0.6)
actionpack (= 5.0.6)
activesupport (= 5.0.6)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
raindrops (0.19.0)
rake (12.3.0)
rb-fsevent (0.10.3)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rblineprof (0.3.7)
debugger-ruby_core_source (~> 1.3)
rbnacl (4.0.2)
ffi
rbnacl-libsodium (1.0.16)
rbnacl (>= 3.0.1)
rdoc (4.3.0)
re2 (1.1.1)
recaptcha (3.4.0)
json
recursive-open-struct (1.0.0)
redcarpet (3.4.0)
redis (3.3.5)
redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 2)
redis-activesupport (5.0.4)
activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2)
redis-namespace (1.5.3)
redis (~> 3.0, >= 3.0.4)
redis-rack (2.0.4)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
redis-rails (5.0.2)
redis-actionpack (>= 5.0, < 6)
redis-activesupport (>= 5.0, < 6)
redis-store (>= 1.2, < 2)
redis-store (1.4.1)
redis (>= 2.2, < 5)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
request_store (1.4.0)
rack (>= 1.4)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
rest-client (2.0.2)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.1)
rinku (2.0.4)
rotp (2.1.2)
rouge (2.2.1)
rqrcode (0.10.1)
chunky_png (~> 1.0)
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
rspec (3.6.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-core (3.6.0)
rspec-support (~> 3.6.0)
rspec-expectations (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-parameterized (0.4.0)
binding_of_caller
parser
proc_to_ast
rspec (>= 2.13, < 4)
unparser
rspec-rails (3.6.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-retry (0.4.6)
rspec-core
rspec-set (0.1.3)
rspec-support (3.6.0)
rspec_profiling (0.0.5)
activerecord
pg
rails
sqlite3
rubocop (0.52.1)
parallel (~> 1.10)
parser (>= 2.4.0.2, < 3.0)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51)
rubocop-rspec (1.22.2)
rubocop (>= 0.52.1)
ruby-enum (0.7.2)
i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.16.2)
ruby-progressbar (1.9.0)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
ruby_parser (3.11.0)
sexp_processor (~> 4.9)
rubyntlm (0.6.2)
rubypants (0.7.0)
rubyzip (1.2.1)
rufus-scheduler (3.4.2)
et-orbi (~> 1.0)
rugged (0.26.0)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
sass (3.5.5)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.7)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
scss_lint (0.56.0)
rake (>= 0.9, < 13)
sass (~> 3.5.3)
securecompare (1.0.0)
seed-fu (2.3.7)
activerecord (>= 3.1)
activesupport (>= 3.1)
select2-rails (3.5.10)
thor (~> 0.14)
selenium-webdriver (3.11.0)
childprocess (~> 0.5)
rubyzip (~> 1.2)
sentry-raven (2.5.3)
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
sexp_processor (4.10.1)
sham_rack (1.3.6)
rack
shoulda-matchers (3.1.2)
activesupport (>= 4.0.0)
sidekiq (5.1.1)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (>= 3.3.5, < 5)
sidekiq-cron (0.6.3)
rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1)
sidekiq-limit_fetch (3.4.0)
sidekiq (>= 4)
signet (0.8.1)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simple_po_parser (1.1.3)
simplecov (0.14.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slack-notifier (1.5.1)
spinach (0.10.1)
colorize
gherkin-ruby (>= 0.3.2)
json
spinach-rails (0.2.1)
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
spinach-rerun-reporter (0.0.2)
spinach (~> 0.8)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
spring-commands-spinach (1.1.0)
spring (>= 0.9.1)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
sshkey (1.9.0)
stackprof (0.2.11)
state_machines (0.5.0)
state_machines-activemodel (0.5.0)
activemodel (>= 4.1, < 5.2)
state_machines (>= 0.5.0)
state_machines-activerecord (0.4.1)
activerecord (>= 4.1, < 5.2)
state_machines-activemodel (>= 0.3.0)
stringex (2.8.4)
sys-filesystem (1.1.9)
ffi
sysexits (1.2.0)
temple (0.7.7)
test-prof (0.2.5)
test_after_commit (1.1.0)
activerecord (>= 3.2)
text (1.3.1)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.8)
timecop (0.8.1)
timfel-krb5-auth (0.8.3)
toml (0.1.2)
parslet (~> 1.5.0)
toml-rb (1.0.0)
citrus (~> 3.0, > 3.0)
truncato (0.7.10)
htmlentities (~> 4.3.1)
nokogiri (~> 1.8.0, >= 1.7.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
u2f (0.2.1)
uber (0.1.0)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.5)
unicode-display_width (1.3.0)
unicorn (5.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-worker-killer (0.4.4)
get_process_mem (~> 0)
unicorn (>= 4, < 6)
uniform_notifier (1.10.0)
unparser (0.2.7)
abstract_type (~> 0.0.7)
adamantium (~> 0.2.0)
concord (~> 0.1.5)
diff-lcs (~> 1.3)
equalizer (~> 0.0.9)
parser (>= 2.3.1.2, < 2.6)
procto (~> 0.0.2)
url_safe_base64 (0.2.2)
validates_hostname (1.0.8)
activerecord (>= 3.0)
activesupport (>= 3.0)
version_sorter (2.1.0)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
vmstat (2.3.0)
warden (1.2.7)
rack (>= 1.0)
webmock (2.3.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
webpack-rails (0.9.11)
railties (>= 3.2.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
wikicloth (0.8.1)
builder
expression_parser
rinku
with_env (1.1.0)
xml-simple (1.1.5)
xpath (3.0.0)
nokogiri (~> 1.8)
PLATFORMS
ruby
DEPENDENCIES
RedCloth (~> 4.3.2)
ace-rails-ap (~> 4.1.0)
activerecord_sane_schema_dumper (= 1.0)
acts-as-taggable-on (~> 4.0)
addressable (~> 2.5.2)
akismet (~> 2.0)
allocations (~> 1.0)
asana (~> 0.6.0)
asciidoctor (~> 1.5.2)
asciidoctor-plantuml (= 0.0.7)
asset_sync (~> 2.2.0)
attr_encrypted (~> 3.0.0)
awesome_print (~> 1.2.0)
babosa (~> 1.0.2)
base32 (~> 0.3.0)
batch-loader (~> 1.2.1)
bcrypt_pbkdf (~> 1.0)
benchmark-ips (~> 2.3.0)
better_errors (~> 2.1.0)
binding_of_caller (~> 0.7.2)
bootstrap-sass (~> 3.3.0)
bootstrap_form (~> 2.7.0)
brakeman (~> 3.6.0)
browser (~> 2.2)
bullet (~> 5.5.0)
bundler-audit (~> 0.5.0)
capybara (~> 2.15)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.2)
charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
commonmarker (~> 0.17)
concurrent-ruby (~> 1.0.5)
connection_pool (~> 2.0)
creole (~> 0.5.0)
d3_rails (~> 3.5.0)
database_cleaner (~> 1.5.0)
deckar01-task_list (= 2.0.0)
default_value_for (~> 3.0.5)
devise (~> 4.2)
devise-two-factor (~> 3.0.0)
diffy (~> 3.1.0)
doorkeeper (~> 4.2.0)
doorkeeper-openid_connect (~> 1.2.0)
dropzonejs-rails (~> 0.7.1)
email_reply_trimmer (~> 0.1)
email_spec (~> 1.6.0)
factory_bot_rails (~> 4.8.2)
faraday (~> 0.12)
fast_blank
ffaker (~> 2.4)
flay (~> 2.10.0)
flipper (~> 0.11.0)
flipper-active_record (~> 0.11.0)
flipper-active_support_cache_store (~> 0.11.0)
fog-aliyun (~> 0.2.0)
fog-aws (~> 1.4)
fog-core (~> 1.44)
fog-google (~> 0.5)
fog-local (~> 0.3)
fog-openstack (~> 0.1)
fog-rackspace (~> 0.1.1)
font-awesome-rails (~> 4.7)
foreman (~> 0.78.0)
fuubar (~> 2.2.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.3)
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.88.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
google-api-client (~> 0.13.6)
google-protobuf (= 3.5.1)
gpgme
grape (~> 1.0)
grape-entity (~> 0.6.0)
grape-route-helpers (~> 2.1.0)
grape_logging (~> 1.7)
grpc (~> 1.10.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.6.1)
hashie-forbidden_attributes
health_check (~> 2.6.0)
hipchat (~> 1.5.0)
html-pipeline (~> 2.6.0)
html2text
httparty (~> 0.13.3)
influxdb (~> 0.2)
jira-ruby (~> 1.4)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.3.1)
json-schema (~> 2.8.0)
jwt (~> 1.5.6)
kaminari (~> 1.0)
knapsack (~> 1.11.0)
kubeclient (~> 2.2.0)
letter_opener_web (~> 1.3.0)
license_finder (~> 3.1)
licensee (~> 8.7.0)
lograge (~> 0.5)
loofah (~> 2.0.3)
mail_room (~> 0.9.1)
method_source (~> 0.8)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.4.10)
net-ldap
net-ssh (~> 4.1.0)
nokogiri (~> 1.8.2)
oauth2 (~> 1.4)
octokit (~> 4.6.2)
oj (~> 2.17.4)
omniauth (~> 1.4.2)
omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4)
omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.2)
omniauth-google-oauth2 (~> 0.5.2)
omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.7.0)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12)
peek (~> 1.0.1)
peek-gc (~> 0.0.2)
peek-host (~> 1.0.0)
peek-mysql2 (~> 1.1.0)
peek-performance_bar (~> 1.3.0)
peek-pg (~> 1.3.0)
peek-rblineprof (~> 0.2.0)
peek-redis (~> 1.2.0)
peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2)
premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.9.1)
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
rack-cors (~> 1.0.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
rails (= 5.0.6)
rails-deprecated_sanitizer (~> 1.0.3)
rails-i18n (~> 5.1)
rainbow (~> 2.2)
raindrops (~> 0.18)
rblineprof (~> 0.3.6)
rbnacl (~> 4.0)
rbnacl-libsodium
rdoc (~> 4.2)
re2 (~> 1.1.1)
recaptcha (~> 3.0)
redcarpet (~> 3.4)
redis (~> 3.2)
redis-namespace (~> 1.5.2)
redis-rails (~> 5.0.2)
request_store (~> 1.3)
responders (~> 2.0)
rouge (~> 2.0)
rqrcode-rails3 (~> 0.1.7)
rspec-parameterized
rspec-rails (~> 3.6.0)
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
rubocop (~> 0.52.1)
rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4)
rugged (~> 0.26.0)
sanitize (~> 2.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3)
settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6)
shoulda-matchers (~> 3.1.2)
sidekiq (~> 5.0)
sidekiq-cron (~> 0.6.0)
sidekiq-limit_fetch (~> 3.4)
simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.1.0)
sprockets (~> 3.7.0)
sshkey (~> 1.9.0)
stackprof (~> 0.2.10)
state_machines-activerecord (~> 0.4.0)
sys-filesystem (~> 1.1.6)
test-prof (~> 0.2.5)
test_after_commit (~> 1.1)
thin (~> 1.7.0)
timecop (~> 0.8.0)
toml-rb (~> 1.0.0)
truncato (~> 0.7.9)
u2f (~> 0.2.1)
uglifier (~> 2.7.2)
unf (~> 0.1.4)
unicorn (~> 5.1.0)
unicorn-worker-killer (~> 0.4.4)
validates_hostname (~> 1.0.6)
version_sorter (~> 2.1.0)
virtus (~> 1.0.1)
vmstat (~> 2.3.0)
webmock (~> 2.3.2)
webpack-rails (~> 0.9.10)
wikicloth (= 0.8.1)
BUNDLED WITH
1.16.1
...@@ -4,4 +4,3 @@ ...@@ -4,4 +4,3 @@
# #
web: RAILS_ENV=development bin/web start_foreground web: RAILS_ENV=development bin/web start_foreground
worker: RAILS_ENV=development bin/background_jobs start_foreground worker: RAILS_ENV=development bin/background_jobs start_foreground
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
10.6.0-pre 10.7.0-pre
...@@ -43,6 +43,7 @@ export default { ...@@ -43,6 +43,7 @@ export default {
'file-open': this.isBlob && this.file.opened, 'file-open': this.isBlob && this.file.opened,
'file-active': this.isBlob && this.file.active, 'file-active': this.isBlob && this.file.active,
folder: this.isTree, folder: this.isTree,
'is-open': this.file.opened,
}; };
}, },
}, },
......
...@@ -54,41 +54,61 @@ const router = new VueRouter({ ...@@ -54,41 +54,61 @@ const router = new VueRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.params.namespace && to.params.project) { if (to.params.namespace && to.params.project) {
store.dispatch('getProjectData', { store
namespace: to.params.namespace, .dispatch('getProjectData', {
projectId: to.params.project, namespace: to.params.namespace,
}) projectId: to.params.project,
.then(() => { })
const fullProjectId = `${to.params.namespace}/${to.params.project}`; .then(() => {
const fullProjectId = `${to.params.namespace}/${to.params.project}`;
if (to.params.branch) { if (to.params.branch) {
store.dispatch('getBranchData', { store.dispatch('getBranchData', {
projectId: fullProjectId, projectId: fullProjectId,
branchId: to.params.branch, branchId: to.params.branch,
}); });
store.dispatch('getFiles', { store
projectId: fullProjectId, .dispatch('getFiles', {
branchId: to.params.branch, projectId: fullProjectId,
}) branchId: to.params.branch,
.then(() => { })
if (to.params[0]) { .then(() => {
const treeEntry = store.state.entries[to.params[0]]; if (to.params[0]) {
if (treeEntry) { const path =
store.dispatch('handleTreeEntryAction', treeEntry); to.params[0].slice(-1) === '/'
} ? to.params[0].slice(0, -1)
} : to.params[0];
}) const treeEntry = store.state.entries[path];
.catch((e) => { if (treeEntry) {
flash('Error while loading the branch files. Please try again.', 'alert', document, null, false, true); store.dispatch('handleTreeEntryAction', treeEntry);
throw e; }
}); }
} })
}) .catch(e => {
.catch((e) => { flash(
flash('Error while loading the project data. Please try again.', 'alert', document, null, false, true); 'Error while loading the branch files. Please try again.',
throw e; 'alert',
}); document,
null,
false,
true,
);
throw e;
});
}
})
.catch(e => {
flash(
'Error while loading the project data. Please try again.',
'alert',
document,
null,
false,
true,
);
throw e;
});
} }
next(); next();
......
import { import { decorateData, sortTree } from '../utils';
decorateData,
sortTree,
} from '../utils';
self.addEventListener('message', (e) => { self.addEventListener('message', e => {
const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data; const {
data,
projectId,
branchId,
tempFile = false,
content = '',
base64 = false,
} = e.data;
const treeList = []; const treeList = [];
let file; let file;
...@@ -15,7 +19,9 @@ self.addEventListener('message', (e) => { ...@@ -15,7 +19,9 @@ self.addEventListener('message', (e) => {
if (pathSplit.length > 0) { if (pathSplit.length > 0) {
pathSplit.reduce((pathAcc, folderName) => { pathSplit.reduce((pathAcc, folderName) => {
const parentFolder = acc[pathAcc[pathAcc.length - 1]]; const parentFolder = acc[pathAcc[pathAcc.length - 1]];
const folderPath = `${(parentFolder ? `${parentFolder.path}/` : '')}${folderName}`; const folderPath = `${
parentFolder ? `${parentFolder.path}/` : ''
}${folderName}`;
const foundEntry = acc[folderPath]; const foundEntry = acc[folderPath];
if (!foundEntry) { if (!foundEntry) {
...@@ -25,9 +31,11 @@ self.addEventListener('message', (e) => { ...@@ -25,9 +31,11 @@ self.addEventListener('message', (e) => {
id: folderPath, id: folderPath,
name: folderName, name: folderName,
path: folderPath, path: folderPath,
url: `/${projectId}/tree/${branchId}/${folderPath}`, url: `/${projectId}/tree/${branchId}/${folderPath}/`,
type: 'tree', type: 'tree',
parentTreeUrl: parentFolder ? parentFolder.url : `/${projectId}/tree/${branchId}/`, parentTreeUrl: parentFolder
? parentFolder.url
: `/${projectId}/tree/${branchId}/`,
tempFile, tempFile,
changed: tempFile, changed: tempFile,
opened: tempFile, opened: tempFile,
...@@ -62,7 +70,9 @@ self.addEventListener('message', (e) => { ...@@ -62,7 +70,9 @@ self.addEventListener('message', (e) => {
path, path,
url: `/${projectId}/blob/${branchId}/${path}`, url: `/${projectId}/blob/${branchId}/${path}`,
type: 'blob', type: 'blob',
parentTreeUrl: fileFolder ? fileFolder.url : `/${projectId}/blob/${branchId}`, parentTreeUrl: fileFolder
? fileFolder.url
: `/${projectId}/blob/${branchId}`,
tempFile, tempFile,
changed: tempFile, changed: tempFile,
content, content,
......
...@@ -1727,6 +1727,7 @@ export default class Notes { ...@@ -1727,6 +1727,7 @@ export default class Notes {
// Get Form metadata // Get Form metadata
const $submitBtn = $(e.target); const $submitBtn = $(e.target);
$submitBtn.prop('disabled', true);
let $form = $submitBtn.parents('form'); let $form = $submitBtn.parents('form');
const $closeBtn = $form.find('.js-note-target-close'); const $closeBtn = $form.find('.js-note-target-close');
const isDiscussionNote = const isDiscussionNote =
...@@ -1761,7 +1762,6 @@ export default class Notes { ...@@ -1761,7 +1762,6 @@ export default class Notes {
// If comment is to resolve discussion, disable submit buttons while // If comment is to resolve discussion, disable submit buttons while
// comment posting is finished. // comment posting is finished.
if (isDiscussionResolve) { if (isDiscussionResolve) {
$submitBtn.disable();
$form.find('.js-comment-submit-button').disable(); $form.find('.js-comment-submit-button').disable();
} }
...@@ -1816,6 +1816,7 @@ export default class Notes { ...@@ -1816,6 +1816,7 @@ export default class Notes {
.then(res => { .then(res => {
const note = res.data; const note = res.data;
$submitBtn.prop('disabled', false);
// Submission successful! remove placeholder // Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
...@@ -1899,7 +1900,7 @@ export default class Notes { ...@@ -1899,7 +1900,7 @@ export default class Notes {
.catch(() => { .catch(() => {
// Submission failed, remove placeholder note and show Flash error message // Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
$submitBtn.prop('disabled', false);
const blurEvent = new CustomEvent('blur.imageDiff', { const blurEvent = new CustomEvent('blur.imageDiff', {
detail: e, detail: e,
}); });
......
...@@ -27,12 +27,21 @@ export default { ...@@ -27,12 +27,21 @@ export default {
required: true, required: true,
}, },
}, },
computed: {
metricDetails() {
return this.currentRequest.details[this.metric];
},
detailsList() {
return this.metricDetails[this.details];
},
},
}; };
</script> </script>
<template> <template>
<div <div
:id="`peek-view-${metric}`" :id="`peek-view-${metric}`"
class="view" class="view"
v-if="currentRequest.details"
> >
<button <button
:data-target="`#modal-peek-${metric}-details`" :data-target="`#modal-peek-${metric}-details`"
...@@ -40,34 +49,39 @@ export default { ...@@ -40,34 +49,39 @@ export default {
type="button" type="button"
data-toggle="modal" data-toggle="modal"
> >
<span {{ metricDetails.duration }}
v-if="currentRequest.details" /
class="bold" {{ metricDetails.calls }}
>
{{ currentRequest.details[metric].duration }}
/
{{ currentRequest.details[metric].calls }}
</span>
</button> </button>
<gl-modal <gl-modal
v-if="currentRequest.details"
:id="`modal-peek-${metric}-details`" :id="`modal-peek-${metric}-details`"
:header-title-text="header" :header-title-text="header"
class="performance-bar-modal" class="performance-bar-modal"
> >
<table class="table"> <table
<tr class="table"
v-for="(item, index) in currentRequest.details[metric][details]" >
:key="index" <template v-if="detailsList.length">
> <tr
<td><strong>{{ item.duration }}ms</strong></td> v-for="(item, index) in detailsList"
<td :key="index"
v-for="key in keys"
:key="key"
> >
{{ item[key] }} <td><strong>{{ item.duration }}ms</strong></td>
</td> <td
</tr> v-for="key in keys"
:key="key"
>
{{ item[key] }}
</td>
</tr>
</template>
<template v-else>
<tr>
<td>
No {{ header.toLowerCase() }} for this request.
</td>
</tr>
</template>
</table> </table>
<div slot="footer"> <div slot="footer">
......
...@@ -113,27 +113,21 @@ export default { ...@@ -113,27 +113,21 @@ export default {
id="js-peek" id="js-peek"
:class="env" :class="env"
> >
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
<div
id="peek-view-host"
class="view prepend-left-5"
>
<span
v-if="currentRequest && currentRequest.details"
class="current-host"
>
{{ currentRequest.details.host.hostname }}
</span>
</div>
<div <div
v-if="currentRequest" v-if="currentRequest"
class="wrapper" class="container-fluid container-limited"
> >
<div
id="peek-view-host"
class="view"
>
<span
v-if="currentRequest.details"
class="current-host"
>
{{ currentRequest.details.host.hostname }}
</span>
</div>
<upstream-performance-bar <upstream-performance-bar
v-if="initialRequest && currentRequest.details" v-if="initialRequest && currentRequest.details"
/> />
...@@ -186,6 +180,12 @@ export default { ...@@ -186,6 +180,12 @@ export default {
gc gc
</span> </span>
</div> </div>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
</div> </div>
</div> </div>
</template> </template>
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
<template> <template>
<div <div
id="peek-request-selector" id="peek-request-selector"
class="append-right-5 pull-right" class="pull-right"
> >
<select v-model="currentRequestId"> <select v-model="currentRequestId">
<option <option
......
...@@ -5,6 +5,8 @@ export default { ...@@ -5,6 +5,8 @@ export default {
.getElementById('peek-view-performance-bar') .getElementById('peek-view-performance-bar')
.cloneNode(true); .cloneNode(true);
upstreamPerformanceBar.classList.remove('hidden');
this.$refs.wrapper.appendChild(upstreamPerformanceBar); this.$refs.wrapper.appendChild(upstreamPerformanceBar);
}, },
}; };
......
...@@ -4,9 +4,9 @@ import Vue from 'vue'; ...@@ -4,9 +4,9 @@ import Vue from 'vue';
import performanceBarApp from './components/performance_bar_app.vue'; import performanceBarApp from './components/performance_bar_app.vue';
import PerformanceBarStore from './stores/performance_bar_store'; import PerformanceBarStore from './stores/performance_bar_store';
export default () => export default ({ container }) =>
new Vue({ new Vue({
el: '#js-peek', el: container,
components: { components: {
performanceBarApp, performanceBarApp,
}, },
......
import stopwatchSvg from 'icons/_icon_stopwatch.svg';
import { abbreviateTime } from '../../../lib/utils/pretty_time';
export default {
name: 'time-tracking-collapsed-state',
props: {
showComparisonState: {
type: Boolean,
required: true,
},
showSpentOnlyState: {
type: Boolean,
required: true,
},
showEstimateOnlyState: {
type: Boolean,
required: true,
},
showNoTimeTrackingState: {
type: Boolean,
required: true,
},
timeSpentHumanReadable: {
type: String,
required: false,
default: '',
},
timeEstimateHumanReadable: {
type: String,
required: false,
default: '',
},
},
computed: {
timeSpent() {
return this.abbreviateTime(this.timeSpentHumanReadable);
},
timeEstimate() {
return this.abbreviateTime(this.timeEstimateHumanReadable);
},
divClass() {
if (this.showComparisonState) {
return 'compare';
} else if (this.showEstimateOnlyState) {
return 'estimate-only';
} else if (this.showSpentOnlyState) {
return 'spend-only';
} else if (this.showNoTimeTrackingState) {
return 'no-tracking';
}
return '';
},
spanClass() {
if (this.showComparisonState) {
return '';
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
return 'bold';
} else if (this.showNoTimeTrackingState) {
return 'no-value';
}
return '';
},
text() {
if (this.showComparisonState) {
return `${this.timeSpent} / ${this.timeEstimate}`;
} else if (this.showEstimateOnlyState) {
return `-- / ${this.timeEstimate}`;
} else if (this.showSpentOnlyState) {
return `${this.timeSpent} / --`;
} else if (this.showNoTimeTrackingState) {
return 'None';
}
return '';
},
},
methods: {
abbreviateTime(timeStr) {
return abbreviateTime(timeStr);
},
},
template: `
<div class="sidebar-collapsed-icon">
${stopwatchSvg}
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
<span :class="spanClass">
{{ text }}
</span>
</div>
</div>
</div>
`,
};
<script>
import icon from '../../../vue_shared/components/icon.vue';
import { abbreviateTime } from '../../../lib/utils/pretty_time';
export default {
name: 'TimeTrackingCollapsedState',
components: {
icon,
},
props: {
showComparisonState: {
type: Boolean,
required: true,
},
showSpentOnlyState: {
type: Boolean,
required: true,
},
showEstimateOnlyState: {
type: Boolean,
required: true,
},
showNoTimeTrackingState: {
type: Boolean,
required: true,
},
timeSpentHumanReadable: {
type: String,
required: false,
default: '',
},
timeEstimateHumanReadable: {
type: String,
required: false,
default: '',
},
},
computed: {
timeSpent() {
return this.abbreviateTime(this.timeSpentHumanReadable);
},
timeEstimate() {
return this.abbreviateTime(this.timeEstimateHumanReadable);
},
divClass() {
if (this.showComparisonState) {
return 'compare';
} else if (this.showEstimateOnlyState) {
return 'estimate-only';
} else if (this.showSpentOnlyState) {
return 'spend-only';
} else if (this.showNoTimeTrackingState) {
return 'no-tracking';
}
return '';
},
spanClass() {
if (this.showComparisonState) {
return '';
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
return 'bold';
} else if (this.showNoTimeTrackingState) {
return 'no-value';
}
return '';
},
text() {
if (this.showComparisonState) {
return `${this.timeSpent} / ${this.timeEstimate}`;
} else if (this.showEstimateOnlyState) {
return `-- / ${this.timeEstimate}`;
} else if (this.showSpentOnlyState) {
return `${this.timeSpent} / --`;
} else if (this.showNoTimeTrackingState) {
return 'None';
}
return '';
},
},
methods: {
abbreviateTime(timeStr) {
return abbreviateTime(timeStr);
},
},
};
</script>
<template>
<div class="sidebar-collapsed-icon">
<icon name="timer" />
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
<span :class="spanClass">
{{ text }}
</span>
</div>
</div>
</div>
</template>
<script> <script>
import timeTrackingHelpState from './help_state'; import timeTrackingHelpState from './help_state';
import timeTrackingCollapsedState from './collapsed_state'; import TimeTrackingCollapsedState from './collapsed_state.vue';
import timeTrackingSpentOnlyPane from './spent_only_pane'; import timeTrackingSpentOnlyPane from './spent_only_pane';
import timeTrackingNoTrackingPane from './no_tracking_pane'; import timeTrackingNoTrackingPane from './no_tracking_pane';
import timeTrackingEstimateOnlyPane from './estimate_only_pane'; import timeTrackingEstimateOnlyPane from './estimate_only_pane';
...@@ -11,7 +11,7 @@ import eventHub from '../../event_hub'; ...@@ -11,7 +11,7 @@ import eventHub from '../../event_hub';
export default { export default {
name: 'IssuableTimeTracker', name: 'IssuableTimeTracker',
components: { components: {
'time-tracking-collapsed-state': timeTrackingCollapsedState, TimeTrackingCollapsedState,
'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane, 'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane, 'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane, 'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
......
...@@ -62,8 +62,7 @@ ...@@ -62,8 +62,7 @@
return `${gon.sprite_file_icons}#${iconName}`; return `${gon.sprite_file_icons}#${iconName}`;
}, },
folderIconName() { folderIconName() {
// We don't have a open folder icon yet return this.opened ? 'folder-open' : 'folder';
return this.opened ? 'folder' : 'folder';
}, },
iconSizeClass() { iconSizeClass() {
return this.size ? `s${this.size}` : ''; return this.size ? `s${this.size}` : '';
......
...@@ -43,12 +43,6 @@ ...@@ -43,12 +43,6 @@
} }
} }
.wrapper {
width: 80%;
height: $performance-bar-height;
margin: 0 auto;
}
// UI Elements // UI Elements
.bucket { .bucket {
background: $perf-bar-bucket-bg; background: $perf-bar-bucket-bg;
......
...@@ -377,4 +377,11 @@ module IssuablesHelper ...@@ -377,4 +377,11 @@ module IssuablesHelper
def parent def parent
@project || @group @project || @group
end end
def issuable_milestone_tooltip_title(issuable)
if issuable.milestone
milestone_tooltip = milestone_tooltip_title(issuable.milestone)
_('Milestone') + (milestone_tooltip ? ': ' + milestone_tooltip : '')
end
end
end end
...@@ -14,7 +14,7 @@ module Ci ...@@ -14,7 +14,7 @@ module Ci
has_many :stages has_many :stages
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable' has_many :variables, class_name: 'Ci::PipelineVariable'
......
...@@ -230,13 +230,13 @@ class Group < Namespace ...@@ -230,13 +230,13 @@ class Group < Namespace
end end
GroupMember GroupMember
.active_without_invites .active_without_invites_and_requests
.where(source_id: source_ids) .where(source_id: source_ids)
end end
def members_with_descendants def members_with_descendants
GroupMember GroupMember
.active_without_invites .active_without_invites_and_requests
.where(source_id: self_and_descendants.reorder(nil).select(:id)) .where(source_id: self_and_descendants.reorder(nil).select(:id))
end end
......
...@@ -52,7 +52,7 @@ class Member < ActiveRecord::Base ...@@ -52,7 +52,7 @@ class Member < ActiveRecord::Base
end end
# Like active, but without invites. For when a User is required. # Like active, but without invites. For when a User is required.
scope :active_without_invites, -> do scope :active_without_invites_and_requests, -> do
left_join_users left_join_users
.where(users: { state: 'active' }) .where(users: { state: 'active' })
.non_request .non_request
......
...@@ -208,9 +208,9 @@ class NotificationService ...@@ -208,9 +208,9 @@ class NotificationService
def new_access_request(member) def new_access_request(member)
return true unless member.notifiable?(:subscription) return true unless member.notifiable?(:subscription)
recipients = member.source.members.active_without_invites.owners_and_masters recipients = member.source.members.active_without_invites_and_requests.owners_and_masters
if fallback_to_group_owners_masters?(recipients, member) if fallback_to_group_owners_masters?(recipients, member)
recipients = member.source.group.members.active_without_invites.owners_and_masters recipients = member.source.group.members.active_without_invites_and_requests.owners_and_masters
end end
recipients.each { |recipient| deliver_access_request_email(recipient, member) } recipients.each { |recipient| deliver_access_request_email(recipient, member) }
......
...@@ -67,12 +67,8 @@ ...@@ -67,12 +67,8 @@
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
%img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/ %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
%div %div
%a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications - manage_notifications_link = link_to(_("Manage all notifications"), profile_notifications_url, style: "color:#3777b0;text-decoration:none;")
&middot; - help_link = link_to(_("Help"), help_url, style: "color:#3777b0;text-decoration:none;")
%a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help = _("You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}").html_safe % { host: Gitlab.config.gitlab.host, manage_notifications_link: manage_notifications_link, help_link: help_link }
%div
You're receiving this email because of your account on
= succeed "." do
%a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host
= yield :additional_footer = yield :additional_footer
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
profile_url: url_for(params.merge(lineprofiler: 'true')) }, profile_url: url_for(params.merge(lineprofiler: 'true')) },
class: Peek.env } class: Peek.env }
#peek-view-performance-bar #peek-view-performance-bar.hidden
= render_server_response_time = render_server_response_time
%span#serverstats %span#serverstats
%ul.performance-bar %ul.performance-bar
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
.issue-main-info .issue-main-info
.issue-title.title .issue-title.title
%span.issue-title-text %span.issue-title-text
= confidential_icon(issue) - if issue.confidential?
%span.has-tooltip{ title: _('Confidential') }
= confidential_icon(issue)
= link_to issue.title, issue_path(issue) = link_to issue.title, issue_path(issue)
- if issue.tasks? - if issue.tasks?
%span.task-status.hidden-xs %span.task-status.hidden-xs
...@@ -24,11 +26,11 @@ ...@@ -24,11 +26,11 @@
- if issue.milestone - if issue.milestone
%span.issuable-milestone.hidden-xs %span.issuable-milestone.hidden-xs
&nbsp; &nbsp;
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 1, toggle: 'tooltip', title: milestone_tooltip_title(issue.milestone) } do = link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 1, toggle: 'tooltip', title: issuable_milestone_tooltip_title(issue) } do
= icon('clock-o') = icon('clock-o')
= issue.milestone.title = issue.milestone.title
- if issue.due_date - if issue.due_date
%span.issuable-due-date.hidden-xs{ class: "#{'cred' if issue.overdue?}" } %span.issuable-due-date.hidden-xs.has-tooltip{ class: "#{'cred' if issue.overdue?}", title: _('Due date') }
&nbsp; &nbsp;
= icon('calendar') = icon('calendar')
= issue.due_date.to_s(:medium) = issue.due_date.to_s(:medium)
......
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
- if merge_request.milestone - if merge_request.milestone
%span.issuable-milestone.hidden-xs %span.issuable-milestone.hidden-xs
&nbsp; &nbsp;
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), data: { html: 1, toggle: 'tooltip', title: milestone_tooltip_title(merge_request.milestone) } do = link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), data: { html: 1, toggle: 'tooltip', title: issuable_milestone_tooltip_title(merge_request) } do
= icon('clock-o') = icon('clock-o')
= merge_request.milestone.title = merge_request.milestone.title
- if merge_request.target_project.default_branch != merge_request.target_branch - if merge_request.target_project.default_branch != merge_request.target_branch
%span.project-ref-path %span.project-ref-path.has-tooltip{ title: _('Target branch') }
&nbsp; &nbsp;
= link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do = link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do
= sprite_icon('fork', size: 12, css_class: 'fork-sprite') = sprite_icon('fork', size: 12, css_class: 'fork-sprite')
...@@ -51,11 +51,11 @@ ...@@ -51,11 +51,11 @@
= render_pipeline_status(merge_request.head_pipeline) = render_pipeline_status(merge_request.head_pipeline)
- if merge_request.open? && merge_request.broken? - if merge_request.open? && merge_request.broken?
%li.issuable-pipeline-broken.hidden-xs %li.issuable-pipeline-broken.hidden-xs
= link_to merge_request_path(merge_request), class: "has-tooltip", title: "Cannot be merged automatically", data: { container: 'body' } do = link_to merge_request_path(merge_request), class: "has-tooltip", title: _('Cannot be merged automatically') do
= icon('exclamation-triangle') = icon('exclamation-triangle')
- if merge_request.assignee - if merge_request.assignee
%li %li
= link_to_member(merge_request.source_project, merge_request.assignee, name: false, title: "Assigned to :name") = link_to_member(merge_request.source_project, merge_request.assignee, name: false, title: _('Assigned to :name'))
= render 'shared/issuable_meta_data', issuable: merge_request = render 'shared/issuable_meta_data', issuable: merge_request
......
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
= render 'projects/find_file_link' = render 'projects/find_file_link'
= succeed " " do = succeed " " do
= link_to ide_edit_path(@project, @id), class: 'btn btn-default' do = link_to ide_edit_path(@project, @id, ""), class: 'btn btn-default' do
= _('Web IDE') = _('Web IDE')
= render 'projects/buttons/download', project: @project, ref: @ref = render 'projects/buttons/download', project: @project, ref: @ref
...@@ -5,21 +5,21 @@ ...@@ -5,21 +5,21 @@
- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count - issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
- if issuable_mr > 0 - if issuable_mr > 0
%li.issuable-mr.hidden-xs %li.issuable-mr.hidden-xs.has-tooltip{ title: _('Related merge requests') }
= image_tag('icon-merge-request-unmerged.svg', class: 'icon-merge-request-unmerged') = image_tag('icon-merge-request-unmerged.svg', class: 'icon-merge-request-unmerged')
= issuable_mr = issuable_mr
- if upvotes > 0 - if upvotes > 0
%li.issuable-upvotes.hidden-xs %li.issuable-upvotes.hidden-xs.has-tooltip{ title: _('Upvotes') }
= icon('thumbs-up') = icon('thumbs-up')
= upvotes = upvotes
- if downvotes > 0 - if downvotes > 0
%li.issuable-downvotes.hidden-xs %li.issuable-downvotes.hidden-xs.has-tooltip{ title: _('Downvotes') }
= icon('thumbs-down') = icon('thumbs-down')
= downvotes = downvotes
%li.issuable-comments.hidden-xs %li.issuable-comments.hidden-xs
= link_to issuable_url, class: ('no-comments' if note_count.zero?) do = link_to issuable_url, class: ['has-tooltip', ('no-comments' if note_count.zero?)], title: _('Comments') do
= icon('comments') = icon('comments')
= note_count = note_count
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%header.board-header{ ":class" => '{ "has-border": list.label && list.label.color }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }", "@click" => "toggleExpanded($event)" } %header.board-header{ ":class" => '{ "has-border": list.label && list.label.color }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }", "@click" => "toggleExpanded($event)" }
%h3.board-title.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset) }' } %h3.board-title.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset) }' }
%i.fa.fa-fw.board-title-expandable-toggle{ "v-if": "list.isExpandable", %i.fa.fa-fw.board-title-expandable-toggle{ "v-if": "list.isExpandable",
":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-right\": !list.isExpanded && list.position === -1, \"fa-caret-left\": !list.isExpanded && list.position !== -1 }", ":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-right\": !list.isExpanded }",
"aria-hidden": "true" } "aria-hidden": "true" }
%span.board-title-text.has-tooltip{ "v-if": "list.type !== \"label\"", %span.board-title-text.has-tooltip{ "v-if": "list.type !== \"label\"",
......
---
title: Add missing pagination on the commit diff endpoint
merge_request: 17203
author: Maxime Roussin-Bélanger
type: fixed
---
title: Moved o_auth/saml/ldap modules under gitlab/auth
merge_request: 17359
author: Horatiu Eugen Vlad
---
title: Update issue closing pattern to allow variations in punctuation
merge_request: 17198
author: Vicky Chijwani
type: changed
---
title: Clear the Labels dropdown search filter after a selection is made
merge_request: 17393
author: Andrew Torres
type: changed
---
title: Update to github-linguist 5.3.x
merge_request: 17241
author: Ken Ding
type: other
---
title: Group MRs on issue page by project and namespace.
merge_request: 8494
author: Jeff Stubler
---
title: Add project export API
merge_request: 15860
author: Travis Miller
type: added
---
title: Add verification for GitLab Pages custom domains
merge_request:
author:
type: security
---
title: Add email button to new issue by email
merge_request: 10942
author: Islam Wazery
---
title: Fix duplicate system notes when merging a merge request.
merge_request: 17035
author:
type: fixed
---
title: Allow installation of GitLab Runner with a single click
merge_request: 17134
author:
type: added
---
title: Fix Slack/Mattermost notifications not respecting `notify_only_default_branch` setting for pushes
merge_request: 17345
author:
type: fixed
---
title: remove avater underline
merge_request: 17219
author: Ken Ding
type: fixed
---
title: Fix Teleporting Emoji
merge_request: 16963
author: Jared Deckard <jared.deckard@gmail.com>
type: fixed
---
title: update toml-rb to 1.0.0
merge_request: 17259
author: Ken Ding
type: other
---
title: Display a link to external issue tracker when enabled
merge_request:
author:
type: changed
---
title: Handle empty state in Pipelines page
merge_request:
author:
type: fixed
---
title: Set margins around dropdown dividers to 4px
merge_request: 17517
author:
type: fixed
---
title: "Fix user avatar's vertical align on the issues and merge requests pages"
merge_request: 17072
author: Laszlo Karpati
type: fixed
---
title: Add overview of branches and a filter for active/stale branches
merge_request: 15402
author: Takuya Noguchi
type: added
---
title: Improve database response time for user activity listing.
merge_request: 17454
author:
type: performance
---
title: Sanitize extra blank spaces used when uploading a SSH key
merge_request: 40552
author:
type: fixed
title: Fix 404 when listing archived projects in a group where all projects have been archived
merge_request: 17077
author: Ashley Dumaine
type: fixed
---
title: Fix get a single pages domain when project path contains a period
merge_request: 17206
author: Travis Miller
type: fixed
---
title: 'Expose GITLAB_FEATURES as CI/CD variable (fixes #40994)'
merge_request:
author:
type: added
---
title: Adds updated_at filter to issues and merge_requests API
merge_request: 17417
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Render htmlentities correctly for links not supported by Rinku
merge_request:
author:
type: fixed
---
title: Include cycle time in usage ping data
merge_request: 16973
author:
type: added
---
title: Enables eslint in codeclimate job
merge_request: 17392
author:
type: other
---
title: API endpoint for importing a project export
merge_request: 17025
author:
type: added
---
title: expose more metrics in merge requests api
merge_request: 16589
author: haseebeqx
type: added
---
title: Remember assignee when moving an issue
merge_request:
author:
type: fixed
---
title: Add a button to deploy a runner to a Kubernetes cluster in the settings page
merge_request: 17278
author:
type: changed
---
title: Fix long list of recipients on group request membership email
merge_request: 17121
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Render modified icon for moved file in changes dropdown
merge_request:
author:
type: fixed
---
title: Fix 500 error being shown when diff has context marker with invalid encoding
merge_request:
author:
type: fixed
---
title: Add a button on the project page to set up a Kubernetes cluster and enable
Auto DevOps
merge_request: 16900
author:
type: added
---
title: Allow commits endpoint to work over all commits of a repository
merge_request: 17182
author:
type: added
---
title: Remove user notification settings for groups and projects when user leaves
merge_request: 16906
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Allow to call PUT /projects/:id API with only ci_config_path specified
merge_request: 17105
author: Laszlo Karpati
type: fixed
---
title: Allows the usage of /milestone quick action for group milestones
merge_request: 17239
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Display ingress IP address in the Kubernetes page
merge_request: 17052
author:
type: added
---
title: Add search param to Branches API
merge_request: 17005
author: bunufi
type: added
---
title: Use a user object in ApplicationHelper#avatar_icon where possible to avoid
N+1 queries.
merge_request: 42800
author:
type: performance
---
title: Fix "Remove source branch" button in Merge request widget during merge when pipeline
succeeds state
merge_request: 17192
author:
type: fixed
---
title: CI charts now include the current day
merge_request: 17032
author: Dakkaron
type: changed
---
title: Adds tooltip in environment names to increase readability
merge_request:
author:
type: fixed
---
title: Fix close button on issues not working on mobile
merge_request:
author:
type: fixed
---
title: Hide CI secret variable values after saving
merge_request: 17044
author:
type: changed
---
title: Update tooltip on pipeline cancel to Stop (#42946)
merge_request: 17444
author:
type: fixed
---
title: Improve performance of pipeline page by reducing DB queries
merge_request: 17168
author:
type: performance
---
title: Fix settings panels not expanding when fragment hash linked
merge_request: 17074
author:
type: fixed
---
title: Allows project rename after validation error
merge_request: 17150
author:
type: fixed
---
title: Keep "Import project" tab/form active when validation fails trying to import
"Repo by URL"
merge_request: 17136
author:
type: fixed
---
title: Remove duplicated error message on duplicate variable validation
merge_request: 17135
author:
type: fixed
---
title: Fixes gpg popover layout
merge_request: 17323
author:
type: fixed
---
title: Fix quick actions for users who cannot update issues and merge requests
merge_request: 17482
author:
type: fixed
---
title: Keep track of projects a user interacted with.
merge_request: 17327
author:
type: other
---
title: Display Runner IP Address
merge_request: 17286
author:
type: added
---
title: Do not persist Google Project verification flash errors after a page reload
merge_request: 17299
author:
type: fixed
---
title: Fix Group labels load failure when there are duplicate labels present
merge_request: 17353
author:
type: fixed
---
title: Enable filtering MR list based on clicked label in MR sidebar
merge_request: 17390
author:
type: fixed
---
title: Add a paragraph about security implications on Cluster's page
merge_request: 17486
author:
type: added
---
title: Add tooltips to icons in lists of issues and merge requests
merge_request: 17700
author:
type: changed
---
title: Enable privileged mode for GitLab Runner
merge_request: 17528
author:
type: added
---
title: Ensure foreign keys on clusters applications
merge_request: 17488
author:
type: other
---
title: Update SSH key link to include existing keys
merge_request:
author: Brendan O'Leary
type: changed
---
title: Stop loading spinner on error of milestone update on issue
merge_request: 17507
author: Takuya Noguchi
type: fixed
---
title: Remove extra breadcrumb on tags
merge_request: 17562
author: Takuya Noguchi
type: fixed
---
title: Fix markdown table showing extra column
merge_request: 17669
author:
type: fixed
---
title: Fix broken loading state for close issue button
merge_request:
author:
type: fixed
---
title: Add documentation for displayed K8s Ingress IP address (#44330)
merge_request: 17836
author:
type: other
---
title: Make sure wiki exists when it's enabled
merge_request:
author:
type: fixed
---
title: Create empty wiki when import from GitLab and wiki is not there
merge_request:
author:
type: fixed
---
title: "[GitHub Import] Create an empty wiki if wiki import failed"
merge_request:
author:
type: fixed
--- ---
title: Store sha256 checksum to job artifacts title: Add indexes for user activity queries.
merge_request: 17354 merge_request: 17890
author: author:
type: performance type: performance
---
title: Add partial indexes on todos to handle users with many todos
merge_request:
author:
type: performance
--- ---
title: Move Ruby endpoints to OPT_OUT title: Add query counts to profiler output
merge_request: merge_request:
author: author:
type: other type: other
---
title: Prevent the graphs page from generating unnecessary Gitaly requests
merge_request: 37602
author:
type: performance
---
title: Upgrade Workhorse to version 3.8.0 to support structured logging
merge_request:
author:
type: other
---
title: 'API: Get references a commit is pushed to'
merge_request: 15026
author: Robert Schilling
type: added
---
title: Asciidoc now support inter-document cross references between files in repository
merge_request: 17125
author: Turo Soisenniemi
type: changed
---
title: Add Assignees vue component missing data container
merge_request: 17426
author: George Tsiolis
type: fixed
---
title: Allow maintainers to push to forks of their projects when a merge request is open
merge_request: 17395
author:
type: added
---
title: Started translation into Turkish, Indonesian and Filipino
merge_request: 17526
author:
type: other
---
title: Cache MergeRequests can_be_resolved_in_ui? git operations
merge_request: 17589
author:
type: performance
---
title: Hook data for pipelines includes detailed_status
merge_request: 17607
author:
type: changed
---
title: Avoid showing unnecessary Trigger checkboxes for project Integrations with
only one event
merge_request: 17607
author:
type: changed
---
title: Remove whitespace from the username/email sign in form field
merge_request: 17020
author: Peter lauck
type: changed
---
title: Add discussions API for Issues and Snippets
merge_request:
author:
type: added
---
title: Don't cache a nil repository root ref to prevent caching issues
merge_request:
author:
type: fixed
---
title: Escape HTML entities in commit messages
merge_request:
author:
type: fixed
---
title: Allow token authentication on go-get request
merge_request:
author:
type: changed
---
title: Verify project import status again before marking as failed
merge_request:
author:
type: fixed
---
title: Update vue component naming guidelines
merge_request: 17018
author: George Tsiolis
type: other
---
title: Add NOT NULL constraint to projects.namespace_id
merge_request: 17448
author:
type: other
---
title: Add plugins list to the system hooks page
merge_request: 17518
author:
type: added
---
title: Add ability to use external plugins as an alternative to system hooks
merge_request: 17003
author:
type: added
---
title: Foreground verification of uploads and LFS objects
merge_request: 17402
author:
type: added
---
title: "#28481: Display time tracking totals on milestone page"
merge_request: 16753
author: Riccardo Padovani
type: added
---
title: Count comments on diffs and discussions as contributions for the contributions calendar
merge_request: 17418
author: Riccardo Padovani
type: fixed
---
title: Added clear button to ci lint editor
merge_request:
author: Michael Robinson
---
title: 'Pages custom domain: allow update of key/certificate'
merge_request: 17376
author: rfwatson
type: changed
---
title: Add catch-up background migration to migrate pipeline stages
merge_request: 15741
author:
type: performance
---
title: Allow including custom attributes in API responses
merge_request: 16526
author: Markus Koller
type: changed
---
title: Add groups to OpenID Connect claims
merge_request: 16929
author: Hassan Zamani
---
title: Apply new default and inline label design
merge_request: 16956
author: George Tsiolis
type: changed
---
title: Fix file upload on project show page
merge_request:
author:
type: fixed
---
title: Fix new project path input overlapping
merge_request: 16755
author: George Tsiolis
type: fixed
---
title: Fix squashing when a file is renamed
merge_request:
author:
type: fixed
---
title: Respect description and visibility when creating project from template
merge_request: 16820
author: George Tsiolis
type: fixed
---
title: Removing the two factor check when the user sets a new password
merge_request: 17457
author:
type: fixed
---
title: Implemented badge API endpoints
merge_request: 17082
author:
type: added
---
title: Fixed bug with unauthenticated requests through git ssh
merge_request: 17149
author:
type: fixed
---
title: Show loading button inline in refresh button in MR widget
merge_request:
author:
type: fixed
---
title: Fix breadcrumb on labels page for groups
merge_request: 17045
author: Onuwa Nnachi Isaac
type: fixed
--- ---
title: Keep link when redacting unauthorized object links title: Fixed IDE button opening the wrong URL in tree list
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: 'Ensure users cannot create environments with leading or trailing slashes (Fixes #39885)'
merge_request: 15273
author:
type: fixed
---
title: Use host URL to build JIRA remote link icon
merge_request:
author:
type: other
---
title: Add one group board to Libre
merge_request:
author:
type: added
---
title: Added new design for promotion modals
merge_request: 17197
author:
type: other
---
title: Optimize search queries on the search page by setting a limit for matching
records in project scope
merge_request:
author:
type: performance
---
title: Port Labels Select dropdown to Vue
merge_request: 17411
author:
type: other
---
title: Add support for filtering by source and target branch to merge requests API
merge_request:
author:
type: added
---
title: Move email footer info to a single line
merge_request: 17916
author:
type: changed
---
title: Use persisted/memoized value for MRs shas instead of doing git lookups
merge_request: 17555
author:
type: performance
---
title: Make oauth provider login generic
merge_request: 8809
author: Horatiu Eugen Vlad
\ No newline at end of file
---
title: Submit a single batch blob RPC to Gitaly per HTTP request when viewing diffs
merge_request:
author:
type: performance
---
title: Avoid re-fetching merge-base SHA from Gitaly unnecessarily
merge_request:
author:
type: performance
---
title: Add archive feature to trace
merge_request: 17314
author:
type: added
---
title: Move BoardNewIssue vue component
merge_request: 16947
author: George Tsiolis
type: performance
---
title: Move RecentSearchesDropdownContent vue component
merge_request: 16951
author: George Tsiolis
type: performance
---
title: Move IssuableTimeTracker vue component
merge_request: 16948
author: George Tsiolis
type: performance
---
title: Move SidebarAssignees vue component
merge_request: 17398
author: George Tsiolis
type: performance
--- ---
title: Move Assignees vue component title: Move TimeTrackingCollapsedState vue component
merge_request: 16952 merge_request: 17399
author: George Tsiolis author: George Tsiolis
type: performance type: performance
---
title: Add CommonMark markdown engine (experimental)
merge_request: 14835
author: blackst0ne
type: added
---
title: Cache column_exists? for application settings
merge_request:
author:
type: performance
---
title: Cache table_exists?('application_settings') to reduce repeated schema reloads
merge_request:
author:
type: performance
---
title: Release libgit2 cache and open file descriptors after `git gc` run
merge_request:
author:
type: fixed
---
title: Fix project dashboard showing the wrong timestamps
merge_request:
author:
type: fixed
---
title: Fix "Can't modify frozen hash" error when project is destroyed
merge_request:
author:
type: fixed
---
title: Fix Error 500 when viewing a commit with a GPG signature in Geo
merge_request:
author:
type: fixed
---
title: Don't error out in system hook if user has `nil` datetime columns
merge_request:
author:
type: fixed
---
title: Ensure that OTP backup codes are always invalidated
merge_request:
author:
type: security
---
title: Make --prune a configurable parameter in fetching a git remote
merge_request:
author:
type: performance
---
title: Fix timeouts loading /admin/projects page
merge_request:
author:
type: performance
---
title: Ensure the API returns https links when https is configured
merge_request: 17681
author:
type: fixed
---
title: Don't delete todos or unassign issues and MRs when a user leaves a project
merge_request:
author:
type: fixed
---
title: Upgrade GitLab Workhorse to 4.0.0
merge_request:
author:
type: added
---
title: Add new modal Vue component
merge_request: 17108
author:
type: changed
---
title: Port /wip quick action command to Merge Request creation (on description)
merge_request: 17463
author: Adam Pahlevi
type: added
---
title: Allow CI/CD Jobs being grouped on version strings
merge_request:
author:
type: added
# Port ActiveRecord::Relation#in_batches from ActiveRecord 5. # Remove this file when upgraded to rails 5.0.
# https://github.com/rails/rails/blob/ac027338e4a165273607dccee49a3d38bc836794/activerecord/lib/active_record/relation/batches.rb#L184 unless Gitlab.rails5?
# TODO: this can be removed once we're using AR5. module ActiveRecord
raise "Vendored ActiveRecord 5 code! Delete #{__FILE__}!" if ActiveRecord::VERSION::MAJOR >= 5 module Batches
# Differences from upstream: enumerator support was removed, and custom
module ActiveRecord # order/limit clauses are ignored without a warning.
module Batches def in_batches(of: 1000, start: nil, finish: nil, load: false)
# Differences from upstream: enumerator support was removed, and custom raise "Must provide a block" unless block_given?
# order/limit clauses are ignored without a warning.
def in_batches(of: 1000, start: nil, finish: nil, load: false) relation = self.reorder(batch_order).limit(of)
raise "Must provide a block" unless block_given? relation = relation.where(arel_table[primary_key].gteq(start)) if start
relation = relation.where(arel_table[primary_key].lteq(finish)) if finish
relation = self.reorder(batch_order).limit(of) batch_relation = relation
relation = relation.where(arel_table[primary_key].gteq(start)) if start
relation = relation.where(arel_table[primary_key].lteq(finish)) if finish loop do
batch_relation = relation if load
records = batch_relation.records
loop do ids = records.map(&:id)
if load yielded_relation = self.where(primary_key => ids)
records = batch_relation.records yielded_relation.load_records(records)
ids = records.map(&:id) else
yielded_relation = self.where(primary_key => ids) ids = batch_relation.pluck(primary_key)
yielded_relation.load_records(records) yielded_relation = self.where(primary_key => ids)
else end
ids = batch_relation.pluck(primary_key)
yielded_relation = self.where(primary_key => ids) break if ids.empty?
primary_key_offset = ids.last
raise ArgumentError.new("Primary key not included in the custom select clause") unless primary_key_offset
yield yielded_relation
break if ids.length < of
batch_relation = relation.where(arel_table[primary_key].gt(primary_key_offset))
end end
break if ids.empty?
primary_key_offset = ids.last
raise ArgumentError.new("Primary key not included in the custom select clause") unless primary_key_offset
yield yielded_relation
break if ids.length < of
batch_relation = relation.where(arel_table[primary_key].gt(primary_key_offset))
end end
end end
end end
......
raise "Vendored ActiveRecord 5 code! Delete #{__FILE__}!" if ActiveRecord::VERSION::MAJOR >= 5 # Remove this file when upgraded to rails 5.0.
if !Gitlab.rails5? && Gitlab::Database.postgresql?
if Gitlab::Database.postgresql?
require 'active_record/connection_adapters/postgresql_adapter' require 'active_record/connection_adapters/postgresql_adapter'
require 'active_record/connection_adapters/postgresql/schema_statements' require 'active_record/connection_adapters/postgresql/schema_statements'
......
...@@ -219,49 +219,5 @@ Devise.setup do |config| ...@@ -219,49 +219,5 @@ Devise.setup do |config|
end end
end end
Gitlab.config.omniauth.providers.each do |provider| Gitlab::OmniauthInitializer.new(config).execute(Gitlab.config.omniauth.providers)
provider_arguments = []
%w[app_id app_secret].each do |argument|
provider_arguments << provider[argument] if provider[argument]
end
case provider['args']
when Array
# An Array from the configuration will be expanded.
provider_arguments.concat provider['args']
when Hash
# Add procs for handling SLO
if provider['name'] == 'cas3'
provider['args'][:on_single_sign_out] = lambda do |request|
ticket = request.params[:session_index]
raise "Service Ticket not found." unless Gitlab::Auth::OAuth::Session.valid?(:cas3, ticket)
Gitlab::Auth::OAuth::Session.destroy(:cas3, ticket)
true
end
end
if provider['name'] == 'authentiq'
provider['args'][:remote_sign_out_handler] = lambda do |request|
authentiq_session = request.params['sid']
if Gitlab::Auth::OAuth::Session.valid?(:authentiq, authentiq_session)
Gitlab::Auth::OAuth::Session.destroy(:authentiq, authentiq_session)
true
else
false
end
end
end
if provider['name'] == 'shibboleth'
provider['args'][:fail_with_empty_uid] = true
end
# A Hash from the configuration will be passed as is.
provider_arguments << provider['args'].symbolize_keys
end
config.omniauth provider['name'].to_sym, *provider_arguments
end
end end
...@@ -154,7 +154,7 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -154,7 +154,7 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
end end
def add_foreign_key_if_not_exists(source, target, column:) def add_foreign_key_if_not_exists(source, target, column:)
return if foreign_key_exists?(source, column) return if foreign_key_exists?(source, target, column: column)
add_concurrent_foreign_key(source, target, column: column) add_concurrent_foreign_key(source, target, column: column)
end end
...@@ -175,12 +175,6 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -175,12 +175,6 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
rescue ArgumentError rescue ArgumentError
end end
def foreign_key_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
def connection def connection
# Rails memoizes connection objects, but this causes them to be shared # Rails memoizes connection objects, but this causes them to be shared
# amongst threads; we don't want that. # amongst threads; we don't want that.
......
...@@ -10,13 +10,13 @@ class AddStageIdForeignKeyToBuilds < ActiveRecord::Migration ...@@ -10,13 +10,13 @@ class AddStageIdForeignKeyToBuilds < ActiveRecord::Migration
add_concurrent_index(:ci_builds, :stage_id) add_concurrent_index(:ci_builds, :stage_id)
end end
unless foreign_key_exists?(:ci_builds, :stage_id) unless foreign_key_exists?(:ci_builds, :ci_stages, column: :stage_id)
add_concurrent_foreign_key(:ci_builds, :ci_stages, column: :stage_id, on_delete: :cascade) add_concurrent_foreign_key(:ci_builds, :ci_stages, column: :stage_id, on_delete: :cascade)
end end
end end
def down def down
if foreign_key_exists?(:ci_builds, :stage_id) if foreign_key_exists?(:ci_builds, column: :stage_id)
remove_foreign_key(:ci_builds, column: :stage_id) remove_foreign_key(:ci_builds, column: :stage_id)
end end
...@@ -24,12 +24,4 @@ class AddStageIdForeignKeyToBuilds < ActiveRecord::Migration ...@@ -24,12 +24,4 @@ class AddStageIdForeignKeyToBuilds < ActiveRecord::Migration
remove_concurrent_index(:ci_builds, :stage_id) remove_concurrent_index(:ci_builds, :stage_id)
end end
end end
private
def foreign_key_exists?(table, column)
foreign_keys(:ci_builds).any? do |key|
key.options[:column] == column.to_s
end
end
end end
...@@ -23,23 +23,15 @@ class AddForeignKeyToMergeRequests < ActiveRecord::Migration ...@@ -23,23 +23,15 @@ class AddForeignKeyToMergeRequests < ActiveRecord::Migration
merge_requests.update_all(head_pipeline_id: nil) merge_requests.update_all(head_pipeline_id: nil)
end end
unless foreign_key_exists?(:merge_requests, :head_pipeline_id) unless foreign_key_exists?(:merge_requests, column: :head_pipeline_id)
add_concurrent_foreign_key(:merge_requests, :ci_pipelines, add_concurrent_foreign_key(:merge_requests, :ci_pipelines,
column: :head_pipeline_id, on_delete: :nullify) column: :head_pipeline_id, on_delete: :nullify)
end end
end end
def down def down
if foreign_key_exists?(:merge_requests, :head_pipeline_id) if foreign_key_exists?(:merge_requests, column: :head_pipeline_id)
remove_foreign_key(:merge_requests, column: :head_pipeline_id) remove_foreign_key(:merge_requests, column: :head_pipeline_id)
end end
end end
private
def foreign_key_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
end end
class AddIndexesForUserActivityQueries < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :events, [:author_id, :project_id] unless index_exists?(:events, [:author_id, :project_id])
add_concurrent_index :user_interacted_projects, :user_id unless index_exists?(:user_interacted_projects, :user_id)
end
def down
remove_concurrent_index :events, [:author_id, :project_id] if index_exists?(:events, [:author_id, :project_id])
patch_foreign_keys do
remove_concurrent_index :user_interacted_projects, :user_id if index_exists?(:user_interacted_projects, :user_id)
end
end
private
def patch_foreign_keys
return yield if Gitlab::Database.postgresql?
# MySQL doesn't like to remove the index with a foreign key using it.
remove_foreign_key :user_interacted_projects, :users if fk_exists?(:user_interacted_projects, :user_id)
yield
# Let's re-add the foreign key using the existing index on (user_id, project_id)
add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id unless fk_exists?(:user_interacted_projects, :user_id)
end
def fk_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
end
...@@ -26,11 +26,11 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration ...@@ -26,11 +26,11 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration
def down def down
execute "TRUNCATE user_interacted_projects" execute "TRUNCATE user_interacted_projects"
if foreign_key_exists?(:user_interacted_projects, :user_id) if foreign_key_exists?(:user_interacted_projects, :users)
remove_foreign_key :user_interacted_projects, :users remove_foreign_key :user_interacted_projects, :users
end end
if foreign_key_exists?(:user_interacted_projects, :project_id) if foreign_key_exists?(:user_interacted_projects, :projects)
remove_foreign_key :user_interacted_projects, :projects remove_foreign_key :user_interacted_projects, :projects
end end
...@@ -115,7 +115,7 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration ...@@ -115,7 +115,7 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration
end end
def create_fk(table, target, column) def create_fk(table, target, column)
return if foreign_key_exists?(table, column) return if foreign_key_exists?(table, target, column: column)
add_foreign_key table, target, column: column, on_delete: :cascade add_foreign_key table, target, column: column, on_delete: :cascade
end end
...@@ -158,11 +158,11 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration ...@@ -158,11 +158,11 @@ class BuildUserInteractedProjectsTable < ActiveRecord::Migration
add_concurrent_index :user_interacted_projects, [:project_id, :user_id], unique: true, name: UNIQUE_INDEX_NAME add_concurrent_index :user_interacted_projects, [:project_id, :user_id], unique: true, name: UNIQUE_INDEX_NAME
end end
unless foreign_key_exists?(:user_interacted_projects, :user_id) unless foreign_key_exists?(:user_interacted_projects, :users, column: :user_id)
add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id, on_delete: :cascade add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id, on_delete: :cascade
end end
unless foreign_key_exists?(:user_interacted_projects, :project_id) unless foreign_key_exists?(:user_interacted_projects, :projects, column: :project_id)
add_concurrent_foreign_key :user_interacted_projects, :projects, column: :project_id, on_delete: :cascade add_concurrent_foreign_key :user_interacted_projects, :projects, column: :project_id, on_delete: :cascade
end end
end end
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180309160427) do ActiveRecord::Schema.define(version: 20180320182229) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -728,6 +728,7 @@ ActiveRecord::Schema.define(version: 20180309160427) do ...@@ -728,6 +728,7 @@ ActiveRecord::Schema.define(version: 20180309160427) do
end end
add_index "events", ["action"], name: "index_events_on_action", using: :btree add_index "events", ["action"], name: "index_events_on_action", using: :btree
add_index "events", ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id", using: :btree
add_index "events", ["author_id"], name: "index_events_on_author_id", using: :btree add_index "events", ["author_id"], name: "index_events_on_author_id", using: :btree
add_index "events", ["project_id", "id"], name: "index_events_on_project_id_and_id", using: :btree add_index "events", ["project_id", "id"], name: "index_events_on_project_id_and_id", using: :btree
add_index "events", ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree add_index "events", ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree
...@@ -1864,6 +1865,7 @@ ActiveRecord::Schema.define(version: 20180309160427) do ...@@ -1864,6 +1865,7 @@ ActiveRecord::Schema.define(version: 20180309160427) do
end end
add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree
add_index "user_interacted_projects", ["user_id"], name: "index_user_interacted_projects_on_user_id", using: :btree
create_table "user_synced_attributes_metadata", force: :cascade do |t| create_table "user_synced_attributes_metadata", force: :cascade do |t|
t.boolean "name_synced", default: false t.boolean "name_synced", default: false
......
...@@ -65,7 +65,8 @@ learn how to leverage its potential even more. ...@@ -65,7 +65,8 @@ learn how to leverage its potential even more.
environments and use them for different purposes like testing, building and environments and use them for different purposes like testing, building and
deploying deploying
- [Job artifacts](../user/project/pipelines/job_artifacts.md) - [Job artifacts](../user/project/pipelines/job_artifacts.md)
- [Git submodules](git_submodules.md): How to run your CI jobs when Git - [Caching dependencies](caching/index.md)
- [Git submodules](git_submodules.md) - How to run your CI jobs when Git
submodules are involved submodules are involved
- [Use SSH keys in your build environment](ssh_keys/README.md) - [Use SSH keys in your build environment](ssh_keys/README.md)
- [Trigger pipelines through the GitLab API](triggers/README.md) - [Trigger pipelines through the GitLab API](triggers/README.md)
......
# Cache dependencies in GitLab CI/CD
GitLab CI/CD provides a caching mechanism that can be used to save time
when your jobs are running.
Caching is about speeding the time a job is executed by reusing the same
content of a previous job. It can be particularly useful when your are
developing software that depends on other libraries which are fetched via the
internet during build time.
If caching is enabled, it's shared between pipelines and jobs by default,
starting from GitLab 9.0.
Make sure you read the [`cache` reference](../yaml/README.md#cache) to learn
how it is defined in `.gitlab-ci.yml`.
## Good caching practices
We have the cache from the perspective of the developers (who consume a cache
within the job) and the cache from the perspective of the Runner. Depending on
which type of Runner you are using, cache can act differently.
From the perspective of the developer, to ensure maximum availability of the
cache, when declaring `cache` in your jobs, use one or a mix of the following:
- [Tag your Runners](../runners/README.md#using-tags) and use the tag on jobs
that share their cache.
- [Use sticky Runners](../runners/README.md#locking-a-specific-runner-from-being-enabled-for-other-projects)
that will be only available to a particular project.
- [Use a `key`](../yaml/README.md#cache-key) that fits your workflow (e.g.,
different caches on each branch). For that, you can take advantage of the
[CI/CD predefined variables](../variables/README.md#predefined-variables-environment-variables).
TIP: **Tip:**
Using the same Runner for your pipeline, is the most simple and efficient way to
cache files in one stage or pipeline, and pass this cache to subsequent stages
or pipelines in a guaranteed manner.
From the perspective of the Runner, in order for cache to work effectively, one
of the following must be true:
- Use a single Runner for all your jobs
- Use multiple Runners (in autoscale mode or not) that use
[distributed caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching),
where the cache is stored in S3 buckets (like shared Runners on GitLab.com)
- Use multiple Runners (not in autoscale mode) of the same architecture that
share a common network-mounted directory (using NFS or something similar)
where the cache will be stored
TIP: **Tip:**
Read about the [availability of the cache](#availability-of-the-cache)
to learn more about the internals and get a better idea how cache works.
### Sharing caches across the same branch
Define a cache with the `key: ${CI_COMMIT_REF_SLUG}` so that jobs of each
branch always use the same cache:
```yaml
cache:
key: ${CI_COMMIT_REF_SLUG}
```
While this feels like it might be safe from accidentally overwriting the cache,
it means merge requests get slow first pipelines, which might be a bad
developer experience. The next time a new commit is pushed to the branch, the
cache will be re-used.
To enable per-job and per-branch caching:
```yaml
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
```
To enable per-branch and per-stage caching:
```yaml
cache:
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
```
### Sharing caches across different branches
If the files you are caching need to be shared across all branches and all jobs,
you can use the same key for all of them:
```yaml
cache:
key: one-key-to-rull-them-all
```
To share the same cache between branches, but separate them by job:
```yaml
cache:
key: ${CI_JOB_NAME}
```
### Disabling cache on specific jobs
If you have defined the cache globally, it means that each job will use the
same definition. You can override this behavior per-job, and if you want to
disable it completely, use an empty hash:
```yaml
job:
cache: {}
```
For more fine tuning, read also about the
[`cache: policy`](../yaml/README.md#cache-policy).
## Common use cases
The most common use case of cache is to preserve contents between subsequent
runs of jobs for things like dependencies and commonly used libraries
(Nodejs packages, PHP packages, rubygems, python libraries, etc.),
so they don't have to be re-fetched from the public internet.
NOTE: **Note:**
For more examples, check the [GitLab CI Yml](https://gitlab.com/gitlab-org/gitlab-ci-yml)
project.
### Caching Nodejs dependencies
Assuming your project is using [npm](https://www.npmjs.com/) or
[Yarn](https://yarnpkg.com/en/) to install the Nodejs dependencies, the
following example defines `cache` globally so that all jobs inherit it.
Nodejs modules are installed in `node_modules/` and are cached per-branch:
```yaml
#
# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Nodejs.gitlab-ci.yml
#
image: node:latest
# Cache modules in between jobs
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
before_script:
- npm install
test_async:
script:
- node ./specs/start.js ./specs/async.spec.js
```
### Caching PHP dependencies
Assuming your project is using [Composer](https://getcomposer.org/) to install
the PHP dependencies, the following example defines `cache` globally so that
all jobs inherit it. PHP libraries modules are installed in `vendor/` and
are cached per-branch:
```yaml
#
# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/PHP.gitlab-ci.yml
#
image: php:7.2
# Cache libraries in between jobs
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- vendor/
before_script:
# Install and run Composer
- curl --show-error --silent https://getcomposer.org/installer | php
- php composer.phar install
test:
script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
```
### Caching Python dependencies
Assuming your project is using [pip](https://pip.pypa.io/en/stable/) to install
the python dependencies, the following example defines `cache` globally so that
all jobs inherit it. Python libraries are installed in a virtualenv under `venv/`,
pip's cache is defined under `.cache/pip/` and both are cached per-branch:
```yaml
#
# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Python.gitlab-ci.yml
#
image: python:latest
# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache"
# Pip's cache doesn't store the python packages
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
paths:
- .cache/
- venv/
before_script:
- python -V # Print out python version for debugging
- pip install virtualenv
- virtualenv venv
- source venv/bin/activate
test:
script:
- python setup.py test
- pip install flake8
- flake8 .
```
### Caching Ruby dependencies
Assuming your project is using [Bundler](https://bundler.io) to install the
gem dependencies, the following example defines `cache` globally so that all
jobs inherit it. Gems are installed in `vendor/ruby/` and are cached per-branch:
```yaml
#
# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Ruby.gitlab-ci.yml
#
image: ruby:2.5
# Cache gems in between builds
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- vendor/ruby
before_script:
- ruby -v # Print out ruby version for debugging
- gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image
- bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby
rspec:
script:
- rspec spec
```
## Availability of the cache
Caching is an optimization, but isn't guaranteed to always work, so you need to
be prepared to regenerate any cached files in each job that needs them.
Assuming you have properly [defined `cache` in `.gitlab-ci.yml`](../yaml/README.md#cache)
according to your workflow, the availability of the cache ultimately depends on
how the Runner has been configured (the executor type and whether different
Runners are used for passing the cache between jobs).
### Where the caches are stored
Since the Runner is the one responsible for storing the cache, it's essential
to know **where** it's stored. All the cache paths defined under a job in
`.gitlab-ci.yml` are archived in a single `cache.zip` file and stored in the
Runner's configured cache location. By default, they are stored locally in the
machine where the Runner is installed and depends on the type of the executor.
| GitLab Runner executor | Default path of the cache |
| ---------------------- | ------------------------- |
| [Shell](https://docs.gitlab.com/runner/executors/shell.html) | Locally, stored under the `gitlab-runner` user's home directory: `/home/gitlab-runner/cache/<user>/<project>/<cache-key>/cache.zip`. |
| [Docker](https://docs.gitlab.com/runner/executors/docker.html) | Locally, stored under [Docker volumes](https://docs.gitlab.com/runner/executors/docker.html#the-builds-and-cache-storage): `/var/lib/docker/volumes/<volume-id>/_data/<user>/<project>/<cache-key>/cache.zip`. |
| [Docker machine](https://docs.gitlab.com/runner/executors/docker_machine.html) (autoscale Runners) | Behaves the same as the Docker executor. |
### How archiving and extracting works
In the most simple scenario, consider that you use only one machine where the
Runner is installed, and all jobs of your project run on the same host.
Let's see the following example of two jobs that belong to two consecutive
stages:
```yaml
stages:
- build
- test
before_script:
- echo "Hello"
job A:
stage: build
script:
- mkdir vendor/
- echo "build" > vendor/hello.txt
cache:
key: build-cache
paths:
- vendor/
after_script:
- echo "World"
job B:
stage: test
script:
- cat vendor/hello.txt
cache:
key: build-cache
```
Here's what happens behind the scenes:
1. Pipeline starts
1. `job A` runs
1. `before_script` is executed
1. `script` is executed
1. `after_script` is executed
1. `cache` runs and the `vendor/` directory is zipped into `cache.zip`.
This file is then saved in the directory based on the
[Runner's setting](#where-the-caches-are-stored) and the `cache: key`.
1. `job B` runs
1. The cache is extracted (if found)
1. `before_script` is executed
1. `script` is executed
1. Pipeline finishes
By using a single Runner on a single machine, you'll not have the issue where
`job B` might execute on a Runner different from `job A`, thus guaranteeing the
cache between stages. That will only work if the build goes from stage `build`
to `test` in the same Runner/machine, otherwise, you [might not have the cache
available](#cache-mismatch).
During the caching process, there's also a couple of things to consider:
- If some other job, with another cache configuration had saved its
cache in the same zip file, it is overwritten. If the S3 based shared cache is
used, the file is additionally uploaded to S3 to an object based on the cache
key. So, two jobs with different paths, but the same cache key, will overwrite
their cache.
- When extracting the cache from `cache.zip`, everything in the zip file is
extracted in the job's working directory (usually the repository which is
pulled down), and the Runner doesn't mind if the archive of `job A` overwrites
things in the archive of `job B`.
The reason why it works this way is because the cache created for one Runner
often will not be valid when used by a different one which can run on a
**different architecture** (e.g., when the cache includes binary files). And
since the different steps might be executed by Runners running on different
machines, it is a safe default.
### Cache mismatch
In the following table, you can see some reasons where you might hit a cache
mismatch and a few ideas how to fix it.
| Reason of a cache mismatch | How to fix it |
| -------------------------- | ------------- |
| You use multiple standalone Runners (not in autoscale mode) attached to one project without a shared cache | Use only one Runner for your project or use multiple Runners with distributed cache enabled |
| You use Runners in autoscale mode without a distributed cache enabled | Configure the autoscale Runner to use a distributed cache |
| The machine the Runner is installed on is low on disk space or, if you've set up distributed cache, the S3 bucket where the cache is stored doesn't have enough space | Make sure you clear some space to allow new caches to be stored. Currently, there's no automatic way to do this. |
| You use the same `key` for jobs where they cache different paths. | Use different cache keys to that the cache archive is stored to a different location and doesn't overwrite wrong caches. |
Let's explore some examples.
---
Let's assume you have only one Runner assigned to your project, so the cache
will be stored in the Runner's machine by default. If two jobs, A and B,
have the same cache key, but they cache different paths, cache B would overwrite
cache A, even if their `paths` don't match:
We want `job A` and `job B` to re-use their
cache when the pipeline is run for a second time.
```yaml
stages:
- build
- test
job A:
stage: build
script: make build
cache:
key: same-key
paths:
- public/
job B:
stage: test
script: make test
cache:
key: same-key
paths:
- vendor/
```
1. `job A` runs
1. `public/` is cached as cache.zip
1. `job B` runs
1. The previous cache, if any, is unzipped
1. `vendor/` is cached as cache.zip and overwrites the previous one
1. The next time `job A` runs it will use the cache of `job B` which is different
and thus will be ineffective
To fix that, use different `keys` for each job.
---
In another case, let's assume you have more than one Runners assigned to your
project, but the distributed cache is not enabled. We want the second time the
pipeline is run, `job A` and `job B` to re-use their cache (which in this case
will be different):
```yaml
stages:
- build
- test
job A:
stage: build
script: build
cache:
key: keyA
paths:
- vendor/
job B:
stage: test
script: test
cache:
key: keyB
paths:
- vendor/
```
In that case, even if the `key` is different (no fear of overwriting), you
might experience the cached files to "get cleaned" before each stage if the
jobs run on different Runners in the subsequent pipelines.
## Clearing the cache
GitLab Runners use [cache](../yaml/README.md#cache) to speed up the execution
of your jobs by reusing existing data. This however, can sometimes lead to an
inconsistent behavior.
To start with a fresh copy of the cache, there are two ways to do that.
### Clearing the cache by changing `cache:key`
All you have to do is set a new `cache: key` in your `.gitlab-ci.yml`. In the
next run of the pipeline, the cache will be stored in a different location.
### Clearing the cache manually
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41249) in GitLab 10.4.
If you want to avoid editing `.gitlab-ci.yml`, you can easily clear the cache
via GitLab's UI. This will have an impact on all caches of your project as
name of the cache directory will be renamed by appending an integer to it
(`-1`, `-2`, etc.):
1. Navigate to your project's **CI/CD > Pipelines** page.
1. Click on the **Clear Runner caches** to clean up the cache.
1. On the next push, your CI/CD job will use a new cache.
Behind the scenes, this works by increasing a counter in the database, and the
value of that counter is used to create the key for the cache. After a push, a
new key is generated and the old cache is not valid anymore.
## Cache vs artifacts
NOTE: **Note:**
Be careful if you use cache and artifacts to store the same path in your jobs
as **caches are restored before artifacts** and the content would be overwritten.
Don't mix the caching with passing artifacts between stages. Caching is not
designed to pass artifacts between stages. Cache is for runtime dependencies
needed to compile the project:
- `cache` - **Use for temporary storage for project dependencies.** Not useful
for keeping intermediate build results, like `jar` or `apk` files.
Cache was designed to be used to speed up invocations of subsequent runs of a
given job, by keeping things like dependencies (e.g., npm packages, Go vendor
packages, etc.) so they don't have to be re-fetched from the public internet.
While the cache can be abused to pass intermediate build results between stages,
there may be cases where artifacts are a better fit.
- `artifacts` - **Use for stage results that will be passed between stages.**
Artifacts were designed to upload some compiled/generated bits of the build,
and they can be fetched by any number of concurrent Runners. They are
guaranteed to be available and are there to pass data between jobs. They are
also exposed to be downloaded from the UI.
It's sometimes confusing because the name artifact sounds like something that
is only useful outside of the job, like for downloading a final image. But
artifacts are also available in between stages within a pipeline. So if you
build your application by downloading all the required modules, you might want
to declare them as artifacts so that each subsequent stage can depend on them
being there. There are some optimizations like declaring an
[expiry time](../yaml/README.md#artifacts-expire_in) so you don't keep artifacts
around too long, and using [dependencies](../yaml/README.md#dependencies) to
control exactly where artifacts are passed around.
So, to sum up:
- Caches are disabled if not defined globally or per job (using `cache:`)
- Caches are available for all jobs in your `.gitlab-ci.yml` if enabled globally
- Caches can be used by subsequent pipelines of that very same job (a script in
a stage) in which the cache was created (if not defined globally).
- Caches are stored where the Runner is installed **and** uploaded to S3 if
[distributed cache is enabled](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching)
- Caches defined per job are only used either a) for the next pipeline of that job,
or b) if that same cache is also defined in a subsequent job of the same pipeline
- Artifacts are disabled if not defined per job (using `artifacts:`)
- Artifacts can only be enabled per job, not globally
- Artifacts are created during a pipeline and can be used by the subsequent
jobs of that currently active pipeline
- Artifacts are always uploaded to GitLab (known as coordinator)
- Artifacts can have an expiration value for controlling disk usage (30 days by default)
...@@ -146,24 +146,7 @@ To protect/unprotect Runners: ...@@ -146,24 +146,7 @@ To protect/unprotect Runners:
## Manually clearing the Runners cache ## Manually clearing the Runners cache
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41249) in GitLab 10.4. Read [clearing the cache](../caching/index.md#clearing-the-cache).
GitLab Runners use [cache](../yaml/README.md#cache) to speed up the execution
of your jobs by reusing existing data. This however, can sometimes lead to an
inconsistent behavior.
To start with a fresh copy of the cache, you can easily do it via GitLab's UI:
1. Navigate to your project's **CI/CD > Pipelines** page.
1. Click on the **Clear Runner caches** to clean up the cache.
1. On the next push, your CI/CD job will use a new cache.
That way, you don't have to change the [cache key](../yaml/README.md#cache-key)
in your `.gitlab-ci.yml`.
Behind the scenes, this works by increasing a counter in the database, and the
value of that counter is used to create the key for the cache. After a push, a
new key is generated and the old cache is not valid anymore.
## How shared Runners pick jobs ## How shared Runners pick jobs
...@@ -227,15 +210,16 @@ that it may encounter on the projects it's shared over. This would be ...@@ -227,15 +210,16 @@ that it may encounter on the projects it's shared over. This would be
problematic for large amounts of projects, if it wasn't for tags. problematic for large amounts of projects, if it wasn't for tags.
By tagging a Runner for the types of jobs it can handle, you can make sure By tagging a Runner for the types of jobs it can handle, you can make sure
shared Runners will only run the jobs they are equipped to run. shared Runners will [only run the jobs they are equipped to run](../yaml/README.md#tags).
For instance, at GitLab we have Runners tagged with "rails" if they contain For instance, at GitLab we have Runners tagged with "rails" if they contain
the appropriate dependencies to run Rails test suites. the appropriate dependencies to run Rails test suites.
### Preventing Runners with tags from picking jobs without tags ### Preventing Runners with tags from picking jobs without tags
You can configure a Runner to prevent it from picking jobs with tags when You can configure a Runner to prevent it from picking
the Runner does not have tags assigned. This setting can be enabled the first [jobs with tags](../yaml/README.md#tags) when the Runner does not have tags
assigned. This setting can be enabled the first
time you [register a Runner][register] and can be changed afterwards under time you [register a Runner][register] and can be changed afterwards under
each Runner's settings. each Runner's settings.
......
...@@ -674,6 +674,10 @@ as Review Apps. You can see a simple example using Review Apps at ...@@ -674,6 +674,10 @@ as Review Apps. You can see a simple example using Review Apps at
by default. by default.
- From GitLab 9.2, caches are restored before [artifacts](#artifacts). - From GitLab 9.2, caches are restored before [artifacts](#artifacts).
TIP: **Learn more:**
Read how caching works and find out some good practices in the
[caching dependencies documentation](../caching/index.md).
`cache` is used to specify a list of files and directories which should be `cache` is used to specify a list of files and directories which should be
cached between jobs. You can only use paths that are within the project cached between jobs. You can only use paths that are within the project
workspace. workspace.
...@@ -681,35 +685,20 @@ workspace. ...@@ -681,35 +685,20 @@ workspace.
If `cache` is defined outside the scope of jobs, it means it is set If `cache` is defined outside the scope of jobs, it means it is set
globally and all jobs will use that definition. globally and all jobs will use that definition.
Cache all files in `binaries` and `.config`: ### `cache:paths`
```yaml
rspec:
script: test
cache:
paths:
- binaries/
- .config
```
Cache all Git untracked files:
```yaml Use the `paths` directive to choose which files or directories will be cached.
rspec: Wildcards can be used as well.
script: test
cache:
untracked: true
```
Cache all Git untracked files and files in `binaries`: Cache all files in `binaries` that end in `.apk` and the `.config` file:
```yaml ```yaml
rspec: rspec:
script: test script: test
cache: cache:
untracked: true
paths: paths:
- binaries/ - binaries/*.apk
- .config
``` ```
Locally defined cache overrides globally defined options. The following `rspec` Locally defined cache overrides globally defined options. The following `rspec`
...@@ -723,33 +712,26 @@ cache: ...@@ -723,33 +712,26 @@ cache:
rspec: rspec:
script: test script: test
cache: cache:
key: rspec
paths: paths:
- binaries/ - binaries/
``` ```
Note that since cache is shared between jobs, if you're using different
paths for different jobs, you should also set a different **cache:key**
otherwise cache content can be overwritten.
NOTE: **Note:**
The cache is provided on a best-effort basis, so don't expect that the cache
will be always present.
### `cache:key` ### `cache:key`
> Introduced in GitLab Runner v1.0.0. > Introduced in GitLab Runner v1.0.0.
The `key` directive allows you to define the affinity of caching Since the cache is shared between jobs, if you're using different
between jobs, allowing to have a single cache for all jobs, paths for different jobs, you should also set a different `cache:key`
cache per-job, cache per-branch or any other way that fits your needs. otherwise cache content can be overwritten.
This way, you can fine tune caching, allowing you to cache data between The `key` directive allows you to define the affinity of caching between jobs,
different jobs or even different branches. allowing to have a single cache for all jobs, cache per-job, cache per-branch
or any other way that fits your workflow. This way, you can fine tune caching,
allowing you to cache data between different jobs or even different branches.
The `cache:key` variable can use any of the The `cache:key` variable can use any of the
[predefined variables](../variables/README.md), and the default key, if not set, [predefined variables](../variables/README.md), and the default key, if not set,
is set as `$CI_JOB_NAME-$CI_COMMIT_REF_NAME` which translates as "per-job and is `$CI_JOB_NAME-$CI_COMMIT_REF_NAME` which translates as "per-job and
per-branch". It is the default across the project, therefore everything is per-branch". It is the default across the project, therefore everything is
shared between pipelines and jobs running on the same branch by default. shared between pipelines and jobs running on the same branch by default.
...@@ -757,56 +739,56 @@ NOTE: **Note:** ...@@ -757,56 +739,56 @@ NOTE: **Note:**
The `cache:key` variable cannot contain the `/` character, or the equivalent The `cache:key` variable cannot contain the `/` character, or the equivalent
URI-encoded `%2F`; a value made only of dots (`.`, `%2E`) is also forbidden. URI-encoded `%2F`; a value made only of dots (`.`, `%2E`) is also forbidden.
**Example configurations** For example, to enable per-branch caching:
To enable per-job caching:
```yaml
cache:
key: "$CI_JOB_NAME"
untracked: true
```
To enable per-branch caching:
```yaml ```yaml
cache: cache:
key: "$CI_COMMIT_REF_SLUG" key: "$CI_COMMIT_REF_SLUG"
untracked: true paths:
- binaries/
``` ```
To enable per-job and per-branch caching: If you use **Windows Batch** to run your shell scripts you need to replace
`$` with `%`:
```yaml ```yaml
cache: cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" key: "%CI_JOB_STAGE%-%CI_COMMIT_REF_SLUG%"
untracked: true paths:
- binaries/
``` ```
To enable per-branch and per-stage caching: If you use **Windows PowerShell** to run your shell scripts you need to replace
`$` with `$env:`:
```yaml ```yaml
cache: cache:
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" key: "$env:CI_JOB_STAGE-$env:CI_COMMIT_REF_SLUG"
untracked: true paths:
- binaries/
``` ```
If you use **Windows Batch** to run your shell scripts you need to replace ### `cache:untracked`
`$` with `%`:
Set `untracked: true` to cache all files that are untracked in your Git
repository:
```yaml ```yaml
cache: rspec:
key: "%CI_JOB_STAGE%-%CI_COMMIT_REF_SLUG%" script: test
untracked: true cache:
untracked: true
``` ```
If you use **Windows PowerShell** to run your shell scripts you need to replace Cache all Git untracked files and files in `binaries`:
`$` with `$env:`:
```yaml ```yaml
cache: rspec:
key: "$env:CI_JOB_STAGE-$env:CI_COMMIT_REF_SLUG" script: test
untracked: true cache:
untracked: true
paths:
- binaries/
``` ```
### `cache:policy` ### `cache:policy`
......
...@@ -60,16 +60,10 @@ See the [Rails guides] for more info. ...@@ -60,16 +60,10 @@ See the [Rails guides] for more info.
As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`. As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
1. Uncomment the `mail_room` line in your `Procfile`: 1. Run this command in the GitLab root directory to launch `mail_room`:
```yaml
mail_room: bundle exec mail_room -q -c config/mail_room.yml
```
1. Restart GitLab:
```sh ```sh
bundle exec foreman start bundle exec mail_room -q -c config/mail_room.yml
``` ```
1. Verify that everything is configured correctly: 1. Verify that everything is configured correctly:
......
...@@ -136,11 +136,14 @@ class MyMigration < ActiveRecord::Migration ...@@ -136,11 +136,14 @@ class MyMigration < ActiveRecord::Migration
disable_ddl_transaction! disable_ddl_transaction!
def up def up
remove_concurrent_index :table_name, :column_name if index_exists?(:table_name, :column_name) remove_concurrent_index :table_name, :column_name
end end
end end
``` ```
Note that it is not necessary to check if the index exists prior to
removing it.
## Adding indexes ## Adding indexes
If you need to add a unique index please keep in mind there is the possibility If you need to add a unique index please keep in mind there is the possibility
......
...@@ -109,7 +109,7 @@ module API ...@@ -109,7 +109,7 @@ module API
# Return the Gitaly Address if it is enabled # Return the Gitaly Address if it is enabled
def gitaly_payload(action) def gitaly_payload(action)
return unless %w[git-receive-pack git-upload-pack].include?(action) return unless %w[git-receive-pack git-upload-pack git-upload-archive].include?(action)
{ {
repository: repository.gitaly_repository, repository: repository.gitaly_repository,
......
...@@ -59,6 +59,11 @@ module Gitlab ...@@ -59,6 +59,11 @@ module Gitlab
disable_statement_timeout disable_statement_timeout
end end
if index_exists?(table_name, column_name, options)
Rails.logger.warn "Index not created because it already exists (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}"
return
end
add_index(table_name, column_name, options) add_index(table_name, column_name, options)
end end
...@@ -83,6 +88,11 @@ module Gitlab ...@@ -83,6 +88,11 @@ module Gitlab
disable_statement_timeout disable_statement_timeout
end end
unless index_exists?(table_name, column_name, options)
Rails.logger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}"
return
end
remove_index(table_name, options.merge({ column: column_name })) remove_index(table_name, options.merge({ column: column_name }))
end end
...@@ -107,6 +117,11 @@ module Gitlab ...@@ -107,6 +117,11 @@ module Gitlab
disable_statement_timeout disable_statement_timeout
end end
unless index_exists_by_name?(table_name, index_name)
Rails.logger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, index_name: #{index_name}"
return
end
remove_index(table_name, options.merge({ name: index_name })) remove_index(table_name, options.merge({ name: index_name }))
end end
...@@ -140,6 +155,13 @@ module Gitlab ...@@ -140,6 +155,13 @@ module Gitlab
# of PostgreSQL's "VALIDATE CONSTRAINT". As a result we'll just fall # of PostgreSQL's "VALIDATE CONSTRAINT". As a result we'll just fall
# back to the normal foreign key procedure. # back to the normal foreign key procedure.
if Database.mysql? if Database.mysql?
if foreign_key_exists?(source, target, column: column)
Rails.logger.warn "Foreign key not created because it exists already " \
"(this may be due to an aborted migration or similar): " \
"source: #{source}, target: #{target}, column: #{column}"
return
end
return add_foreign_key(source, target, return add_foreign_key(source, target,
column: column, column: column,
on_delete: on_delete) on_delete: on_delete)
...@@ -151,25 +173,43 @@ module Gitlab ...@@ -151,25 +173,43 @@ module Gitlab
key_name = concurrent_foreign_key_name(source, column) key_name = concurrent_foreign_key_name(source, column)
# Using NOT VALID allows us to create a key without immediately unless foreign_key_exists?(source, target, column: column)
# validating it. This means we keep the ALTER TABLE lock only for a Rails.logger.warn "Foreign key not created because it exists already " \
# short period of time. The key _is_ enforced for any newly created "(this may be due to an aborted migration or similar): " \
# data. "source: #{source}, target: #{target}, column: #{column}"
execute <<-EOF.strip_heredoc
ALTER TABLE #{source} # Using NOT VALID allows us to create a key without immediately
ADD CONSTRAINT #{key_name} # validating it. This means we keep the ALTER TABLE lock only for a
FOREIGN KEY (#{column}) # short period of time. The key _is_ enforced for any newly created
REFERENCES #{target} (id) # data.
#{on_delete ? "ON DELETE #{on_delete.upcase}" : ''} execute <<-EOF.strip_heredoc
NOT VALID; ALTER TABLE #{source}
EOF ADD CONSTRAINT #{key_name}
FOREIGN KEY (#{column})
REFERENCES #{target} (id)
#{on_delete ? "ON DELETE #{on_delete.upcase}" : ''}
NOT VALID;
EOF
end
# Validate the existing constraint. This can potentially take a very # Validate the existing constraint. This can potentially take a very
# long time to complete, but fortunately does not lock the source table # long time to complete, but fortunately does not lock the source table
# while running. # while running.
#
# Note this is a no-op in case the constraint is VALID already
execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{key_name};") execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{key_name};")
end end
def foreign_key_exists?(source, target = nil, column: nil)
foreign_keys(source).any? do |key|
if column
key.options[:column].to_s == column.to_s
else
key.to_table.to_s == target.to_s
end
end
end
# Returns the name for a concurrent foreign key. # Returns the name for a concurrent foreign key.
# #
# PostgreSQL constraint names have a limit of 63 bytes. The logic used # PostgreSQL constraint names have a limit of 63 bytes. The logic used
...@@ -860,12 +900,6 @@ into similar problems in the future (e.g. when new tables are created). ...@@ -860,12 +900,6 @@ into similar problems in the future (e.g. when new tables are created).
end end
end end
def foreign_key_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
# Rails' index_exists? doesn't work when you only give it a table and index # Rails' index_exists? doesn't work when you only give it a table and index
# name. As such we have to use some extra code to check if an index exists for # name. As such we have to use some extra code to check if an index exists for
# a given name. # a given name.
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
end end
def call(env) def call(env)
ReadOnly::Controller.new(@app, env).call ::Gitlab::Middleware::ReadOnly::Controller.new(@app, env).call
end end
end end
end end
......
module Gitlab
class OmniauthInitializer
def initialize(devise_config)
@devise_config = devise_config
end
def execute(providers)
providers.each do |provider|
add_provider(provider['name'].to_sym, *arguments_for(provider))
end
end
private
def add_provider(*args)
@devise_config.omniauth(*args)
end
def arguments_for(provider)
provider_arguments = []
%w[app_id app_secret].each do |argument|
provider_arguments << provider[argument] if provider[argument]
end
case provider['args']
when Array
# An Array from the configuration will be expanded.
provider_arguments.concat provider['args']
when Hash
hash_arguments = provider['args'].merge(provider_defaults(provider))
# A Hash from the configuration will be passed as is.
provider_arguments << hash_arguments.symbolize_keys
end
provider_arguments
end
def provider_defaults(provider)
case provider['name']
when 'cas3'
{ on_single_sign_out: cas3_signout_handler }
when 'authentiq'
{ remote_sign_out_handler: authentiq_signout_handler }
when 'shibboleth'
{ fail_with_empty_uid: true }
else
{}
end
end
def cas3_signout_handler
lambda do |request|
ticket = request.params[:session_index]
raise "Service Ticket not found." unless Gitlab::Auth::OAuth::Session.valid?(:cas3, ticket)
Gitlab::Auth::OAuth::Session.destroy(:cas3, ticket)
true
end
end
def authentiq_signout_handler
lambda do |request|
authentiq_session = request.params['sid']
if Gitlab::Auth::OAuth::Session.valid?(:authentiq, authentiq_session)
Gitlab::Auth::OAuth::Session.destroy(:authentiq, authentiq_session)
true
else
false
end
end
end
end
end
...@@ -92,8 +92,8 @@ module Gitlab ...@@ -92,8 +92,8 @@ module Gitlab
if type && time if type && time
@load_times_by_model ||= {} @load_times_by_model ||= {}
@load_times_by_model[type] ||= 0 @load_times_by_model[type] ||= []
@load_times_by_model[type] += time.to_f @load_times_by_model[type] << time.to_f
end end
super super
...@@ -135,8 +135,12 @@ module Gitlab ...@@ -135,8 +135,12 @@ module Gitlab
def self.log_load_times_by_model(logger) def self.log_load_times_by_model(logger)
return unless logger.respond_to?(:load_times_by_model) return unless logger.respond_to?(:load_times_by_model)
logger.load_times_by_model.to_a.sort_by(&:last).reverse.each do |(model, time)| summarised_load_times = logger.load_times_by_model.to_a.map do |(model, times)|
logger.info("#{model} total: #{time.round(2)}ms") [model, times.count, times.sum]
end
summarised_load_times.sort_by(&:last).reverse.each do |(model, query_count, time)|
logger.info("#{model} total (#{query_count}): #{time.round(2)}ms")
end end
end end
end end
......
...@@ -2,14 +2,5 @@ unless Rails.env.production? ...@@ -2,14 +2,5 @@ unless Rails.env.production?
require 'haml_lint/rake_task' require 'haml_lint/rake_task'
require 'haml_lint/inline_javascript' require 'haml_lint/inline_javascript'
# Workaround for warnings from parser/current
# TODO: Remove this after we update parser gem
task :haml_lint do
require 'parser'
def Parser.warn(*args)
puts(*args) # static-analysis ignores stdout if status is 0
end
end
HamlLint::RakeTask.new HamlLint::RakeTask.new
end end
...@@ -25,4 +25,18 @@ feature 'Projects tree' do ...@@ -25,4 +25,18 @@ feature 'Projects tree' do
expect(page).to have_selector('.label-lfs', text: 'LFS') expect(page).to have_selector('.label-lfs', text: 'LFS')
end end
end end
context 'web IDE', :js do
before do
visit project_tree_path(project, File.join('master', 'bar'))
click_link 'Web IDE'
find('.ide-file-list')
end
it 'opens folder in IDE' do
expect(page).to have_selector('.is-open', text: 'bar')
end
end
end end
...@@ -549,6 +549,20 @@ import timeoutPromise from './helpers/set_timeout_promise_helper'; ...@@ -549,6 +549,20 @@ import timeoutPromise from './helpers/set_timeout_promise_helper';
}); });
}); });
it('should disable the submit button when comment button is clicked', (done) => {
expect($form.find('.js-comment-submit-button').is(':disabled')).toEqual(false);
mockNotesPost();
$('.js-comment-button').click();
expect($form.find('.js-comment-submit-button').is(':disabled')).toEqual(true);
setTimeout(() => {
expect($form.find('.js-comment-submit-button').is(':disabled')).toEqual(false);
done();
});
});
it('should show actual note element when new comment is done posting', (done) => { it('should show actual note element when new comment is done posting', (done) => {
mockNotesPost(); mockNotesPost();
......
...@@ -20,16 +20,8 @@ describe('detailedMetric', () => { ...@@ -20,16 +20,8 @@ describe('detailedMetric', () => {
}); });
}); });
it('does not display details', () => { it('does not render the element', () => {
expect(vm.$el.innerText).not.toContain('/'); expect(vm.$el.innerHTML).toEqual(undefined);
});
it('does not display the modal', () => {
expect(vm.$el.querySelector('.performance-bar-modal')).toBeNull();
});
it('displays the metric name', () => {
expect(vm.$el.innerText).toContain('gitaly');
}); });
}); });
......
...@@ -67,17 +67,35 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -67,17 +67,35 @@ describe Gitlab::Database::MigrationHelpers do
model.add_concurrent_index(:users, :foo, unique: true) model.add_concurrent_index(:users, :foo, unique: true)
end end
it 'does nothing if the index exists already' do
expect(model).to receive(:index_exists?)
.with(:users, :foo, { algorithm: :concurrently, unique: true }).and_return(true)
expect(model).not_to receive(:add_index)
model.add_concurrent_index(:users, :foo, unique: true)
end
end end
context 'using MySQL' do context 'using MySQL' do
it 'creates a regular index' do before do
expect(Gitlab::Database).to receive(:postgresql?).and_return(false) allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
end
it 'creates a regular index' do
expect(model).to receive(:add_index) expect(model).to receive(:add_index)
.with(:users, :foo, {}) .with(:users, :foo, {})
model.add_concurrent_index(:users, :foo) model.add_concurrent_index(:users, :foo)
end end
it 'does nothing if the index exists already' do
expect(model).to receive(:index_exists?)
.with(:users, :foo, { unique: true }).and_return(true)
expect(model).not_to receive(:add_index)
model.add_concurrent_index(:users, :foo, unique: true)
end
end end
end end
...@@ -95,6 +113,7 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -95,6 +113,7 @@ describe Gitlab::Database::MigrationHelpers do
context 'outside a transaction' do context 'outside a transaction' do
before do before do
allow(model).to receive(:transaction_open?).and_return(false) allow(model).to receive(:transaction_open?).and_return(false)
allow(model).to receive(:index_exists?).and_return(true)
end end
context 'using PostgreSQL' do context 'using PostgreSQL' do
...@@ -103,18 +122,41 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -103,18 +122,41 @@ describe Gitlab::Database::MigrationHelpers do
allow(model).to receive(:disable_statement_timeout) allow(model).to receive(:disable_statement_timeout)
end end
it 'removes the index concurrently by column name' do describe 'by column name' do
expect(model).to receive(:remove_index) it 'removes the index concurrently' do
.with(:users, { algorithm: :concurrently, column: :foo }) expect(model).to receive(:remove_index)
.with(:users, { algorithm: :concurrently, column: :foo })
model.remove_concurrent_index(:users, :foo) model.remove_concurrent_index(:users, :foo)
end
it 'does nothing if the index does not exist' do
expect(model).to receive(:index_exists?)
.with(:users, :foo, { algorithm: :concurrently, unique: true }).and_return(false)
expect(model).not_to receive(:remove_index)
model.remove_concurrent_index(:users, :foo, unique: true)
end
end end
it 'removes the index concurrently by index name' do describe 'by index name' do
expect(model).to receive(:remove_index) before do
.with(:users, { algorithm: :concurrently, name: "index_x_by_y" }) allow(model).to receive(:index_exists_by_name?).with(:users, "index_x_by_y").and_return(true)
end
it 'removes the index concurrently by index name' do
expect(model).to receive(:remove_index)
.with(:users, { algorithm: :concurrently, name: "index_x_by_y" })
model.remove_concurrent_index_by_name(:users, "index_x_by_y")
end
it 'does nothing if the index does not exist' do
expect(model).to receive(:index_exists_by_name?).with(:users, "index_x_by_y").and_return(false)
expect(model).not_to receive(:remove_index)
model.remove_concurrent_index_by_name(:users, "index_x_by_y") model.remove_concurrent_index_by_name(:users, "index_x_by_y")
end
end end
end end
...@@ -141,6 +183,10 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -141,6 +183,10 @@ describe Gitlab::Database::MigrationHelpers do
end end
describe '#add_concurrent_foreign_key' do describe '#add_concurrent_foreign_key' do
before do
allow(model).to receive(:foreign_key_exists?).and_return(false)
end
context 'inside a transaction' do context 'inside a transaction' do
it 'raises an error' do it 'raises an error' do
expect(model).to receive(:transaction_open?).and_return(true) expect(model).to receive(:transaction_open?).and_return(true)
...@@ -157,14 +203,23 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -157,14 +203,23 @@ describe Gitlab::Database::MigrationHelpers do
end end
context 'using MySQL' do context 'using MySQL' do
it 'creates a regular foreign key' do before do
allow(Gitlab::Database).to receive(:mysql?).and_return(true) allow(Gitlab::Database).to receive(:mysql?).and_return(true)
end
it 'creates a regular foreign key' do
expect(model).to receive(:add_foreign_key) expect(model).to receive(:add_foreign_key)
.with(:projects, :users, column: :user_id, on_delete: :cascade) .with(:projects, :users, column: :user_id, on_delete: :cascade)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id) model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end end
it 'does not create a foreign key if it exists already' do
expect(model).to receive(:foreign_key_exists?).with(:projects, :users, column: :user_id).and_return(true)
expect(model).not_to receive(:add_foreign_key)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end
end end
context 'using PostgreSQL' do context 'using PostgreSQL' do
...@@ -189,6 +244,14 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -189,6 +244,14 @@ describe Gitlab::Database::MigrationHelpers do
column: :user_id, column: :user_id,
on_delete: :nullify) on_delete: :nullify)
end end
it 'does not create a foreign key if it exists already' do
expect(model).to receive(:foreign_key_exists?).with(:projects, :users, column: :user_id).and_return(true)
expect(model).not_to receive(:execute).with(/ADD CONSTRAINT/)
expect(model).to receive(:execute).with(/VALIDATE CONSTRAINT/)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end
end end
end end
end end
...@@ -203,6 +266,29 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -203,6 +266,29 @@ describe Gitlab::Database::MigrationHelpers do
end end
end end
describe '#foreign_key_exists?' do
before do
key = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(:projects, :users, { column: :non_standard_id })
allow(model).to receive(:foreign_keys).with(:projects).and_return([key])
end
it 'finds existing foreign keys by column' do
expect(model.foreign_key_exists?(:projects, :users, column: :non_standard_id)).to be_truthy
end
it 'finds existing foreign keys by target table only' do
expect(model.foreign_key_exists?(:projects, :users)).to be_truthy
end
it 'compares by column name if given' do
expect(model.foreign_key_exists?(:projects, :users, column: :user_id)).to be_falsey
end
it 'compares by target if no column given' do
expect(model.foreign_key_exists?(:projects, :other_table)).to be_falsey
end
end
describe '#disable_statement_timeout' do describe '#disable_statement_timeout' do
context 'using PostgreSQL' do context 'using PostgreSQL' do
it 'disables statement timeouts' do it 'disables statement timeouts' do
......
require 'spec_helper'
describe Gitlab::OmniauthInitializer do
let(:devise_config) { class_double(Devise) }
subject { described_class.new(devise_config) }
describe '#execute' do
it 'configures providers from array' do
generic_config = { 'name' => 'generic' }
expect(devise_config).to receive(:omniauth).with(:generic)
subject.execute([generic_config])
end
it 'allows "args" array for app_id and app_secret' do
legacy_config = { 'name' => 'legacy', 'args' => %w(123 abc) }
expect(devise_config).to receive(:omniauth).with(:legacy, '123', 'abc')
subject.execute([legacy_config])
end
it 'passes app_id and app_secret as additional arguments' do
twitter_config = { 'name' => 'twitter', 'app_id' => '123', 'app_secret' => 'abc' }
expect(devise_config).to receive(:omniauth).with(:twitter, '123', 'abc')
subject.execute([twitter_config])
end
it 'passes "args" hash as symbolized hash argument' do
hash_config = { 'name' => 'hash', 'args' => { 'custom' => 'format' } }
expect(devise_config).to receive(:omniauth).with(:hash, custom: 'format')
subject.execute([hash_config])
end
it 'configures fail_with_empty_uid for shibboleth' do
shibboleth_config = { 'name' => 'shibboleth', 'args' => {} }
expect(devise_config).to receive(:omniauth).with(:shibboleth, fail_with_empty_uid: true)
subject.execute([shibboleth_config])
end
it 'configures remote_sign_out_handler proc for authentiq' do
authentiq_config = { 'name' => 'authentiq', 'args' => {} }
expect(devise_config).to receive(:omniauth).with(:authentiq, remote_sign_out_handler: an_instance_of(Proc))
subject.execute([authentiq_config])
end
it 'configures on_single_sign_out proc for cas3' do
cas3_config = { 'name' => 'cas3', 'args' => {} }
expect(devise_config).to receive(:omniauth).with(:cas3, on_single_sign_out: an_instance_of(Proc))
subject.execute([cas3_config])
end
end
end
...@@ -110,8 +110,8 @@ describe Gitlab::Profiler do ...@@ -110,8 +110,8 @@ describe Gitlab::Profiler do
custom_logger.debug('User Load (1.3ms)') custom_logger.debug('User Load (1.3ms)')
custom_logger.debug('Project Load (10.4ms)') custom_logger.debug('Project Load (10.4ms)')
expect(custom_logger.load_times_by_model).to eq('User' => 2.5, expect(custom_logger.load_times_by_model).to eq('User' => [1.2, 1.3],
'Project' => 10.4) 'Project' => [10.4])
end end
it 'logs the backtrace, ignoring lines as appropriate' do it 'logs the backtrace, ignoring lines as appropriate' do
...@@ -164,4 +164,24 @@ describe Gitlab::Profiler do ...@@ -164,4 +164,24 @@ describe Gitlab::Profiler do
end end
end end
end end
describe '.log_load_times_by_model' do
it 'logs the model, query count, and time by slowest first' do
expect(null_logger).to receive(:load_times_by_model).and_return(
'User' => [1.2, 1.3],
'Project' => [10.4]
)
expect(null_logger).to receive(:info).with('Project total (1): 10.4ms')
expect(null_logger).to receive(:info).with('User total (2): 2.5ms')
described_class.log_load_times_by_model(null_logger)
end
it 'does nothing when called with a logger that does not have load times' do
expect(null_logger).not_to receive(:info)
expect(described_class.log_load_times_by_model(null_logger)).to be_nil
end
end
end end
...@@ -447,6 +447,12 @@ describe API::Internal do ...@@ -447,6 +447,12 @@ describe API::Internal do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy expect(json_response["status"]).to be_truthy
expect(json_response["gitaly"]).not_to be_nil
expect(json_response["gitaly"]["repository"]).not_to be_nil
expect(json_response["gitaly"]["repository"]["storage_name"]).to eq(project.repository.gitaly_repository.storage_name)
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
end end
end end
......
...@@ -9,6 +9,8 @@ describe Ci::ProcessPipelineService, '#execute' do ...@@ -9,6 +9,8 @@ describe Ci::ProcessPipelineService, '#execute' do
end end
before do before do
stub_ci_pipeline_to_return_yaml_file
stub_not_protect_default_branch stub_not_protect_default_branch
project.add_developer(user) project.add_developer(user)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment