Commit 4899de87 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'ce_upstream' into 'master'

CE upstream

CE changes https://gitlab.com/gitlab-org/gitlab-ce/compare/1d51bc7dfd04886fa5af69a60bb509691d697813...73b4eecddecf1e86d5e0c26166e2027583b680cf

See merge request !752
parents 47317f18 b4cc44cd
...@@ -13,7 +13,7 @@ variables: ...@@ -13,7 +13,7 @@ variables:
ELASTIC_HOST: "registry.gitlab.com-gitlab-org-test-elastic-image" ELASTIC_HOST: "registry.gitlab.com-gitlab-org-test-elastic-image"
RAILS_ENV: "test" RAILS_ENV: "test"
SIMPLECOV: "true" SIMPLECOV: "true"
USE_DB: "true" SETUP_DB: "true"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20" GIT_DEPTH: "20"
PHANTOMJS_VERSION: "2.1.1" PHANTOMJS_VERSION: "2.1.1"
...@@ -24,7 +24,7 @@ before_script: ...@@ -24,7 +24,7 @@ before_script:
- bundle --version - bundle --version
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"'
- retry gem install knapsack - retry gem install knapsack
- '[ "$USE_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate' - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate'
stages: stages:
- prepare - prepare
...@@ -36,7 +36,7 @@ stages: ...@@ -36,7 +36,7 @@ stages:
.knapsack-state: &knapsack-state .knapsack-state: &knapsack-state
services: [] services: []
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false" USE_BUNDLE_INSTALL: "false"
cache: cache:
key: "knapsack" key: "knapsack"
...@@ -198,7 +198,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -198,7 +198,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
.ruby-static-analysis: &ruby-static-analysis .ruby-static-analysis: &ruby-static-analysis
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
.exec: &exec .exec: &exec
...@@ -226,6 +226,23 @@ rake db:migrate:reset: ...@@ -226,6 +226,23 @@ rake db:migrate:reset:
script: script:
- rake db:migrate:reset - rake db:migrate:reset
rake db:seed_fu:
stage: test
<<: *use-db
variables:
SIZE: "1"
SETUP_DB: "false"
RAILS_ENV: "development"
script:
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git
- bundle exec rake db:setup db:seed_fu
artifacts:
when: on_failure
expire_in: 1d
paths:
- log/development.log
teaspoon: teaspoon:
stage: test stage: test
<<: *use-db <<: *use-db
...@@ -274,7 +291,7 @@ coverage: ...@@ -274,7 +291,7 @@ coverage:
stage: post-test stage: post-test
services: [] services: []
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
script: script:
- bundle exec scripts/merge-simplecov - bundle exec scripts/merge-simplecov
...@@ -290,7 +307,7 @@ coverage: ...@@ -290,7 +307,7 @@ coverage:
notify:slack: notify:slack:
stage: post-test stage: post-test
variables: variables:
USE_DB: "false" SETUP_DB: "false"
USE_BUNDLE_INSTALL: "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>"
......
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.12.1 (unreleased) v 8.13.0 (unreleased)
- Speed-up group milestones show page
v 8.12.2 (unreleased)
- Fix Import/Export not recognising correctly the imported services.
v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
- Fix issue with search filter labels not displaying
v 8.12.0 v 8.12.0
- Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251 - Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251
...@@ -11,10 +19,8 @@ v 8.12.0 ...@@ -11,10 +19,8 @@ v 8.12.0
- Cleanup misalignments in Issue list view !6206 - Cleanup misalignments in Issue list view !6206
- Only create a protected branch upon a push to a new branch if a rule for that branch doesn't exist - Only create a protected branch upon a push to a new branch if a rule for that branch doesn't exist
- Prune events older than 12 months. (ritave) - Prune events older than 12 months. (ritave)
- Prevent secrets to be pushed to the repository
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell) - Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- Fix issues/merge-request templates dropdown for forked projects - Fix issues/merge-request templates dropdown for forked projects
- Amends the packager.io configuration file to create a build for Ubuntu 16.04. !6247 (Jon "The Nice Guy" Spriggs)
- Filter tags by name !6121 - Filter tags by name !6121
- Update gitlab shell secret file also when it is empty. !3774 (glensc) - Update gitlab shell secret file also when it is empty. !3774 (glensc)
- Give project selection dropdowns responsive width, make non-wrapping. - Give project selection dropdowns responsive width, make non-wrapping.
...@@ -31,6 +37,7 @@ v 8.12.0 ...@@ -31,6 +37,7 @@ v 8.12.0
- Move pushes_since_gc from the database to Redis - Move pushes_since_gc from the database to Redis
- Limit number of shown environments on Merge Request: show only environments for target_branch, source_branch and tags - Limit number of shown environments on Merge Request: show only environments for target_branch, source_branch and tags
- Add font color contrast to external label in admin area (ClemMakesApps) - Add font color contrast to external label in admin area (ClemMakesApps)
- Fix find file navigation links (ClemMakesApps)
- Change logo animation to CSS (ClemMakesApps) - Change logo animation to CSS (ClemMakesApps)
- Instructions for enabling Git packfile bitmaps !6104 - Instructions for enabling Git packfile bitmaps !6104
- Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint - Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint
...@@ -49,6 +56,7 @@ v 8.12.0 ...@@ -49,6 +56,7 @@ v 8.12.0
- Fix file permissions change when updating a file on the Gitlab UI !5979 - Fix file permissions change when updating a file on the Gitlab UI !5979
- Added horizontal padding on build page sidebar on code coverage block. !6196 (Vitaly Baev) - Added horizontal padding on build page sidebar on code coverage block. !6196 (Vitaly Baev)
- Change merge_error column from string to text type - Change merge_error column from string to text type
- Fix issue with search filter labels not displaying
- Reduce contributions calendar data payload (ClemMakesApps) - Reduce contributions calendar data payload (ClemMakesApps)
- Show all pipelines for merge requests even from discarded commits !6414 - Show all pipelines for merge requests even from discarded commits !6414
- Replace contributions calendar timezone payload with dates (ClemMakesApps) - Replace contributions calendar timezone payload with dates (ClemMakesApps)
...@@ -83,6 +91,7 @@ v 8.12.0 ...@@ -83,6 +91,7 @@ v 8.12.0
- Fix markdown anchor icon interaction (ClemMakesApps) - Fix markdown anchor icon interaction (ClemMakesApps)
- Test migration paths from 8.5 until current release !4874 - Test migration paths from 8.5 until current release !4874
- Replace animateEmoji timeout with eventListener (ClemMakesApps) - Replace animateEmoji timeout with eventListener (ClemMakesApps)
- Show badges in Milestone tabs. !5946 (Dan Rowden)
- Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention)
- Require confirmation when not logged in for unsubscribe links !6223 (Maximiliano Perez Coto) - Require confirmation when not logged in for unsubscribe links !6223 (Maximiliano Perez Coto)
- Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add `wiki_page_events` to project hook APIs (Ben Boeckel)
...@@ -184,6 +193,11 @@ v 8.12.0 ...@@ -184,6 +193,11 @@ v 8.12.0
- Fix non-master branch readme display in tree view - Fix non-master branch readme display in tree view
- Add UX improvements for merge request version diffs - Add UX improvements for merge request version diffs
v 8.11.7
- Avoid conflict with admin labels when importing GitHub labels. !6158
- Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234
- Allow the Rails cookie to be used for API authentication.
v 8.11.6 v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005 - Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
- Make merge conflict file size limit 200 KB, to match the docs. !6052 - Make merge conflict file size limit 200 KB, to match the docs. !6052
...@@ -228,8 +242,6 @@ v 8.11.3 ...@@ -228,8 +242,6 @@ v 8.11.3
- Allow system info page to handle case where info is unavailable - Allow system info page to handle case where info is unavailable
- Label list shows all issues (opened or closed) with that label - Label list shows all issues (opened or closed) with that label
- Don't show resolve conflicts link before MR status is updated - Don't show resolve conflicts link before MR status is updated
- Fix "Wiki" link not appearing in navigation for projects with external wiki
- Fix IE11 fork button bug !598
- Fix IE11 fork button bug !5982 - Fix IE11 fork button bug !5982
- Don't prevent viewing the MR when git refs for conflicts can't be found on disk - Don't prevent viewing the MR when git refs for conflicts can't be found on disk
- Fix external issue tracker "Issues" link leading to 404s - Fix external issue tracker "Issues" link leading to 404s
...@@ -254,7 +266,6 @@ v 8.11.0 ...@@ -254,7 +266,6 @@ v 8.11.0
- Add Koding (online IDE) integration - Add Koding (online IDE) integration
- Ability to specify branches for Pivotal Tracker integration (Egor Lynko) - Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres) - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
- Add delimiter to project stars and forks count (ClemMakesApps)
- Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres) - Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
- Fix adding line comments on the initial commit to a repo !5900 - Fix adding line comments on the initial commit to a repo !5900
- Fix the title of the toggle dropdown button. !5515 (herminiotorres) - Fix the title of the toggle dropdown button. !5515 (herminiotorres)
...@@ -308,7 +319,6 @@ v 8.11.0 ...@@ -308,7 +319,6 @@ v 8.11.0
- Enforce 2FA restrictions on API authentication endpoints !5820 - Enforce 2FA restrictions on API authentication endpoints !5820
- Limit git rev-list output count to one in forced push check - Limit git rev-list output count to one in forced push check
- Show deployment status on merge requests with external URLs - Show deployment status on merge requests with external URLs
- Fix branch title trailing space on hover (ClemMakesApps)
- Clean up unused routes (Josef Strzibny) - Clean up unused routes (Josef Strzibny)
- Fix issue on empty project to allow developers to only push to protected branches if given permission - Fix issue on empty project to allow developers to only push to protected branches if given permission
- API: Add enpoints for pipelines - API: Add enpoints for pipelines
...@@ -402,6 +412,9 @@ v 8.11.0 ...@@ -402,6 +412,9 @@ v 8.11.0
- Update gitlab_git gem to 10.4.7 - Update gitlab_git gem to 10.4.7
- Simplify SQL queries of marking a todo as done - Simplify SQL queries of marking a todo as done
v 8.10.10
- Allow the Rails cookie to be used for API authentication.
v 8.10.9 v 8.10.9
- Exclude some pending or inactivated rows in Member scopes - Exclude some pending or inactivated rows in Member scopes
...@@ -513,9 +526,6 @@ v 8.10.0 ...@@ -513,9 +526,6 @@ v 8.10.0
- Display tooltip for mentioned users and groups. !5261 (winniehell) - Display tooltip for mentioned users and groups. !5261 (winniehell)
- Allow build email service to be tested - Allow build email service to be tested
- Added day name to contribution calendar tooltips - Added day name to contribution calendar tooltips
- Make images fit to the size of the viewport !4810
- Fixed misplaced mirror repository button on tags page
- Fix check for New Branch button on Issue page !4630 (winniehell)
- Refactor user authorization check for a single project to avoid querying all user projects - Refactor user authorization check for a single project to avoid querying all user projects
- Make images fit to the size of the viewport. !4810 - Make images fit to the size of the viewport. !4810
- Fix check for New Branch button on Issue page. !4630 (winniehell) - Fix check for New Branch button on Issue page. !4630 (winniehell)
...@@ -631,12 +641,15 @@ v 8.10.0 ...@@ -631,12 +641,15 @@ v 8.10.0
- Render only commit message title in builds (Katarzyna Kobierska Ula Budziszewska) - Render only commit message title in builds (Katarzyna Kobierska Ula Budziszewska)
- Allow bulk (un)subscription from issues in issue index - Allow bulk (un)subscription from issues in issue index
- Fix MR diff encoding issues exporting GitLab projects - Fix MR diff encoding issues exporting GitLab projects
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
- Move builds settings out of project settings and rename Pipelines - Move builds settings out of project settings and rename Pipelines
- Add builds badge to Pipelines settings page - Add builds badge to Pipelines settings page
- Export and import avatar as part of project import/export - Export and import avatar as part of project import/export
- Fix migration corrupting import data for old version upgrades - Fix migration corrupting import data for old version upgrades
- Show tooltip on GitLab export link in new project page - Show tooltip on GitLab export link in new project page
- Fix import_data wrongly saved as a result of an invalid import_url !5206
v 8.9.10
- Allow the Rails cookie to be used for API authentication.
v 8.9.9 v 8.9.9
- Exclude some pending or inactivated rows in Member scopes - Exclude some pending or inactivated rows in Member scopes
...@@ -657,12 +670,6 @@ v 8.9.6 ...@@ -657,12 +670,6 @@ v 8.9.6
- Keeps issue number when importing from Gitlab.com - Keeps issue number when importing from Gitlab.com
- Add Pending tab for Builds (Katarzyna Kobierska, Urszula Budziszewska) - Add Pending tab for Builds (Katarzyna Kobierska, Urszula Budziszewska)
v 8.9.7 (unreleased)
- Fix import_data wrongly saved as a result of an invalid import_url
v 8.9.6
- Fix importing of events under notes for GitLab projects
v 8.9.5 v 8.9.5
- Add more debug info to import/export and memory killer. !5108 - Add more debug info to import/export and memory killer. !5108
- Fixed avatar alignment in new MR view. !5095 - Fixed avatar alignment in new MR view. !5095
...@@ -763,9 +770,6 @@ v 8.9.0 ...@@ -763,9 +770,6 @@ v 8.9.0
- Fix builds API response not including commit data - Fix builds API response not including commit data
- Fix error when CI job variables key specified but not defined - Fix error when CI job variables key specified but not defined
- Fix pipeline status when there are no builds in pipeline - Fix pipeline status when there are no builds in pipeline
v 8.10.0 (unreleased)
v 8.9.0
- Fix Error 500 when using closes_issues API with an external issue tracker - Fix Error 500 when using closes_issues API with an external issue tracker
- Add more information into RSS feed for issues (Alexander Matyushentsev) - Add more information into RSS feed for issues (Alexander Matyushentsev)
- Bulk assign/unassign labels to issues. - Bulk assign/unassign labels to issues.
...@@ -1095,7 +1099,6 @@ v 8.7.4 ...@@ -1095,7 +1099,6 @@ v 8.7.4
- Running rake gitlab:db:drop_tables now drops tables with cascade !4020 - Running rake gitlab:db:drop_tables now drops tables with cascade !4020
- Running rake gitlab:db:drop_tables uses "IF EXISTS" as a precaution !4100 - Running rake gitlab:db:drop_tables uses "IF EXISTS" as a precaution !4100
- Use a case-insensitive comparison in sanitizing URI schemes - Use a case-insensitive comparison in sanitizing URI schemes
- Bump GitLab Pages to 0.2.4 to fix Content-Type for predefined 404
v 8.7.3 v 8.7.3
- Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented - Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
...@@ -1125,7 +1128,6 @@ v 8.7.0 ...@@ -1125,7 +1128,6 @@ v 8.7.0
- Fix vulnerability that made it possible to gain access to private labels and milestones - Fix vulnerability that made it possible to gain access to private labels and milestones
- The number of InfluxDB points stored per UDP packet can now be configured - The number of InfluxDB points stored per UDP packet can now be configured
- Fix error when cross-project label reference used with non-existent project - Fix error when cross-project label reference used with non-existent project
v 8.7.0
- Transactions for /internal/allowed now have an "action" tag set - Transactions for /internal/allowed now have an "action" tag set
- Method instrumentation now uses Module#prepend instead of aliasing methods - Method instrumentation now uses Module#prepend instead of aliasing methods
- Repository.clean_old_archives is now instrumented - Repository.clean_old_archives is now instrumented
...@@ -1201,7 +1203,6 @@ v 8.7.0 ...@@ -1201,7 +1203,6 @@ v 8.7.0
- Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
- Fix admin/projects when using visibility levels on search (PotHix) - Fix admin/projects when using visibility levels on search (PotHix)
- Build status notifications - Build status notifications
- Update GitLab Pages to 0.2.2: fixes content-type of predefined 404 page
- Update email confirmation interface - Update email confirmation interface
- API: Expose user location (Robert Schilling) - API: Expose user location (Robert Schilling)
- API: Do not leak group existence via return code (Robert Schilling) - API: Do not leak group existence via return code (Robert Schilling)
...@@ -1209,7 +1210,6 @@ v 8.7.0 ...@@ -1209,7 +1210,6 @@ v 8.7.0
- Update number of Todos in the sidebar when it's marked as "Done". !3600 - Update number of Todos in the sidebar when it's marked as "Done". !3600
- Sanitize branch names created for confidential issues - Sanitize branch names created for confidential issues
- API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling) - API: Expose 'updated_at' for issue, snippet, and merge request notes (Robert Schilling)
- Add ability to sync to remote mirrors. !249
- API: User can leave a project through the API when not master or owner. !3613 - API: User can leave a project through the API when not master or owner. !3613
- Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu) - Fix repository cache invalidation issue when project is recreated with an empty repo (Stan Hu)
- Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld) - Fix: Allow empty recipients list for builds emails service when pushed is added (Frank Groeneveld)
...@@ -1484,24 +1484,6 @@ v 8.5.1 ...@@ -1484,24 +1484,6 @@ v 8.5.1
- Add build coverage in project's builds page (Steffen Köhler) - Add build coverage in project's builds page (Steffen Köhler)
- Changed # to ! for merge requests in activity view - Changed # to ! for merge requests in activity view
v 8.5.1
- Fix group projects styles
- Show Crowd login tab when sign in is disabled and Crowd is enabled (Peter Hudec)
- Fix a set of small UI glitches in project, profile, and wiki pages
- Restrict permissions on public/uploads
- Fix the merge request side-by-side view after loading diff results
- Fix the look of tooltip for the "Revert" button
- Add when the Builds & Runners API changes got introduced
- Fix error 500 on some merged merge requests
- Fix an issue causing the content of the issuable sidebar to disappear
- Fix error 500 when trying to mark an already done todo as "done"
- Fix an issue where MRs weren't sortable
- Issues can now be dragged & dropped into empty milestone lists. This is also
possible with MRs
- Changed padding & background color for highlighted notes
- Re-add the newrelic_rpm gem which was removed without any deprecation or warning (Stan Hu)
- Update sentry-raven gem to 0.15.6
v 8.5.0 v 8.5.0
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu) - Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
- Cache various Repository methods to improve performance - Cache various Repository methods to improve performance
...@@ -1648,8 +1630,6 @@ v 8.4.1 ...@@ -1648,8 +1630,6 @@ v 8.4.1
- Fix diff highlighting for all syntax themes - Fix diff highlighting for all syntax themes
- Delete project and associations in a background worker - Delete project and associations in a background worker
v 8.4.0 (unreleased)
- Hide issues settings when issues are disabled (Hannes Rosenögger)
v 8.4.0 v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server - Allow LDAP users to change their email if it was not set by the LDAP server
- Ensure Gravatar host looks like an actual host - Ensure Gravatar host looks like an actual host
...@@ -1666,14 +1646,11 @@ v 8.4.0 ...@@ -1666,14 +1646,11 @@ v 8.4.0
- Add user's last used IP addresses to admin page (Stan Hu) - Add user's last used IP addresses to admin page (Stan Hu)
- Add housekeeping function to project settings page - Add housekeeping function to project settings page
- The default GitLab logo now acts as a loading indicator - The default GitLab logo now acts as a loading indicator
- LDAP group sync: Remove user from group when they are removed from LDAP
- Fix caching issue where build status was not updating in project dashboard (Stan Hu) - Fix caching issue where build status was not updating in project dashboard (Stan Hu)
- Accept 2xx status codes for successful Webhook triggers (Stan Hu) - Accept 2xx status codes for successful Webhook triggers (Stan Hu)
- Fix missing date of month in network graph when commits span a month (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Fix error with file size check with submodules (Stan Hu)
- Remove gray background from layout in UI
- Remove gray background from layout in UI - Remove gray background from layout in UI
- Fix signup for OAuth providers that don't provide a name - Fix signup for OAuth providers that don't provide a name
- Implement new UI for group page - Implement new UI for group page
...@@ -1682,7 +1659,6 @@ v 8.4.0 ...@@ -1682,7 +1659,6 @@ v 8.4.0
- Add API support for looking up a user by username (Stan Hu) - Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu) - Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note - Link to milestone in "Milestone changed" system note
- LDAP Group Sync: Allow group role downgradegit
- Only allow group/project members to mention `@all` - Only allow group/project members to mention `@all`
- Expose Git's version in the admin area (Trey Davis) - Expose Git's version in the admin area (Trey Davis)
- Add "Frequently used" category to emoji picker - Add "Frequently used" category to emoji picker
...@@ -1959,7 +1935,7 @@ v 8.1.3 ...@@ -1959,7 +1935,7 @@ v 8.1.3
- Use issue editor as cross reference comment author when issue is edited with a new mention - Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication - Add Facebook authentication
v 8.1.1 v 8.1.2
- Fix cloning Wiki repositories via HTTP (Stan Hu) - Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory - Add migration to remove satellites directory
- Fix specific runners visibility - Fix specific runners visibility
......
...@@ -145,8 +145,7 @@ gem 'after_commit_queue', '~> 1.3.0' ...@@ -145,8 +145,7 @@ gem 'after_commit_queue', '~> 1.3.0'
gem 'acts-as-taggable-on', '~> 3.4' gem 'acts-as-taggable-on', '~> 3.4'
# Background jobs # Background jobs
gem 'sinatra', '~> 1.4.4', require: false gem 'sidekiq', '~> 4.2'
gem 'sidekiq', '~> 4.0'
gem 'sidekiq-cron', '~> 0.4.0' gem 'sidekiq-cron', '~> 0.4.0'
gem 'redis-namespace', '~> 1.5.2' gem 'redis-namespace', '~> 1.5.2'
...@@ -334,10 +333,6 @@ group :test do ...@@ -334,10 +333,6 @@ group :test do
gem 'timecop', '~> 0.8.0' gem 'timecop', '~> 0.8.0'
end end
group :production do
gem 'gitlab_meta', '7.0'
end
gem 'newrelic_rpm', '~> 3.16' gem 'newrelic_rpm', '~> 3.16'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.3.0'
......
...@@ -306,7 +306,6 @@ GEM ...@@ -306,7 +306,6 @@ GEM
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
rugged (~> 0.24.0) rugged (~> 0.24.0)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1) gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9) net-ldap (~> 0.9)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -697,11 +696,11 @@ GEM ...@@ -697,11 +696,11 @@ GEM
rack rack
shoulda-matchers (2.8.0) shoulda-matchers (2.8.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (4.1.4) sidekiq (4.2.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
rack-protection (~> 1.5)
redis (~> 3.2, >= 3.2.1) redis (~> 3.2, >= 3.2.1)
sinatra (>= 1.4.7)
sidekiq-cron (0.4.0) sidekiq-cron (0.4.0)
redis-namespace (>= 1.5.2) redis-namespace (>= 1.5.2)
rufus-scheduler (>= 2.0.24) rufus-scheduler (>= 2.0.24)
...@@ -711,10 +710,6 @@ GEM ...@@ -711,10 +710,6 @@ GEM
json (>= 1.8, < 3) 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)
rack (~> 1.5)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
slack-notifier (1.2.1) slack-notifier (1.2.1)
slop (3.6.0) slop (3.6.0)
spinach (0.8.10) spinach (0.8.10)
...@@ -899,7 +894,6 @@ DEPENDENCIES ...@@ -899,7 +894,6 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab_git (~> 10.6.6) gitlab_git (~> 10.6.6)
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)
...@@ -993,10 +987,9 @@ DEPENDENCIES ...@@ -993,10 +987,9 @@ DEPENDENCIES
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0) sidekiq (~> 4.2)
sidekiq-cron (~> 0.4.0) sidekiq-cron (~> 0.4.0)
simplecov (= 0.12.0) simplecov (= 0.12.0)
sinatra (~> 1.4.4)
slack-notifier (~> 1.2.0) slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1) spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2) spinach-rerun-reporter (~> 0.0.2)
...@@ -1030,4 +1023,4 @@ DEPENDENCIES ...@@ -1030,4 +1023,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.12.5 1.13.1
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
## Canonical source ## Canonical source
The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible. The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
The source of GitLab Enterprise Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ee). The source of GitLab Enterprise Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ee).
......
8.12.0-ee 8.13.0-ee-pre
((global) => { ((global) => {
const COOKIE_NAME = 'cycle_analytics_help_dismissed'; const COOKIE_NAME = 'cycle_analytics_help_dismissed';
const store = gl.cycleAnalyticsStore = {
isLoading: true,
hasError: false,
isHelpDismissed: $.cookie(COOKIE_NAME),
analytics: {}
};
gl.CycleAnalytics = class CycleAnalytics { gl.CycleAnalytics = class CycleAnalytics {
constructor() { constructor() {
const that = this; const that = this;
this.isHelpDismissed = $.cookie(COOKIE_NAME);
this.vue = new Vue({ this.vue = new Vue({
el: '#cycle-analytics', el: '#cycle-analytics',
name: 'CycleAnalytics', name: 'CycleAnalytics',
created: this.fetchData(), created: this.fetchData(),
data: this.decorateData({ isLoading: true }), data: store,
methods: { methods: {
dismissLanding() { dismissLanding() {
that.dismissLanding(); that.dismissLanding();
...@@ -21,6 +26,7 @@ ...@@ -21,6 +26,7 @@
} }
fetchData(options) { fetchData(options) {
store.isLoading = true;
options = options || { startDate: 30 }; options = options || { startDate: 30 };
$.ajax({ $.ajax({
...@@ -30,22 +36,20 @@ ...@@ -30,22 +36,20 @@
contentType: 'application/json', contentType: 'application/json',
data: { start_date: options.startDate } data: { start_date: options.startDate }
}).done((data) => { }).done((data) => {
this.vue.$data = this.decorateData(data); this.decorateData(data);
this.initDropdown(); this.initDropdown();
}) })
.error((data) => { .error((data) => {
this.handleError(data); this.handleError(data);
}) })
.always(() => { .always(() => {
this.vue.isLoading = false; store.isLoading = false;
}) })
} }
decorateData(data) { decorateData(data) {
data.summary = data.summary || []; data.summary = data.summary || [];
data.stats = data.stats || []; data.stats = data.stats || [];
data.isHelpDismissed = this.isHelpDismissed;
data.isLoading = data.isLoading || false;
data.summary.forEach((item) => { data.summary.forEach((item) => {
item.value = item.value || '-'; item.value = item.value || '-';
...@@ -53,23 +57,21 @@ ...@@ -53,23 +57,21 @@
data.stats.forEach((item) => { data.stats.forEach((item) => {
item.value = item.value || '- - -'; item.value = item.value || '- - -';
}) });
return data; store.analytics = data;
} }
handleError(data) { handleError(data) {
this.vue.$data = { store.hasError = true;
hasError: true,
isHelpDismissed: this.isHelpDismissed
};
new Flash('There was an error while fetching cycle analytics data.', 'alert'); new Flash('There was an error while fetching cycle analytics data.', 'alert');
} }
dismissLanding() { dismissLanding() {
this.vue.isHelpDismissed = true; store.isHelpDismissed = true;
$.cookie(COOKIE_NAME, true); $.cookie(COOKIE_NAME, true, {
path: gon.relative_url_root || '/'
});
} }
initDropdown() { initDropdown() {
...@@ -82,7 +84,6 @@ ...@@ -82,7 +84,6 @@
const value = $target.data('value'); const value = $target.data('value');
$label.text($target.text().trim()); $label.text($target.text().trim());
this.vue.isLoading = true;
this.fetchData({ startDate: value }); this.fetchData({ startDate: value });
}) })
} }
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
function ProjectFindFile(element1, options) { function ProjectFindFile(element1, options) {
this.element = element1; this.element = element1;
this.options = options; this.options = options;
this.goToBlob = bind(this.goToBlob, this);
this.goToTree = bind(this.goToTree, this); this.goToTree = bind(this.goToTree, this);
this.selectRowDown = bind(this.selectRowDown, this); this.selectRowDown = bind(this.selectRowDown, this);
this.selectRowUp = bind(this.selectRowUp, this); this.selectRowUp = bind(this.selectRowUp, this);
...@@ -36,16 +35,6 @@ ...@@ -36,16 +35,6 @@
} }
}; };
})(this)); })(this));
return this.element.find(".tree-content-holder .tree-table").on("click", function(event) {
var path;
if (event.target.nodeName !== "A") {
path = this.element.find(".tree-item-file-name a", this).attr("href");
if (path) {
return location.href = path;
}
}
});
// init event
}; };
ProjectFindFile.prototype.findFile = function() { ProjectFindFile.prototype.findFile = function() {
...@@ -121,11 +110,12 @@ ...@@ -121,11 +110,12 @@
// make tbody row html // make tbody row html
ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) { ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) {
var $tr; var $tr;
$tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>"); $tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>");
if (matches) { if (matches) {
$tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)); $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl));
} else { } else {
$tr.find("a").attr("href", blobItemUrl).text(filePath); $tr.find("a").attr("href", blobItemUrl);
$tr.find(".str-truncated").text(filePath);
} }
return $tr; return $tr;
}; };
...@@ -164,14 +154,6 @@ ...@@ -164,14 +154,6 @@
return location.href = this.options.treeUrl; return location.href = this.options.treeUrl;
}; };
ProjectFindFile.prototype.goToBlob = function() {
var path;
path = this.element.find(".tree-item.selected .tree-item-file-name a").attr("href");
if (path) {
return location.href = path;
}
};
return ProjectFindFile; return ProjectFindFile;
})(); })();
......
...@@ -67,7 +67,6 @@ ...@@ -67,7 +67,6 @@
dataType: 'json', dataType: 'json',
data: { data: {
_method: 'PATCH', _method: 'PATCH',
id: this.$wrap.data('banchId'),
protected_branch: formData protected_branch: formData
}, },
success: (response) => { success: (response) => {
......
...@@ -129,8 +129,6 @@ ...@@ -129,8 +129,6 @@
position: relative; position: relative;
.avatar-holder { .avatar-holder {
margin-bottom: 16px;
.avatar, .identicon { .avatar, .identicon {
margin: 0 auto; margin: 0 auto;
float: none; float: none;
...@@ -143,13 +141,7 @@ ...@@ -143,13 +141,7 @@
.cover-title { .cover-title {
color: $gl-header-color; color: $gl-header-color;
margin: 0;
font-size: 24px;
font-weight: normal;
margin-bottom: 10px;
color: #4c4e54;
font-size: 23px; font-size: 23px;
line-height: 1.1;
h1 { h1 {
color: $gl-gray-dark; color: $gl-gray-dark;
...@@ -213,6 +205,9 @@ ...@@ -213,6 +205,9 @@
} }
} }
} }
&.user-cover-block {
padding: 24px 0 0;
}
.group-info { .group-info {
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
margin: 0; margin: 0;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
font-size: 14px; font-size: 14px;
z-index: 100;
.flash-notice { .flash-notice {
@extend .alert; @extend .alert;
...@@ -41,4 +40,3 @@ ...@@ -41,4 +40,3 @@
} }
} }
} }
...@@ -204,7 +204,7 @@ body { ...@@ -204,7 +204,7 @@ body {
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color: $gl-header-color; color: $gl-title-color;
font-weight: 600; font-weight: 600;
} }
......
...@@ -102,7 +102,7 @@ $gl-grayish-blue: #7f8fa4; ...@@ -102,7 +102,7 @@ $gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color; $gl-gray: $gl-text-color;
$gl-gray-dark: #313236; $gl-gray-dark: #313236;
$gl-gray-light: $gl-placeholder-color; $gl-gray-light: $gl-placeholder-color;
$gl-header-color: $gl-title-color; $gl-header-color: #4c4e54;
/* /*
* Lists * Lists
...@@ -269,6 +269,12 @@ $calendar-hover-bg: #ecf3fe; ...@@ -269,6 +269,12 @@ $calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1); $calendar-border-color: rgba(#000, .1);
$calendar-unselectable-bg: $gray-light; $calendar-unselectable-bg: $gray-light;
/*
* Cycle Analytics
*/
$cycle-analytics-box-padding: 30px;
$cycle-analytics-box-text-color: #8c8c8c;
/* /*
* Personal Access Tokens * Personal Access Tokens
*/ */
......
#cycle-analytics { #cycle-analytics {
margin: 24px auto 0; margin: 24px auto 0;
width: 800px; max-width: 800px;
position: relative; position: relative;
.panel { .panel {
...@@ -9,10 +9,18 @@ ...@@ -9,10 +9,18 @@
padding: 24px 0; padding: 24px 0;
border-bottom: none; border-bottom: none;
position: relative; position: relative;
@media (max-width: $screen-sm-min) {
padding: 6px 0 24px;
}
} }
.column { .column {
text-align: center; text-align: center;
@media (max-width: $screen-sm-min) {
padding: 15px 0;
}
.header { .header {
font-size: 30px; font-size: 30px;
...@@ -28,11 +36,14 @@ ...@@ -28,11 +36,14 @@
&:last-child { &:last-child {
text-align: right; text-align: right;
@media (max-width: $screen-sm-min) {
text-align: center;
}
} }
} }
.dropdown { .dropdown {
position: relative;
top: 13px; top: 13px;
} }
} }
...@@ -40,7 +51,7 @@ ...@@ -40,7 +51,7 @@
.bordered-box { .bordered-box {
border: 1px solid $border-color; border: 1px solid $border-color;
@include border-radius($border-radius-default); @include border-radius($border-radius-default);
position: relative;
} }
.content-list { .content-list {
...@@ -60,9 +71,15 @@ ...@@ -60,9 +71,15 @@
line-height: 19px; line-height: 19px;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
color: $gl-title-color;
} }
&:text {
color: #8c8c8c; &.text {
color: $layout-link-gray;
&.value-col {
color: $gl-title-color;
}
} }
} }
} }
...@@ -71,7 +88,9 @@ ...@@ -71,7 +88,9 @@
text-align: right; text-align: right;
span { span {
line-height: 42px; position: relative;
vertical-align: middle;
top: 3px;
} }
} }
} }
...@@ -82,21 +101,25 @@ ...@@ -82,21 +101,25 @@
.dismiss-icon { .dismiss-icon {
position: absolute; position: absolute;
right: $gl-padding; right: $cycle-analytics-box-padding;
cursor: pointer; cursor: pointer;
color: #b2b2b2; color: #b2b2b2;
} }
svg { .svg-container {
margin: 0 20px; text-align: center;
float: left;
width: 136px; svg {
height: 136px; width: 136px;
height: 136px;
}
} }
.inner-content { .inner-content {
width: 480px; @media (max-width: $screen-sm-min) {
float: left; padding: 0 28px;
text-align: center;
}
h4 { h4 {
color: $gl-text-color; color: $gl-text-color;
...@@ -104,7 +127,7 @@ ...@@ -104,7 +127,7 @@
} }
p { p {
color: #8c8c8c; color: $cycle-analytics-box-text-color;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
} }
} }
......
...@@ -2,13 +2,17 @@ ...@@ -2,13 +2,17 @@
max-width: 90%; max-width: 90%;
} }
li.milestone { .milestones {
h4 { .milestone {
font-weight: bold; padding: 10px 16px;
}
h4 {
font-weight: bold;
}
.progress { .progress {
height: 6px; height: 6px;
}
} }
} }
...@@ -64,3 +68,14 @@ li.milestone { ...@@ -64,3 +68,14 @@ li.milestone {
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
padding: 20px 0; padding: 20px 0;
} }
@media (max-width: $screen-sm-min) {
.milestone-actions {
@include clearfix();
padding-top: $gl-vert-padding;
.btn:first-child {
margin-left: 0;
}
}
}
...@@ -177,6 +177,10 @@ ...@@ -177,6 +177,10 @@
border-bottom: 2px solid $border-color; border-bottom: 2px solid $border-color;
} }
} }
a {
display: block;
}
} }
} }
......
...@@ -93,8 +93,9 @@ ...@@ -93,8 +93,9 @@
.profile-user-bio { .profile-user-bio {
// Limits the width of the user bio for readability. // Limits the width of the user bio for readability.
max-width: 750px; max-width: 600px;
margin: auto; margin: 15px auto 0;
padding: 0 16px;
} }
.user-avatar-button { .user-avatar-button {
...@@ -212,6 +213,28 @@ ...@@ -212,6 +213,28 @@
} }
.user-profile { .user-profile {
.cover-controls a {
margin-left: 5px;
}
.profile-header {
margin: 0 auto;
.avatar-holder {
width: 90px;
display: inline-block;
}
.user-info {
display: inline-block;
text-align: left;
vertical-align: middle;
margin-left: 15px;
.handle {
color: $gl-gray-light;
}
.member-date {
margin-bottom: 4px;
}
}
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.cover-block { .cover-block {
padding-top: 20px; padding-top: 20px;
...@@ -219,16 +242,26 @@ ...@@ -219,16 +242,26 @@
.cover-controls { .cover-controls {
position: static; position: static;
padding: 0 16px;
margin-bottom: 20px; margin-bottom: 20px;
display: -webkit-flex;
display: flex;
.btn { .btn {
display: inline-block; -webkit-flex-grow: 1;
width: 46%; flex-grow: 1;
&:first-child {
margin-left: 0;
}
} }
} }
} }
} }
.user-profile-nav {
margin-top: 15px;
}
table.u2f-registrations { table.u2f-registrations {
th:not(:last-child), td:not(:last-child) { th:not(:last-child), td:not(:last-child) {
border-right: solid 1px transparent; border-right: solid 1px transparent;
......
...@@ -55,6 +55,15 @@ ...@@ -55,6 +55,15 @@
} }
.tree-item { .tree-item {
.link-container {
padding: 0;
a {
padding: 10px $gl-padding;
display: block;
}
}
.tree-item-file-name { .tree-item-file-name {
max-width: 320px; max-width: 320px;
vertical-align: middle; vertical-align: middle;
......
...@@ -6,8 +6,6 @@ class SearchController < ApplicationController ...@@ -6,8 +6,6 @@ class SearchController < ApplicationController
layout 'search' layout 'search'
def show def show
return if params[:search].nil? || params[:search].blank?
if params[:project_id].present? if params[:project_id].present?
@project = Project.find_by(id: params[:project_id]) @project = Project.find_by(id: params[:project_id])
@project = nil unless can?(current_user, :download_code, @project) @project = nil unless can?(current_user, :download_code, @project)
...@@ -18,6 +16,8 @@ class SearchController < ApplicationController ...@@ -18,6 +16,8 @@ class SearchController < ApplicationController
@group = nil unless can?(current_user, :read_group, @group) @group = nil unless can?(current_user, :read_group, @group)
end end
return if params[:search].nil? || params[:search].blank?
@search_term = params[:search] @search_term = params[:search]
@scope = params[:scope] @scope = params[:scope]
......
...@@ -35,6 +35,30 @@ module MilestonesHelper ...@@ -35,6 +35,30 @@ module MilestonesHelper
milestone.issues.with_label(label.title).send(state).size milestone.issues.with_label(label.title).send(state).size
end end
# Returns count of milestones for different states
# Uses explicit hash keys as the 'opened' state URL params differs from the db value
# and we need to add the total
def milestone_counts(milestones)
counts = milestones.reorder(nil).group(:state).count
{
opened: counts['active'] || 0,
closed: counts['closed'] || 0,
all: counts.values.sum || 0
}
end
# Show 'active' class if provided GET param matches check
# `or_blank` allows the function to return 'active' when given an empty param
# Could be refactored to be simpler but that may make it harder to read
def milestone_class_for_state(param, check, match_blank_param = false)
if match_blank_param
'active' if param.blank? || param == check
else
'active' if param == check
end
end
def milestone_progress_bar(milestone) def milestone_progress_bar(milestone)
options = { options = {
class: 'progress-bar progress-bar-success', class: 'progress-bar progress-bar-success',
......
...@@ -91,7 +91,7 @@ module Ci ...@@ -91,7 +91,7 @@ module Ci
sha: build.sha, sha: build.sha,
ref: build.ref, ref: build.ref,
tag: build.tag, tag: build.tag,
options: build.options[:environment], options: build.options.to_h[:environment],
variables: build.variables) variables: build.variables)
service.execute(build) service.execute(build)
end end
......
...@@ -8,7 +8,8 @@ class GlobalMilestone ...@@ -8,7 +8,8 @@ class GlobalMilestone
milestones = milestones.group_by(&:title) milestones = milestones.group_by(&:title)
milestones.map do |title, milestones| milestones.map do |title, milestones|
new(title, milestones) milestones_relation = Milestone.where(id: milestones.map(&:id))
new(title, milestones_relation)
end end
end end
...@@ -31,7 +32,7 @@ class GlobalMilestone ...@@ -31,7 +32,7 @@ class GlobalMilestone
end end
def projects def projects
@projects ||= Project.for_milestones(milestones.map(&:id)) @projects ||= Project.for_milestones(milestones.select(:id))
end end
def state def state
...@@ -53,19 +54,19 @@ class GlobalMilestone ...@@ -53,19 +54,19 @@ class GlobalMilestone
end end
def issues def issues
@issues ||= Issue.of_milestones(milestones.map(&:id)).includes(:project) @issues ||= Issue.of_milestones(milestones.select(:id)).includes(:project, :assignee, :labels)
end end
def merge_requests def merge_requests
@merge_requests ||= MergeRequest.of_milestones(milestones.map(&:id)).includes(:target_project) @merge_requests ||= MergeRequest.of_milestones(milestones.select(:id)).includes(:target_project, :assignee, :labels)
end end
def participants def participants
@participants ||= milestones.map(&:participants).flatten.compact.uniq @participants ||= milestones.includes(:participants).map(&:participants).flatten.compact.uniq
end end
def labels def labels
@labels ||= GlobalLabel.build_collection(milestones.map(&:labels).flatten) @labels ||= GlobalLabel.build_collection(milestones.includes(:labels).map(&:labels).flatten)
.sort_by!(&:title) .sort_by!(&:title)
end end
......
...@@ -9,6 +9,10 @@ class CustomIssueTrackerService < IssueTrackerService ...@@ -9,6 +9,10 @@ class CustomIssueTrackerService < IssueTrackerService
end end
end end
def title=(value)
self.properties['title'] = value if self.properties
end
def description def description
if self.properties && self.properties['description'].present? if self.properties && self.properties['description'].present?
self.properties['description'] self.properties['description']
......
...@@ -165,7 +165,7 @@ class ProjectTeam ...@@ -165,7 +165,7 @@ class ProjectTeam
# Each group produces a list of maximum access level per user. We take the # Each group produces a list of maximum access level per user. We take the
# max of the values produced by each group. # max of the values produced by each group.
if project.invited_groups.any? && project.allowed_to_share_with_group? if project_shared_with_group?
project.project_group_links.each do |group_link| project.project_group_links.each do |group_link|
invited_access = max_invited_level_for_users(group_link, user_ids) invited_access = max_invited_level_for_users(group_link, user_ids)
merge_max!(access, invited_access) merge_max!(access, invited_access)
...@@ -202,43 +202,17 @@ class ProjectTeam ...@@ -202,43 +202,17 @@ class ProjectTeam
def fetch_members(level = nil) def fetch_members(level = nil)
project_members = project.members project_members = project.members
group_members = group ? group.members : [] group_members = group ? group.members : []
invited_members = []
if project.invited_groups.any? && project.allowed_to_share_with_group?
project.project_group_links.includes(group: [:group_members]).each do |group_link|
invited_group = group_link.group
im = invited_group.members
if level
int_level = GroupMember.access_level_roles[level.to_s.singularize.titleize]
# Skip group members if we ask for masters
# but max group access is developers
next if int_level > group_link.group_access
# If we ask for developers and max
# group access is developers we need to provide
# both group master, developers as devs
if int_level == group_link.group_access
im.where("access_level >= ?)", group_link.group_access)
else
im.send(level)
end
end
invited_members << im
end
invited_members = invited_members.flatten.compact
end
if level if level
project_members = project_members.send(level) project_members = project_members.public_send(level)
group_members = group_members.send(level) if group group_members = group_members.public_send(level) if group
end end
user_ids = project_members.pluck(:user_id) user_ids = project_members.pluck(:user_id)
invited_members = fetch_invited_members(level)
user_ids.push(*invited_members.map(&:user_id)) if invited_members.any? user_ids.push(*invited_members.map(&:user_id)) if invited_members.any?
user_ids.push(*group_members.pluck(:user_id)) if group user_ids.push(*group_members.pluck(:user_id)) if group
User.where(id: user_ids) User.where(id: user_ids)
...@@ -255,4 +229,38 @@ class ProjectTeam ...@@ -255,4 +229,38 @@ class ProjectTeam
def merge_max!(first_hash, second_hash) def merge_max!(first_hash, second_hash)
first_hash.merge!(second_hash) { |_key, old, new| old > new ? old : new } first_hash.merge!(second_hash) { |_key, old, new| old > new ? old : new }
end end
def project_shared_with_group?
project.invited_groups.any? && project.allowed_to_share_with_group?
end
def fetch_invited_members(level = nil)
invited_members = []
return invited_members unless project_shared_with_group?
project.project_group_links.includes(group: [:group_members]).each do |link|
invited_group_members = link.group.members
if level
numeric_level = GroupMember.access_level_roles[level.to_s.singularize.titleize]
# If we're asked for a level that's higher than the group's access,
# there's nothing left to do
next if numeric_level > link.group_access
# Make sure we include everyone _above_ the requested level as well
invited_group_members =
if numeric_level == link.group_access
invited_group_members.where("access_level >= ?", link.group_access)
else
invited_group_members.public_send(level)
end
end
invited_members << invited_group_members
end
invited_members.flatten.compact
end
end end
...@@ -29,25 +29,25 @@ class AkismetService ...@@ -29,25 +29,25 @@ class AkismetService
end end
def submit_ham def submit_ham
return false unless akismet_enabled? submit(:ham)
end
params = { def submit_spam
type: 'comment', submit(:spam)
text: text, end
author: owner.name,
author_email: owner.email
}
begin private
akismet_client.submit_ham(options[:ip_address], options[:user_agent], params)
true def akismet_client
rescue => e @akismet_client ||= ::Akismet::Client.new(current_application_settings.akismet_api_key,
Rails.logger.error("Unable to connect to Akismet: #{e}, skipping!") Gitlab.config.gitlab.url)
false
end
end end
def submit_spam def akismet_enabled?
current_application_settings.akismet_enabled
end
def submit(type)
return false unless akismet_enabled? return false unless akismet_enabled?
params = { params = {
...@@ -58,22 +58,11 @@ class AkismetService ...@@ -58,22 +58,11 @@ class AkismetService
} }
begin begin
akismet_client.submit_spam(options[:ip_address], options[:user_agent], params) akismet_client.public_send(type, options[:ip_address], options[:user_agent], params)
true true
rescue => e rescue => e
Rails.logger.error("Unable to connect to Akismet: #{e}, skipping!") Rails.logger.error("Unable to connect to Akismet: #{e}, skipping!")
false false
end end
end end
private
def akismet_client
@akismet_client ||= ::Akismet::Client.new(current_application_settings.akismet_api_key,
Gitlab.config.gitlab.url)
end
def akismet_enabled?
current_application_settings.akismet_enabled
end
end end
= form_tag(user_omniauth_callback_path(server['provider_name']), id: 'new_ldap_user' ) do = form_tag(omniauth_callback_path(:user, server['provider_name']), id: 'new_ldap_user') do
= text_field_tag :username, nil, {class: "form-control top", placeholder: "#{server['label']} Login", autofocus: "autofocus"} = text_field_tag :username, nil, {class: "form-control top", placeholder: "#{server['label']} Login", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"} = password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
- if devise_mapping.rememberable? - if devise_mapping.rememberable?
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%thead %thead
%tr %tr
%th Status %th Status
%th Commit %th Build
- if admin - if admin
%th Project %th Project
%th Runner %th Runner
......
...@@ -2,18 +2,20 @@ ...@@ -2,18 +2,20 @@
- page_title "Cycle Analytics" - page_title "Cycle Analytics"
= render "projects/pipelines/head" = render "projects/pipelines/head"
#cycle-analytics{"v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project)}} #cycle-analytics{class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project)}}
.bordered-box.landing.content-block{"v-if" => "!isHelpDismissed"} .bordered-box.landing.content-block{"v-if" => "!isHelpDismissed"}
= icon('times', class: 'dismiss-icon', "@click": "dismissLanding()") = icon('times', class: 'dismiss-icon', "@click": "dismissLanding()")
= custom_icon('icon_cycle_analytics_splash') .row
.inner-content .col-sm-3.col-xs-12.svg-container
%h4 = custom_icon('icon_cycle_analytics_splash')
Introducing Cycle Analytics .col-sm-8.col-xs-12.inner-content
%p %h4
Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project. Introducing Cycle Analytics
%p
Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.
= link_to "Read more", help_page_path('user/project/cycle_analytics'), target: '_blank', class: 'btn' = link_to "Read more", help_page_path('user/project/cycle_analytics'), target: '_blank', class: 'btn'
= icon("spinner spin", "v-show" => "isLoading") = icon("spinner spin", "v-show" => "isLoading")
...@@ -25,11 +27,11 @@ ...@@ -25,11 +27,11 @@
.content-block .content-block
.container-fluid .container-fluid
.row .row
.col-xs-3.column{"v-for" => "item in summary"} .col-sm-3.col-xs-12.column{"v-for" => "item in analytics.summary"}
%h3.header {{item.value}} %h3.header {{item.value}}
%p.text {{item.title}} %p.text {{item.title}}
.col-xs-3.column .col-sm-3.col-xs-12.column
.dropdown.inline.js-ca-dropdown .dropdown.inline.js-ca-dropdown
%button.dropdown-menu-toggle{"data-toggle" => "dropdown", :type => "button"} %button.dropdown-menu-toggle{"data-toggle" => "dropdown", :type => "button"}
%span.dropdown-label Last 30 days %span.dropdown-label Last 30 days
...@@ -44,14 +46,14 @@ ...@@ -44,14 +46,14 @@
.bordered-box .bordered-box
%ul.content-list %ul.content-list
%li{"v-for" => "item in stats"} %li{"v-for" => "item in analytics.stats"}
.container-fluid .container-fluid
.row .row
.col-xs-10.title-col .col-xs-8.title-col
%p.title %p.title
{{item.title}} {{item.title}}
%p.text %p.text
{{item.description}} {{item.description}}
.col-xs-2.value-col .col-xs-4.value-col
%span %span
{{item.value}} {{item.value}}
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
.disabled-comment.text-center .disabled-comment.text-center
.disabled-comment-text.inline .disabled-comment-text.inline
Please Please
= link_to "register", new_session_path(:user, redirect_to_referer: 'yes') = link_to "sign up", new_session_path(:user, redirect_to_referer: 'yes')
or or
= link_to "login", new_session_path(:user, redirect_to_referer: 'yes') = link_to "sign in", new_session_path(:user, redirect_to_referer: 'yes')
to post a comment to post a comment
:javascript :javascript
......
%tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch), branch_id: protected_branch.id } } %tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch) } }
%td %td
= protected_branch.name = protected_branch.name
- if @project.root_ref?(protected_branch.name) - if @project.root_ref?(protected_branch.name)
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
= succeed '.' do = succeed '.' do
More examples are in the More examples are in the
= link_to 'documentation', help_page_path("user/project/markdown", anchor: "wiki-specific-markdown") = link_to 'documentation', help_page_path("user/markdown", anchor: "wiki-specific-markdown")
.form-group .form-group
= f.label :commit_message, class: 'control-label' = f.label :commit_message, class: 'control-label'
......
- if @project
- counts = milestone_counts(@project.milestones)
%ul.nav-links %ul.nav-links
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} %li{class: milestone_class_for_state(params[:state], 'opened', true)}
= link_to milestones_filter_path(state: 'opened') do = link_to milestones_filter_path(state: 'opened') do
Open Open
%li{class: ("active" if params[:state] == 'closed')} - if @project
%span.badge #{counts[:opened]}
%li{class: milestone_class_for_state(params[:state], 'closed')}
= link_to milestones_filter_path(state: 'closed') do = link_to milestones_filter_path(state: 'closed') do
Closed Closed
%li{class: ("active" if params[:state] == 'all')} - if @project
%span.badge #{counts[:closed]}
%li{class: milestone_class_for_state(params[:state], 'all')}
= link_to milestones_filter_path(state: 'all') do = link_to milestones_filter_path(state: 'all') do
All All
- if @project
%span.badge #{counts[:all]}
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="5 0 30 40"> <svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="5 0 30 40"><path fill="#7E7E7E" fill-rule="evenodd" d="M22 29.535V22.72c4.19-1.21 7.4-5.917 7.4-5.917.34-.446.6-1.247.6-1.795v-4.543C31.196 9.773 32 8.48 32 7c0-2.21-1.79-4-4-4s-4 1.79-4 4c0 1.48.804 2.773 2 3.465v4.243c0 .17-.094.39-.21.502 0 0-1.253 1.203-1.84 1.742C22.5 18.277 21.12 19 20.09 19c-1.042 0-2.473-.74-3.977-2.086-.61-.546-1.746-1.574-1.746-1.574-.2-.182-.367-.555-.367-.83v-4.045C15.196 9.773 16 8.48 16 7c0-2.21-1.79-4-4-4S8 4.79 8 7c0 1.48.804 2.773 2 3.465v4.543c0 .537.274 1.345.61 1.78 0 0 3.25 4.59 7.39 5.88v6.867c-1.196.692-2 1.984-2 3.465 0 2.21 1.79 4 4 4s4-1.79 4-4c0-1.48-.804-2.773-2-3.465zM14 7c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2zm16 0c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2zm-8 26c0-1.105-.895-2-2-2s-2 .895-2 2 .895 2 2 2 2-.895 2-2z"/></svg>
<path fill="#7E7E7E" fill-rule="evenodd" d="M22,29.5351288 L22,22.7193602 C26.1888699,21.5098039 29.3985457,16.802989 29.3985457,16.802989 C29.740988,16.3567547 30,15.5559546 30,15.0081969 L30,10.4648712 C31.1956027,9.77325238 32,8.48056471 32,7 C32,4.790861 30.209139,3 28,3 C25.790861,3 24,4.790861 24,7 C24,8.48056471 24.8043973,9.77325238 26,10.4648712 L26,14.7083871 C26,14.8784435 25.9055559,15.0987329 25.7890533,15.2104147 C25.7890533,15.2104147 24.5373893,16.4126202 23.9488702,16.9515733 C22.5015398,18.2770075 21.1191354,19 20.090554,19 C19.0477772,19 17.6172728,18.2608988 16.1128852,16.9142923 C15.5030182,16.3683886 14.3672121,15.3403307 14.3672121,15.3403307 C14.1659605,15.1583364 14.0000086,14.7846305 14.0000192,14.5088473 C14.0000192,14.5088473 14.0000932,12.7539451 14.0001308,10.4647956 C15.1956614,9.77315812 16,8.48051074 16,7 C16,4.790861 14.209139,3 12,3 C9.790861,3 8,4.790861 8,7 C8,8.48056471 8.80439726,9.77325238 10,10.4648712 L10,15.0081969 C10,15.5446944 10.2736352,16.3534183 10.6111812,16.7893819 C10.6111812,16.7893819 13.8599776,21.3779363 18,22.6668724 L18,29.5351288 C16.8043973,30.2267476 16,31.5194353 16,33 C16,35.209139 17.790861,37 20,37 C22.209139,37 24,35.209139 24,33 C24,31.5194353 23.1956027,30.2267476 22,29.5351288 Z M14,7 C14,5.8954305 13.1045695,5 12,5 C10.8954305,5 10,5.8954305 10,7 C10,8.1045695 10.8954305,9 12,9 C13.1045695,9 14,8.1045695 14,7 Z M30,7 C30,5.8954305 29.1045695,5 28,5 C26.8954305,5 26,5.8954305 26,7 C26,8.1045695 26.8954305,9 28,9 C29.1045695,9 30,8.1045695 30,7 Z M22,33 C22,31.8954305 21.1045695,31 20,31 C18.8954305,31 18,31.8954305 18,33 C18,34.1045695 18.8954305,35 20,35 C21.1045695,35 22,34.1045695 22,33 Z"/>
</svg>
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
- if @project - if @project
.row .row
.col-sm-6= render('shared/milestone_expired', milestone: milestone) .col-sm-6= render('shared/milestone_expired', milestone: milestone)
.col-sm-6 .col-sm-6.milestone-actions
- if can?(current_user, :admin_milestone, milestone.project) and milestone.active? - if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
= link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs btn-grouped" do = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs btn-grouped" do
Edit Edit
......
...@@ -10,72 +10,72 @@ ...@@ -10,72 +10,72 @@
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
.user-profile .user-profile
.cover-block .cover-block.user-cover-block
.cover-controls .cover-controls
- if @user == current_user - if @user == current_user
= link_to profile_path, class: 'btn btn-gray' do = link_to profile_path, class: 'btn btn-gray' do
= icon('pencil') = icon('pencil')
- elsif current_user - elsif current_user
%span.report-abuse - if @user.abuse_report
- if @user.abuse_report %button.btn.btn-danger{ title: 'Already reported for abuse',
%button.btn.btn-danger{ title: 'Already reported for abuse', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}
data: { toggle: 'tooltip', placement: 'left', container: 'body' }} = icon('exclamation-circle')
= icon('exclamation-circle') - else
- else = link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referrer), class: 'btn btn-gray',
= link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referrer), class: 'btn btn-gray', title: 'Report abuse', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do = icon('exclamation-circle')
= icon('exclamation-circle')
- if current_user - if current_user
&nbsp;
= link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do
= icon('rss') = icon('rss')
- if current_user.admin? - if current_user.admin?
&nbsp;
= link_to [:admin, @user], class: 'btn btn-gray', title: 'View user in admin area', = link_to [:admin, @user], class: 'btn btn-gray', title: 'View user in admin area',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('users') = icon('users')
.avatar-holder .profile-header
= link_to avatar_icon(@user, 400), target: '_blank' do .avatar-holder
= image_tag avatar_icon(@user, 90), class: "avatar s90", alt: '' = link_to avatar_icon(@user, 400), target: '_blank' do
.cover-title = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: ''
= @user.name
.user-info
.cover-desc .cover-title
%span.middle-dot-divider = @user.name
@#{@user.username} %span.handle
%span.middle-dot-divider @#{@user.username}
Member since #{@user.created_at.to_s(:medium)}
.cover-desc.member-date
%span.middle-dot-divider
Member since #{@user.created_at.to_s(:medium)}
.cover-desc
- unless @user.public_email.blank?
.profile-link-holder.middle-dot-divider
= link_to @user.public_email, "mailto:#{@user.public_email}"
- unless @user.skype.blank?
.profile-link-holder.middle-dot-divider
= link_to "skype:#{@user.skype}", title: "Skype" do
= icon('skype')
- unless @user.linkedin.blank?
.profile-link-holder.middle-dot-divider
= link_to "https://www.linkedin.com/in/#{@user.linkedin}", title: "LinkedIn" do
= icon('linkedin-square')
- unless @user.twitter.blank?
.profile-link-holder.middle-dot-divider
= link_to "https://twitter.com/#{@user.twitter}", title: "Twitter" do
= icon('twitter-square')
- unless @user.website_url.blank?
.profile-link-holder.middle-dot-divider
= link_to @user.short_website_url, @user.full_website_url
- unless @user.location.blank?
.profile-link-holder.middle-dot-divider
= icon('map-marker')
= @user.location
- if @user.bio.present? - if @user.bio.present?
.cover-desc .cover-desc
%p.profile-user-bio %p.profile-user-bio
= @user.bio = @user.bio
.cover-desc
- unless @user.public_email.blank?
.profile-link-holder.middle-dot-divider
= link_to @user.public_email, "mailto:#{@user.public_email}"
- unless @user.skype.blank?
.profile-link-holder.middle-dot-divider
= link_to "skype:#{@user.skype}", title: "Skype" do
= icon('skype')
- unless @user.linkedin.blank?
.profile-link-holder.middle-dot-divider
= link_to "https://www.linkedin.com/in/#{@user.linkedin}", title: "LinkedIn" do
= icon('linkedin-square')
- unless @user.twitter.blank?
.profile-link-holder.middle-dot-divider
= link_to "https://twitter.com/#{@user.twitter}", title: "Twitter" do
= icon('twitter-square')
- unless @user.website_url.blank?
.profile-link-holder.middle-dot-divider
= link_to @user.short_website_url, @user.full_website_url
- unless @user.location.blank?
.profile-link-holder.middle-dot-divider
= icon('map-marker')
= @user.location
%ul.nav-links.center.user-profile-nav %ul.nav-links.center.user-profile-nav
%li.js-activity-tab %li.js-activity-tab
= link_to user_calendar_activities_path, data: {target: 'div#activity', action: 'activity', toggle: 'tab'} do = link_to user_calendar_activities_path, data: {target: 'div#activity', action: 'activity', toggle: 'tab'} do
......
...@@ -3,11 +3,11 @@ require 'sidekiq/testing' ...@@ -3,11 +3,11 @@ require 'sidekiq/testing'
Sidekiq::Testing.inline! do Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do Gitlab::Seeder.quiet do
project_urls = [ project_urls = [
'https://github.com/documentcloud/underscore.git', 'https://gitlab.com/gitlab-org/gitlab-test.git',
'https://gitlab.com/gitlab-org/gitlab-ce.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git',
'https://gitlab.com/gitlab-org/gitlab-ci.git', 'https://gitlab.com/gitlab-org/gitlab-ci.git',
'https://gitlab.com/gitlab-org/gitlab-shell.git', 'https://gitlab.com/gitlab-org/gitlab-shell.git',
'https://gitlab.com/gitlab-org/gitlab-test.git', 'https://github.com/documentcloud/underscore.git',
'https://github.com/twitter/flight.git', 'https://github.com/twitter/flight.git',
'https://github.com/twitter/typeahead.js.git', 'https://github.com/twitter/typeahead.js.git',
'https://github.com/h5bp/html5-boilerplate.git', 'https://github.com/h5bp/html5-boilerplate.git',
...@@ -38,12 +38,7 @@ Sidekiq::Testing.inline! do ...@@ -38,12 +38,7 @@ Sidekiq::Testing.inline! do
] ]
# You can specify how many projects you need during seed execution # You can specify how many projects you need during seed execution
size = if ENV['SIZE'].present? size = ENV['SIZE'].present? ? ENV['SIZE'].to_i : 8
ENV['SIZE'].to_i
else
8
end
project_urls.first(size).each_with_index do |url, i| project_urls.first(size).each_with_index do |url, i|
group_path, project_path = url.split('/')[-2..-1] group_path, project_path = url.split('/')[-2..-1]
......
class AddIndexToLabelsTitle < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def change
add_concurrent_index :labels, :title
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160915201649) do ActiveRecord::Schema.define(version: 20160920160832) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -582,6 +582,7 @@ ActiveRecord::Schema.define(version: 20160915201649) do ...@@ -582,6 +582,7 @@ ActiveRecord::Schema.define(version: 20160915201649) do
add_index "labels", ["priority"], name: "index_labels_on_priority", using: :btree add_index "labels", ["priority"], name: "index_labels_on_priority", using: :btree
add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree
add_index "labels", ["title"], name: "index_labels_on_title", using: :btree
create_table "ldap_group_links", force: :cascade do |t| create_table "ldap_group_links", force: :cascade do |t|
t.string "cn", null: false t.string "cn", null: false
......
...@@ -10,6 +10,7 @@ following locations: ...@@ -10,6 +10,7 @@ following locations:
- [Award Emoji](award_emoji.md) - [Award Emoji](award_emoji.md)
- [Branches](branches.md) - [Branches](branches.md)
- [Broadcast Messages](broadcast_messages.md)
- [Builds](builds.md) - [Builds](builds.md)
- [Build Triggers](build_triggers.md) - [Build Triggers](build_triggers.md)
- [Build Variables](build_variables.md) - [Build Variables](build_variables.md)
......
...@@ -13,7 +13,7 @@ Apart from those, here is an collection of tutorials and guides on setting up yo ...@@ -13,7 +13,7 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Test a Scala application](test-scala-application.md) - [Test a Scala application](test-scala-application.md)
- [Using `dpl` as deployment tool](deployment/README.md) - [Using `dpl` as deployment tool](deployment/README.md)
- [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) - [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples) - [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) - [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
[gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml [gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml
...@@ -44,7 +44,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -44,7 +44,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project | | **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project |
| **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the build is run | | **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the build is run |
| **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry | | **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry |
| **CI_REGISTRY_IMAGE** | 8.10 | 0.5 | If the Container Registry is enabled for the project it returnes the address of the registry tied to the specific project | | **CI_REGISTRY_IMAGE** | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project |
| **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used | | **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used |
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags | | **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
......
...@@ -28,6 +28,7 @@ module API ...@@ -28,6 +28,7 @@ module API
helpers ::SentryHelper helpers ::SentryHelper
helpers ::API::Helpers helpers ::API::Helpers
# Keep in alphabetical order
mount ::API::AccessRequests mount ::API::AccessRequests
mount ::API::AwardEmoji mount ::API::AwardEmoji
mount ::API::Branches mount ::API::Branches
...@@ -52,6 +53,7 @@ module API ...@@ -52,6 +53,7 @@ module API
mount ::API::Lint mount ::API::Lint
mount ::API::Members mount ::API::Members
mount ::API::MergeRequests mount ::API::MergeRequests
mount ::API::MergeRequestDiffs
mount ::API::Milestones mount ::API::Milestones
mount ::API::Namespaces mount ::API::Namespaces
mount ::API::Notes mount ::API::Notes
...@@ -76,6 +78,5 @@ module API ...@@ -76,6 +78,5 @@ module API
mount ::API::Triggers mount ::API::Triggers
mount ::API::Users mount ::API::Users
mount ::API::Variables mount ::API::Variables
mount ::API::MergeRequestDiffs
end end
end end
...@@ -61,8 +61,8 @@ module API ...@@ -61,8 +61,8 @@ module API
# #
# Parameters: # Parameters:
# id (required) - The ID of a group # id (required) - The ID of a group
# name (required) - The name of the group # name (optional) - The name of the group
# path (required) - The path of the group # path (optional) - The path of the group
# description (optional) - The details of the group # description (optional) - The details of the group
# visibility_level (optional) - The visibility level of the group # visibility_level (optional) - The visibility level of the group
# lfs_enabled (optional) - Enable/disable LFS for the projects in this group # lfs_enabled (optional) - Enable/disable LFS for the projects in this group
......
...@@ -7,7 +7,7 @@ module Banzai ...@@ -7,7 +7,7 @@ module Banzai
UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
def whitelist def whitelist
whitelist = super.dup whitelist = super
customize_whitelist(whitelist) customize_whitelist(whitelist)
...@@ -42,58 +42,58 @@ module Banzai ...@@ -42,58 +42,58 @@ module Banzai
# Allow any protocol in `a` elements... # Allow any protocol in `a` elements...
whitelist[:protocols].delete('a') whitelist[:protocols].delete('a')
whitelist[:transformers] = whitelist[:transformers].dup
# ...but then remove links with unsafe protocols # ...but then remove links with unsafe protocols
whitelist[:transformers].push(remove_unsafe_links) whitelist[:transformers].push(self.class.remove_unsafe_links)
# Remove `rel` attribute from `a` elements # Remove `rel` attribute from `a` elements
whitelist[:transformers].push(remove_rel) whitelist[:transformers].push(self.class.remove_rel)
# Remove `class` attribute from non-highlight spans # Remove `class` attribute from non-highlight spans
whitelist[:transformers].push(clean_spans) whitelist[:transformers].push(self.class.clean_spans)
whitelist whitelist
end end
def remove_unsafe_links class << self
lambda do |env| def remove_unsafe_links
node = env[:node] lambda do |env|
node = env[:node]
return unless node.name == 'a' return unless node.name == 'a'
return unless node.has_attribute?('href') return unless node.has_attribute?('href')
begin begin
uri = Addressable::URI.parse(node['href']) uri = Addressable::URI.parse(node['href'])
uri.scheme = uri.scheme.strip.downcase if uri.scheme uri.scheme = uri.scheme.strip.downcase if uri.scheme
node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme) node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme)
rescue Addressable::URI::InvalidURIError rescue Addressable::URI::InvalidURIError
node.remove_attribute('href') node.remove_attribute('href')
end
end end
end end
end
def remove_rel def remove_rel
lambda do |env| lambda do |env|
if env[:node_name] == 'a' if env[:node_name] == 'a'
env[:node].remove_attribute('rel') env[:node].remove_attribute('rel')
end
end end
end end
end
def clean_spans def clean_spans
lambda do |env| lambda do |env|
node = env[:node] node = env[:node]
return unless node.name == 'span' return unless node.name == 'span'
return unless node.has_attribute?('class') return unless node.has_attribute?('class')
unless has_ancestor?(node, 'pre') unless node.ancestors.any? { |n| n.name.casecmp('pre').zero? }
node.remove_attribute('class') node.remove_attribute('class')
end end
{ node_whitelist: [node] } { node_whitelist: [node] }
end
end end
end end
end end
......
...@@ -63,10 +63,8 @@ module Gitlab ...@@ -63,10 +63,8 @@ module Gitlab
# When the DBMS is not available, an exception (e.g. PG::ConnectionBad) is raised # When the DBMS is not available, an exception (e.g. PG::ConnectionBad) is raised
active_db_connection = ActiveRecord::Base.connection.active? rescue false active_db_connection = ActiveRecord::Base.connection.active? rescue false
ENV['USE_DB'] != 'false' &&
active_db_connection && active_db_connection &&
ActiveRecord::Base.connection.table_exists?('application_settings') ActiveRecord::Base.connection.table_exists?('application_settings')
rescue ActiveRecord::NoDatabaseError rescue ActiveRecord::NoDatabaseError
false false
end end
......
...@@ -73,5 +73,7 @@ excluded_attributes: ...@@ -73,5 +73,7 @@ excluded_attributes:
methods: methods:
statuses: statuses:
- :type - :type
services:
- :type
merge_request_diff: merge_request_diff:
- :utf8_st_diffs - :utf8_st_diffs
...@@ -9,19 +9,22 @@ module Gitlab ...@@ -9,19 +9,22 @@ module Gitlab
SIDEKIQ_NAMESPACE = 'resque:gitlab' SIDEKIQ_NAMESPACE = 'resque:gitlab'
MAILROOM_NAMESPACE = 'mail_room:gitlab' MAILROOM_NAMESPACE = 'mail_room:gitlab'
DEFAULT_REDIS_URL = 'redis://localhost:6379' DEFAULT_REDIS_URL = 'redis://localhost:6379'
CONFIG_FILE = File.expand_path('../../config/resque.yml', __dir__)
# To be thread-safe we must be careful when writing the class instance # To be thread-safe we must be careful when writing the class instance
# variables @url and @pool. Because @pool depends on @url we need two # variables @_raw_config and @pool. Because @pool depends on @_raw_config we need two
# mutexes to prevent deadlock. # mutexes to prevent deadlock.
PARAMS_MUTEX = Mutex.new RAW_CONFIG_MUTEX = Mutex.new
POOL_MUTEX = Mutex.new POOL_MUTEX = Mutex.new
private_constant :PARAMS_MUTEX, :POOL_MUTEX private_constant :RAW_CONFIG_MUTEX, :POOL_MUTEX
class << self class << self
# Do NOT cache in an instance variable. Result may be mutated by caller.
def params def params
@params || PARAMS_MUTEX.synchronize { @params = new.params } new.params
end end
# Do NOT cache in an instance variable. Result may be mutated by caller.
# @deprecated Use .params instead to get sentinel support # @deprecated Use .params instead to get sentinel support
def url def url
new.url new.url
...@@ -36,8 +39,17 @@ module Gitlab ...@@ -36,8 +39,17 @@ module Gitlab
@pool.with { |redis| yield redis } @pool.with { |redis| yield redis }
end end
def reset_params! def _raw_config
@params = nil return @_raw_config if defined?(@_raw_config)
RAW_CONFIG_MUTEX.synchronize do
begin
@_raw_config = File.read(CONFIG_FILE).freeze
rescue Errno::ENOENT
@_raw_config = false
end
end
@_raw_config
end end
end end
...@@ -83,12 +95,7 @@ module Gitlab ...@@ -83,12 +95,7 @@ module Gitlab
end end
def fetch_config def fetch_config
file = config_file self.class._raw_config ? YAML.load(self.class._raw_config)[@rails_env] : false
File.exist?(file) ? YAML.load_file(file)[@rails_env] : false
end
def config_file
File.expand_path('../../../config/resque.yml', __FILE__)
end end
end end
end end
...@@ -44,7 +44,7 @@ module Gitlab ...@@ -44,7 +44,7 @@ module Gitlab
end end
def file_name_regex_message def file_name_regex_message
"can contain only letters, digits, '_', '-', '@' and '.'. " "can contain only letters, digits, '_', '-', '@' and '.'."
end end
def file_path_regex def file_path_regex
...@@ -52,7 +52,7 @@ module Gitlab ...@@ -52,7 +52,7 @@ module Gitlab
end end
def file_path_regex_message def file_path_regex_message
"can contain only letters, digits, '_', '-', '@' and '.'. Separate directories with a '/'. " "can contain only letters, digits, '_', '-', '@' and '.'. Separate directories with a '/'."
end end
def directory_traversal_regex def directory_traversal_regex
...@@ -60,7 +60,7 @@ module Gitlab ...@@ -60,7 +60,7 @@ module Gitlab
end end
def directory_traversal_regex_message def directory_traversal_regex_message
"cannot include directory traversal. " "cannot include directory traversal."
end end
def archive_formats_regex def archive_formats_regex
......
...@@ -60,7 +60,7 @@ module Gitlab ...@@ -60,7 +60,7 @@ module Gitlab
def send_git_diff(repository, diff_refs) def send_git_diff(repository, diff_refs)
params = { params = {
'RepoPath' => repository.path_to_repo, 'RepoPath' => repository.path_to_repo,
'ShaFrom' => diff_refs.start_sha, 'ShaFrom' => diff_refs.base_sha,
'ShaTo' => diff_refs.head_sha 'ShaTo' => diff_refs.head_sha
} }
...@@ -73,7 +73,7 @@ module Gitlab ...@@ -73,7 +73,7 @@ module Gitlab
def send_git_patch(repository, diff_refs) def send_git_patch(repository, diff_refs)
params = { params = {
'RepoPath' => repository.path_to_repo, 'RepoPath' => repository.path_to_repo,
'ShaFrom' => diff_refs.start_sha, 'ShaFrom' => diff_refs.base_sha,
'ShaTo' => diff_refs.head_sha 'ShaTo' => diff_refs.head_sha
} }
...@@ -107,15 +107,15 @@ module Gitlab ...@@ -107,15 +107,15 @@ module Gitlab
bytes bytes
end end
end end
def write_secret def write_secret
bytes = SecureRandom.random_bytes(SECRET_LENGTH) bytes = SecureRandom.random_bytes(SECRET_LENGTH)
File.open(secret_path, 'w:BINARY', 0600) do |f| File.open(secret_path, 'w:BINARY', 0600) do |f|
f.chmod(0600) f.chmod(0600)
f.write(Base64.strict_encode64(bytes)) f.write(Base64.strict_encode64(bytes))
end end
end end
def verify_api_request!(request_headers) def verify_api_request!(request_headers)
JWT.decode( JWT.decode(
request_headers[INTERNAL_API_REQUEST_HEADER], request_headers[INTERNAL_API_REQUEST_HEADER],
...@@ -128,7 +128,7 @@ module Gitlab ...@@ -128,7 +128,7 @@ module Gitlab
def secret_path def secret_path
Rails.root.join('.gitlab_workhorse_secret') Rails.root.join('.gitlab_workhorse_secret')
end end
protected protected
def encode(hash) def encode(hash)
......
...@@ -10,6 +10,15 @@ then ...@@ -10,6 +10,15 @@ then
exit 1 exit 1
fi fi
# Ensure that the CHANGELOG does not contain duplicate versions
DUPLICATE_CHANGELOG_VERSIONS=$(grep --extended-regexp '^v [0-9.]+' CHANGELOG | sed 's| (unreleased)||' | sort | uniq -d)
if [ "${DUPLICATE_CHANGELOG_VERSIONS}" != "" ]
then
echo '✖ ERROR: Duplicate versions in CHANGELOG:' >&2
echo "${DUPLICATE_CHANGELOG_VERSIONS}" >&2
exit 1
fi
echo "✔ Linting passed" echo "✔ Linting passed"
exit 0 exit 0
...@@ -3,5 +3,11 @@ FactoryGirl.define do ...@@ -3,5 +3,11 @@ FactoryGirl.define do
access_level { GroupMember::OWNER } access_level { GroupMember::OWNER }
group group
user user
trait(:guest) { access_level GroupMember::GUEST }
trait(:reporter) { access_level GroupMember::REPORTER }
trait(:developer) { access_level GroupMember::DEVELOPER }
trait(:master) { access_level GroupMember::MASTER }
trait(:owner) { access_level GroupMember::OWNER }
end end
end end
...@@ -3,10 +3,15 @@ FactoryGirl.define do ...@@ -3,10 +3,15 @@ FactoryGirl.define do
title title
project project
trait :active do
state "active"
end
trait :closed do trait :closed do
state :closed state "closed"
end end
factory :active_milestone, traits: [:active]
factory :closed_milestone, traits: [:closed] factory :closed_milestone, traits: [:closed]
end end
end end
require 'spec_helper' require 'spec_helper'
describe "Search", feature: true do describe "Search", feature: true do
include WaitForAjax
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, assignee: user) } let!(:issue) { create(:issue, project: project, assignee: user) }
...@@ -16,6 +18,36 @@ describe "Search", feature: true do ...@@ -16,6 +18,36 @@ describe "Search", feature: true do
expect(page).not_to have_selector('.search') expect(page).not_to have_selector('.search')
end end
context 'search filters', js: true do
let(:group) { create(:group) }
before do
group.add_owner(user)
end
it 'shows group name after filtering' do
find('.js-search-group-dropdown').click
wait_for_ajax
page.within '.search-holder' do
click_link group.name
end
expect(find('.js-search-group-dropdown')).to have_content(group.name)
end
it 'shows project name after filtering' do
page.within('.project-filter') do
find('.js-search-project-dropdown').click
wait_for_ajax
click_link project.name_with_namespace
end
expect(find('.js-search-project-dropdown')).to have_content(project.name_with_namespace)
end
end
describe 'searching for Projects' do describe 'searching for Projects' do
it 'finds a project' do it 'finds a project' do
page.within '.search-holder' do page.within '.search-holder' do
......
require 'spec_helper'
describe MilestonesHelper do
describe '#milestone_counts' do
let(:project) { FactoryGirl.create(:project) }
let(:counts) { helper.milestone_counts(project.milestones) }
context 'when there are milestones' do
let!(:milestone_1) { FactoryGirl.create(:active_milestone, project: project) }
let!(:milestone_2) { FactoryGirl.create(:active_milestone, project: project) }
let!(:milestone_3) { FactoryGirl.create(:closed_milestone, project: project) }
it 'returns the correct counts' do
expect(counts).to eq(opened: 2, closed: 1, all: 3)
end
end
context 'when there are only milestones of one type' do
let!(:milestone_1) { FactoryGirl.create(:active_milestone, project: project) }
let!(:milestone_2) { FactoryGirl.create(:active_milestone, project: project) }
it 'returns the correct counts' do
expect(counts).to eq(opened: 2, closed: 0, all: 2)
end
end
context 'when there are no milestones' do
it 'returns the correct counts' do
expect(counts).to eq(opened: 0, closed: 0, all: 0)
end
end
end
end
...@@ -6918,6 +6918,7 @@ ...@@ -6918,6 +6918,7 @@
"note_events": true, "note_events": true,
"build_events": true, "build_events": true,
"category": "issue_tracker", "category": "issue_tracker",
"type": "CustomIssueTrackerService",
"default": true, "default": true,
"wiki_page_events": true "wiki_page_events": true
}, },
......
...@@ -107,6 +107,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do ...@@ -107,6 +107,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(Label.first.label_links.first.target).not_to be_nil expect(Label.first.label_links.first.target).not_to be_nil
end end
it 'restores the correct service' do
restored_project_json
expect(CustomIssueTrackerService.first).not_to be_nil
end
context 'Merge requests' do context 'Merge requests' do
before do before do
restored_project_json restored_project_json
......
...@@ -111,6 +111,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -111,6 +111,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(saved_project_json['issues'].first['label_links'].first['label']).not_to be_empty expect(saved_project_json['issues'].first['label_links'].first['label']).not_to be_empty
end end
it 'saves the correct service type' do
expect(saved_project_json['services'].first['type']).to eq('CustomIssueTrackerService')
end
it 'has project feature' do it 'has project feature' do
project_feature = saved_project_json['project_feature'] project_feature = saved_project_json['project_feature']
expect(project_feature).not_to be_empty expect(project_feature).not_to be_empty
...@@ -161,6 +165,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -161,6 +165,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
commit_id: ci_pipeline.sha) commit_id: ci_pipeline.sha)
create(:event, target: milestone, project: project, action: Event::CREATED, author: user) create(:event, target: milestone, project: project, action: Event::CREATED, author: user)
create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker')
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::ENABLED) project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::ENABLED)
......
...@@ -3,19 +3,27 @@ require 'spec_helper' ...@@ -3,19 +3,27 @@ require 'spec_helper'
describe Gitlab::Redis do describe Gitlab::Redis do
let(:redis_config) { Rails.root.join('config', 'resque.yml').to_s } let(:redis_config) { Rails.root.join('config', 'resque.yml').to_s }
before(:each) { described_class.reset_params! } before(:each) { clear_raw_config }
after(:each) { described_class.reset_params! } after(:each) { clear_raw_config }
describe '.params' do describe '.params' do
subject { described_class.params } subject { described_class.params }
it 'withstands mutation' do
params1 = described_class.params
params2 = described_class.params
params1[:foo] = :bar
expect(params2).not_to have_key(:foo)
end
context 'when url contains unix socket reference' do context 'when url contains unix socket reference' do
let(:config_old) { Rails.root.join('spec/fixtures/config/redis_old_format_socket.yml').to_s } let(:config_old) { Rails.root.join('spec/fixtures/config/redis_old_format_socket.yml').to_s }
let(:config_new) { Rails.root.join('spec/fixtures/config/redis_new_format_socket.yml').to_s } let(:config_new) { Rails.root.join('spec/fixtures/config/redis_new_format_socket.yml').to_s }
context 'with old format' do context 'with old format' do
it 'returns path key instead' do it 'returns path key instead' do
expect_any_instance_of(described_class).to receive(:config_file) { config_old } stub_const("#{described_class}::CONFIG_FILE", config_old)
is_expected.to include(path: '/path/to/old/redis.sock') is_expected.to include(path: '/path/to/old/redis.sock')
is_expected.not_to have_key(:url) is_expected.not_to have_key(:url)
...@@ -24,7 +32,7 @@ describe Gitlab::Redis do ...@@ -24,7 +32,7 @@ describe Gitlab::Redis do
context 'with new format' do context 'with new format' do
it 'returns path key instead' do it 'returns path key instead' do
expect_any_instance_of(described_class).to receive(:config_file) { config_new } stub_const("#{described_class}::CONFIG_FILE", config_new)
is_expected.to include(path: '/path/to/redis.sock') is_expected.to include(path: '/path/to/redis.sock')
is_expected.not_to have_key(:url) is_expected.not_to have_key(:url)
...@@ -38,7 +46,7 @@ describe Gitlab::Redis do ...@@ -38,7 +46,7 @@ describe Gitlab::Redis do
context 'with old format' do context 'with old format' do
it 'returns hash with host, port, db, and password' do it 'returns hash with host, port, db, and password' do
expect_any_instance_of(described_class).to receive(:config_file) { config_old } stub_const("#{described_class}::CONFIG_FILE", config_old)
is_expected.to include(host: 'localhost', password: 'mypassword', port: 6379, db: 99) is_expected.to include(host: 'localhost', password: 'mypassword', port: 6379, db: 99)
is_expected.not_to have_key(:url) is_expected.not_to have_key(:url)
...@@ -47,7 +55,7 @@ describe Gitlab::Redis do ...@@ -47,7 +55,7 @@ describe Gitlab::Redis do
context 'with new format' do context 'with new format' do
it 'returns hash with host, port, db, and password' do it 'returns hash with host, port, db, and password' do
expect_any_instance_of(described_class).to receive(:config_file) { config_new } stub_const("#{described_class}::CONFIG_FILE", config_new)
is_expected.to include(host: 'localhost', password: 'mynewpassword', port: 6379, db: 99) is_expected.to include(host: 'localhost', password: 'mynewpassword', port: 6379, db: 99)
is_expected.not_to have_key(:url) is_expected.not_to have_key(:url)
...@@ -56,6 +64,30 @@ describe Gitlab::Redis do ...@@ -56,6 +64,30 @@ describe Gitlab::Redis do
end end
end end
describe '.url' do
it 'withstands mutation' do
url1 = described_class.url
url2 = described_class.url
url1 << 'foobar'
expect(url2).not_to end_with('foobar')
end
end
describe '._raw_config' do
subject { described_class._raw_config }
it 'should be frozen' do
expect(subject).to be_frozen
end
it 'returns false when the file does not exist' do
stub_const("#{described_class}::CONFIG_FILE", '/var/empty/doesnotexist')
expect(subject).to eq(false)
end
end
describe '#raw_config_hash' do describe '#raw_config_hash' do
it 'returns default redis url when no config file is present' do it 'returns default redis url when no config file is present' do
expect(subject).to receive(:fetch_config) { false } expect(subject).to receive(:fetch_config) { false }
...@@ -71,9 +103,15 @@ describe Gitlab::Redis do ...@@ -71,9 +103,15 @@ describe Gitlab::Redis do
describe '#fetch_config' do describe '#fetch_config' do
it 'returns false when no config file is present' do it 'returns false when no config file is present' do
allow(File).to receive(:exist?).with(redis_config) { false } allow(described_class).to receive(:_raw_config) { false }
expect(subject.send(:fetch_config)).to be_falsey expect(subject.send(:fetch_config)).to be_falsey
end end
end end
def clear_raw_config
described_class.remove_instance_variable(:@_raw_config)
rescue NameError
# raised if @_raw_config was not set; ignore
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Workhorse, lib: true do describe Gitlab::Workhorse, lib: true do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:subject) { Gitlab::Workhorse } let(:repository) { project.repository }
def decode_workhorse_header(array)
key, value = array
command, encoded_params = value.split(":")
params = JSON.parse(Base64.urlsafe_decode64(encoded_params))
[key, command, params]
end
describe ".send_git_archive" do describe ".send_git_archive" do
context "when the repository doesn't have an archive file path" do context "when the repository doesn't have an archive file path" do
...@@ -11,11 +19,37 @@ describe Gitlab::Workhorse, lib: true do ...@@ -11,11 +19,37 @@ describe Gitlab::Workhorse, lib: true do
end end
it "raises an error" do it "raises an error" do
expect { subject.send_git_archive(project.repository, ref: "master", format: "zip") }.to raise_error(RuntimeError) expect { described_class.send_git_archive(project.repository, ref: "master", format: "zip") }.to raise_error(RuntimeError)
end end
end end
end end
describe '.send_git_patch' do
let(:diff_refs) { double(base_sha: "base", head_sha: "head") }
subject { described_class.send_git_patch(repository, diff_refs) }
it 'sets the header correctly' do
key, command, params = decode_workhorse_header(subject)
expect(key).to eq("Gitlab-Workhorse-Send-Data")
expect(command).to eq("git-format-patch")
expect(params).to eq("RepoPath" => repository.path_to_repo, "ShaFrom" => "base", "ShaTo" => "head")
end
end
describe '.send_git_diff' do
let(:diff_refs) { double(base_sha: "base", head_sha: "head") }
subject { described_class.send_git_patch(repository, diff_refs) }
it 'sets the header correctly' do
key, command, params = decode_workhorse_header(subject)
expect(key).to eq("Gitlab-Workhorse-Send-Data")
expect(command).to eq("git-format-patch")
expect(params).to eq("RepoPath" => repository.path_to_repo, "ShaFrom" => "base", "ShaTo" => "head")
end
end
describe ".secret" do describe ".secret" do
subject { described_class.secret } subject { described_class.secret }
......
...@@ -50,8 +50,9 @@ describe GlobalMilestone, models: true do ...@@ -50,8 +50,9 @@ describe GlobalMilestone, models: true do
milestone1_project2, milestone1_project2,
milestone1_project3, milestone1_project3,
] ]
milestones_relation = Milestone.where(id: milestones.map(&:id))
@global_milestone = GlobalMilestone.new(milestone1_project1.title, milestones) @global_milestone = GlobalMilestone.new(milestone1_project1.title, milestones_relation)
end end
it 'has exactly one group milestone' do it 'has exactly one group milestone' do
...@@ -67,7 +68,7 @@ describe GlobalMilestone, models: true do ...@@ -67,7 +68,7 @@ describe GlobalMilestone, models: true do
let(:milestone) { create(:milestone, title: "git / test", project: project1) } let(:milestone) { create(:milestone, title: "git / test", project: project1) }
it 'strips out slashes and spaces' do it 'strips out slashes and spaces' do
global_milestone = GlobalMilestone.new(milestone.title, [milestone]) global_milestone = GlobalMilestone.new(milestone.title, Milestone.where(id: milestone.id))
expect(global_milestone.safe_title).to eq('git-test') expect(global_milestone.safe_title).to eq('git-test')
end end
......
...@@ -25,5 +25,21 @@ describe CustomIssueTrackerService, models: true do ...@@ -25,5 +25,21 @@ describe CustomIssueTrackerService, models: true do
it { is_expected.not_to validate_presence_of(:issues_url) } it { is_expected.not_to validate_presence_of(:issues_url) }
it { is_expected.not_to validate_presence_of(:new_issue_url) } it { is_expected.not_to validate_presence_of(:new_issue_url) }
end end
context 'title' do
let(:issue_tracker) { described_class.new(properties: {}) }
it 'sets a default title' do
issue_tracker.title = nil
expect(issue_tracker.title).to eq('Custom Issue Tracker')
end
it 'sets the custom title' do
issue_tracker.title = 'test title'
expect(issue_tracker.title).to eq('test title')
end
end
end end
end end
...@@ -73,6 +73,68 @@ describe ProjectTeam, models: true do ...@@ -73,6 +73,68 @@ describe ProjectTeam, models: true do
end end
end end
describe '#fetch_members' do
context 'personal project' do
let(:project) { create(:empty_project) }
it 'returns project members' do
user = create(:user)
project.team << [user, :guest]
expect(project.team.members).to contain_exactly(user)
end
it 'returns project members of a specified level' do
user = create(:user)
project.team << [user, :reporter]
expect(project.team.guests).to be_empty
expect(project.team.reporters).to contain_exactly(user)
end
it 'returns invited members of a group' do
group_member = create(:group_member)
project.project_group_links.create!(
group: group_member.group,
group_access: Gitlab::Access::GUEST
)
expect(project.team.members).to contain_exactly(group_member.user)
end
it 'returns invited members of a group of a specified level' do
group_member = create(:group_member)
project.project_group_links.create!(
group: group_member.group,
group_access: Gitlab::Access::REPORTER
)
expect(project.team.guests).to be_empty
expect(project.team.reporters).to contain_exactly(group_member.user)
end
end
context 'group project' do
let(:group) { create(:group) }
let(:project) { create(:empty_project, group: group) }
it 'returns project members' do
group_member = create(:group_member, group: group)
expect(project.team.members).to contain_exactly(group_member.user)
end
it 'returns project members of a specified level' do
group_member = create(:group_member, :reporter, group: group)
expect(project.team.guests).to be_empty
expect(project.team.reporters).to contain_exactly(group_member.user)
end
end
end
describe '#find_member' do describe '#find_member' do
context 'personal project' do context 'personal project' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
......
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