Commit 8ae22209 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'master' into feature/svg-badge-template

* master: (363 commits)
  Added changelog item for issuable form dropdowns
  Add 'run tests' docs from GDK
  Bump gitlab_git to lazy load compare commits
  Add examples to repository files API (!5465)
  Ignore URLs starting with // (!5677)
  Add failing test for #7032
  Update timeago to shorter representation
  Add missing DOWNTIME constant to the AddTimestampsToMembersAgain migration
  Added guide about migrations and downtime
  Update CHANGELOG for 8.10.4
  Add a data migration to fix some missing timestamps in the members table (again)
  Move abilities by subject class to a dedicated method
  Remove unnecessary empty line after css var
  Set consistency in list text height css
  Add description to text/plain emails
  Fix Rename `add_users_into_project` and `projects_ids`
  fix spec
  Underscore variable to camelCase
  using shared path for project import uploads and refactored gitlab remove export worker
  Structure the development documentation
  ...
parents 1b5e2303 91030230
...@@ -28,6 +28,7 @@ stages: ...@@ -28,6 +28,7 @@ stages:
- prepare - prepare
- test - test
- post-test - post-test
- pages
# Prepare and merge knapsack tests # Prepare and merge knapsack tests
.knapsack-state: &knapsack-state .knapsack-state: &knapsack-state
...@@ -40,6 +41,7 @@ stages: ...@@ -40,6 +41,7 @@ stages:
paths: paths:
- knapsack/ - knapsack/
artifacts: artifacts:
expire_in: 31d
paths: paths:
- knapsack/ - knapsack/
...@@ -81,8 +83,10 @@ update-knapsack: ...@@ -81,8 +83,10 @@ update-knapsack:
- cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH} - cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH}
- knapsack rspec - knapsack rspec
artifacts: artifacts:
expire_in: 31d
paths: paths:
- knapsack/ - knapsack/
- coverage/
.spinach-knapsack: &spinach-knapsack .spinach-knapsack: &spinach-knapsack
stage: test stage: test
...@@ -97,8 +101,10 @@ update-knapsack: ...@@ -97,8 +101,10 @@ update-knapsack:
- cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH} - cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH}
- knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)' - knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
artifacts: artifacts:
expire_in: 31d
paths: paths:
- knapsack/ - knapsack/
- coverage/
rspec 0 20: *rspec-knapsack rspec 0 20: *rspec-knapsack
rspec 1 20: *rspec-knapsack rspec 1 20: *rspec-knapsack
...@@ -186,14 +192,14 @@ spinach 9 10 ruby23: *spinach-knapsack-ruby23 ...@@ -186,14 +192,14 @@ spinach 9 10 ruby23: *spinach-knapsack-ruby23
# Other generic tests # Other generic tests
.static-analyses-variables: &static-analyses-variables .ruby-static-analysis: &ruby-static-analysis
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
USE_DB: "false" USE_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
.exec: &exec .exec: &exec
<<: *static-analyses-variables <<: *ruby-static-analysis
stage: test stage: test
script: script:
- bundle exec $CI_BUILD_NAME - bundle exec $CI_BUILD_NAME
...@@ -220,16 +226,35 @@ teaspoon: ...@@ -220,16 +226,35 @@ teaspoon:
bundler:audit: bundler:audit:
stage: test stage: test
<<: *static-analyses-variables <<: *ruby-static-analysis
only: only:
- master - master
script: script:
- "bundle exec bundle-audit check --update --ignore OSVDB-115941" - "bundle exec bundle-audit check --update --ignore OSVDB-115941"
coverage:
stage: post-test
services: []
variables:
USE_DB: "false"
USE_BUNDLE_INSTALL: "true"
script:
- bundle exec scripts/merge-simplecov
artifacts:
name: coverage
expire_in: 31d
paths:
- coverage/index.html
- coverage/assets/
# Notify slack in the end # Notify slack in the end
notify:slack: notify:slack:
stage: post-test stage: post-test
variables:
USE_DB: "false"
USE_BUNDLE_INSTALL: "false"
script: script:
- ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>" - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>"
when: on_failure when: on_failure
...@@ -238,3 +263,18 @@ notify:slack: ...@@ -238,3 +263,18 @@ notify:slack:
- tags@gitlab-org/gitlab-ce - tags@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
- tags@gitlab-org/gitlab-ee - tags@gitlab-org/gitlab-ee
pages:
before_script: []
stage: pages
dependencies:
- coverage
script:
- mv public/ .public/
- mkdir public/
- mv coverage public/coverage-ruby
artifacts:
paths:
- public
only:
- master
...@@ -510,6 +510,15 @@ Metrics/PerceivedComplexity: ...@@ -510,6 +510,15 @@ Metrics/PerceivedComplexity:
#################### Lint ################################ #################### Lint ################################
# Checks for useless access modifiers.
Lint/UselessAccessModifier:
Enabled: true
# Checks for attempts to use `private` or `protected` to set the visibility
# of a class method, which does not work.
Lint/IneffectiveAccessModifier:
Enabled: false
# Checks for ambiguous operators in the first argument of a method invocation # Checks for ambiguous operators in the first argument of a method invocation
# without parentheses. # without parentheses.
Lint/AmbiguousOperator: Lint/AmbiguousOperator:
......
...@@ -19,10 +19,6 @@ Lint/AssignmentInCondition: ...@@ -19,10 +19,6 @@ Lint/AssignmentInCondition:
Lint/HandleExceptions: Lint/HandleExceptions:
Enabled: false Enabled: false
# Offense count: 21
Lint/IneffectiveAccessModifier:
Enabled: false
# Offense count: 2 # Offense count: 2
Lint/Loop: Lint/Loop:
Enabled: false Enabled: false
...@@ -48,10 +44,6 @@ Lint/UnusedBlockArgument: ...@@ -48,10 +44,6 @@ Lint/UnusedBlockArgument:
Lint/UnusedMethodArgument: Lint/UnusedMethodArgument:
Enabled: false Enabled: false
# Offense count: 11
Lint/UselessAccessModifier:
Enabled: false
# Offense count: 12 # Offense count: 12
# Cop supports --auto-correct. # Cop supports --auto-correct.
Performance/PushSplat: Performance/PushSplat:
......
# .simplecov
SimpleCov.start 'rails' do
merge_timeout 3600
end
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.11.0 (unreleased) v 8.11.0 (unreleased)
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
- Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
- Fix the title of the toggle dropdown button. !5515 (herminiotorres)
- Improve diff performance by eliminating redundant checks for text blobs
- Convert switch icon into icon font (ClemMakesApps)
- Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell) - Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell)
- Add support for relative links starting with ./ or / to RelativeLinkFilter (winniehell)
- Ignore URLs starting with // in Markdown links !5677 (winniehell)
- Fix CI status icon link underline (ClemMakesApps) - Fix CI status icon link underline (ClemMakesApps)
- The Repository class is now instrumented
- Cache the commit author in RequestStore to avoid extra lookups in PostReceive
- Expand commit message width in repo view (ClemMakesApps)
- Cache highlighted diff lines for merge requests
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI' - Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable - Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
- Optimize maximum user access level lookup in loading of notes - Optimize maximum user access level lookup in loading of notes
- Add "No one can push" as an option for protected branches. !5081
- Improve performance of AutolinkFilter#text_parse by using XPath
- Environments have an url to link to
- Update `timeago` plugin to use multiple string/locale settings
- Remove unused images (ClemMakesApps)
- Limit git rev-list output count to one in forced push check - Limit git rev-list output count to one in forced push check
- Clean up unused routes (Josef Strzibny) - Clean up unused routes (Josef Strzibny)
- Add green outline to New Branch button. !5447 (winniehell) - Add green outline to New Branch button. !5447 (winniehell)
- Improve performance of syntax highlighting Markdown code blocks
- Update to gitlab_git 10.4.1 and take advantage of preserved Ref objects
- Remove delay when hitting "Reply..." button on page with a lot of discussions
- Retrieve rendered HTML from cache in one request - Retrieve rendered HTML from cache in one request
- Fix renaming repository when name contains invalid chararacters under project settings
- Fix devise deprecation warnings.
- Optimize checking if a user has read access to a list of issues !5370
- Nokogiri's various parsing methods are now instrumented - Nokogiri's various parsing methods are now instrumented
- Add simple identifier to public SSH keys (muteor)
- Add a way to send an email and create an issue based on private personal token. Find the email address from issues page. !3363
- Fix filter input alignment (ClemMakesApps)
- Include old revision in merge request update hooks (Ben Boeckel)
- Add build event color in HipChat messages (David Eisner)
- Make fork counter always clickable. !5463 (winniehell) - Make fork counter always clickable. !5463 (winniehell)
- Gitlab::Highlight is now instrumented
- All created issues, API or WebUI, can be submitted to Akismet for spam check !5333
- The overhead of instrumented method calls has been reduced
- Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le) - Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le)
- Load project invited groups and members eagerly in `ProjectTeam#fetch_members` - Load project invited groups and members eagerly in `ProjectTeam#fetch_members`
- Bump gitlab_git to speedup DiffCollection iterations
- Rewrite description of a blocked user in admin settings. (Elias Werberich)
- Make branches sortable without push permission !5462 (winniehell) - Make branches sortable without push permission !5462 (winniehell)
- Check for Ci::Build artifacts at database level on pipeline partial
- Convert image diff background image to CSS (ClemMakesApps)
- Remove unnecessary index_projects_on_builds_enabled index from the projects table
- Make "New issue" button in Issue page less obtrusive !5457 (winniehell)
- Gitlab::Metrics.current_transaction needs to be public for RailsQueueDuration
- Fix search for notes which belongs to deleted objects
- Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska) - Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska)
- Allow branch names ending with .json for graph and network page !5579 (winniehell)
- Add the `sprockets-es6` gem - Add the `sprockets-es6` gem
- Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska) - Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska)
- Profile requests when a header is passed - Profile requests when a header is passed
- Avoid calculation of line_code and position for _line partial when showing diff notes on discussion tab.
v 8.10.2 (unreleased) - Speedup DiffNote#active? on discussions, preloading noteables and avoid touching git repository to return diff_refs when possible
- Add commit stats in commit api. !5517 (dixpac)
- Add CI configuration button on project page
- Make error pages responsive (Takuya Noguchi)
- Fix skip_repo parameter being ignored when destroying a namespace
- Change requests_profiles resource constraint to catch virtually any file
- Bump gitlab_git to lazy load compare commits
- Reduce number of queries made for merge_requests/:id/diffs
- Sensible state specific default sort order for issues and merge requests !5453 (tomb0y)
- Fix RequestProfiler::Middleware error when code is reloaded in development
- Catch what warden might throw when profiling requests to re-throw it
- Add description to new_issue email and new_merge_request_email in text/plain content type. !5663 (dixpac)
- Speed up and reduce memory usage of Commit#repo_changes, Repository#expire_avatar_cache and IrkerWorker
- Add unfold links for Side-by-Side view. !5415 (Tim Masliuchenko)
v 8.10.5 (unreleased)
v 8.10.4
- Don't close referenced upstream issues from a forked project.
- Fixes issue with dropdowns `enter` key not working correctly. !5544
- Fix Import/Export project import not working in HA mode. !5618
- Fix Import/Export error checking versions. !5638
v 8.10.3
- Fix Import/Export issue importing milestones and labels not associated properly. !5426
- Fix timing problems running imports on production. !5523
- Add a log message when a project is scheduled for destruction for debugging. !5540
- Fix hooks missing on imported GitLab projects. !5549
- Properly abort a merge when merge conflicts occur. !5569
- Fix importer for GitHub Pull Requests when a branch was removed. !5573
- Ignore invalid IPs in X-Forwarded-For when trusted proxies are configured. !5584
- Trim extra displayed carriage returns in diffs and files with CRLFs. !5588
v 8.10.2
- User can now search branches by name. !5144 - User can now search branches by name. !5144
- Add ENV variable to skip repository storages validations - Page is now properly rendered after committing the first file and creating the first branch. !5399
- Add branch or tag icon to ref in builds page. !5434
- Fix backup restore. !5459 - Fix backup restore. !5459
- Rescue Rugged::OSError (lock exists) when creating references. !5497
- Disable MySQL foreign key checks before dropping all tables. !5472
- Fix a bug where forking a project from a repository storage to another would fail
- Show release notes in tags list
- Use project ID in repository cache to prevent stale data from persisting across projects. !5460 - Use project ID in repository cache to prevent stale data from persisting across projects. !5460
- Fix issue with autocomplete search not working with enter key. !5466
- Add iid to MR API response. !5468
- Disable MySQL foreign key checks before dropping all tables. !5472
- Ensure relative paths for video are rewritten as we do for images. !5474 - Ensure relative paths for video are rewritten as we do for images. !5474
- Ensure current user can retry a build before showing the 'Retry' button. !5476 - Ensure current user can retry a build before showing the 'Retry' button. !5476
- Fix expand all diffs button in compare view - Add ENV variable to skip repository storages validations. !5478
- Added `*.js.es6 gitlab-language=javascript` to `.gitattributes`. !5486
- Don't show comment button in gutter of diffs on MR discussion tab. !5493
- Rescue Rugged::OSError (lock exists) when creating references. !5497
- Fix expand all diffs button in compare view. !5500
- Show release notes in tags list. !5503
- Fix a bug where forking a project from a repository storage to another would fail. !5509
- Fix missing schema update for `20160722221922`. !5512
- Update `gitlab-shell` version to 3.2.1 in the 8.9->8.10 update guide. !5516
v 8.10.1 v 8.10.1
- Refactor repository storages documentation. !5428 - Refactor repository storages documentation. !5428
...@@ -89,6 +169,9 @@ v 8.10.0 ...@@ -89,6 +169,9 @@ v 8.10.0
- Fix check for New Branch button on Issue page. !4630 (winniehell) - Fix check for New Branch button on Issue page. !4630 (winniehell)
- Fix GFM autocomplete not working on wiki pages - Fix GFM autocomplete not working on wiki pages
- Fixed enter key not triggering click on first row when searching in a dropdown - Fixed enter key not triggering click on first row when searching in a dropdown
- Updated dropdowns in issuable form to use new GitLab dropdown style
- Make images fit to the size of the viewport !4810
- Fix check for New Branch button on Issue page !4630 (winniehell)
- Fix MR-auto-close text added to description. !4836 - Fix MR-auto-close text added to description. !4836
- Support U2F devices in Firefox. !5177 - Support U2F devices in Firefox. !5177
- Fix issue, preventing users w/o push access to sort tags. !5105 (redetection) - Fix issue, preventing users w/o push access to sort tags. !5105 (redetection)
......
...@@ -41,6 +41,8 @@ abbreviation. ...@@ -41,6 +41,8 @@ abbreviation.
If you have read this guide and want to know how the GitLab [core team] If you have read this guide and want to know how the GitLab [core team]
operates please see [the GitLab contributing process](PROCESS.md). operates please see [the GitLab contributing process](PROCESS.md).
- [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
## Contributor license agreement ## Contributor license agreement
By submitting code as an individual you agree to the By submitting code as an individual you agree to the
...@@ -460,7 +462,8 @@ merge request: ...@@ -460,7 +462,8 @@ merge request:
- string literal quoting style **Option A**: single quoted by default - string literal quoting style **Option A**: single quoted by default
1. [Rails](https://github.com/bbatsov/rails-style-guide) 1. [Rails](https://github.com/bbatsov/rails-style-guide)
1. [Testing](doc/development/testing.md) 1. [Testing](doc/development/testing.md)
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript) 1. [JavaScript (ES6)](https://github.com/airbnb/javascript)
1. [JavaScript (ES5)](https://github.com/airbnb/javascript/tree/master/es5)
1. [SCSS styleguide][scss-styleguide] 1. [SCSS styleguide][scss-styleguide]
1. [Shell commands](doc/development/shell_commands.md) created by GitLab 1. [Shell commands](doc/development/shell_commands.md) created by GitLab
contributors to enhance security contributors to enhance security
......
...@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2' ...@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.3.2' gem 'gitlab_git', '~> 10.4.5'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -225,7 +225,7 @@ gem 'addressable', '~> 2.3.8' ...@@ -225,7 +225,7 @@ gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.3.0' gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.6.1' gem 'font-awesome-rails', '~> 4.6.1'
gem 'gemojione', '~> 3.0' gem 'gemojione', '~> 3.0'
gem 'gon', '~> 6.0.1' gem 'gon', '~> 6.1.0'
gem 'jquery-atwho-rails', '~> 1.3.2' gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0' gem 'jquery-rails', '~> 4.1.0'
gem 'jquery-ui-rails', '~> 5.0.0' gem 'jquery-ui-rails', '~> 5.0.0'
...@@ -253,7 +253,7 @@ group :development do ...@@ -253,7 +253,7 @@ group :development do
gem 'letter_opener_web', '~> 1.3.0' gem 'letter_opener_web', '~> 1.3.0'
gem 'rerun', '~> 0.11.0' gem 'rerun', '~> 0.11.0'
gem 'bullet', '~> 5.0.0', require: false gem 'bullet', '~> 5.2.0', require: false
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
gem 'web-console', '~> 2.0' gem 'web-console', '~> 2.0'
...@@ -303,7 +303,7 @@ group :development, :test do ...@@ -303,7 +303,7 @@ group :development, :test do
gem 'rubocop', '~> 0.41.2', require: false gem 'rubocop', '~> 0.41.2', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'simplecov', '~> 0.11.0', require: false gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false gem 'flay', '~> 2.6.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false gem 'bundler-audit', '~> 0.5.0', require: false
...@@ -326,7 +326,7 @@ group :production do ...@@ -326,7 +326,7 @@ group :production do
gem 'gitlab_meta', '7.0' gem 'gitlab_meta', '7.0'
end end
gem 'newrelic_rpm', '~> 3.14' gem 'newrelic_rpm', '~> 3.16'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.3.0'
......
...@@ -59,7 +59,7 @@ GEM ...@@ -59,7 +59,7 @@ GEM
oauth2 (~> 1.0) oauth2 (~> 1.0)
asciidoctor (1.5.3) asciidoctor (1.5.3)
ast (2.3.0) ast (2.3.0)
attr_encrypted (3.0.1) attr_encrypted (3.0.3)
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
attr_required (1.0.0) attr_required (1.0.0)
autoprefixer-rails (6.2.3) autoprefixer-rails (6.2.3)
...@@ -104,9 +104,9 @@ GEM ...@@ -104,9 +104,9 @@ GEM
brakeman (3.3.2) brakeman (3.3.2)
browser (2.2.0) browser (2.2.0)
builder (3.2.2) builder (3.2.2)
bullet (5.0.0) bullet (5.2.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.9.0) uniform_notifier (~> 1.10.0)
bundler-audit (0.5.0) bundler-audit (0.5.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
...@@ -156,8 +156,8 @@ GEM ...@@ -156,8 +156,8 @@ GEM
database_cleaner (1.5.3) database_cleaner (1.5.3)
debug_inspector (0.0.2) debug_inspector (0.0.2)
debugger-ruby_core_source (1.3.8) debugger-ruby_core_source (1.3.8)
default_value_for (3.0.1) default_value_for (3.0.2)
activerecord (>= 3.2.0, < 5.0) activerecord (>= 3.2.0, < 5.1)
descendants_tracker (0.0.4) descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
devise (4.1.1) devise (4.1.1)
...@@ -278,7 +278,7 @@ GEM ...@@ -278,7 +278,7 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_git (10.3.2) gitlab_git (10.4.5)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -303,7 +303,7 @@ GEM ...@@ -303,7 +303,7 @@ GEM
gollum-rugged_adapter (0.4.2) gollum-rugged_adapter (0.4.2)
mime-types (>= 1.15) mime-types (>= 1.15)
rugged (~> 0.24.0, >= 0.21.3) rugged (~> 0.24.0, >= 0.21.3)
gon (6.0.1) gon (6.1.0)
actionpack (>= 3.0) actionpack (>= 3.0)
json json
multi_json multi_json
...@@ -404,7 +404,7 @@ GEM ...@@ -404,7 +404,7 @@ GEM
nested_form (0.3.2) nested_form (0.3.2)
net-ldap (0.12.1) net-ldap (0.12.1)
net-ssh (3.0.1) net-ssh (3.0.1)
newrelic_rpm (3.14.1.311) newrelic_rpm (3.16.0.318)
nokogiri (1.6.8) nokogiri (1.6.8)
mini_portile2 (~> 2.1.0) mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7) pkg-config (~> 1.1.7)
...@@ -509,7 +509,7 @@ GEM ...@@ -509,7 +509,7 @@ GEM
rack-cors (0.4.0) rack-cors (0.4.0)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-oauth2 (1.2.1) rack-oauth2 (1.2.3)
activesupport (>= 2.3) activesupport (>= 2.3)
attr_required (>= 0.0.5) attr_required (>= 0.0.5)
httpclient (>= 2.4) httpclient (>= 2.4)
...@@ -575,7 +575,7 @@ GEM ...@@ -575,7 +575,7 @@ GEM
redis-store (~> 1.1.0) redis-store (~> 1.1.0)
redis-store (1.1.7) redis-store (1.1.7)
redis (>= 2.2) redis (>= 2.2)
request_store (1.3.0) request_store (1.3.1)
rerun (0.11.0) rerun (0.11.0)
listen (~> 3.0) listen (~> 3.0)
responders (2.1.1) responders (2.1.1)
...@@ -673,9 +673,9 @@ GEM ...@@ -673,9 +673,9 @@ GEM
rufus-scheduler (>= 2.0.24) rufus-scheduler (>= 2.0.24)
sidekiq (>= 4.0.0) sidekiq (>= 4.0.0)
simple_oauth (0.1.9) simple_oauth (0.1.9)
simplecov (0.11.2) simplecov (0.12.0)
docile (~> 1.1.0) docile (~> 1.1.0)
json (~> 1.8) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.0) simplecov-html (0.10.0)
sinatra (1.4.7) sinatra (1.4.7)
...@@ -775,7 +775,7 @@ GEM ...@@ -775,7 +775,7 @@ GEM
unicorn-worker-killer (0.4.4) unicorn-worker-killer (0.4.4)
get_process_mem (~> 0) get_process_mem (~> 0)
unicorn (>= 4, < 6) unicorn (>= 4, < 6)
uniform_notifier (1.9.0) uniform_notifier (1.10.0)
uuid (2.3.8) uuid (2.3.8)
macaddr (~> 1.0) macaddr (~> 1.0)
version_sorter (2.0.0) version_sorter (2.0.0)
...@@ -830,7 +830,7 @@ DEPENDENCIES ...@@ -830,7 +830,7 @@ DEPENDENCIES
bootstrap-sass (~> 3.3.0) bootstrap-sass (~> 3.3.0)
brakeman (~> 3.3.0) brakeman (~> 3.3.0)
browser (~> 2.2) browser (~> 2.2)
bullet (~> 5.0.0) bullet (~> 5.2.0)
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
byebug (~> 8.2.1) byebug (~> 8.2.1)
capybara (~> 2.6.2) capybara (~> 2.6.2)
...@@ -870,12 +870,12 @@ DEPENDENCIES ...@@ -870,12 +870,12 @@ DEPENDENCIES
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
github-markup (~> 1.4) github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_git (~> 10.3.2) gitlab_git (~> 10.4.5)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2) gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.0.1) gon (~> 6.1.0)
grape (~> 0.13.0) grape (~> 0.13.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
hamlit (~> 2.5) hamlit (~> 2.5)
...@@ -902,7 +902,7 @@ DEPENDENCIES ...@@ -902,7 +902,7 @@ DEPENDENCIES
mysql2 (~> 0.3.16) mysql2 (~> 0.3.16)
nested_form (~> 0.3.2) nested_form (~> 0.3.2)
net-ssh (~> 3.0.1) net-ssh (~> 3.0.1)
newrelic_rpm (~> 3.14) newrelic_rpm (~> 3.16)
nokogiri (~> 1.6.7, >= 1.6.7.2) nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.2.0) oauth2 (~> 1.2.0)
octokit (~> 4.3.0) octokit (~> 4.3.0)
...@@ -962,7 +962,7 @@ DEPENDENCIES ...@@ -962,7 +962,7 @@ DEPENDENCIES
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0) sidekiq (~> 4.0)
sidekiq-cron (~> 0.4.0) sidekiq-cron (~> 0.4.0)
simplecov (~> 0.11.0) simplecov (= 0.12.0)
sinatra (~> 1.4.4) sinatra (~> 1.4.4)
six (~> 0.2.0) six (~> 0.2.0)
slack-notifier (~> 1.2.0) slack-notifier (~> 1.2.0)
......
...@@ -8,6 +8,8 @@ treatment, etc.). And so that maintainers know what to expect from contributors ...@@ -8,6 +8,8 @@ treatment, etc.). And so that maintainers know what to expect from contributors
(use the latest version, ensure that the issue is addressed, friendly treatment, (use the latest version, ensure that the issue is addressed, friendly treatment,
etc.). etc.).
- [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
## Common actions ## Common actions
### Issue team ### Issue team
......
...@@ -287,7 +287,7 @@ ...@@ -287,7 +287,7 @@
$('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned'); $('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned');
$('.navbar-fixed-top').removeClass('header-pinned-nav'); $('.navbar-fixed-top').removeClass('header-pinned-nav');
} }
return $document.off('click', '.js-nav-pin').on('click', '.js-nav-pin', function(e) { $document.off('click', '.js-nav-pin').on('click', '.js-nav-pin', function(e) {
var $page, $pinBtn, $tooltip, $topNav, doPinNav, tooltipText; var $page, $pinBtn, $tooltip, $topNav, doPinNav, tooltipText;
e.preventDefault(); e.preventDefault();
$pinBtn = $(e.currentTarget); $pinBtn = $(e.currentTarget);
...@@ -315,6 +315,8 @@ ...@@ -315,6 +315,8 @@
$tooltip.find('.tooltip-inner').text(tooltipText); $tooltip.find('.tooltip-inner').text(tooltipText);
return $pinBtn.attr('title', tooltipText).tooltip('fixTitle'); return $pinBtn.attr('title', tooltipText).tooltip('fixTitle');
}); });
});
// Custom time ago
gl.utils.shortTimeAgo($('.js-short-timeago'));
});
}).call(this); }).call(this);
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
$date = $('.js-artifacts-remove'); $date = $('.js-artifacts-remove');
if ($date.length) { if ($date.length) {
date = $date.text(); date = $date.text();
return $date.text($.timefor(new Date(date), ' ')); return $date.text($.timefor(new Date(date.replace(/-/g, '/')), ' '));
} }
}; };
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
$(document).off('click', '.js-unfold'); $(document).off('click', '.js-unfold');
$(document).on('click', '.js-unfold', (function(_this) { $(document).on('click', '.js-unfold', (function(_this) {
return function(event) { return function(event) {
var line_number, link, offset, old_line, params, prev_new_line, prev_old_line, ref, ref1, since, target, to, unfold, unfoldBottom; var line_number, link, file, offset, old_line, params, prev_new_line, prev_old_line, ref, ref1, since, target, to, unfold, unfoldBottom;
target = $(event.target); target = $(event.target);
unfoldBottom = target.hasClass('js-unfold-bottom'); unfoldBottom = target.hasClass('js-unfold-bottom');
unfold = true; unfold = true;
...@@ -31,14 +31,16 @@ ...@@ -31,14 +31,16 @@
unfold = false; unfold = false;
} }
} }
link = target.parents('.diff-file').attr('data-blob-diff-path'); file = target.parents('.diff-file');
link = file.data('blob-diff-path');
params = { params = {
since: since, since: since,
to: to, to: to,
bottom: unfoldBottom, bottom: unfoldBottom,
offset: offset, offset: offset,
unfold: unfold, unfold: unfold,
indent: 1 indent: 1,
view: file.data('view')
}; };
return $.get(link, params, function(response) { return $.get(link, params, function(response) {
return target.parent().replaceWith(response); return target.parent().replaceWith(response);
...@@ -48,26 +50,13 @@ ...@@ -48,26 +50,13 @@
} }
Diff.prototype.lineNumbers = function(line) { Diff.prototype.lineNumbers = function(line) {
var i, l, len, line_number, line_numbers, lines, results;
if (!line.children().length) { if (!line.children().length) {
return [0, 0]; return [0, 0];
} }
lines = line.children().slice(0, 2);
line_numbers = (function() { return line.find('.diff-line-num').map(function() {
var i, len, results; return parseInt($(this).data('linenumber'));
results = []; });
for (i = 0, len = lines.length; i < len; i++) {
l = lines[i];
results.push($(l).attr('data-linenumber'));
}
return results;
})();
results = [];
for (i = 0, len = line_numbers.length; i < len; i++) {
line_number = line_numbers[i];
results.push(parseInt(line_number));
}
return results;
}; };
return Diff; return Diff;
......
...@@ -171,6 +171,11 @@ ...@@ -171,6 +171,11 @@
break; break;
case 'search:show': case 'search:show':
new Search(); new Search();
break;
case 'projects:protected_branches:index':
new ProtectedBranchesAccessSelect($(".new_protected_branch"), false, true);
new ProtectedBranchesAccessSelect($(".protected-branches-list"), true, false);
break;
} }
switch (path.first()) { switch (path.first()) {
case 'admin': case 'admin':
......
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
} }
} }
}, },
setup: function(wrap) { setup: function(input) {
this.input = $('.js-gfm-input'); this.input = input || $('.js-gfm-input');
this.destroyAtWho(); this.destroyAtWho();
this.setupAtWho(); this.setupAtWho();
if (this.dataSource) { if (this.dataSource) {
......
...@@ -28,38 +28,43 @@ ...@@ -28,38 +28,43 @@
}; };
})(this)); })(this));
timeout = ""; timeout = "";
this.input.on("keyup", (function(_this) { this.input
return function(e) { .on('keydown', function (e) {
var keyCode = e.which;
if (keyCode === 13) {
e.preventDefault()
}
})
.on('keyup', function(e) {
var keyCode; var keyCode;
keyCode = e.which; keyCode = e.which;
if (ARROW_KEY_CODES.indexOf(keyCode) >= 0) { if (ARROW_KEY_CODES.indexOf(keyCode) >= 0) {
return; return;
} }
if (_this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.addClass(HAS_VALUE_CLASS); $inputContainer.addClass(HAS_VALUE_CLASS);
} else if (_this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.removeClass(HAS_VALUE_CLASS); $inputContainer.removeClass(HAS_VALUE_CLASS);
} }
if (keyCode === 13) { if (keyCode === 13) {
return false; return false;
} }
if (_this.options.remote) { if (this.options.remote) {
clearTimeout(timeout); clearTimeout(timeout);
return timeout = setTimeout(function() { return timeout = setTimeout(function() {
var blur_field; var blurField = this.shouldBlur(keyCode);
blur_field = _this.shouldBlur(keyCode); if (blurField && this.filterInputBlur) {
if (blur_field && _this.filterInputBlur) { this.input.blur();
_this.input.blur();
} }
return _this.options.query(_this.input.val(), function(data) { return this.options.query(this.input.val(), function(data) {
return _this.options.callback(data); return this.options.callback(data);
}); }.bind(this));
}, 250); }.bind(this), 250);
} else { } else {
return _this.filter(_this.input.val()); return this.filter(this.input.val());
} }
}; }.bind(this));
})(this));
} }
GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) { GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) {
...@@ -382,6 +387,7 @@ ...@@ -382,6 +387,7 @@
GitLabDropdown.prototype.opened = function() { GitLabDropdown.prototype.opened = function() {
var contentHtml; var contentHtml;
currentIndex = -1;
this.addArrowKeyEvent(); this.addArrowKeyEvent();
if (this.options.setIndeterminateIds) { if (this.options.setIndeterminateIds) {
this.options.setIndeterminateIds.call(this); this.options.setIndeterminateIds.call(this);
...@@ -619,7 +625,7 @@ ...@@ -619,7 +625,7 @@
var $input, ARROW_KEY_CODES, selector; var $input, ARROW_KEY_CODES, selector;
ARROW_KEY_CODES = [38, 40]; ARROW_KEY_CODES = [38, 40];
$input = this.dropdown.find(".dropdown-input-field"); $input = this.dropdown.find(".dropdown-input-field");
selector = '.dropdown-content li:not(.divider,.dropdown-header,.separator)'; selector = '.dropdown-content li:not(.divider,.dropdown-header,.separator):visible';
if (this.dropdown.find(".dropdown-toggle-page").length) { if (this.dropdown.find(".dropdown-toggle-page").length) {
selector = ".dropdown-page-one " + selector; selector = ".dropdown-page-one " + selector;
} }
...@@ -647,7 +653,7 @@ ...@@ -647,7 +653,7 @@
return false; return false;
} }
if (currentKeyCode === 13 && currentIndex !== -1) { if (currentKeyCode === 13 && currentIndex !== -1) {
return _this.selectRowAtIndex(e, currentIndex); return _this.selectRowAtIndex(e, $('.is-focused', _this.dropdown).closest('li').index() - 1);
} }
}; };
})(this)); })(this));
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
this.form.find('.div-dropzone').remove(); this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form'); this.form.addClass('gfm-form');
disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
GitLab.GfmAutoComplete.setup(); GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
new DropzoneInput(this.form); new DropzoneInput(this.form);
autosize(this.textarea); autosize(this.textarea);
this.addEventListeners(); this.addEventListeners();
......
...@@ -8,13 +8,16 @@ ...@@ -8,13 +8,16 @@
base.utils = {}; base.utils = {};
} }
w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
w.gl.utils.formatDate = function(datetime) { w.gl.utils.formatDate = function(datetime) {
return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z');
}; };
w.gl.utils.getDayName = function(date) { w.gl.utils.getDayName = function(date) {
return this.days[date.getDay()]; return this.days[date.getDay()];
}; };
return w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago) {
w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago) {
if (setTimeago == null) { if (setTimeago == null) {
setTimeago = true; setTimeago = true;
} }
...@@ -31,6 +34,39 @@ ...@@ -31,6 +34,39 @@
}); });
} }
}; };
w.gl.utils.shortTimeAgo = function($el) {
var shortLocale, tmpLocale;
shortLocale = {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: 'ago',
suffixFromNow: 'from now',
seconds: '1 min',
minute: '1 min',
minutes: '%d mins',
hour: '1 hr',
hours: '%d hrs',
day: '1 day',
days: '%d days',
month: '1 month',
months: '%d months',
year: '1 year',
years: '%d years',
wordSeparator: ' ',
numbers: []
};
tmpLocale = $.timeago.settings.strings;
$el.each(function(el) {
var $el1;
$el1 = $(this);
return $el1.attr('title', gl.utils.formatDate($el.attr('datetime')));
});
$.timeago.settings.strings = shortLocale;
$el.timeago();
$.timeago.settings.strings = tmpLocale;
};
})(window); })(window);
}).call(this); }).call(this);
function md5 (str) {
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + namespaced by: Michael White (http://getsprink.com)
// + tweaked by: Jack
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + input by: Brett Zamir (http://brett-zamir.me)
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// - depends on: utf8_encode
// * example 1: md5('Kevin van Zonneveld');
// * returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
var xl;
var rotateLeft = function (lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
};
var addUnsigned = function (lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
};
var _F = function (x, y, z) {
return (x & y) | ((~x) & z);
};
var _G = function (x, y, z) {
return (x & z) | (y & (~z));
};
var _H = function (x, y, z) {
return (x ^ y ^ z);
};
var _I = function (x, y, z) {
return (y ^ (x | (~z)));
};
var _FF = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _GG = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _HH = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _II = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var convertToWordArray = function (str) {
var lWordCount;
var lMessageLength = str.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = new Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
var wordToHex = function (lValue) {
var wordToHexValue = "",
wordToHexValue_temp = "",
lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
wordToHexValue_temp = "0" + lByte.toString(16);
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
}
return wordToHexValue;
};
var x = [],
k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
S12 = 12,
S13 = 17,
S14 = 22,
S21 = 5,
S22 = 9,
S23 = 14,
S24 = 20,
S31 = 4,
S32 = 11,
S33 = 16,
S34 = 23,
S41 = 6,
S42 = 10,
S43 = 15,
S44 = 21;
str = this.utf8_encode(str);
x = convertToWordArray(str);
a = 0x67452301;
b = 0xEFCDAB89;
c = 0x98BADCFE;
d = 0x10325476;
xl = x.length;
for (k = 0; k < xl; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = addUnsigned(a, AA);
b = addUnsigned(b, BB);
c = addUnsigned(c, CC);
d = addUnsigned(d, DD);
}
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
return temp.toLowerCase();
}
function utf8_encode (argString) {
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: sowberry
// + tweaked by: Jack
// + bugfixed by: Onno Marsman
// + improved by: Yves Sucaet
// + bugfixed by: Onno Marsman
// + bugfixed by: Ulrich
// + bugfixed by: Rafal Kukawski
// + improved by: kirilloid
// + bugfixed by: kirilloid
// * example 1: utf8_encode('Kevin van Zonneveld');
// * returns 1: 'Kevin van Zonneveld'
if (argString === null || typeof argString === "undefined") {
return "";
}
var string = (argString + ''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
var utftext = '',
start, end, stringl = 0;
start = end = 0;
stringl = string.length;
for (var n = 0; n < stringl; n++) {
var c1 = string.charCodeAt(n);
var enc = null;
if (c1 < 128) {
end++;
} else if (c1 > 127 && c1 < 2048) {
enc = String.fromCharCode(
(c1 >> 6) | 192,
( c1 & 63) | 128
);
} else if (c1 & 0xF800 != 0xD800) {
enc = String.fromCharCode(
(c1 >> 12) | 224,
((c1 >> 6) & 63) | 128,
( c1 & 63) | 128
);
} else { // surrogate pairs
if (c1 & 0xFC00 != 0xD800) { throw new RangeError("Unmatched trail surrogate at " + n); }
var c2 = string.charCodeAt(++n);
if (c2 & 0xFC00 != 0xDC00) { throw new RangeError("Unmatched lead surrogate at " + (n-1)); }
c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
enc = String.fromCharCode(
(c1 >> 18) | 240,
((c1 >> 12) & 63) | 128,
((c1 >> 6) & 63) | 128,
( c1 & 63) | 128
);
}
if (enc !== null) {
if (end > start) {
utftext += string.slice(start, end);
}
utftext += enc;
start = end = n + 1;
}
}
if (end > start) {
utftext += string.slice(start, stringl);
}
return utftext;
}
...@@ -89,8 +89,14 @@ ...@@ -89,8 +89,14 @@
toggleLabel: function(obj, $el) { toggleLabel: function(obj, $el) {
return $el.text().trim(); return $el.text().trim();
}, },
clicked: function(e) { clicked: function(selected, $el, e) {
return $dropdown.closest('form').submit(); e.preventDefault()
if ($('input[name="ref"]').length) {
var $form = $dropdown.closest('form'),
action = $form.attr('action'),
divider = action.indexOf('?') < 0 ? '?' : '&';
Turbolinks.visit(action + '' + divider + '' + $form.serialize());
}
} }
}); });
}); });
......
(function() {
$(function() {
return $(".protected-branches-list :checkbox").change(function(e) {
var can_push, id, name, obj, url;
name = $(this).attr("name");
if (name === "developers_can_push" || name === "developers_can_merge") {
id = $(this).val();
can_push = $(this).is(":checked");
url = $(this).data("url");
return $.ajax({
type: "PATCH",
url: url,
dataType: "json",
data: {
id: id,
protected_branch: (
obj = {},
obj["" + name] = can_push,
obj
)
},
success: function() {
var row;
row = $(e.target);
return row.closest('tr').effect('highlight');
},
error: function() {
return new Flash("Failed to update branch!", "alert");
}
});
}
});
});
}).call(this);
class ProtectedBranchesAccessSelect {
constructor(container, saveOnSelect, selectDefault) {
this.container = container;
this.saveOnSelect = saveOnSelect;
this.container.find(".allowed-to-merge").each((i, element) => {
var fieldName = $(element).data('field-name');
var dropdown = $(element).glDropdown({
data: gon.merge_access_levels,
selectable: true,
fieldName: fieldName,
clicked: _.chain(this.onSelect).partial(element).bind(this).value()
});
if (selectDefault) {
dropdown.data('glDropdown').selectRowAtIndex(document.createEvent("Event"), 0);
}
});
this.container.find(".allowed-to-push").each((i, element) => {
var fieldName = $(element).data('field-name');
var dropdown = $(element).glDropdown({
data: gon.push_access_levels,
selectable: true,
fieldName: fieldName,
clicked: _.chain(this.onSelect).partial(element).bind(this).value()
});
if (selectDefault) {
dropdown.data('glDropdown').selectRowAtIndex(document.createEvent("Event"), 0);
}
});
}
onSelect(dropdown, selected, element, e) {
$(dropdown).find('.dropdown-toggle-text').text(selected.text);
if (this.saveOnSelect) {
return $.ajax({
type: "POST",
url: $(dropdown).data('url'),
dataType: "json",
data: {
_method: 'PATCH',
id: $(dropdown).data('id'),
protected_branch: {
["" + ($(dropdown).data('type')) + "_attributes"]: {
"access_level": selected.id
}
}
},
success: function() {
var row;
row = $(e.target);
return row.closest('tr').effect('highlight');
},
error: function() {
return new Flash("Failed to update branch!", "alert");
}
});
}
}
}
...@@ -189,6 +189,7 @@ ...@@ -189,6 +189,7 @@
_this.groupId = $(select).data('group-id'); _this.groupId = $(select).data('group-id');
_this.showCurrentUser = $(select).data('current-user'); _this.showCurrentUser = $(select).data('current-user');
_this.authorId = $(select).data('author-id'); _this.authorId = $(select).data('author-id');
_this.skipUsers = $(select).data('skip-users');
showNullUser = $(select).data('null-user'); showNullUser = $(select).data('null-user');
showAnyUser = $(select).data('any-user'); showAnyUser = $(select).data('any-user');
showEmailUser = $(select).data('email-user'); showEmailUser = $(select).data('email-user');
...@@ -320,7 +321,8 @@ ...@@ -320,7 +321,8 @@
project_id: this.projectId, project_id: this.projectId,
group_id: this.groupId, group_id: this.groupId,
current_user: this.showCurrentUser, current_user: this.showCurrentUser,
author_id: this.authorId author_id: this.authorId,
skip_users: this.skipUsers
}, },
dataType: "json" dataType: "json"
}).done(function(users) { }).done(function(users) {
......
...@@ -114,6 +114,12 @@ ul.content-list { ...@@ -114,6 +114,12 @@ ul.content-list {
font-size: $list-font-size; font-size: $list-font-size;
color: $list-text-color; color: $list-text-color;
&.no-description {
.title {
line-height: $list-text-height;
}
}
.title { .title {
font-weight: 600; font-weight: 600;
} }
...@@ -134,12 +140,11 @@ ul.content-list { ...@@ -134,12 +140,11 @@ ul.content-list {
} }
.controls { .controls {
padding-top: 1px;
float: right; float: right;
> .control-text { > .control-text {
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
line-height: 40px; line-height: $list-text-height;
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
...@@ -150,7 +155,7 @@ ul.content-list { ...@@ -150,7 +155,7 @@ ul.content-list {
> .btn-group { > .btn-group {
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
display: inline-block; display: inline-block;
margin-top: 4px; margin-top: 3px;
margin-bottom: 4px; margin-bottom: 4px;
&:last-child { &:last-child {
......
...@@ -182,7 +182,6 @@ ...@@ -182,7 +182,6 @@
> form { > form {
display: inline-block; display: inline-block;
margin-top: -1px;
} }
.icon-label { .icon-label {
...@@ -193,7 +192,6 @@ ...@@ -193,7 +192,6 @@
height: 35px; height: 35px;
display: inline-block; display: inline-block;
position: relative; position: relative;
top: 2px;
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
/* Medium devices (desktops, 992px and up) */ /* Medium devices (desktops, 992px and up) */
......
...@@ -43,6 +43,7 @@ $gl-header-color: $gl-title-color; ...@@ -43,6 +43,7 @@ $gl-header-color: $gl-title-color;
$list-font-size: $gl-font-size; $list-font-size: $gl-font-size;
$list-title-color: $gl-title-color; $list-title-color: $gl-title-color;
$list-text-color: $gl-text-color; $list-text-color: $gl-text-color;
$list-text-height: 42px;
/* /*
* Markdown * Markdown
......
.commits-compare-switch { .commits-compare-switch {
@include btn-default; @include btn-default;
@include btn-white; @include btn-white;
background: image-url("switch_icon.png") no-repeat center center;
text-indent: -9999px;
float: left; float: left;
margin-right: 9px; margin-right: 9px;
} }
...@@ -61,6 +59,10 @@ ...@@ -61,6 +59,10 @@
font-size: 0; font-size: 0;
} }
.ci-status-link {
display: inline-block;
}
.btn-clipboard, .btn-transparent { .btn-clipboard, .btn-transparent {
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
......
...@@ -164,7 +164,10 @@ ...@@ -164,7 +164,10 @@
line-height: 0; line-height: 0;
img { img {
border: 1px solid #fff; border: 1px solid #fff;
background: image-url('trans_bg.gif'); background-image: linear-gradient(45deg, #e5e5e5 25%, transparent 25%, transparent 75%, #e5e5e5 75%, #e5e5e5 100%),
linear-gradient(45deg, #e5e5e5 25%, transparent 25%, transparent 75%, #e5e5e5 75%, #e5e5e5 100%);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
max-width: 100%; max-width: 100%;
} }
&.deleted { &.deleted {
......
...@@ -23,15 +23,9 @@ ...@@ -23,15 +23,9 @@
} }
.group-row { .group-row {
&.no-description {
.group-name {
line-height: 44px;
}
}
.stats { .stats {
float: right; float: right;
line-height: 44px; line-height: $list-text-height;
color: $gl-gray; color: $gl-gray;
span { span {
......
...@@ -99,3 +99,33 @@ form.edit-issue { ...@@ -99,3 +99,33 @@ form.edit-issue {
.issue-form .select2-container { .issue-form .select2-container {
width: 250px !important; width: 250px !important;
} }
.issues-footer {
padding-top: $gl-padding;
padding-bottom: 37px;
}
.issue-email-modal-btn {
padding: 0;
color: $gl-link-color;
background-color: transparent;
border: 0;
outline: 0;
&:hover {
text-decoration: underline;
}
}
.email-modal-input-group {
margin-bottom: 10px;
.form-control {
background-color: $white-light;
}
.btn {
background-color: $background-color;
border: 1px solid $border-gray-light;
}
}
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
.btn { .btn {
margin: 4px; margin: 4px;
} }
.table.builds {
min-width: 1200px;
}
} }
.content-list { .content-list {
...@@ -35,7 +39,7 @@ ...@@ -35,7 +39,7 @@
} }
.table.builds { .table.builds {
min-width: 1200px; min-width: 900px;
&.pipeline { &.pipeline {
min-width: 650px; min-width: 650px;
...@@ -128,7 +132,7 @@ ...@@ -128,7 +132,7 @@
.icon-container { .icon-container {
display: inline-block; display: inline-block;
text-align: right; text-align: right;
width: 20px; width: 15px;
.fa { .fa {
position: relative; position: relative;
......
...@@ -512,18 +512,12 @@ pre.light-well { ...@@ -512,18 +512,12 @@ pre.light-well {
.project-row { .project-row {
border-color: $table-border-color; border-color: $table-border-color;
&.no-description {
.project {
line-height: 40px;
}
}
.project-full-name { .project-full-name {
@include str-truncated; @include str-truncated;
} }
.controls { .controls {
line-height: 40px; line-height: $list-text-height;
a:hover { a:hover {
text-decoration: none; text-decoration: none;
...@@ -661,14 +655,28 @@ pre.light-well { ...@@ -661,14 +655,28 @@ pre.light-well {
} }
} }
.new_protected_branch {
.dropdown {
display: inline;
margin-left: 15px;
}
label {
min-width: 120px;
}
}
.protected-branches-list { .protected-branches-list {
a { a {
color: $gl-gray; color: $gl-gray;
font-weight: 600;
&:hover { &:hover {
color: $gl-link-color; color: $gl-link-color;
} }
&.is-active {
font-weight: 600;
}
} }
} }
......
...@@ -58,6 +58,10 @@ ...@@ -58,6 +58,10 @@
.tree_commit { .tree_commit {
max-width: 320px; max-width: 320px;
.str-truncated {
max-width: 100%;
}
} }
.tree_time_ago { .tree_time_ago {
......
...@@ -243,42 +243,6 @@ class ApplicationController < ActionController::Base ...@@ -243,42 +243,6 @@ class ApplicationController < ActionController::Base
end end
end end
def set_filters_params
set_default_sort
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@sort = params[:sort]
@filter_params = params.dup
if @project
@filter_params[:project_id] = @project.id
elsif @group
@filter_params[:group_id] = @group.id
else
# TODO: this filter ignore issues/mr created in public or
# internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you
# created or assigned or mentioned
# @filter_params[:authorized_only] = true
end
@filter_params
end
def get_issues_collection
set_filters_params
@issuable_finder = IssuesFinder.new(current_user, @filter_params)
@issuable_finder.execute
end
def get_merge_requests_collection
set_filters_params
@issuable_finder = MergeRequestsFinder.new(current_user, @filter_params)
@issuable_finder.execute
end
def import_sources_enabled? def import_sources_enabled?
!current_application_settings.import_sources.empty? !current_application_settings.import_sources.empty?
end end
...@@ -363,24 +327,4 @@ class ApplicationController < ActionController::Base ...@@ -363,24 +327,4 @@ class ApplicationController < ActionController::Base
def u2f_app_id def u2f_app_id
request.base_url request.base_url
end end
private
def set_default_sort
key = if is_a_listing_page_for?('issues') || is_a_listing_page_for?('merge_requests')
'issuable_sort'
end
cookies[key] = params[:sort] if key && params[:sort].present?
params[:sort] = cookies[key] if key
params[:sort] ||= 'id_desc'
end
def is_a_listing_page_for?(page_type)
controller_name, action_name = params.values_at(:controller, :action)
(controller_name == "projects/#{page_type}" && action_name == 'index') ||
(controller_name == 'groups' && action_name == page_type) ||
(controller_name == 'dashboard' && action_name == page_type)
end
end end
...@@ -5,6 +5,7 @@ class AutocompleteController < ApplicationController ...@@ -5,6 +5,7 @@ class AutocompleteController < ApplicationController
def users def users
@users ||= User.none @users ||= User.none
@users = @users.search(params[:search]) if params[:search].present? @users = @users.search(params[:search]) if params[:search].present?
@users = @users.where.not(id: params[:skip_users]) if params[:skip_users].present?
@users = @users.active @users = @users.active
@users = @users.reorder(:name) @users = @users.reorder(:name)
@users = @users.page(params[:page]) @users = @users.page(params[:page])
......
module DiffForPath module DiffForPath
extend ActiveSupport::Concern extend ActiveSupport::Concern
def render_diff_for_path(diffs, diff_refs, project) def render_diff_for_path(diffs)
diff_file = safe_diff_files(diffs, diff_refs: diff_refs, repository: project.repository).find do |diff| diff_file = diffs.diff_files.find do |diff|
diff.old_path == params[:old_path] && diff.new_path == params[:new_path] diff.old_path == params[:old_path] && diff.new_path == params[:new_path]
end end
...@@ -14,7 +14,7 @@ module DiffForPath ...@@ -14,7 +14,7 @@ module DiffForPath
locals = { locals = {
diff_file: diff_file, diff_file: diff_file,
diff_commit: diff_commit, diff_commit: diff_commit,
diff_refs: diff_refs, diff_refs: diffs.diff_refs,
blob: blob, blob: blob,
project: project project: project
} }
......
module IssuableCollections
extend ActiveSupport::Concern
include SortingHelper
included do
helper_method :issues_finder
helper_method :merge_requests_finder
end
private
def issues_collection
issues_finder.execute
end
def merge_requests_collection
merge_requests_finder.execute
end
def issues_finder
@issues_finder ||= issuable_finder_for(IssuesFinder)
end
def merge_requests_finder
@merge_requests_finder ||= issuable_finder_for(MergeRequestsFinder)
end
def issuable_finder_for(finder_class)
finder_class.new(current_user, filter_params)
end
def filter_params
set_sort_order_from_cookie
set_default_scope
set_default_state
@filter_params = params.dup
@filter_params[:sort] ||= default_sort_order
@sort = @filter_params[:sort]
if @project
@filter_params[:project_id] = @project.id
elsif @group
@filter_params[:group_id] = @group.id
else
# TODO: this filter ignore issues/mr created in public or
# internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you
# created or assigned or mentioned
# @filter_params[:authorized_only] = true
end
@filter_params
end
def set_default_scope
params[:scope] = 'all' if params[:scope].blank?
end
def set_default_state
params[:state] = 'opened' if params[:state].blank?
end
def set_sort_order_from_cookie
key = 'issuable_sort'
cookies[key] = params[:sort] if params[:sort].present?
params[:sort] = cookies[key]
end
def default_sort_order
case params[:state]
when 'opened', 'all' then sort_value_recently_created
when 'merged', 'closed' then sort_value_recently_updated
else sort_value_recently_created
end
end
end
module IssuesAction module IssuesAction
extend ActiveSupport::Concern extend ActiveSupport::Concern
include IssuableCollections
def issues def issues
@issues = get_issues_collection.non_archived @label = issues_finder.labels.first
@issues = @issues.page(params[:page])
@issues = @issues.preload(:author, :project)
@label = @issuable_finder.labels.first @issues = issues_collection
.non_archived
.preload(:author, :project)
.page(params[:page])
respond_to do |format| respond_to do |format|
format.html format.html
......
module MergeRequestsAction module MergeRequestsAction
extend ActiveSupport::Concern extend ActiveSupport::Concern
include IssuableCollections
def merge_requests def merge_requests
@merge_requests = get_merge_requests_collection.non_archived @label = merge_requests_finder.labels.first
@merge_requests = @merge_requests.page(params[:page])
@merge_requests = @merge_requests.preload(:author, :target_project)
@label = @issuable_finder.labels.first @merge_requests = merge_requests_collection
.non_archived
.preload(:author, :target_project)
.page(params[:page])
end end
end end
class Explore::ApplicationController < ApplicationController class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked skip_before_action :authenticate_user!, :reject_blocked!
layout 'explore' layout 'explore'
end end
class HelpController < ApplicationController class HelpController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked skip_before_action :authenticate_user!, :reject_blocked!
layout 'help' layout 'help'
......
...@@ -82,8 +82,6 @@ class Import::BitbucketController < Import::BaseController ...@@ -82,8 +82,6 @@ class Import::BitbucketController < Import::BaseController
go_to_bitbucket_for_permissions go_to_bitbucket_for_permissions
end end
private
def access_params def access_params
{ {
bitbucket_access_token: session[:bitbucket_access_token], bitbucket_access_token: session[:bitbucket_access_token],
......
...@@ -61,8 +61,6 @@ class Import::GitlabController < Import::BaseController ...@@ -61,8 +61,6 @@ class Import::GitlabController < Import::BaseController
go_to_gitlab_for_permissions go_to_gitlab_for_permissions
end end
private
def access_params def access_params
{ gitlab_access_token: session[:gitlab_access_token] } { gitlab_access_token: session[:gitlab_access_token] }
end end
......
...@@ -12,13 +12,14 @@ class Import::GitlabProjectsController < Import::BaseController ...@@ -12,13 +12,14 @@ class Import::GitlabProjectsController < Import::BaseController
return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive." }) return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive." })
end end
imported_file = project_params[:file].path + "-import" import_upload_path = Gitlab::ImportExport.import_upload_path(filename: project_params[:file].original_filename)
FileUtils.copy_entry(project_params[:file].path, imported_file) FileUtils.mkdir_p(File.dirname(import_upload_path))
FileUtils.copy_entry(project_params[:file].path, import_upload_path)
@project = Gitlab::ImportExport::ProjectCreator.new(project_params[:namespace_id], @project = Gitlab::ImportExport::ProjectCreator.new(project_params[:namespace_id],
current_user, current_user,
File.expand_path(imported_file), import_upload_path,
project_params[:path]).execute project_params[:path]).execute
if @project.saved? if @project.saved?
......
...@@ -76,6 +76,8 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -76,6 +76,8 @@ class Projects::BlobController < Projects::ApplicationController
end end
def diff def diff
apply_diff_view_cookie!
@form = UnfoldForm.new(params) @form = UnfoldForm.new(params)
@lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path) @lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path)
@lines = @lines[@form.since - 1..@form.to - 1] @lines = @lines[@form.since - 1..@form.to - 1]
......
...@@ -6,6 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -6,6 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy] before_action :authorize_push_code!, only: [:new, :create, :destroy]
def index def index
@sort = params[:sort].presence || 'name'
@branches = BranchesFinder.new(@repository, params).execute @branches = BranchesFinder.new(@repository, params).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page]) @branches = Kaminari.paginate_array(@branches).page(params[:page])
......
...@@ -28,7 +28,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -28,7 +28,7 @@ class Projects::CommitController < Projects::ApplicationController
end end
def diff_for_path def diff_for_path
render_diff_for_path(@diffs, @commit.diff_refs, @project) render_diff_for_path(@commit.diffs(diff_options))
end end
def builds def builds
......
...@@ -21,7 +21,7 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -21,7 +21,7 @@ class Projects::CompareController < Projects::ApplicationController
def diff_for_path def diff_for_path
return render_404 unless @compare return render_404 unless @compare
render_diff_for_path(@diffs, @diff_refs, @project) render_diff_for_path(@compare.diffs(diff_options))
end end
def create def create
...@@ -40,18 +40,12 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -40,18 +40,12 @@ class Projects::CompareController < Projects::ApplicationController
@compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref) @compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref)
if @compare if @compare
@commits = Commit.decorate(@compare.commits, @project) @commits = @compare.commits
@start_commit = @compare.start_commit
@start_commit = @project.commit(@start_ref) @commit = @compare.commit
@commit = @project.commit(@head_ref) @base_commit = @compare.base_commit
@base_commit = @project.merge_base_commit(@start_ref, @head_ref)
@diffs = @compare.diffs(diff_options) @diffs = @compare.diffs(diff_options)
@diff_refs = Gitlab::Diff::DiffRefs.new(
base_sha: @base_commit.try(:sha),
start_sha: @start_commit.try(:sha),
head_sha: @commit.try(:sha)
)
@diff_notes_disabled = true @diff_notes_disabled = true
@grouped_diff_discussions = {} @grouped_diff_discussions = {}
......
...@@ -2,8 +2,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -2,8 +2,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
layout 'project' layout 'project'
before_action :authorize_read_environment! before_action :authorize_read_environment!
before_action :authorize_create_environment!, only: [:new, :create] before_action :authorize_create_environment!, only: [:new, :create]
before_action :authorize_update_environment!, only: [:destroy] before_action :authorize_update_environment!, only: [:edit, :update, :destroy]
before_action :environment, only: [:show, :destroy] before_action :environment, only: [:show, :edit, :update, :destroy]
def index def index
@environments = project.environments @environments = project.environments
...@@ -17,13 +17,24 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -17,13 +17,24 @@ class Projects::EnvironmentsController < Projects::ApplicationController
@environment = project.environments.new @environment = project.environments.new
end end
def edit
end
def create def create
@environment = project.environments.create(create_params) @environment = project.environments.create(environment_params)
if @environment.persisted? if @environment.persisted?
redirect_to namespace_project_environment_path(project.namespace, project, @environment) redirect_to namespace_project_environment_path(project.namespace, project, @environment)
else else
render 'new' render :new
end
end
def update
if @environment.update(environment_params)
redirect_to namespace_project_environment_path(project.namespace, project, @environment)
else
render :edit
end end
end end
...@@ -39,8 +50,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -39,8 +50,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
private private
def create_params def environment_params
params.require(:environment).permit(:name) params.require(:environment).permit(:name, :external_url)
end end
def environment def environment
......
...@@ -3,7 +3,9 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -3,7 +3,9 @@ class Projects::IssuesController < Projects::ApplicationController
include ToggleSubscriptionAction include ToggleSubscriptionAction
include IssuableActions include IssuableActions
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests, before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
:related_branches, :can_create_branch] :related_branches, :can_create_branch]
...@@ -24,7 +26,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -24,7 +26,7 @@ class Projects::IssuesController < Projects::ApplicationController
def index def index
terms = params['issue_search'] terms = params['issue_search']
@issues = get_issues_collection @issues = issues_collection
if terms.present? if terms.present?
if terms =~ /\A#(\d+)\z/ if terms =~ /\A#(\d+)\z/
...@@ -82,7 +84,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -82,7 +84,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def create def create
@issue = Issues::CreateService.new(project, current_user, issue_params).execute @issue = Issues::CreateService.new(project, current_user, issue_params.merge(request: request)).execute
respond_to do |format| respond_to do |format|
format.html do format.html do
...@@ -92,7 +94,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -92,7 +94,7 @@ class Projects::IssuesController < Projects::ApplicationController
render :new render :new
end end
end end
format.js do |format| format.js do
@link = @issue.attachment.url.to_js @link = @issue.attachment.url.to_js
end end
end end
...@@ -200,6 +202,18 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -200,6 +202,18 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless @project.issues_enabled && @project.default_issues_tracker? return render_404 unless @project.issues_enabled && @project.default_issues_tracker?
end end
def redirect_to_external_issue_tracker
external = @project.external_issue_tracker
return unless external
if action_name == 'new'
redirect_to external.new_issue_path
else
redirect_to external.issues_url
end
end
# Since iids are implemented only in 6.1 # Since iids are implemented only in 6.1
# user may navigate to issue page using old global ids. # user may navigate to issue page using old global ids.
# #
......
...@@ -5,6 +5,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -5,6 +5,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include IssuableActions include IssuableActions
include NotesHelper include NotesHelper
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections
before_action :module_enabled before_action :module_enabled
before_action :merge_request, only: [ before_action :merge_request, only: [
...@@ -29,7 +30,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -29,7 +30,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def index def index
terms = params['issue_search'] terms = params['issue_search']
@merge_requests = get_merge_requests_collection @merge_requests = merge_requests_collection
if terms.present? if terms.present?
if terms =~ /\A[#!](\d+)\z/ if terms =~ /\A[#!](\d+)\z/
...@@ -84,7 +85,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -84,7 +85,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html { define_discussion_vars } format.html { define_discussion_vars }
format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } } format.json do
@diffs = @merge_request.diffs(diff_options)
render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") }
end
end end
end end
...@@ -102,9 +107,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -102,9 +107,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
define_commit_vars define_commit_vars
diffs = @merge_request.diffs(diff_options)
render_diff_for_path(diffs, @merge_request.diff_refs, @merge_request.project) render_diff_for_path(@merge_request.diffs(diff_options))
end end
def commits def commits
...@@ -152,7 +156,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -152,7 +156,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@commits = @merge_request.compare_commits.reverse @commits = @merge_request.compare_commits.reverse
@commit = @merge_request.diff_head_commit @commit = @merge_request.diff_head_commit
@base_commit = @merge_request.diff_base_commit @base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diffs = @merge_request.diffs(diff_options) if @merge_request.compare
@diff_notes_disabled = true @diff_notes_disabled = true
@pipeline = @merge_request.pipeline @pipeline = @merge_request.pipeline
...@@ -377,6 +381,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -377,6 +381,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
fresh. fresh.
discussions discussions
preload_noteable_for_regular_notes(@discussions.flat_map(&:notes))
# This is not executed lazily # This is not executed lazily
@notes = Banzai::NoteRenderer.render( @notes = Banzai::NoteRenderer.render(
@discussions.flat_map(&:notes), @discussions.flat_map(&:notes),
...@@ -407,7 +413,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -407,7 +413,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
} }
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes? @use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
@grouped_diff_discussions = @merge_request.notes.grouped_diff_discussions @grouped_diff_discussions = @merge_request.notes.inc_author_project_award_emoji.grouped_diff_discussions
Banzai::NoteRenderer.render( Banzai::NoteRenderer.render(
@grouped_diff_discussions.values.flat_map(&:notes), @grouped_diff_discussions.values.flat_map(&:notes),
......
...@@ -3,19 +3,24 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -3,19 +3,24 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :load_protected_branch, only: [:show, :update, :destroy] before_action :load_protected_branch, only: [:show, :update, :destroy]
before_action :load_protected_branches, only: [:index]
layout "project_settings" layout "project_settings"
def index def index
@protected_branches = @project.protected_branches.order(:name).page(params[:page])
@protected_branch = @project.protected_branches.new @protected_branch = @project.protected_branches.new
gon.push({ open_branches: @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } } }) load_protected_branches_gon_variables
end end
def create def create
@project.protected_branches.create(protected_branch_params) @protected_branch = ProtectedBranches::CreateService.new(@project, current_user, protected_branch_params).execute
redirect_to namespace_project_protected_branches_path(@project.namespace, if @protected_branch.persisted?
@project) redirect_to namespace_project_protected_branches_path(@project.namespace, @project)
else
load_protected_branches
load_protected_branches_gon_variables
render :index
end
end end
def show def show
...@@ -23,7 +28,9 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -23,7 +28,9 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
end end
def update def update
if @protected_branch && @protected_branch.update_attributes(protected_branch_params) @protected_branch = ProtectedBranches::UpdateService.new(@project, current_user, protected_branch_params).execute(@protected_branch)
if @protected_branch.valid?
respond_to do |format| respond_to do |format|
format.json { render json: @protected_branch, status: :ok } format.json { render json: @protected_branch, status: :ok }
end end
...@@ -50,6 +57,18 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -50,6 +57,18 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
end end
def protected_branch_params def protected_branch_params
params.require(:protected_branch).permit(:name, :developers_can_push, :developers_can_merge) params.require(:protected_branch).permit(:name,
merge_access_level_attributes: [:access_level],
push_access_level_attributes: [:access_level])
end
def load_protected_branches
@protected_branches = @project.protected_branches.order(:name).page(params[:page])
end
def load_protected_branches_gon_variables
gon.push({ open_branches: @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } },
push_access_levels: ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text } },
merge_access_levels: ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text } } })
end end
end end
...@@ -97,7 +97,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -97,7 +97,7 @@ class ProjectsController < Projects::ApplicationController
end end
if @project.pending_delete? if @project.pending_delete?
flash[:alert] = "Project queued for delete." flash[:alert] = "Project #{@project.name} queued for deletion."
end end
respond_to do |format| respond_to do |format|
......
class SearchController < ApplicationController class SearchController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked skip_before_action :authenticate_user!, :reject_blocked!
include SearchHelper include SearchHelper
......
...@@ -101,7 +101,7 @@ class SessionsController < Devise::SessionsController ...@@ -101,7 +101,7 @@ class SessionsController < Devise::SessionsController
# Prevent alert from popping up on the first page shown after authentication. # Prevent alert from popping up on the first page shown after authentication.
flash[:alert] = nil flash[:alert] = nil
redirect_to user_omniauth_authorize_path(provider.to_sym) redirect_to omniauth_authorize_path(:user, provider)
end end
def valid_otp_attempt?(user) def valid_otp_attempt?(user)
......
...@@ -109,7 +109,7 @@ class IssuableFinder ...@@ -109,7 +109,7 @@ class IssuableFinder
scope.where(title: params[:milestone_title]) scope.where(title: params[:milestone_title])
else else
nil Milestone.none
end end
end end
......
...@@ -163,9 +163,13 @@ module ApplicationHelper ...@@ -163,9 +163,13 @@ module ApplicationHelper
# `html_class` argument is provided. # `html_class` argument is provided.
# #
# Returns an HTML-safe String # Returns an HTML-safe String
def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false) def time_ago_with_tooltip(time, placement: 'top', html_class: '', skip_js: false, short_format: false)
css_classes = short_format ? 'js-short-timeago' : 'js-timeago'
css_classes << " #{html_class}" unless html_class.blank?
css_classes << ' js-timeago-pending' unless skip_js
element = content_tag :time, time.to_s, element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago #{"js-timeago-pending" unless skip_js}", class: css_classes,
datetime: time.to_time.getutc.iso8601, datetime: time.to_time.getutc.iso8601,
title: time.to_time.in_time_zone.to_s(:medium), title: time.to_time.in_time_zone.to_s(:medium),
data: { toggle: 'tooltip', placement: placement, container: 'body' } data: { toggle: 'tooltip', placement: placement, container: 'body' }
...@@ -245,7 +249,6 @@ module ApplicationHelper ...@@ -245,7 +249,6 @@ module ApplicationHelper
milestone_title: params[:milestone_title], milestone_title: params[:milestone_title],
assignee_id: params[:assignee_id], assignee_id: params[:assignee_id],
author_id: params[:author_id], author_id: params[:author_id],
sort: params[:sort],
issue_search: params[:issue_search], issue_search: params[:issue_search],
label_name: params[:label_name] label_name: params[:label_name]
} }
......
...@@ -13,7 +13,7 @@ module BlobHelper ...@@ -13,7 +13,7 @@ module BlobHelper
blob = project.repository.blob_at(ref, path) rescue nil blob = project.repository.blob_at(ref, path) rescue nil
return unless blob && blob_text_viewable?(blob) return unless blob
from_mr = options[:from_merge_request_id] from_mr = options[:from_merge_request_id]
link_opts = {} link_opts = {}
......
...@@ -206,10 +206,10 @@ module CommitsHelper ...@@ -206,10 +206,10 @@ module CommitsHelper
end end
end end
def view_file_btn(commit_sha, diff, project) def view_file_btn(commit_sha, diff_new_path, project)
link_to( link_to(
namespace_project_blob_path(project.namespace, project, namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff.new_path)), tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file btn-file-option' class: 'btn view-file js-view-file btn-file-option'
) do ) do
raw('View file @') + content_tag(:span, commit_sha[0..6], raw('View file @') + content_tag(:span, commit_sha[0..6],
......
...@@ -13,12 +13,11 @@ module DiffHelper ...@@ -13,12 +13,11 @@ module DiffHelper
end end
def diff_view def diff_view
diff_views = %w(inline parallel) @diff_view ||= begin
diff_views = %w(inline parallel)
if diff_views.include?(cookies[:diff_view]) diff_view = cookies[:diff_view]
cookies[:diff_view] diff_view = diff_views.first unless diff_views.include?(diff_view)
else diff_view.to_sym
diff_views.first
end end
end end
...@@ -30,19 +29,26 @@ module DiffHelper ...@@ -30,19 +29,26 @@ module DiffHelper
options[:paths] = params.values_at(:old_path, :new_path) options[:paths] = params.values_at(:old_path, :new_path)
end end
Commit.max_diff_options.merge(options) options
end end
def safe_diff_files(diffs, diff_refs: nil, repository: nil) def diff_match_line(old_pos, new_pos, text: '', view: :inline, bottom: false)
diffs.decorate! { |diff| Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) } content = content_tag :td, text, class: "line_content match #{view == :inline ? '' : view}"
end cls = ['diff-line-num', 'unfold', 'js-unfold']
cls << 'js-unfold-bottom' if bottom
def unfold_bottom_class(bottom) html = ''
bottom ? 'js-unfold js-unfold-bottom' : '' if old_pos
end html << content_tag(:td, '...', class: cls + ['old_line'], data: { linenumber: old_pos })
html << content unless view == :inline
end
def unfold_class(unfold) if new_pos
unfold ? 'unfold js-unfold' : '' html << content_tag(:td, '...', class: cls + ['new_line'], data: { linenumber: new_pos })
html << content
end
html.html_safe
end end
def diff_line_content(line, line_type = nil) def diff_line_content(line, line_type = nil)
...@@ -71,11 +77,11 @@ module DiffHelper ...@@ -71,11 +77,11 @@ module DiffHelper
end end
def inline_diff_btn def inline_diff_btn
diff_btn('Inline', 'inline', diff_view == 'inline') diff_btn('Inline', 'inline', diff_view == :inline)
end end
def parallel_diff_btn def parallel_diff_btn
diff_btn('Side-by-side', 'parallel', diff_view == 'parallel') diff_btn('Side-by-side', 'parallel', diff_view == :parallel)
end end
def submodule_link(blob, ref, repository = @repository) def submodule_link(blob, ref, repository = @repository)
...@@ -107,7 +113,8 @@ module DiffHelper ...@@ -107,7 +113,8 @@ module DiffHelper
commit = commit_for_diff(diff_file) commit = commit_for_diff(diff_file)
{ {
blob_diff_path: namespace_project_blob_diff_path(project.namespace, project, blob_diff_path: namespace_project_blob_diff_path(project.namespace, project,
tree_join(commit.id, diff_file.file_path)) tree_join(commit.id, diff_file.file_path)),
view: diff_view
} }
end end
...@@ -144,8 +151,6 @@ module DiffHelper ...@@ -144,8 +151,6 @@ module DiffHelper
toggle_whitespace_link(url, options) toggle_whitespace_link(url, options)
end end
private
def hide_whitespace? def hide_whitespace?
params[:w] == '1' params[:w] == '1'
end end
......
...@@ -13,38 +13,6 @@ module IssuesHelper ...@@ -13,38 +13,6 @@ module IssuesHelper
OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned') OpenStruct.new(id: 0, title: 'None (backlog)', name: 'Unassigned')
end end
def url_for_project_issues(project = @project, options = {})
return '' if project.nil?
url =
if options[:only_path]
project.issues_tracker.project_path
else
project.issues_tracker.project_url
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def url_for_new_issue(project = @project, options = {})
return '' if project.nil?
url =
if options[:only_path]
project.issues_tracker.new_issue_path
else
project.issues_tracker.new_issue_url
end
# Ensure we return a valid URL to prevent possible XSS.
URI.parse(url).to_s
rescue URI::InvalidURIError
''
end
def url_for_issue(issue_iid, project = @project, options = {}) def url_for_issue(issue_iid, project = @project, options = {})
return '' if project.nil? return '' if project.nil?
......
...@@ -92,6 +92,10 @@ module NotesHelper ...@@ -92,6 +92,10 @@ module NotesHelper
project.team.max_member_access_for_user_ids(user_ids) project.team.max_member_access_for_user_ids(user_ids)
end end
def preload_noteable_for_regular_notes(notes)
ActiveRecord::Associations::Preloader.new.preload(notes.select { |note| !note.for_commit? }, :noteable)
end
def note_max_access_for_user(note) def note_max_access_for_user(note)
note.project.team.human_max_access(note.author_id) note.project.team.human_max_access(note.author_id)
end end
......
...@@ -263,6 +263,10 @@ module ProjectsHelper ...@@ -263,6 +263,10 @@ module ProjectsHelper
filename_path(project, :version) filename_path(project, :version)
end end
def ci_configuration_path(project)
filename_path(project, :gitlab_ci_yml)
end
def project_wiki_path_with_version(proj, page, version, is_newest) def project_wiki_path_with_version(proj, page, version, is_newest)
url_params = is_newest ? {} : { version_id: version } url_params = is_newest ? {} : { version_id: version }
namespace_project_wiki_path(proj.namespace, proj, page, url_params) namespace_project_wiki_path(proj.namespace, proj, page, url_params)
......
...@@ -5,21 +5,9 @@ module SelectsHelper ...@@ -5,21 +5,9 @@ module SelectsHelper
css_class << "skip_ldap " if opts[:skip_ldap] css_class << "skip_ldap " if opts[:skip_ldap]
css_class << (opts[:class] || '') css_class << (opts[:class] || '')
value = opts[:selected] || '' value = opts[:selected] || ''
first_user = opts[:first_user] && current_user ? current_user.username : false
html = { html = {
class: css_class, class: css_class,
data: { data: users_select_data_attributes(opts)
placeholder: opts[:placeholder] || 'Search for a user',
null_user: opts[:null_user] || false,
any_user: opts[:any_user] || false,
email_user: opts[:email_user] || false,
first_user: first_user,
current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || ''
}
} }
unless opts[:scope] == :all unless opts[:scope] == :all
...@@ -68,4 +56,20 @@ module SelectsHelper ...@@ -68,4 +56,20 @@ module SelectsHelper
hidden_field_tag(id, value, class: css_class) hidden_field_tag(id, value, class: css_class)
end end
private
def users_select_data_attributes(opts)
{
placeholder: opts[:placeholder] || 'Search for a user',
null_user: opts[:null_user] || false,
any_user: opts[:any_user] || false,
email_user: opts[:email_user] || false,
first_user: opts[:first_user] && current_user ? current_user.username : false,
current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || '',
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
}
end
end end
...@@ -102,11 +102,11 @@ module SortingHelper ...@@ -102,11 +102,11 @@ module SortingHelper
end end
def sort_value_oldest_created def sort_value_oldest_created
'id_asc' 'created_asc'
end end
def sort_value_recently_created def sort_value_recently_created
'id_desc' 'created_desc'
end end
def sort_value_milestone_soon def sort_value_milestone_soon
......
...@@ -6,6 +6,10 @@ class Ability ...@@ -6,6 +6,10 @@ class Ability
return [] unless user.is_a?(User) return [] unless user.is_a?(User)
return [] if user.blocked? return [] if user.blocked?
abilities_by_subject_class(user: user, subject: subject)
end
def abilities_by_subject_class(user:, subject:)
case subject case subject
when CommitStatus then commit_status_abilities(user, subject) when CommitStatus then commit_status_abilities(user, subject)
when Project then project_abilities(user, subject) when Project then project_abilities(user, subject)
...@@ -47,6 +51,16 @@ class Ability ...@@ -47,6 +51,16 @@ class Ability
end end
end end
# Returns an Array of Issues that can be read by the given user.
#
# issues - The issues to reduce down to those readable by the user.
# user - The User for which to check the issues
def issues_readable_by_user(issues, user = nil)
return issues if user && user.admin?
issues.select { |issue| issue.visible_to_user?(user) }
end
# List of possible abilities for anonymous user # List of possible abilities for anonymous user
def anonymous_abilities(user, subject) def anonymous_abilities(user, subject)
if subject.is_a?(PersonalSnippet) if subject.is_a?(PersonalSnippet)
......
...@@ -13,6 +13,7 @@ module Ci ...@@ -13,6 +13,7 @@ module Ci
scope :unstarted, ->() { where(runner_id: nil) } scope :unstarted, ->() { where(runner_id: nil) }
scope :ignore_failures, ->() { where(allow_failure: false) } scope :ignore_failures, ->() { where(allow_failure: false) }
scope :with_artifacts, ->() { where.not(artifacts_file: [nil, '']) } scope :with_artifacts, ->() { where.not(artifacts_file: [nil, '']) }
scope :with_artifacts_not_expired, ->() { with_artifacts.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) } scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) } scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
scope :manual_actions, ->() { where(when: :manual) } scope :manual_actions, ->() { where(when: :manual) }
...@@ -331,7 +332,7 @@ module Ci ...@@ -331,7 +332,7 @@ module Ci
end end
def valid_token?(token) def valid_token?(token)
project.valid_runners_token? token project.valid_runners_token?(token)
end end
def has_tags? def has_tags?
......
...@@ -104,7 +104,7 @@ class Commit ...@@ -104,7 +104,7 @@ class Commit
end end
def diff_line_count def diff_line_count
@diff_line_count ||= Commit::diff_line_count(self.diffs) @diff_line_count ||= Commit::diff_line_count(raw_diffs)
@diff_line_count @diff_line_count
end end
...@@ -123,15 +123,17 @@ class Commit ...@@ -123,15 +123,17 @@ class Commit
# In case this first line is longer than 100 characters, it is cut off # In case this first line is longer than 100 characters, it is cut off
# after 80 characters and ellipses (`&hellp;`) are appended. # after 80 characters and ellipses (`&hellp;`) are appended.
def title def title
title = safe_message full_title.length > 100 ? full_title[0..79] << "…" : full_title
end
return no_commit_message if title.blank? # Returns the full commits title
def full_title
return @full_title if @full_title
title_end = title.index("\n") if safe_message.blank?
if (!title_end && title.length > 100) || (title_end && title_end > 100) @full_title = no_commit_message
title[0..79] << "…"
else else
title.split("\n", 2).first @full_title = safe_message.split("\n", 2).first
end end
end end
...@@ -178,7 +180,18 @@ class Commit ...@@ -178,7 +180,18 @@ class Commit
end end
def author def author
@author ||= User.find_by_any_email(author_email.downcase) if RequestStore.active?
key = "commit_author:#{author_email.downcase}"
# nil is a valid value since no author may exist in the system
if RequestStore.store.has_key?(key)
@author = RequestStore.store[key]
else
@author = find_author_by_any_email
RequestStore.store[key] = @author
end
else
@author ||= find_author_by_any_email
end
end end
def committer def committer
...@@ -304,12 +317,24 @@ class Commit ...@@ -304,12 +317,24 @@ class Commit
nil nil
end end
def raw_diffs(*args)
raw.diffs(*args)
end
def diffs(diff_options = nil)
Gitlab::Diff::FileCollection::Commit.new(self, diff_options: diff_options)
end
private private
def find_author_by_any_email
User.find_by_any_email(author_email.downcase)
end
def repo_changes def repo_changes
changes = { added: [], modified: [], removed: [] } changes = { added: [], modified: [], removed: [] }
diffs.each do |diff| raw_diffs(deltas_only: true).each do |diff|
if diff.deleted_file if diff.deleted_file
changes[:removed] << diff.old_path changes[:removed] << diff.old_path
elsif diff.renamed_file || diff.new_file elsif diff.renamed_file || diff.new_file
......
class Compare
delegate :same, :head, :base, to: :@compare
attr_reader :project
def self.decorate(compare, project)
if compare.is_a?(Compare)
compare
else
self.new(compare, project)
end
end
def initialize(compare, project)
@compare = compare
@project = project
end
def commits
@commits ||= Commit.decorate(@compare.commits, project)
end
def start_commit
return @start_commit if defined?(@start_commit)
commit = @compare.base
@start_commit = commit ? ::Commit.new(commit, project) : nil
end
def head_commit
return @head_commit if defined?(@head_commit)
commit = @compare.head
@head_commit = commit ? ::Commit.new(commit, project) : nil
end
alias_method :commit, :head_commit
def base_commit
return @base_commit if defined?(@base_commit)
@base_commit = if start_commit && head_commit
project.merge_base_commit(start_commit.id, head_commit.id)
else
nil
end
end
def raw_diffs(*args)
@compare.diffs(*args)
end
def diffs(diff_options = nil)
Gitlab::Diff::FileCollection::Compare.new(self,
project: project,
diff_options: diff_options,
diff_refs: diff_refs)
end
def diff_refs
Gitlab::Diff::DiffRefs.new(
base_sha: base_commit.try(:sha),
start_sha: start_commit.try(:sha),
head_sha: commit.try(:sha)
)
end
end
...@@ -17,7 +17,7 @@ module Issuable ...@@ -17,7 +17,7 @@ module Issuable
belongs_to :assignee, class_name: "User" belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
belongs_to :milestone belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy do has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy do
def authors_loaded? def authors_loaded?
# We check first if we're loaded to not load unnecessarily. # We check first if we're loaded to not load unnecessarily.
loaded? && to_a.all? { |note| note.association(:author).loaded? } loaded? && to_a.all? { |note| note.association(:author).loaded? }
......
module Spammable
extend ActiveSupport::Concern
included do
attr_accessor :spam
after_validation :check_for_spam, on: :create
end
def spam?
@spam
end
def check_for_spam
self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
end
end
module TokenAuthenticatable module TokenAuthenticatable
extend ActiveSupport::Concern extend ActiveSupport::Concern
private
def write_new_token(token_field)
new_token = generate_token(token_field)
write_attribute(token_field, new_token)
end
def generate_token(token_field)
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.find_by(token_field => token)
end
end
class_methods do class_methods do
def authentication_token_fields def authentication_token_fields
@token_fields || [] @token_fields || []
end end
private private # rubocop:disable Lint/UselessAccessModifier
def add_authentication_token_field(token_field) def add_authentication_token_field(token_field)
@token_fields = [] unless @token_fields @token_fields = [] unless @token_fields
...@@ -32,18 +46,4 @@ module TokenAuthenticatable ...@@ -32,18 +46,4 @@ module TokenAuthenticatable
end end
end end
end end
private
def write_new_token(token_field)
new_token = generate_token(token_field)
write_attribute(token_field, new_token)
end
def generate_token(token_field)
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.find_by(token_field => token)
end
end
end end
...@@ -67,7 +67,7 @@ class DiffNote < Note ...@@ -67,7 +67,7 @@ class DiffNote < Note
return false unless supported? return false unless supported?
return true if for_commit? return true if for_commit?
diff_refs ||= self.noteable.diff_refs diff_refs ||= noteable_diff_refs
self.position.diff_refs == diff_refs self.position.diff_refs == diff_refs
end end
...@@ -78,6 +78,14 @@ class DiffNote < Note ...@@ -78,6 +78,14 @@ class DiffNote < Note
!self.for_merge_request? || self.noteable.support_new_diff_notes? !self.for_merge_request? || self.noteable.support_new_diff_notes?
end end
def noteable_diff_refs
if noteable.respond_to?(:diff_sha_refs)
noteable.diff_sha_refs
else
noteable.diff_refs
end
end
def set_original_position def set_original_position
self.original_position = self.position.dup self.original_position = self.position.dup
end end
...@@ -96,7 +104,7 @@ class DiffNote < Note ...@@ -96,7 +104,7 @@ class DiffNote < Note
self.project, self.project,
nil, nil,
old_diff_refs: self.position.diff_refs, old_diff_refs: self.position.diff_refs,
new_diff_refs: self.noteable.diff_refs, new_diff_refs: noteable_diff_refs,
paths: self.position.paths paths: self.position.paths
).execute(self) ).execute(self)
end end
......
...@@ -49,6 +49,12 @@ class Discussion ...@@ -49,6 +49,12 @@ class Discussion
self.noteable == target && !diff_discussion? self.noteable == target && !diff_discussion?
end end
def active?
return @active if defined?(@active)
@active = first_note.active?
end
def expanded? def expanded?
!diff_discussion? || active? !diff_discussion? || active?
end end
......
...@@ -3,6 +3,8 @@ class Environment < ActiveRecord::Base ...@@ -3,6 +3,8 @@ class Environment < ActiveRecord::Base
has_many :deployments has_many :deployments
before_validation :nullify_external_url
validates :name, validates :name,
presence: true, presence: true,
uniqueness: { scope: :project_id }, uniqueness: { scope: :project_id },
...@@ -10,7 +12,17 @@ class Environment < ActiveRecord::Base ...@@ -10,7 +12,17 @@ class Environment < ActiveRecord::Base
format: { with: Gitlab::Regex.environment_name_regex, format: { with: Gitlab::Regex.environment_name_regex,
message: Gitlab::Regex.environment_name_regex_message } message: Gitlab::Regex.environment_name_regex_message }
validates :external_url,
uniqueness: { scope: :project_id },
length: { maximum: 255 },
allow_nil: true,
addressable_url: true
def last_deployment def last_deployment
deployments.last deployments.last
end end
def nullify_external_url
self.external_url = nil if self.external_url.blank?
end
end end
...@@ -6,6 +6,7 @@ class Issue < ActiveRecord::Base ...@@ -6,6 +6,7 @@ class Issue < ActiveRecord::Base
include Referable include Referable
include Sortable include Sortable
include Taskable include Taskable
include Spammable
DueDateStruct = Struct.new(:title, :name).freeze DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
...@@ -229,6 +230,34 @@ class Issue < ActiveRecord::Base ...@@ -229,6 +230,34 @@ class Issue < ActiveRecord::Base
self.closed_by_merge_requests(current_user).empty? self.closed_by_merge_requests(current_user).empty?
end end
# Returns `true` if the current issue can be viewed by either a logged in User
# or an anonymous user.
def visible_to_user?(user = nil)
user ? readable_by?(user) : publicly_visible?
end
# Returns `true` if the given User can read the current Issue.
def readable_by?(user)
if user.admin?
true
elsif project.owner == user
true
elsif confidential?
author == user ||
assignee == user ||
project.team.member?(user, Gitlab::Access::REPORTER)
else
project.public? ||
project.internal? && !user.external? ||
project.team.member?(user)
end
end
# Returns `true` if this Issue is visible to everybody.
def publicly_visible?
project.public? && !confidential?
end
def overdue? def overdue?
due_date.try(:past?) || false due_date.try(:past?) || false
end end
......
...@@ -26,8 +26,9 @@ class Key < ActiveRecord::Base ...@@ -26,8 +26,9 @@ class Key < ActiveRecord::Base
end end
def publishable_key def publishable_key
# Removes anything beyond the keytype and key itself # Strip out the keys comment so we don't leak email addresses
self.key.split[0..1].join(' ') # Replace with simple ident of user_name (hostname)
self.key.split[0..1].push("#{self.user_name} (#{Gitlab.config.gitlab.host})").join(' ')
end end
# projects that has this key # projects that has this key
......
class LabelLink < ActiveRecord::Base class LabelLink < ActiveRecord::Base
include Importable
belongs_to :target, polymorphic: true belongs_to :target, polymorphic: true
belongs_to :label belongs_to :label
validates :target, presence: true validates :target, presence: true, unless: :importing?
validates :label, presence: true validates :label, presence: true, unless: :importing?
end end
...@@ -25,6 +25,14 @@ class LegacyDiffNote < Note ...@@ -25,6 +25,14 @@ class LegacyDiffNote < Note
@discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code) @discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code)
end end
def project_repository
if RequestStore.active?
RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
else
self.project.repository
end
end
def diff_file_hash def diff_file_hash
line_code.split('_')[0] if line_code line_code.split('_')[0] if line_code
end end
...@@ -34,7 +42,7 @@ class LegacyDiffNote < Note ...@@ -34,7 +42,7 @@ class LegacyDiffNote < Note
end end
def diff_file def diff_file
@diff_file ||= Gitlab::Diff::File.new(diff, repository: self.project.repository) if diff @diff_file ||= Gitlab::Diff::File.new(diff, repository: project_repository) if diff
end end
def diff_line def diff_line
...@@ -77,7 +85,7 @@ class LegacyDiffNote < Note ...@@ -77,7 +85,7 @@ class LegacyDiffNote < Note
return nil unless noteable return nil unless noteable
return @diff if defined?(@diff) return @diff if defined?(@diff)
@diff = noteable.diffs(Commit.max_diff_options).find do |d| @diff = noteable.raw_diffs(Commit.max_diff_options).find do |d|
d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
end end
end end
...@@ -108,7 +116,7 @@ class LegacyDiffNote < Note ...@@ -108,7 +116,7 @@ class LegacyDiffNote < Note
# Find the diff on noteable that matches our own # Find the diff on noteable that matches our own
def find_noteable_diff def find_noteable_diff
diffs = noteable.diffs(Commit.max_diff_options) diffs = noteable.raw_diffs(Commit.max_diff_options)
diffs.find { |d| d.new_path == self.diff.new_path } diffs.find { |d| d.new_path == self.diff.new_path }
end end
end end
...@@ -21,19 +21,19 @@ class ProjectMember < Member ...@@ -21,19 +21,19 @@ class ProjectMember < Member
# or symbol like :master representing role # or symbol like :master representing role
# #
# Ex. # Ex.
# add_users_into_projects( # add_users_to_projects(
# project_ids, # project_ids,
# user_ids, # user_ids,
# ProjectMember::MASTER # ProjectMember::MASTER
# ) # )
# #
# add_users_into_projects( # add_users_to_projects(
# project_ids, # project_ids,
# user_ids, # user_ids,
# :master # :master
# ) # )
# #
def add_users_into_projects(project_ids, user_ids, access, current_user = nil) def add_users_to_projects(project_ids, user_ids, access, current_user = nil)
access_level = if roles_hash.has_key?(access) access_level = if roles_hash.has_key?(access)
roles_hash[access] roles_hash[access]
elsif roles_hash.values.include?(access.to_i) elsif roles_hash.values.include?(access.to_i)
......
...@@ -164,8 +164,16 @@ class MergeRequest < ActiveRecord::Base ...@@ -164,8 +164,16 @@ class MergeRequest < ActiveRecord::Base
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end end
def diffs(*args) def raw_diffs(*args)
merge_request_diff ? merge_request_diff.diffs(*args) : compare.diffs(*args) merge_request_diff ? merge_request_diff.raw_diffs(*args) : compare.raw_diffs(*args)
end
def diffs(diff_options = nil)
if self.compare
self.compare.diffs(diff_options)
else
Gitlab::Diff::FileCollection::MergeRequest.new(self, diff_options: diff_options)
end
end end
def diff_size def diff_size
...@@ -238,11 +246,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -238,11 +246,11 @@ class MergeRequest < ActiveRecord::Base
end end
def target_branch_sha def target_branch_sha
target_branch_head.try(:sha) @target_branch_sha || target_branch_head.try(:sha)
end end
def source_branch_sha def source_branch_sha
source_branch_head.try(:sha) @source_branch_sha || source_branch_head.try(:sha)
end end
def diff_refs def diff_refs
...@@ -255,6 +263,19 @@ class MergeRequest < ActiveRecord::Base ...@@ -255,6 +263,19 @@ class MergeRequest < ActiveRecord::Base
) )
end end
# Return diff_refs instance trying to not touch the git repository
def diff_sha_refs
if merge_request_diff && merge_request_diff.diff_refs_by_sha?
return Gitlab::Diff::DiffRefs.new(
base_sha: merge_request_diff.base_commit_sha,
start_sha: merge_request_diff.start_commit_sha,
head_sha: merge_request_diff.head_commit_sha
)
else
diff_refs
end
end
def validate_branches def validate_branches
if target_project == source_project && target_branch == source_branch if target_project == source_project && target_branch == source_branch
errors.add :branch_conflict, "You can not use same project/branch for source and target" errors.add :branch_conflict, "You can not use same project/branch for source and target"
...@@ -300,6 +321,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -300,6 +321,8 @@ class MergeRequest < ActiveRecord::Base
merge_request_diff.reload_content merge_request_diff.reload_content
MergeRequests::MergeRequestDiffCacheService.new.execute(self)
new_diff_refs = self.diff_refs new_diff_refs = self.diff_refs
update_diff_notes_positions( update_diff_notes_positions(
...@@ -659,7 +682,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -659,7 +682,7 @@ class MergeRequest < ActiveRecord::Base
end end
def support_new_diff_notes? def support_new_diff_notes?
diff_refs && diff_refs.complete? diff_sha_refs && diff_sha_refs.complete?
end end
def update_diff_notes_positions(old_diff_refs:, new_diff_refs:) def update_diff_notes_positions(old_diff_refs:, new_diff_refs:)
......
...@@ -33,12 +33,12 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -33,12 +33,12 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def size def size
real_size.presence || diffs.size real_size.presence || raw_diffs.size
end end
def diffs(options={}) def raw_diffs(options={})
if options[:ignore_whitespace_change] if options[:ignore_whitespace_change]
@diffs_no_whitespace ||= begin @raw_diffs_no_whitespace ||= begin
compare = Gitlab::Git::Compare.new( compare = Gitlab::Git::Compare.new(
repository.raw_repository, repository.raw_repository,
self.start_commit_sha || self.target_branch_sha, self.start_commit_sha || self.target_branch_sha,
...@@ -47,8 +47,8 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -47,8 +47,8 @@ class MergeRequestDiff < ActiveRecord::Base
compare.diffs(options) compare.diffs(options)
end end
else else
@diffs ||= {} @raw_diffs ||= {}
@diffs[options] ||= load_diffs(st_diffs, options) @raw_diffs[options] ||= load_diffs(st_diffs, options)
end end
end end
...@@ -82,6 +82,10 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -82,6 +82,10 @@ class MergeRequestDiff < ActiveRecord::Base
project.commit(self.head_commit_sha) project.commit(self.head_commit_sha)
end end
def diff_refs_by_sha?
base_commit_sha? && head_commit_sha? && start_commit_sha?
end
def compare def compare
@compare ||= @compare ||=
begin begin
......
...@@ -378,11 +378,6 @@ class Project < ActiveRecord::Base ...@@ -378,11 +378,6 @@ class Project < ActiveRecord::Base
joins(join_body).reorder('join_note_counts.amount DESC') joins(join_body).reorder('join_note_counts.amount DESC')
end end
# Deletes gitlab project export files older than 24 hours
def remove_gitlab_exports!
Gitlab::Popen.popen(%W(find #{Gitlab::ImportExport.storage_path} -not -path #{Gitlab::ImportExport.storage_path} -mmin +1440 -delete))
end
end end
def repository_storage_path def repository_storage_path
...@@ -586,7 +581,11 @@ class Project < ActiveRecord::Base ...@@ -586,7 +581,11 @@ class Project < ActiveRecord::Base
end end
def to_param def to_param
path if persisted? && errors.include?(:path)
path_was
else
path
end
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil)
...@@ -601,6 +600,13 @@ class Project < ActiveRecord::Base ...@@ -601,6 +600,13 @@ class Project < ActiveRecord::Base
web_url.split('://')[1] web_url.split('://')[1]
end end
def new_issue_address(author)
if Gitlab::IncomingEmail.enabled? && author
Gitlab::IncomingEmail.reply_address(
"#{path_with_namespace}+#{author.authentication_token}")
end
end
def build_commit_note(commit) def build_commit_note(commit)
notes.new(commit_id: commit.id, noteable_type: 'Commit') notes.new(commit_id: commit.id, noteable_type: 'Commit')
end end
...@@ -863,14 +869,6 @@ class Project < ActiveRecord::Base ...@@ -863,14 +869,6 @@ class Project < ActiveRecord::Base
ProtectedBranch.matching(branch_name, protected_branches: @protected_branches).present? ProtectedBranch.matching(branch_name, protected_branches: @protected_branches).present?
end end
def developers_can_push_to_protected_branch?(branch_name)
protected_branches.matching(branch_name).any?(&:developers_can_push)
end
def developers_can_merge_to_protected_branch?(branch_name)
protected_branches.matching(branch_name).any?(&:developers_can_merge)
end
def forked? def forked?
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
end end
...@@ -1153,7 +1151,10 @@ class Project < ActiveRecord::Base ...@@ -1153,7 +1151,10 @@ class Project < ActiveRecord::Base
def schedule_delete!(user_id, params) def schedule_delete!(user_id, params)
# Queue this task for after the commit, so once we mark pending_delete it will run # Queue this task for after the commit, so once we mark pending_delete it will run
run_after_commit { ProjectDestroyWorker.perform_async(id, user_id, params) } run_after_commit do
job_id = ProjectDestroyWorker.perform_async(id, user_id, params)
Rails.logger.info("User #{user_id} scheduled destruction of project #{path_with_namespace} with job ID #{job_id}")
end
update_attribute(:pending_delete, true) update_attribute(:pending_delete, true)
end end
...@@ -1247,6 +1248,16 @@ class Project < ActiveRecord::Base ...@@ -1247,6 +1248,16 @@ class Project < ActiveRecord::Base
authorized_for_user_by_shared_projects?(user, min_access_level) authorized_for_user_by_shared_projects?(user, min_access_level)
end end
def append_or_update_attribute(name, value)
old_values = public_send(name.to_s)
if Project.reflect_on_association(name).try(:macro) == :has_many && old_values.any?
update_attribute(name, old_values + value)
else
update_attribute(name, value)
end
end
private private
def authorized_for_user_by_group?(user, min_access_level) def authorized_for_user_by_group?(user, min_access_level)
......
...@@ -46,7 +46,7 @@ class HipchatService < Service ...@@ -46,7 +46,7 @@ class HipchatService < Service
return unless supported_events.include?(data[:object_kind]) return unless supported_events.include?(data[:object_kind])
message = create_message(data) message = create_message(data)
return unless message.present? return unless message.present?
gate[room].send('GitLab', message, message_options) gate[room].send('GitLab', message, message_options(data))
end end
def test(data) def test(data)
...@@ -67,8 +67,8 @@ class HipchatService < Service ...@@ -67,8 +67,8 @@ class HipchatService < Service
@gate ||= HipChat::Client.new(token, options) @gate ||= HipChat::Client.new(token, options)
end end
def message_options def message_options(data = nil)
{ notify: notify.present? && notify == '1', color: color || 'yellow' } { notify: notify.present? && notify == '1', color: message_color(data) }
end end
def create_message(data) def create_message(data)
...@@ -240,6 +240,21 @@ class HipchatService < Service ...@@ -240,6 +240,21 @@ class HipchatService < Service
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
end end
def message_color(data)
build_status_color(data) || color || 'yellow'
end
def build_status_color(data)
return unless data && data[:object_kind] == 'build'
case data[:commit][:status]
when 'success'
'green'
else
'red'
end
end
def project_name def project_name
project.name_with_namespace.gsub(/\s/, '') project.name_with_namespace.gsub(/\s/, '')
end end
......
...@@ -34,7 +34,7 @@ class ProjectTeam ...@@ -34,7 +34,7 @@ class ProjectTeam
end end
def add_users(users, access, current_user = nil) def add_users(users, access, current_user = nil)
ProjectMember.add_users_into_projects( ProjectMember.add_users_to_projects(
[project.id], [project.id],
users, users,
access, access,
...@@ -138,8 +138,13 @@ class ProjectTeam ...@@ -138,8 +138,13 @@ class ProjectTeam
def max_member_access_for_user_ids(user_ids) def max_member_access_for_user_ids(user_ids)
user_ids = user_ids.uniq user_ids = user_ids.uniq
key = "max_member_access:#{project.id}" key = "max_member_access:#{project.id}"
RequestStore.store[key] ||= {}
access = RequestStore.store[key] access = {}
if RequestStore.active?
RequestStore.store[key] ||= {}
access = RequestStore.store[key]
end
# Lookup only the IDs we need # Lookup only the IDs we need
user_ids = user_ids - access.keys user_ids = user_ids - access.keys
......
...@@ -5,6 +5,12 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -5,6 +5,12 @@ class ProtectedBranch < ActiveRecord::Base
validates :name, presence: true validates :name, presence: true
validates :project, presence: true validates :project, presence: true
has_one :merge_access_level, dependent: :destroy
has_one :push_access_level, dependent: :destroy
accepts_nested_attributes_for :push_access_level
accepts_nested_attributes_for :merge_access_level
def commit def commit
project.commit(self.name) project.commit(self.name)
end end
......
class ProtectedBranch::MergeAccessLevel < ActiveRecord::Base
belongs_to :protected_branch
delegate :project, to: :protected_branch
validates :access_level, presence: true, inclusion: { in: [Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER] }
def self.human_access_levels
{
Gitlab::Access::MASTER => "Masters",
Gitlab::Access::DEVELOPER => "Developers + Masters"
}.with_indifferent_access
end
def check_access(user)
return true if user.is_admin?
project.team.max_member_access(user.id) >= access_level
end
def humanize
self.class.human_access_levels[self.access_level]
end
end
class ProtectedBranch::PushAccessLevel < ActiveRecord::Base
belongs_to :protected_branch
delegate :project, to: :protected_branch
validates :access_level, presence: true, inclusion: { in: [Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS] }
def self.human_access_levels
{
Gitlab::Access::MASTER => "Masters",
Gitlab::Access::DEVELOPER => "Developers + Masters",
Gitlab::Access::NO_ACCESS => "No one"
}.with_indifferent_access
end
def check_access(user)
return false if access_level == Gitlab::Access::NO_ACCESS
return true if user.is_admin?
project.team.max_member_access(user.id) >= access_level
end
def humanize
self.class.human_access_levels[self.access_level]
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment