diff options
1034 files changed, 8231 insertions, 5010 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 137c26d7dae..afe9da08495 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.17-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29" +image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29" .dedicated-runner: &dedicated-runner retry: 1 @@ -86,7 +86,9 @@ stages: .rails5: &rails5 allow_failure: true only: - - /rails5/ + variables: + - $CI_COMMIT_REF_NAME =~ /rails5/ + - $RAILS5_ENABLED variables: BUNDLE_GEMFILE: "Gemfile.rails5" RAILS5: "true" @@ -327,7 +329,7 @@ cloud-native-image: cache: {} script: - gem install gitlab --no-ri --no-rdoc - - ./scripts/trigger-build cng + - BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN scripts/trigger-build cng only: - tags@gitlab-org/gitlab-ce - tags@gitlab-org/gitlab-ee @@ -348,24 +350,6 @@ retrieve-tests-metadata: - wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH - '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}' -danger-review: - image: registry.gitlab.com/gitlab-org/gitaly/dangercontainer:latest - stage: prepare - before_script: - - source scripts/utils.sh - - retry gem install danger --no-ri --no-rdoc - cache: {} - only: - refs: - - branches@gitlab-org/gitlab-ce - - branches@gitlab-org/gitlab-ee - except: - variables: - - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ - script: - - git version - - danger --fail-on-errors=true - update-tests-metadata: <<: *tests-metadata-state <<: *only-canonical-masters @@ -454,6 +438,27 @@ setup-test-env: - config/secrets.yml - vendor/gitaly-ruby +danger-review: + image: registry.gitlab.com/gitlab-org/gitaly/dangercontainer:latest + stage: test + allow_failure: true + before_script: + - source scripts/utils.sh + - retry gem install danger --no-ri --no-rdoc + cache: {} + only: + refs: + - branches@gitlab-org/gitlab-ce + - branches@gitlab-org/gitlab-ee + except: + refs: + - master + variables: + - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ + script: + - git version + - danger --fail-on-errors=true + rspec-pg 0 30: *rspec-metadata-pg rspec-pg 1 30: *rspec-metadata-pg rspec-pg 2 30: *rspec-metadata-pg diff --git a/.gitlab/merge_request_templates/Database changes.md b/.gitlab/merge_request_templates/Database changes.md index d14d52e1b6b..e636ec313df 100644 --- a/.gitlab/merge_request_templates/Database changes.md +++ b/.gitlab/merge_request_templates/Database changes.md @@ -34,17 +34,17 @@ When removing columns, tables, indexes or other structures: ## General checklist - [ ] [Changelog entry](https://docs.gitlab.com/ee/development/changelog.html) added, if necessary -- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/doc_styleguide.html) -- [ ] API support added -- [ ] Tests added for this feature/bug -- Conform by the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html) - - [ ] Has been reviewed by a Backend maintainer - - [ ] Has been reviewed by a Database specialist -- [ ] Conform by the [merge request performance guides](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html) -- [ ] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CONTRIBUTING.md#style-guides) +- [ ] [Documentation created/updated](https://docs.gitlab.com/ee/development/documentation/index.html#contributing-to-docs) +- [ ] [API support added](https://docs.gitlab.com/ee/development/api_styleguide.html) +- [ ] [Tests added for this feature/bug](https://docs.gitlab.com/ee/development/testing_guide/index.html) +- Conforms to the [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html) + - [ ] Has been reviewed by a Backend [maintainer](https://about.gitlab.com/handbook/engineering/#maintainer) + - [ ] Has been reviewed by a Database [specialist](https://about.gitlab.com/team/structure/#specialist) +- [ ] Conforms to the [merge request performance guidelines](https://docs.gitlab.com/ee/development/merge_request_performance_guidelines.html) +- [ ] Conforms to the [style guides](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/CONTRIBUTING.md#style-guides) - [ ] If you have multiple commits, please combine them into a few logically organized commits by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) -- [ ] Internationalization required/considered -- [ ] If paid feature, have we considered GitLab.com plan and how it works for groups and is there a design for promoting it to users who aren't on the correct plan -- [ ] End-to-end tests pass (`package-and-qa` manual pipeline job) +- [ ] [Internationalization required/considered](https://docs.gitlab.com/ee/development/i18n/index.html) +- [ ] For a paid feature, have we considered GitLab.com plans, how it works for groups, and is there a design for promoting it to users who aren't on the correct plan? +- [ ] [End-to-end tests](https://docs.gitlab.com/ee/development/testing_guide/end_to_end_tests.html#testing-code-in-merge-requests) pass (`package-and-qa` manual pipeline job) /label ~database diff --git a/.gitlab/merge_request_templates/Documentation.md b/.gitlab/merge_request_templates/Documentation.md index da38a703c3c..531035b3766 100644 --- a/.gitlab/merge_request_templates/Documentation.md +++ b/.gitlab/merge_request_templates/Documentation.md @@ -1,4 +1,4 @@ -<!--See the general Documentation guidelines https://docs.gitlab.com/ce/development/writing_documentation.html --> +<!--See the general Documentation guidelines https://docs.gitlab.com/ee/development/documentation/index.html --> ## What does this MR do? @@ -13,17 +13,17 @@ Closes ## Moving docs to a new location? Read the guidelines: -https://docs.gitlab.com/ce/development/writing_documentation.html#changing-document-location +https://docs.gitlab.com/ee/development/documentation/#changing-document-location - [ ] Make sure the old link is not removed and has its contents replaced with a link to the new location. - [ ] Make sure internal links pointing to the document in question are not broken. -- [ ] Search and replace any links referring to old docs in GitLab Rails app, - specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories. -- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/writing_documentation.html#redirections-for-pages-with-disqus-comments) +- [ ] Search and replace any links referring to the old docs in the GitLab Rails app, + specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories. +- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ee/development/documentation/index.html#redirections-for-pages-with-disqus-comments) to the new document if there are any Disqus comments on the old document thread. -- [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE - with the changes as well (https://docs.gitlab.com/ce/development/writing_documentation.html#cherry-picking-from-ce-to-ee). +- [ ] If working on CE and the `ee-compat-check` jobs fails, [submit an MR to EE + with the changes](https://docs.gitlab.com/ee/development/documentation/index.html#cherry-picking-from-ce-to-ee) as well. - [ ] Ping one of the technical writers for review. /label ~Documentation diff --git a/CHANGELOG.md b/CHANGELOG.md index e90f599ced1..76a016b233c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,252 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 11.1.0 (2018-07-22) + +### Security (6 changes) + +- Fix XSS vulnerability for table of content generation. +- Update sanitize gem to 4.6.5 to fix HTML injection vulnerability. +- HTML escape branch name in project graphs page. +- HTML escape the name of the user in ProjectsHelper#link_to_member. +- Don't show events from internal projects for anonymous users in public feed. +- Fix symlink vulnerability in project import. + +### Removed (1 change) + +- Remove deprecated object_storage_upload queue. + +### Fixed (98 changes, 52 of them are from the community) + +- Keep lists ordered when copying only list items. !18522 (Jan Beckmann) +- Fix bug where maintainer would not be allowed to push to forks with merge requests that have `Allow maintainer edits` enabled. !18968 +- mergeError message has been binded using v-html directive. !19058 (Murat Dogan) +- Set MR target branch to default branch if target branch is not valid. !19067 +- Fix CSS for buttons not to be hidden on issues/MR title. !19176 (Takuya Noguchi) +- Use same gem versions for rails5 as for rails4 where possible. !19498 (Jasper Maes) +- Fix extra blank line at start of rendered reStructuredText code block. !19596 +- Fix username validation order on signup, resolves #45575. !19610 (Jan Beckmann) +- Make quick commands case insensitive. !19614 (Jan Beckmann) +- Remove incorrect CI doc re: PowerShell. !19622 (gfyoung) +- Fixes Microsoft Teams notifications for pipeline events. !19632 (Jeff Brown) +- Fix branch name encoding for dropdown on issue page. !19634 +- Rails5 fix expected `issuable.reload.updated_at` to have changed. !19733 (Jasper Maes) +- Rails5 fix stack level too deep. !19762 (Jasper Maes) +- Rails5 ActionController::ParameterMissing: param is missing or the value is empty: application_setting. !19763 (Jasper Maes) +- Invalidate cache with project details when repository is updated. !19774 +- Rails5 fix no implicit conversion of Hash into String. ActionController::Parameters no longer returns an hash in Rails 5. !19792 (Jasper Maes) +- [Rails5] Fix snippets_finder arel queries. !19796 (@blackst0ne) +- Fix fields for author & assignee in MR API docs. !19798 (gfyoung) +- Remove scrollbar in Safari in repo settings page. !19809 (gfyoung) +- Omits operartions and kubernetes item from project sidebar when repository or builds are disabled. !19835 +- Rails5 fix passing Group objects array into for_projects_and_groups milestone scope. !19863 (Jasper Maes) +- Fix chat service tag notifications not sending when only default branch enabled. !19864 +- Only show new issue / new merge request on group page when issues / merge requests are enabled. !19869 (Jan Beckmann) +- [Rails5] Explicitly set request.format for blob_controller. !19876 (@blackst0ne) +- [Rails5] Fix optimistic lock value. !19878 (@blackst0ne) +- Rails5 fix update_attribute usage not causing a save. !19881 (Jasper Maes) +- Rails5 fix connection execute return integer instead of string. !19901 (Jasper Maes) +- Rails5 fix format in uploads actions. !19907 (Jasper Maes) +- [Rails5] Fix "-1 is not a valid data_store". !19917 (@blackst0ne) +- [Rails5] Invalid single-table inheritance type: Group is not a subclass of Namespace. !19918 (@blackst0ne) +- [Rails5] Fix pipeline_schedules_controller_spec. !19919 (@blackst0ne) +- Rails5 fix passing Group objects array into for_projects_and_groups milestone scope. !19920 (Jasper Maes) +- Rails5 update Gemfile.rails5.lock. !19921 (Jasper Maes) +- [Rails5] Fix sessions_controller_spec. !19936 (@blackst0ne) +- [Rails5] Set request.format for artifacts_controller. !19937 (@blackst0ne) +- Fix webhook error when password is not present. !19945 (Jan Beckmann) +- Fix label and milestone duplicated records and IID errors. !19961 +- Rails5 fix expected: 1 time with arguments: (97, anything, {"squash"=>false}) received: 0 times. !20004 (Jasper Maes) +- Rails5 fix Projects::PagesController spec. !20007 (Jasper Maes) +- [Rails5] Fix ActionCable '/cable' mountpoint conflict. !20015 (@blackst0ne) +- Fix branches are not shown in Merge Request dropdown when preferred language is not English. !20016 (Hiroyuki Sato) +- Rails5 fix Admin::HooksController. !20017 (Jasper Maes) +- Rails5 fix expected: 0 times with any arguments received: 1 time with arguments: DashboardController. !20018 (Jasper Maes) +- [Rails5] Set request.format in commits_controller. !20023 (@blackst0ne) +- Keeps the label on an issue when the issue is moved. !20036 +- Cleanup Prometheus ruby metrics. !20039 (Ben Kochie) +- Rails 5 fix Capybara::ElementNotFound: Unable to find visible css #modal-revert-commit and expected: "/bar" got: "/foo". !20044 (Jasper Maes) +- [Rails5] Force the callback run first. !20055 (@blackst0ne) +- Add readme button to non-empty project page. !20104 +- Fixed bug when editing a comment in an issue,the preview mode is toggled in the main textarea. !20112 (Constance Okoghenun) +- Ignore unknown OAuth sources in ApplicationSetting. !20129 +- Fix paragraph line height for emoji. !20137 (George Tsiolis) +- Fixes issue with uploading same image to Profile Avatar twice. !20161 (Chirag Bhatia) +- Rails5 fix arel from in mysql_median_datetime_sql. !20167 (Jasper Maes) +- Adds the `locked` state to the merge request API so that it can be used as a search filter. !20186 +- Enable Doorkeeper option to avoid generating new tokens when users login via oauth. !20200 +- Fix OAuth Application Authorization screen to appear with each access. !20216 +- Rails5 fix MySQL milliseconds problem in specs. !20221 (Jasper Maes) +- Rails5 fix Mysql comparison failure caused by milliseconds problem. !20222 (Jasper Maes) +- Updated last commit link color. !20234 (Constance Okoghenun) +- Fixed Merge request changes dropdown displays incorrectly. !20237 (Constance Okoghenun) +- Show jobs from same pipeline in sidebar in job details view. !20243 +- [Rails5] Fix milestone GROUP BY query. !20256 (@blackst0ne) +- Line separator to the left of the 'Admin area' wrench icon had vanished. !20282 (bitsapien) +- Check if archived trace exist before archive it. !20297 +- Load Devise with Omniauth when auto_sign_in_with_provider is configured. !20302 +- Fix link to job when creating a new issue from a failed job. !20328 +- Fix double "in" in time to artifact deletion message. !20357 (@bbodenmiller) +- Fix wrong role badge displayed in projects dashboard. !20374 +- Stop relying on migrations in the CacheableAttributes cache key and cache attributes for 1 minute instead. !20389 +- Fixes toggle discussion button not expanding collapsed discussions. !20452 +- Resolve compatibility issues with node 6. !20461 +- Fixes base command used in Helm installations. !20471 +- Fix RSS button interaction on Dashboard, Project and Group activities. !20549 +- Use appropriate timeout on Gitaly server info checks, avoid error on timeout. !20552 +- Remove healthchecks from prometheus endpoint. !20565 +- Render MR page when diffs cannot be fetched from the database or the git repository. !20680 +- Expire correct method caches after HEAD changed. +- Ensure MR diffs always exist in the PR importer. +- Fix overlapping file title and file actions in MR changes tag. +- Mark MR as merged regardless of errors when closing issues. +- Fix performance bar modal visibility in Safari. +- Prevent browser autocomplete for milestone date fields. +- Limit the action suffixes in transaction metrics. +- Add /uploads subdirectory to allowed upload paths. +- Fix cross-project label references. +- Invalidate merge request diffs cache if diff data change. +- Don't show context button for diffs of deleted files. +- Structure getters for diff Store properly and adds specs. +- Bump rugged to 0.27.2. +- Fix Bamboo CI status not showing for branch plans. +- Fixed bug that allowed to remove other wiki pages if the title had wildcard characters. +- Disabled Web IDE autocomplete suggestions for Markdown files. (Isaac Smith) +- Fix merge request diffs when created with gitaly_diff_between enabled. +- Properly detect label reference if followed by period or question mark. +- Deactivate new KubernetesService created from active template to prevent project creation from failing. +- Allow trailing whitespace on blockquote fence lines. + +### Deprecated (1 change) + +- Removes unused bootstrap 4 scss files. !19423 + +### Changed (33 changes, 16 of them are from the community) + +- Change label link vertical alignment property. !18777 (George Tsiolis) +- Updated the icon for expand buttons to ellipsis. !18793 (Constance Okoghenun) +- Create new or add existing Kubernetes cluster from a single page. !18963 +- Use object storage as the first class persistable store for new live trace architecture. !19515 +- Hide project name if searching against a project. !19595 +- Allows you to create another deploy token dimmediately after creating one. !19639 +- Removes the environment scope field for users that cannot edit it. !19643 +- Don't hash user ID in OIDC subject claim. !19784 (Markus Koller) +- Milestone page list redesign. !19832 (Constance Okoghenun) +- Add environment dropdown for the metrics page. !19833 +- Allow querying a single merge request within a project. !19853 +- Update WebIDE to show file in tree on load. !19887 +- Remove small container width. !19893 (George Tsiolis) +- Improve U2F workflow when using unsupported browsers. !19938 (Jan Beckmann) +- Update Web IDE file tree styles. !19969 +- Highlight cluster settings message. !19996 (George Tsiolis) +- Fade uneditable area in Web IDE. !20008 +- Update pipeline icon in web ide sidebar. !20058 (George Tsiolis) +- Revert merge request discussion buttons padding. !20060 (George Tsiolis) +- Fix boards issue highlight. !20063 (George Tsiolis) +- Update external link icon in header user dropdown. !20150 (George Tsiolis) +- Update external link icon in merge request widget. !20154 (George Tsiolis) +- Update environments nav controls icons. !20199 (George Tsiolis) +- Update integrations external link icons. !20205 (George Tsiolis) +- Fixes an issue where migrations instead of schema loading were run. !20227 +- Add title placeholder for new issues. !20271 (George Tsiolis) +- Close revoke deploy token modal on escape keypress. !20347 (George Tsiolis) +- Change environment scope text depending on number of project clusters. Update form to only include form-groups. +- Improve Web IDE commit flow. +- Add machine type and pricing documentation links, add class to labels to make bold. +- Remove remaining traces of the Allocations Gem. +- Use one column form layout on Admin Area Settings page. +- Add back copy for existing gcp accounts within offer banner. + +### Performance (16 changes, 4 of them are from the community) + +- Fully migrate pipeline stages position. !19369 +- Use Tooltip component in MrWidgetAuthorTime vue comonent. !19635 (George Tsiolis) +- Move boards modal EmptyState vue component. !20068 (George Tsiolis) +- Bump carrierwave gem verion to 1.2.3. !20287 +- Remove redundant query when removing trace. !20324 +- Improves performance of mr code, by fixing the state being mutated outside of the store in the util function trimFirstCharOfLineContent and in map operations. Avoids map operation in an empty array. Adds specs to the trimFirstCharOfLineContent function. !20380 (filipa) +- Reduce the number of queries when searching for groups. !20398 +- Improve render performance of large wiki pages. !20465 (Peter Leitzen) +- Improves performance on Merge Request diff tab by removing the scroll event listeners being added to every file. +- Remove the ci_job_request_with_tags_matcher. +- Updated Gitaly fail-fast timeout values. +- Add index on deployable_type/id for deployments. +- Eliminate N+1 queries in LFS file locks checks during a push. +- Fix performance problem of accessing tag list for projects api endpoints. +- Improve performance of listing users without projects. +- Fixed pagination of web hook logs. + +### Added (29 changes, 9 of them are from the community) + +- Add dropdown to Groups link in top bar. !18280 +- Web IDE supports now Image + Download Diff Viewing. !18768 +- Use CommonMark syntax and rendering for new Markdown content. !19331 +- Add SHA256 and HEAD on File API. !19439 (ahmet2mir) +- Add filename filtering to code search. !19509 +- Add CI_PIPELINE_URL and CI_JOB_URL. !19618 +- Expose visibility via Snippets API. !19620 (Jan Beckmann) +- Fixed pagination of groups API. !19665 (Marko, Peter) +- Added id sorting option to GET groups and subgroups API. !19665 (Marko, Peter) +- Add a link to the contributing page in the user dropdown. !19708 +- Add Object Storage to project export. !20105 +- Change avatar image in the header when user updates their avatar. !20119 (Jamie Schembri) +- Allow straight diff in Compare API. !20120 (Maciej Nowak) +- Add transfer project API endpoint. !20122 (Aram Visser) +- Expose permissions of the current user on resources in GraphQL. !20152 +- Run repository checks in parallel for each shard. !20179 +- Add pipeline lists to GraphQL. !20249 +- Add option to add README when creating a project. !20335 +- Add option to hide third party offers in admin application settings. !20379 +- Add /confidential quick action. (Jan Beckmann) +- Support direct_upload for generic uploads. +- Display merge request title & description in Web IDE. +- Prune web hook logs older than 90 days. +- Add Web Terminal for Ci Builds. (Vicky Chijwani) +- Expose whether current user can push into a branch on branches API. +- Present state indication on GFM preview. +- migrate backup rake task to gitaly. +- Add Gitlab::SQL:CTE for easily building CTE statements. +- Added with_statsoption for GET /projects/:id/repository/commits. + +### Other (28 changes, 11 of them are from the community) + +- Move some Gitaly RPC's to opt-out. !19591 +- Bump grape-path-helpers to 1.0.5. !19604 (@blackst0ne) +- Add CI job to check Gemfile.rails5.lock. !19605 (@blackst0ne) +- Move Gitaly branch/tag/ref RPC's to opt-out. !19644 +- CE port gitlab-ee!6112. !19714 +- Enable no-multi-assignment in JS files. !19808 (gfyoung) +- Enable no-restricted globals in JS files. !19877 (gfyoung) +- Improve no-multi-assignment fixes after enabling rule. !19915 (gfyoung) +- Enable prefer-structuring in JS files. !19943 (gfyoung) +- Enable frozen string in app/workers/*.rb. !19944 (gfyoung) +- Uses long sha version of the merged commit in MR widget copy to clipboard button. !19955 +- Update new group page to better explain what groups are. !19991 +- Update new SSH key page to improve copy. !19994 +- Update new SSH key page to improve key input validation. !19997 +- Gitaly metrics check for read/writeability. !20022 +- Add ellispsis to web ide commit button. !20030 +- Minor style changes to personal access token form and scope checkboxes. !20052 +- Finish enabling frozen string for app/workers/*.rb. !20197 (gfyoung) +- Allows settings sections to expand by default when linking to them. !20211 +- Enable frozen string in apps/validators/*.rb. !20220 (gfyoung) +- update bcrypt to also support libxcrypt. !20260 (muhammadn) +- Enable frozen string in apps/validators/*.rb. !20382 (gfyoung) +- Removes unused vuex code in mr refactor and removes unneeded dependencies. !20499 +- Delete non-latest merge request diff files upon merge. +- Schedule workers to delete non-latest diffs in post-migration. +- Remove the use of `is_shared` of `Ci::Runner`. +- Add more detailed logging to githost.log when rebasing. +- Use monospaced font for MR diff commit link ref on GFM. + + +## 11.0.4 (2018-07-17) + +### Security (1 change) + +- Fix symlink vulnerability in project import. + + ## 11.0.3 (2018-07-05) ### Fixed (14 changes, 1 of them is from the community) @@ -295,6 +541,14 @@ entry. - Workhorse to send raw diff and patch for commits. +## 10.8.6 (2018-07-17) + +### Security (2 changes) + +- Fix symlink vulnerability in project import. +- Merge branch 'fix-mr-widget-border' into 'master'. + + ## 10.8.5 (2018-06-21) ### Security (5 changes) @@ -524,6 +778,13 @@ entry. - Gitaly handles repository forks by default. +## 10.7.7 (2018-07-17) + +### Security (1 change) + +- Fix symlink vulnerability in project import. + + ## 10.7.6 (2018-06-21) ### Security (6 changes) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a1fa39b41d..631f80c6bd9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,7 +133,7 @@ Most issues will have labels for at least one of the following: - Type: ~"feature proposal", ~bug, ~customer, etc. - Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc. -- Team: ~"CI/CD", ~Discussion, ~Quality, ~Platform, etc. +- Team: ~"CI/CD", ~Plan, ~Manage, ~Quality, etc. - Release Scoping: ~Deliverable, ~Stretch, ~"Next Patch Release" - Priority: ~P1, ~P2, ~P3, ~P4 - Severity: ~S1, ~S2, ~S3, ~S4 @@ -187,13 +187,14 @@ The current team labels are: - ~Configuration - ~"CI/CD" -- ~Discussion +- ~Create - ~Distribution - ~Documentation - ~Geo - ~Gitaly +- ~Manage - ~Monitoring -- ~Platform +- ~Plan - ~Quality - ~Release - ~"Security Products" diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index e23e3fd2982..5fea1768541 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.112.0 +0.113.0 @@ -220,6 +220,9 @@ gem 'gemnasium-gitlab-service', '~> 0.2' # Slack integration gem 'slack-notifier', '~> 1.5.1' +# Hangouts Chat integration +gem 'hangouts-chat', '~> 0.0.5' + # Asana integration gem 'asana', '~> 0.6.0' @@ -323,6 +326,7 @@ group :development do end group :development, :test do + gem 'bootsnap', '~> 1.3' gem 'bullet', '~> 5.5.0', require: !!ENV['ENABLE_BULLET'] gem 'pry-byebug', '~> 3.4.1', platform: :mri gem 'pry-rails', '~> 0.3.4' @@ -418,7 +422,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 0.105.0', require: 'gitaly' +gem 'gitaly-proto', '~> 0.106.0', require: 'gitaly' gem 'grpc', '~> 1.11.0' # Locked until https://github.com/google/protobuf/issues/4210 is closed diff --git a/Gemfile.lock b/Gemfile.lock index 7f9207d9dfe..0976169bb11 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,6 +87,8 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) blankslate (2.1.2.4) + bootsnap (1.3.1) + msgpack (~> 1.0) bootstrap_form (2.7.0) brakeman (4.2.1) browser (2.2.0) @@ -282,7 +284,7 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (0.105.0) + gitaly-proto (0.106.0) google-protobuf (~> 3.1) grpc (~> 1.10) github-linguist (5.3.3) @@ -385,6 +387,7 @@ GEM temple (>= 0.8.0) thor tilt + hangouts-chat (0.0.5) hashdiff (0.3.4) hashie (3.5.7) hashie-forbidden_attributes (0.1.1) @@ -500,6 +503,7 @@ GEM mini_portile2 (2.3.0) minitest (5.7.0) mousetrap-rails (1.4.6) + msgpack (1.2.4) multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) @@ -986,6 +990,7 @@ DEPENDENCIES benchmark-ips (~> 2.3.0) better_errors (~> 2.1.0) binding_of_caller (~> 0.7.2) + bootsnap (~> 1.3) bootstrap_form (~> 2.7.0) brakeman (~> 4.2) browser (~> 2.2) @@ -1037,7 +1042,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 0.105.0) + gitaly-proto (~> 0.106.0) github-linguist (~> 5.3.3) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-gollum-lib (~> 4.2) @@ -1058,6 +1063,7 @@ DEPENDENCIES grpc (~> 1.11.0) haml_lint (~> 0.26.0) hamlit (~> 2.8.8) + hangouts-chat (~> 0.0.5) hashie-forbidden_attributes health_check (~> 2.6.0) hipchat (~> 1.5.0) diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock index 766f2479ea5..1cf612fd4a6 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails5.lock @@ -90,6 +90,8 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) blankslate (2.1.2.4) + bootsnap (1.3.1) + msgpack (~> 1.0) bootstrap_form (2.7.0) brakeman (4.2.1) browser (2.2.0) @@ -285,7 +287,7 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (0.105.0) + gitaly-proto (0.106.0) google-protobuf (~> 3.1) grpc (~> 1.10) github-linguist (5.3.3) @@ -388,6 +390,7 @@ GEM temple (>= 0.8.0) thor tilt + hangouts-chat (0.0.5) hashdiff (0.3.4) hashie (3.5.7) hashie-forbidden_attributes (0.1.1) @@ -503,6 +506,7 @@ GEM mini_portile2 (2.3.0) minitest (5.7.0) mousetrap-rails (1.4.6) + msgpack (1.2.4) multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) @@ -996,6 +1000,7 @@ DEPENDENCIES benchmark-ips (~> 2.3.0) better_errors (~> 2.1.0) binding_of_caller (~> 0.7.2) + bootsnap (~> 1.3) bootstrap_form (~> 2.7.0) brakeman (~> 4.2) browser (~> 2.2) @@ -1047,7 +1052,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 0.105.0) + gitaly-proto (~> 0.106.0) github-linguist (~> 5.3.3) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-gollum-lib (~> 4.2) @@ -1068,6 +1073,7 @@ DEPENDENCIES grpc (~> 1.11.0) haml_lint (~> 0.26.0) hamlit (~> 2.8.8) + hangouts-chat (~> 0.0.5) hashie-forbidden_attributes health_check (~> 2.6.0) hipchat (~> 1.5.0) @@ -1 +1 @@ -11.1.0-pre +11.2.0-pre diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js index fa00a3cf386..e8c59fab609 100644 --- a/app/assets/javascripts/autosave.js +++ b/app/assets/javascripts/autosave.js @@ -53,4 +53,8 @@ export default class Autosave { return window.localStorage.removeItem(this.key); } + + dispose() { + this.field.off('input'); + } } diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index ec23b1e7c11..271c6eac81a 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -105,7 +105,7 @@ export default { </div> <label :for="list.id + '-title'" - class="label-light" + class="label-bold" > Title </label> diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index eb335f352d3..dc887db1e73 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -68,7 +68,7 @@ export default { <template> <div> - <label class="label-light prepend-top-10"> + <label class="label-bold prepend-top-10"> Project </label> <div diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index 8139aa69fc7..e565af800d0 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -162,8 +162,10 @@ export default class Clusters { if (type === 'password') { this.tokenField.setAttribute('type', 'text'); + this.showTokenButton.textContent = s__('ClusterIntegration|Hide'); } else { this.tokenField.setAttribute('type', 'password'); + this.showTokenButton.textContent = s__('ClusterIntegration|Show'); } } diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index d62d3c23654..f595f3c3187 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -14,6 +14,7 @@ import 'core-js/es6/weak-map'; // Browser polyfills import 'classlist-polyfill'; +import 'formdata-polyfill'; import './polyfills/custom_event'; import './polyfills/element'; import './polyfills/event'; diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 1d1415fe6ca..7cc4e6a2c3a 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -85,6 +85,9 @@ export default { } return __('Show latest version'); }, + canCurrentUserFork() { + return this.currentUser.canFork === true && this.currentUser.canCreateMergeRequest; + }, }, watch: { diffViewType() { @@ -192,7 +195,7 @@ export default { v-for="file in diffFiles" :key="file.newPath" :file="file" - :current-user="currentUser" + :can-current-user-fork="canCurrentUserFork" /> </div> <no-changes v-else /> diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue index 20483161033..e64d5511d78 100644 --- a/app/assets/javascripts/diffs/components/diff_discussions.vue +++ b/app/assets/javascripts/diffs/components/diff_discussions.vue @@ -30,6 +30,7 @@ export default { :render-header="false" :render-diff-file="false" :always-expanded="true" + :discussions-by-diff-order="true" /> </ul> </div> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 944084f05c9..7e7058d8d08 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -18,8 +18,8 @@ export default { type: Object, required: true, }, - currentUser: { - type: Object, + canCurrentUserFork: { + type: Boolean, required: true, }, }, @@ -87,7 +87,7 @@ export default { class="diff-file file-holder" > <diff-file-header - :current-user="currentUser" + :can-current-user-fork="canCurrentUserFork" :diff-file="file" :collapsible="true" :expanded="!isCollapsed" diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index c5abd0a9568..c494d3bcd3e 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -39,8 +39,8 @@ export default { required: false, default: true, }, - currentUser: { - type: Object, + canCurrentUserFork: { + type: Boolean, required: true, }, }, @@ -228,7 +228,7 @@ export default { <edit-button v-if="!diffFile.deletedFile" - :current-user="currentUser" + :can-current-user-fork="canCurrentUserFork" :edit-path="diffFile.editPath" :can-modify-blob="diffFile.canModifyBlob" @showForkMessage="showForkMessage" diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index ad838a32518..0fe0007057b 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -77,7 +77,8 @@ export default { diffViewType: state => state.diffs.diffViewType, diffFiles: state => state.diffs.diffFiles, }), - ...mapGetters(['isLoggedIn', 'discussionsByLineCode']), + ...mapGetters(['isLoggedIn']), + ...mapGetters('diffs', ['discussionsByLineCode']), lineHref() { return this.lineCode ? `#${this.lineCode}` : '#'; }, @@ -189,7 +190,6 @@ export default { </button> <a v-if="lineNumber" - v-once :data-linenumber="lineNumber" :href="lineHref" > diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue index db380e68bd1..cbe4551d06b 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -1,24 +1,20 @@ <script> -import $ from 'jquery'; import { mapState, mapGetters, mapActions } from 'vuex'; import createFlash from '~/flash'; import { s__ } from '~/locale'; import noteForm from '../../notes/components/note_form.vue'; import { getNoteFormData } from '../store/utils'; -import Autosave from '../../autosave'; -import { DIFF_NOTE_TYPE, NOTE_TYPE } from '../constants'; +import autosave from '../../notes/mixins/autosave'; +import { DIFF_NOTE_TYPE } from '../constants'; export default { components: { noteForm, }, + mixins: [autosave], props: { - diffFile: { - type: Object, - required: true, - }, - diffLines: { - type: Array, + diffFileHash: { + type: String, required: true, }, line: { @@ -40,41 +36,50 @@ export default { noteableData: state => state.notes.noteableData, diffViewType: state => state.diffs.diffViewType, }), + ...mapGetters('diffs', ['getDiffFileByHash']), ...mapGetters(['isLoggedIn', 'noteableType', 'getNoteableData', 'getNotesDataByProp']), }, mounted() { if (this.isLoggedIn) { - const noteableData = this.getNoteableData; const keys = [ - NOTE_TYPE, - this.noteableType, - noteableData.id, - noteableData.diff_head_sha, + this.noteableData.diff_head_sha, DIFF_NOTE_TYPE, - noteableData.source_project_id, + this.noteableData.source_project_id, this.line.lineCode, ]; - this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), keys); + this.initAutoSave(this.noteableData, keys); } }, methods: { ...mapActions('diffs', ['cancelCommentForm']), ...mapActions(['saveNote', 'refetchDiscussionById']), - handleCancelCommentForm() { - this.autosave.reset(); + handleCancelCommentForm(shouldConfirm, isDirty) { + if (shouldConfirm && isDirty) { + const msg = s__('Notes|Are you sure you want to cancel creating this comment?'); + + // eslint-disable-next-line no-alert + if (!window.confirm(msg)) { + return; + } + } + this.cancelCommentForm({ lineCode: this.line.lineCode, }); + this.$nextTick(() => { + this.resetAutoSave(); + }); }, handleSaveNote(note) { + const selectedDiffFile = this.getDiffFileByHash(this.diffFileHash); const postData = getNoteFormData({ note, noteableData: this.noteableData, noteableType: this.noteableType, noteTargetLine: this.noteTargetLine, diffViewType: this.diffViewType, - diffFile: this.diffFile, + diffFile: selectedDiffFile, linePosition: this.position, }); diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue index bd02b45a63c..5962f30d9bb 100644 --- a/app/assets/javascripts/diffs/components/diff_table_cell.vue +++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue @@ -24,8 +24,12 @@ export default { type: Object, required: true, }, - diffFile: { - type: Object, + fileHash: { + type: String, + required: true, + }, + contextLinesPath: { + type: String, required: true, }, diffViewType: { @@ -120,14 +124,14 @@ export default { :class="classNameMap" > <diff-line-gutter-content - :file-hash="diffFile.fileHash" + :file-hash="fileHash" + :context-lines-path="contextLinesPath" :line-type="normalizedLine.type" :line-code="normalizedLine.lineCode" :line-position="linePosition" :line-number="lineNumber" :meta-data="normalizedLine.metaData" :show-comment-button="showCommentButton" - :context-lines-path="diffFile.contextLinesPath" :is-bottom="isBottom" :is-match-line="isMatchLine" :is-context-line="isContentLine" diff --git a/app/assets/javascripts/diffs/components/edit_button.vue b/app/assets/javascripts/diffs/components/edit_button.vue index ebf90631d76..2fb85ca2f07 100644 --- a/app/assets/javascripts/diffs/components/edit_button.vue +++ b/app/assets/javascripts/diffs/components/edit_button.vue @@ -5,8 +5,8 @@ export default { type: String, required: true, }, - currentUser: { - type: Object, + canCurrentUserFork: { + type: Boolean, required: true, }, canModifyBlob: { @@ -17,12 +17,12 @@ export default { }, methods: { handleEditClick(evt) { - if (!this.currentUser || this.canModifyBlob) { + if (!this.canCurrentUserFork || this.canModifyBlob) { // if we can Edit, do default Edit button behavior return; } - if (this.currentUser.canFork && this.currentUser.canCreateMergeRequest) { + if (this.canCurrentUserFork) { evt.preventDefault(); this.$emit('showForkMessage'); } diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue index 1e8f2eecd76..a6f011ff31e 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -13,12 +13,8 @@ export default { type: Object, required: true, }, - diffFile: { - type: Object, - required: true, - }, - diffLines: { - type: Array, + diffFileHash: { + type: String, required: true, }, lineIndex: { @@ -30,13 +26,16 @@ export default { ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), - ...mapGetters(['discussionsByLineCode']), + ...mapGetters('diffs', ['discussionsByLineCode']), discussions() { return this.discussionsByLineCode[this.line.lineCode] || []; }, className() { return this.discussions.length ? '' : 'js-temp-notes-holder'; }, + hasCommentForm() { + return this.diffLineCommentForms[this.line.lineCode]; + }, }, }; </script> @@ -57,11 +56,10 @@ export default { :discussions="discussions" /> <diff-line-note-form - v-if="diffLineCommentForms[line.lineCode]" - :diff-file="diffFile" - :diff-lines="diffLines" + v-if="hasCommentForm" + :diff-file-hash="diffFileHash" :line="line" - :note-target-line="diffLines[lineIndex]" + :note-target-line="line" /> </div> </td> diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 8e4715c9862..0e306f39a9f 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -16,8 +16,12 @@ export default { DiffTableCell, }, props: { - diffFile: { - type: Object, + fileHash: { + type: String, + required: true, + }, + contextLinesPath: { + type: String, required: true, }, line: { @@ -50,7 +54,7 @@ export default { inlineRowId() { const { lineCode, oldLine, newLine } = this.line; - return lineCode || `${this.diffFile.fileHash}_${oldLine}_${newLine}`; + return lineCode || `${this.fileHash}_${oldLine}_${newLine}`; }, }, created() { @@ -78,7 +82,8 @@ export default { @mouseout="handleMouseMove" > <diff-table-cell - :diff-file="diffFile" + :file-hash="fileHash" + :context-lines-path="contextLinesPath" :line="line" :line-type="oldLineType" :is-bottom="isBottom" @@ -87,7 +92,8 @@ export default { class="diff-line-num old_line" /> <diff-table-cell - :diff-file="diffFile" + :file-hash="fileHash" + :context-lines-path="contextLinesPath" :line="line" :line-type="newLineType" :is-bottom="isBottom" @@ -95,7 +101,6 @@ export default { class="diff-line-num new_line" /> <td - v-once :class="line.type" class="line_content" v-html="line.richText" diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index 9c1359f7c89..8e491d293e5 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -20,8 +20,7 @@ export default { }, }, computed: { - ...mapGetters('diffs', ['commitId']), - ...mapGetters(['discussionsByLineCode']), + ...mapGetters('diffs', ['commitId', 'discussionsByLineCode']), ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), @@ -60,15 +59,15 @@ export default { v-for="(line, index) in normalizedDiffLines" > <inline-diff-table-row - :diff-file="diffFile" + :file-hash="diffFile.fileHash" + :context-lines-path="diffFile.contextLinesPath" :line="line" :is-bottom="index + 1 === diffLinesLength" :key="line.lineCode" /> <inline-diff-comment-row v-if="shouldRenderCommentRow(line)" - :diff-file="diffFile" - :diff-lines="normalizedDiffLines" + :diff-file-hash="diffFile.fileHash" :line="line" :line-index="index" :key="index" diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue index 1e20792b647..05e5cafc717 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -13,12 +13,8 @@ export default { type: Object, required: true, }, - diffFile: { - type: Object, - required: true, - }, - diffLines: { - type: Array, + diffFileHash: { + type: String, required: true, }, lineIndex: { @@ -30,7 +26,7 @@ export default { ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), - ...mapGetters(['discussionsByLineCode']), + ...mapGetters('diffs', ['discussionsByLineCode']), leftLineCode() { return this.line.left.lineCode; }, @@ -91,10 +87,9 @@ export default { <diff-line-note-form v-if="diffLineCommentForms[leftLineCode] && diffLineCommentForms[leftLineCode]" - :diff-file="diffFile" - :diff-lines="diffLines" + :diff-file-hash="diffFileHash" :line="line.left" - :note-target-line="diffLines[lineIndex].left" + :note-target-line="line.left" position="left" /> </td> @@ -112,10 +107,9 @@ export default { <diff-line-note-form v-if="diffLineCommentForms[rightLineCode] && diffLineCommentForms[rightLineCode] && line.right.type" - :diff-file="diffFile" - :diff-lines="diffLines" + :diff-file-hash="diffFileHash" :line="line.right" - :note-target-line="diffLines[lineIndex].right" + :note-target-line="line.right" position="right" /> </td> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index b76fc63205b..0031cedc68f 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -19,8 +19,12 @@ export default { DiffTableCell, }, props: { - diffFile: { - type: Object, + fileHash: { + type: String, + required: true, + }, + contextLinesPath: { + type: String, required: true, }, line: { @@ -103,7 +107,8 @@ export default { @mouseout="handleMouseMove" > <diff-table-cell - :diff-file="diffFile" + :file-hash="fileHash" + :context-lines-path="contextLinesPath" :line="line" :line-type="oldLineType" :line-position="linePositionLeft" @@ -114,7 +119,6 @@ export default { class="diff-line-num old_line" /> <td - v-once :id="line.left.lineCode" :class="parallelViewLeftLineType" class="line_content parallel left-side" @@ -123,7 +127,8 @@ export default { > </td> <diff-table-cell - :diff-file="diffFile" + :file-hash="fileHash" + :context-lines-path="contextLinesPath" :line="line" :line-type="newLineType" :line-position="linePositionRight" @@ -134,7 +139,6 @@ export default { class="diff-line-num new_line" /> <td - v-once :id="line.right.lineCode" :class="line.right.type" class="line_content parallel right-side" diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index 216865474a6..8f8d6bbc818 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -21,8 +21,7 @@ export default { }, }, computed: { - ...mapGetters('diffs', ['commitId']), - ...mapGetters(['discussionsByLineCode']), + ...mapGetters('diffs', ['commitId', 'discussionsByLineCode']), ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), @@ -93,17 +92,17 @@ export default { v-for="(line, index) in parallelDiffLines" > <parallel-diff-table-row - :diff-file="diffFile" + :file-hash="diffFile.fileHash" + :context-lines-path="diffFile.contextLinesPath" :line="line" :is-bottom="index + 1 === diffLinesLength" :key="index" /> <parallel-diff-comment-row v-if="shouldRenderCommentRow(line)" - :key="line.left.lineCode || line.right.lineCode" + :key="`dcr-${index}`" :line="line" - :diff-file="diffFile" - :diff-lines="parallelDiffLines" + :diff-file-hash="diffFile.fileHash" :line-index="index" /> </template> diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index f89acb73ed8..d3881fa1a0a 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,5 +1,7 @@ import _ from 'underscore'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants'; +import { getDiffRefsByLineCode } from './utils'; export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW_TYPE; @@ -56,5 +58,47 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) = discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash), ) || []; +/** + * Returns an Object with discussions by their diff line code + * To avoid rendering outdated discussions on the Changes tab we should do a bunch of SHA + * comparisions. `note.position.formatter` have the current version diff refs but + * `note.original_position.formatter` will have the first version's diff refs. + * If line diff refs matches with one of them, we should render it as a discussion on Changes tab. + * + * @param {Object} diff + * @returns {Array} + */ +export const discussionsByLineCode = (state, getters, rootState, rootGetters) => { + const diffRefsByLineCode = getDiffRefsByLineCode(state.diffFiles); + + return rootGetters.discussions.reduce((acc, note) => { + const isDiffDiscussion = note.diff_discussion; + const hasLineCode = note.line_code; + const isResolvable = note.resolvable; + const diffRefs = diffRefsByLineCode[note.line_code]; + + if (isDiffDiscussion && hasLineCode && isResolvable && diffRefs) { + const refs = convertObjectPropsToCamelCase(note.position.formatter); + const originalRefs = convertObjectPropsToCamelCase(note.original_position.formatter); + + if (_.isEqual(refs, diffRefs) || _.isEqual(originalRefs, diffRefs)) { + const lineCode = note.line_code; + + if (acc[lineCode]) { + acc[lineCode].push(note); + } else { + acc[lineCode] = [note]; + } + } + } + + return acc; + }, {}); +}; + // prevent babel-plugin-rewire from generating an invalid default during karma∂ tests +export const getDiffFileByHash = state => fileHash => + state.diffFiles.find(file => file.fileHash === fileHash); + +// prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index d9589baa76e..82082ac508a 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -173,3 +173,24 @@ export function trimFirstCharOfLineContent(line = {}) { return parsedLine; } + +export function getDiffRefsByLineCode(diffFiles) { + return diffFiles.reduce((acc, diffFile) => { + const { baseSha, headSha, startSha } = diffFile.diffRefs; + const { newPath, oldPath } = diffFile; + + // We can only use highlightedDiffLines to create the map of diff lines because + // highlightedDiffLines will also include every parallel diff line in it. + if (diffFile.highlightedDiffLines) { + diffFile.highlightedDiffLines.forEach(line => { + const { lineCode, oldLine, newLine } = line; + + if (lineCode) { + acc[lineCode] = { baseSha, headSha, startSha, newPath, oldPath, oldLine, newLine }; + } + }); + } + + return acc; + }, {}); +} diff --git a/app/assets/javascripts/ide/components/new_dropdown/button.vue b/app/assets/javascripts/ide/components/new_dropdown/button.vue index 7682b34ce4d..ff114e47741 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/button.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/button.vue @@ -38,6 +38,7 @@ export default { <button :aria-label="label" type="button" + class="btn-blank" @click.stop.prevent="clicked" > <icon diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index 1867b7980d2..833c4b027df 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -66,7 +66,7 @@ export default { <div class="form-group row" > - <label class="label-light col-form-label col-sm-3"> + <label class="label-bold col-form-label col-sm-3"> {{ __('Name') }} </label> <div class="col-sm-9"> diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index cc8dbb942d8..c6d7d218e81 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import VueRouter from 'vue-router'; +import { join as joinPath } from 'path'; import flash from '~/flash'; import store from './stores'; import { activityBarViews } from './constants'; @@ -37,17 +38,29 @@ const router = new VueRouter({ base: `${gon.relative_url_root}/-/ide/`, routes: [ { - path: '/project/:namespace/:project+', + path: '/project/:namespace+/:project', component: EmptyRouterComponent, children: [ { - path: ':targetmode(edit|tree|blob)/*', + path: ':targetmode(edit|tree|blob)/:branchid+/-/*', component: EmptyRouterComponent, }, { + path: ':targetmode(edit|tree|blob)/:branchid+/', + redirect: to => joinPath(to.path, '/-/'), + }, + { + path: ':targetmode(edit|tree|blob)', + redirect: to => joinPath(to.path, '/master/-/'), + }, + { path: 'merge_requests/:mrid', component: EmptyRouterComponent, }, + { + path: '', + redirect: to => joinPath(to.path, '/edit/master/-/'), + }, ], }, ], @@ -63,11 +76,10 @@ router.beforeEach((to, from, next) => { .then(() => { const fullProjectId = `${to.params.namespace}/${to.params.project}`; - const baseSplit = (to.params[0] && to.params[0].split('/-/')) || ['']; - const branchId = baseSplit[0].slice(-1) === '/' ? baseSplit[0].slice(0, -1) : baseSplit[0]; + const branchId = to.params.branchid; if (branchId) { - const basePath = baseSplit.length > 1 ? baseSplit[1] : ''; + const basePath = to.params[0] || ''; store.dispatch('setCurrentBranchId', branchId); @@ -101,6 +113,7 @@ router.beforeEach((to, from, next) => { store .dispatch('getMergeRequestData', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }) .then(mr => { @@ -119,12 +132,14 @@ router.beforeEach((to, from, next) => { .then(() => store.dispatch('getMergeRequestVersions', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }), ) .then(() => store.dispatch('getMergeRequestChanges', { projectId: fullProjectId, + targetProjectId: to.query.target_project, mergeRequestId: to.params.mrid, }), ) diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index 6bdf9dc3028..1887b77b00b 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -4,12 +4,14 @@ import * as types from '../mutation_types'; export const getMergeRequestData = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId] || force) { service - .getProjectMergeRequestData(projectId, mergeRequestId, { render_html: true }) + .getProjectMergeRequestData(targetProjectId || projectId, mergeRequestId, { + render_html: true, + }) .then(({ data }) => { commit(types.SET_MERGE_REQUEST, { projectPath: projectId, @@ -38,12 +40,12 @@ export const getMergeRequestData = ( export const getMergeRequestChanges = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId].changes.length || force) { service - .getProjectMergeRequestChanges(projectId, mergeRequestId) + .getProjectMergeRequestChanges(targetProjectId || projectId, mergeRequestId) .then(({ data }) => { commit(types.SET_MERGE_REQUEST_CHANGES, { projectPath: projectId, @@ -71,12 +73,12 @@ export const getMergeRequestChanges = ( export const getMergeRequestVersions = ( { commit, dispatch, state }, - { projectId, mergeRequestId, force = false } = {}, + { projectId, mergeRequestId, targetProjectId = null, force = false } = {}, ) => new Promise((resolve, reject) => { if (!state.projects[projectId].mergeRequests[mergeRequestId].versions.length || force) { service - .getProjectMergeRequestVersions(projectId, mergeRequestId) + .getProjectMergeRequestVersions(targetProjectId || projectId, mergeRequestId) .then(res => res.data) .then(data => { commit(types.SET_MERGE_REQUEST_VERSIONS, { diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue index 92fe98508ad..1e6803abf3a 100644 --- a/app/assets/javascripts/monitoring/components/graph/flag.vue +++ b/app/assets/javascripts/monitoring/components/graph/flag.vue @@ -125,6 +125,7 @@ export default { :class="flagOrientation" class="prometheus-graph-flag popover" > + <div class="arrow-shadow"></div> <div class="arrow"></div> <div class="popover-title"> <h5 v-if="deploymentFlagData"> diff --git a/app/assets/javascripts/monitoring/stores/monitoring_store.js b/app/assets/javascripts/monitoring/stores/monitoring_store.js index 748b8cb6e6e..176f7d9eef2 100644 --- a/app/assets/javascripts/monitoring/stores/monitoring_store.js +++ b/app/assets/javascripts/monitoring/stores/monitoring_store.js @@ -1,7 +1,10 @@ import _ from 'underscore'; function sortMetrics(metrics) { - return _.chain(metrics).sortBy('title').sortBy('weight').value(); + return _.chain(metrics) + .sortBy('title') + .sortBy('weight') + .value(); } function normalizeMetrics(metrics) { @@ -39,7 +42,9 @@ export default class MonitoringStore { } storeEnvironmentsData(environmentsData = []) { - this.environmentsData = environmentsData; + this.environmentsData = environmentsData.filter( + environment => !!environment.latest.last_deployment, + ); } getMetricsCount() { diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index 9c2908c477e..27ff7dea909 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -1,94 +1,90 @@ <script> - import { mapState, mapActions } from 'vuex'; - import imageDiffHelper from '~/image_diff/helpers/index'; - import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; - import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; - import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; - import { trimFirstCharOfLineContent } from '~/diffs/store/utils'; +import { mapState, mapActions } from 'vuex'; +import imageDiffHelper from '~/image_diff/helpers/index'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; +import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; +import { trimFirstCharOfLineContent } from '~/diffs/store/utils'; - export default { - components: { - DiffFileHeader, - SkeletonLoadingContainer, +export default { + components: { + DiffFileHeader, + SkeletonLoadingContainer, + }, + props: { + discussion: { + type: Object, + required: true, }, - props: { - discussion: { - type: Object, - required: true, - }, + }, + data() { + return { + error: false, + }; + }, + computed: { + ...mapState({ + noteableData: state => state.notes.noteableData, + }), + hasTruncatedDiffLines() { + return this.discussion.truncatedDiffLines && this.discussion.truncatedDiffLines.length !== 0; }, - data() { - return { - error: false, - }; + isDiscussionsExpanded() { + return true; // TODO: @fatihacet - Fix this. }, - computed: { - ...mapState({ - noteableData: state => state.notes.noteableData, - }), - hasTruncatedDiffLines() { - return this.discussion.truncatedDiffLines && - this.discussion.truncatedDiffLines.length !== 0; - }, - isDiscussionsExpanded() { - return true; // TODO: @fatihacet - Fix this. - }, - isCollapsed() { - return this.diffFile.collapsed || false; - }, - isImageDiff() { - return !this.diffFile.text; - }, - diffFileClass() { - const { text } = this.diffFile; - return text ? 'text-file' : 'js-image-file'; - }, - diffFile() { - return convertObjectPropsToCamelCase(this.discussion.diffFile, { deep: true }); - }, - imageDiffHtml() { - return this.discussion.imageDiffHtml; - }, - currentUser() { - return this.noteableData.current_user; - }, - userColorScheme() { - return window.gon.user_color_scheme; - }, - normalizedDiffLines() { - if (this.discussion.truncatedDiffLines) { - return this.discussion.truncatedDiffLines.map(line => - trimFirstCharOfLineContent(convertObjectPropsToCamelCase(line)), - ); - } - - return []; - }, + isCollapsed() { + return this.diffFile.collapsed || false; + }, + isImageDiff() { + return !this.diffFile.text; + }, + diffFileClass() { + const { text } = this.diffFile; + return text ? 'text-file' : 'js-image-file'; + }, + diffFile() { + return convertObjectPropsToCamelCase(this.discussion.diffFile, { deep: true }); }, - mounted() { - if (this.isImageDiff) { - const canCreateNote = false; - const renderCommentBadge = true; - imageDiffHelper.initImageDiff(this.$refs.fileHolder, canCreateNote, renderCommentBadge); - } else if (!this.hasTruncatedDiffLines) { - this.fetchDiff(); + imageDiffHtml() { + return this.discussion.imageDiffHtml; + }, + userColorScheme() { + return window.gon.user_color_scheme; + }, + normalizedDiffLines() { + if (this.discussion.truncatedDiffLines) { + return this.discussion.truncatedDiffLines.map(line => + trimFirstCharOfLineContent(convertObjectPropsToCamelCase(line)), + ); } + + return []; + }, + }, + mounted() { + if (this.isImageDiff) { + const canCreateNote = false; + const renderCommentBadge = true; + imageDiffHelper.initImageDiff(this.$refs.fileHolder, canCreateNote, renderCommentBadge); + } else if (!this.hasTruncatedDiffLines) { + this.fetchDiff(); + } + }, + methods: { + ...mapActions(['fetchDiscussionDiffLines']), + rowTag(html) { + return html.outerHTML ? 'tr' : 'template'; }, - methods: { - ...mapActions(['fetchDiscussionDiffLines']), - rowTag(html) { - return html.outerHTML ? 'tr' : 'template'; - }, - fetchDiff() { - this.error = false; - this.fetchDiscussionDiffLines(this.discussion) - .then(this.highlight) - .catch(() => { - this.error = true; - }); - }, + fetchDiff() { + this.error = false; + this.fetchDiscussionDiffLines(this.discussion) + .then(this.highlight) + .catch(() => { + this.error = true; + }); }, - }; + }, +}; </script> <template> @@ -99,7 +95,7 @@ > <diff-file-header :diff-file="diffFile" - :current-user="currentUser" + :can-current-user-fork="false" :discussions-expanded="isDiscussionsExpanded" :expanded="!isCollapsed" /> diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue index 6385b75e557..ad6e7cf501d 100644 --- a/app/assets/javascripts/notes/components/discussion_counter.vue +++ b/app/assets/javascripts/notes/components/discussion_counter.vue @@ -5,19 +5,20 @@ import resolvedSvg from 'icons/_icon_status_success_solid.svg'; import mrIssueSvg from 'icons/_icon_mr_issue.svg'; import nextDiscussionSvg from 'icons/_next_discussion.svg'; import { pluralize } from '../../lib/utils/text_utility'; -import { scrollToElement } from '../../lib/utils/common_utils'; +import discussionNavigation from '../mixins/discussion_navigation'; import tooltip from '../../vue_shared/directives/tooltip'; export default { directives: { tooltip, }, + mixins: [discussionNavigation], computed: { ...mapGetters([ 'getUserData', 'getNoteableData', 'discussionCount', - 'unresolvedDiscussions', + 'firstUnresolvedDiscussionId', 'resolvedDiscussionCount', ]), isLoggedIn() { @@ -35,11 +36,6 @@ export default { resolveAllDiscussionsIssuePath() { return this.getNoteableData.create_issue_to_resolve_discussions_path; }, - firstUnresolvedDiscussionId() { - const item = this.unresolvedDiscussions[0] || {}; - - return item.id; - }, }, created() { this.resolveSvg = resolveSvg; @@ -50,22 +46,10 @@ export default { methods: { ...mapActions(['expandDiscussion']), jumpToFirstUnresolvedDiscussion() { - const discussionId = this.firstUnresolvedDiscussionId; - if (!discussionId) { - return; - } - - const el = document.querySelector(`[data-discussion-id="${discussionId}"]`); - const activeTab = window.mrTabs.currentAction; - - if (activeTab === 'commits' || activeTab === 'pipelines') { - window.mrTabs.activateTab('show'); - } + const diffTab = window.mrTabs.currentAction === 'diffs'; + const discussionId = this.firstUnresolvedDiscussionId(diffTab); - if (el) { - this.expandDiscussion({ discussionId }); - scrollToElement(el); - } + this.jumpToDiscussion(discussionId); }, }, }; diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 26482a02e00..abcd4422d7c 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -7,7 +7,7 @@ import issuableStateMixin from '../mixins/issuable_state'; import resolvable from '../mixins/resolvable'; export default { - name: 'IssueNoteForm', + name: 'NoteForm', components: { issueWarning, markdownField, diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index bee635398b3..0fe1c16854a 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -1,11 +1,11 @@ <script> -import _ from 'underscore'; import { mapActions, mapGetters } from 'vuex'; import resolveDiscussionsSvg from 'icons/_icon_mr_issue.svg'; import nextDiscussionsSvg from 'icons/_next_discussion.svg'; -import { convertObjectPropsToCamelCase, scrollToElement } from '~/lib/utils/common_utils'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { truncateSha } from '~/lib/utils/text_utility'; import systemNote from '~/vue_shared/components/notes/system_note.vue'; +import { s__ } from '~/locale'; import Flash from '../../flash'; import { SYSTEM_NOTE } from '../constants'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; @@ -20,6 +20,7 @@ import placeholderSystemNote from '../../vue_shared/components/notes/placeholder import autosave from '../mixins/autosave'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; +import discussionNavigation from '../mixins/discussion_navigation'; import tooltip from '../../vue_shared/directives/tooltip'; export default { @@ -39,7 +40,7 @@ export default { directives: { tooltip, }, - mixins: [autosave, noteable, resolvable], + mixins: [autosave, noteable, resolvable, discussionNavigation], props: { discussion: { type: Object, @@ -60,6 +61,11 @@ export default { required: false, default: false, }, + discussionsByDiffOrder: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -74,7 +80,12 @@ export default { 'discussionCount', 'resolvedDiscussionCount', 'allDiscussions', + 'unresolvedDiscussionsIdsByDiff', + 'unresolvedDiscussionsIdsByDate', 'unresolvedDiscussions', + 'unresolvedDiscussionsIdsOrdered', + 'nextUnresolvedDiscussionId', + 'isLastUnresolvedDiscussion', ]), transformedDiscussion() { return { @@ -125,6 +136,10 @@ export default { hasMultipleUnresolvedDiscussions() { return this.unresolvedDiscussions.length > 1; }, + showJumpToNextDiscussion() { + return this.hasMultipleUnresolvedDiscussions && + !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder); + }, shouldRenderDiffs() { const { diffDiscussion, diffFile } = this.transformedDiscussion; @@ -144,19 +159,17 @@ export default { return this.isDiffDiscussion ? '' : 'card discussion-wrapper'; }, }, - mounted() { - if (this.isReplying) { - this.initAutoSave(this.transformedDiscussion); - } - }, - updated() { - if (this.isReplying) { - if (!this.autosave) { - this.initAutoSave(this.transformedDiscussion); + watch: { + isReplying() { + if (this.isReplying) { + this.$nextTick(() => { + // Pass an extra key to separate reply and note edit forms + this.initAutoSave(this.transformedDiscussion, ['Reply']); + }); } else { - this.setAutoSave(); + this.disposeAutoSave(); } - } + }, }, created() { this.resolveDiscussionsSvg = resolveDiscussionsSvg; @@ -194,16 +207,18 @@ export default { showReplyForm() { this.isReplying = true; }, - cancelReplyForm(shouldConfirm) { - if (shouldConfirm && this.$refs.noteForm.isDirty) { + cancelReplyForm(shouldConfirm, isDirty) { + if (shouldConfirm && isDirty) { + const msg = s__('Notes|Are you sure you want to cancel creating this comment?'); + // eslint-disable-next-line no-alert - if (!window.confirm('Are you sure you want to cancel creating this comment?')) { + if (!window.confirm(msg)) { return; } } - this.resetAutoSave(); this.isReplying = false; + this.resetAutoSave(); }, saveReply(noteText, form, callback) { const postData = { @@ -241,21 +256,10 @@ Please check your network connection and try again.`; }); }, jumpToNextDiscussion() { - const discussionIds = this.allDiscussions.map(d => d.id); - const unresolvedIds = this.unresolvedDiscussions.map(d => d.id); - const currentIndex = discussionIds.indexOf(this.discussion.id); - const remainingAfterCurrent = discussionIds.slice(currentIndex + 1); - const nextIndex = _.findIndex(remainingAfterCurrent, id => unresolvedIds.indexOf(id) > -1); - - if (nextIndex > -1) { - const nextId = remainingAfterCurrent[nextIndex]; - const el = document.querySelector(`[data-discussion-id="${nextId}"]`); + const nextId = + this.nextUnresolvedDiscussionId(this.discussion.id, this.discussionsByDiffOrder); - if (el) { - this.expandDiscussion({ discussionId: nextId }); - scrollToElement(el); - } - } + this.jumpToDiscussion(nextId); }, }, }; @@ -397,7 +401,7 @@ Please check your network connection and try again.`; </a> </div> <div - v-if="hasMultipleUnresolvedDiscussions" + v-if="showJumpToNextDiscussion" class="btn-group" role="group"> <button @@ -420,7 +424,8 @@ Please check your network connection and try again.`; :is-editing="false" save-button-title="Comment" @handleFormUpdate="saveReply" - @cancelForm="cancelReplyForm" /> + @cancelForm="cancelReplyForm" + /> <note-signed-out-widget v-if="!canReply" /> </div> </div> diff --git a/app/assets/javascripts/notes/mixins/autosave.js b/app/assets/javascripts/notes/mixins/autosave.js index 36cc8d5d056..4f45f912479 100644 --- a/app/assets/javascripts/notes/mixins/autosave.js +++ b/app/assets/javascripts/notes/mixins/autosave.js @@ -4,12 +4,18 @@ import { capitalizeFirstCharacter } from '../../lib/utils/text_utility'; export default { methods: { - initAutoSave(noteable) { - this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), [ + initAutoSave(noteable, extraKeys = []) { + let keys = [ 'Note', - capitalizeFirstCharacter(noteable.noteable_type), + capitalizeFirstCharacter(noteable.noteable_type || noteable.noteableType), noteable.id, - ]); + ]; + + if (extraKeys) { + keys = keys.concat(extraKeys); + } + + this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), keys); }, resetAutoSave() { this.autosave.reset(); @@ -17,5 +23,8 @@ export default { setAutoSave() { this.autosave.save(); }, + disposeAutoSave() { + this.autosave.dispose(); + }, }, }; diff --git a/app/assets/javascripts/notes/mixins/discussion_navigation.js b/app/assets/javascripts/notes/mixins/discussion_navigation.js new file mode 100644 index 00000000000..f7c4deee1f8 --- /dev/null +++ b/app/assets/javascripts/notes/mixins/discussion_navigation.js @@ -0,0 +1,29 @@ +import { scrollToElement } from '~/lib/utils/common_utils'; + +export default { + methods: { + jumpToDiscussion(id) { + if (id) { + const activeTab = window.mrTabs.currentAction; + const selector = + activeTab === 'diffs' + ? `ul.notes[data-discussion-id="${id}"]` + : `div.discussion[data-discussion-id="${id}"]`; + const el = document.querySelector(selector); + + if (activeTab === 'commits' || activeTab === 'pipelines') { + window.mrTabs.activateTab('show'); + } + + if (el) { + this.expandDiscussion({ discussionId: id }); + + scrollToElement(el); + return true; + } + } + + return false; + }, + }, +}; diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index 5c65e1c3bb5..0d8d197bf71 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -28,18 +28,6 @@ export const notesById = state => return acc; }, {}); -export const discussionsByLineCode = state => - state.discussions.reduce((acc, note) => { - if (note.diff_discussion && note.line_code && note.resolvable) { - // For context about line notes: there might be multiple notes with the same line code - const items = acc[note.line_code] || []; - items.push(note); - - Object.assign(acc, { [note.line_code]: items }); - } - return acc; - }, {}); - export const noteableType = state => { const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants; @@ -82,6 +70,9 @@ export const allDiscussions = (state, getters) => { return Object.values(resolved).concat(unresolved); }; +export const allResolvableDiscussions = (state, getters) => + getters.allDiscussions.filter(d => !d.individual_note && d.resolvable); + export const resolvedDiscussionsById = state => { const map = {}; @@ -98,6 +89,51 @@ export const resolvedDiscussionsById = state => { return map; }; +// Gets Discussions IDs ordered by the date of their initial note +export const unresolvedDiscussionsIdsByDate = (state, getters) => + getters.allResolvableDiscussions + .filter(d => !d.resolved) + .sort((a, b) => { + const aDate = new Date(a.notes[0].created_at); + const bDate = new Date(b.notes[0].created_at); + + if (aDate < bDate) { + return -1; + } + + return aDate === bDate ? 0 : 1; + }) + .map(d => d.id); + +// Gets Discussions IDs ordered by their position in the diff +// +// Sorts the array of resolvable yet unresolved discussions by +// comparing file names first. If file names are the same, compares +// line numbers. +export const unresolvedDiscussionsIdsByDiff = (state, getters) => + getters.allResolvableDiscussions + .filter(d => !d.resolved) + .sort((a, b) => { + if (!a.diff_file || !b.diff_file) { + return 0; + } + + // Get file names comparison result + const filenameComparison = a.diff_file.file_path.localeCompare(b.diff_file.file_path); + + // Get the line numbers, to compare within the same file + const aLines = [a.position.formatter.new_line, a.position.formatter.old_line]; + const bLines = [b.position.formatter.new_line, b.position.formatter.old_line]; + + return filenameComparison < 0 || + (filenameComparison === 0 && + // .max() because one of them might be zero (if removed/added) + Math.max(aLines[0], aLines[1]) < Math.max(bLines[0], bLines[1])) + ? -1 + : 1; + }) + .map(d => d.id); + export const resolvedDiscussionCount = (state, getters) => { const resolvedMap = getters.resolvedDiscussionsById; @@ -114,5 +150,42 @@ export const discussionTabCounter = state => { return all.length; }; +// Returns the list of discussion IDs ordered according to given parameter +// @param {Boolean} diffOrder - is ordered by diff? +export const unresolvedDiscussionsIdsOrdered = (state, getters) => diffOrder => { + if (diffOrder) { + return getters.unresolvedDiscussionsIdsByDiff; + } + return getters.unresolvedDiscussionsIdsByDate; +}; + +// Checks if a given discussion is the last in the current order (diff or date) +// @param {Boolean} discussionId - id of the discussion +// @param {Boolean} diffOrder - is ordered by diff? +export const isLastUnresolvedDiscussion = (state, getters) => (discussionId, diffOrder) => { + const idsOrdered = getters.unresolvedDiscussionsIdsOrdered(diffOrder); + const lastDiscussionId = idsOrdered[idsOrdered.length - 1]; + + return lastDiscussionId === discussionId; +}; + +// Gets the ID of the discussion following the one provided, respecting order (diff or date) +// @param {Boolean} discussionId - id of the current discussion +// @param {Boolean} diffOrder - is ordered by diff? +export const nextUnresolvedDiscussionId = (state, getters) => (discussionId, diffOrder) => { + const idsOrdered = getters.unresolvedDiscussionsIdsOrdered(diffOrder); + const currentIndex = idsOrdered.indexOf(discussionId); + + return idsOrdered.slice(currentIndex + 1, currentIndex + 2)[0]; +}; + +// @param {Boolean} diffOrder - is ordered by diff? +export const firstUnresolvedDiscussionId = (state, getters) => diffOrder => { + if (diffOrder) { + return getters.unresolvedDiscussionsIdsByDiff[0]; + } + return getters.unresolvedDiscussionsIdsByDate[0]; +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue index d0613804067..0d05668b285 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue @@ -68,7 +68,7 @@ :name="inputNameAttribute" :value="cronInterval" :checked="isEditable" - class="label-light" + class="label-bold" type="radio" @click="toggleCustomInput(true)" /> @@ -93,13 +93,13 @@ v-model="cronInterval" :name="inputNameAttribute" :value="cronIntervalPresets.everyDay" - class="label-light" + class="label-bold" type="radio" @click="toggleCustomInput(false)" /> <label - class="label-light" + class="label-bold" for="every-day" > {{ __('Every day (at 4:00am)') }} @@ -112,13 +112,13 @@ v-model="cronInterval" :name="inputNameAttribute" :value="cronIntervalPresets.everyWeek" - class="label-light" + class="label-bold" type="radio" @click="toggleCustomInput(false)" /> <label - class="label-light" + class="label-bold" for="every-week" > {{ __('Every week (Sundays at 4:00am)') }} @@ -131,13 +131,13 @@ v-model="cronInterval" :name="inputNameAttribute" :value="cronIntervalPresets.everyMonth" - class="label-light" + class="label-bold" type="radio" @click="toggleCustomInput(false)" /> <label - class="label-light" + class="label-bold" for="every-month" > {{ __('Every month (on the 1st at 4:00am)') }} diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue index 17b91479ea5..83437363af5 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue @@ -24,7 +24,7 @@ <div class="project-feature-row"> <label v-if="label" - class="label-light" + class="label-bold" > {{ label }} <a diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue index b76965f280b..0fdb0a080cf 100644 --- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue +++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue @@ -1,13 +1,10 @@ <script> import $ from 'jquery'; -import PerformanceBarService from '../services/performance_bar_service'; import detailedMetric from './detailed_metric.vue'; import requestSelector from './request_selector.vue'; import simpleMetric from './simple_metric.vue'; -import Flash from '../../flash'; - export default { components: { detailedMetric, @@ -69,37 +66,13 @@ export default { }, }, mounted() { - this.interceptor = PerformanceBarService.registerInterceptor( - this.peekUrl, - this.loadRequestDetails, - ); - - this.loadRequestDetails(this.requestId, window.location.href); this.currentRequest = this.requestId; if (this.lineProfileModal.length) { this.lineProfileModal.modal('toggle'); } }, - beforeDestroy() { - PerformanceBarService.removeInterceptor(this.interceptor); - }, methods: { - loadRequestDetails(requestId, requestUrl) { - if (!this.store.canTrackRequest(requestUrl)) { - return; - } - - this.store.addRequest(requestId, requestUrl); - - PerformanceBarService.fetchRequestDetails(this.peekUrl, requestId) - .then(res => { - this.store.addRequestDetails(requestId, res.data.data); - }) - .catch(() => - Flash(`Error getting performance bar results for ${requestId}`), - ); - }, changeCurrentRequest(newRequestId) { this.currentRequest = newRequestId; }, diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js index 4a98aed7679..41880d27516 100644 --- a/app/assets/javascripts/performance_bar/index.js +++ b/app/assets/javascripts/performance_bar/index.js @@ -1,12 +1,13 @@ import Vue from 'vue'; -import performanceBarApp from './components/performance_bar_app.vue'; +import Flash from '../flash'; +import PerformanceBarService from './services/performance_bar_service'; import PerformanceBarStore from './stores/performance_bar_store'; export default ({ container }) => new Vue({ el: container, components: { - performanceBarApp, + performanceBarApp: () => import('./components/performance_bar_app.vue'), }, data() { const performanceBarData = document.querySelector(this.$options.el) @@ -21,6 +22,34 @@ export default ({ container }) => profileUrl: performanceBarData.profileUrl, }; }, + mounted() { + this.interceptor = PerformanceBarService.registerInterceptor( + this.peekUrl, + this.loadRequestDetails, + ); + + this.loadRequestDetails(this.requestId, window.location.href); + }, + beforeDestroy() { + PerformanceBarService.removeInterceptor(this.interceptor); + }, + methods: { + loadRequestDetails(requestId, requestUrl) { + if (!this.store.canTrackRequest(requestUrl)) { + return; + } + + this.store.addRequest(requestId, requestUrl); + + PerformanceBarService.fetchRequestDetails(this.peekUrl, requestId) + .then(res => { + this.store.addRequestDetails(requestId, res.data.data); + }) + .catch(() => + Flash(`Error getting performance bar results for ${requestId}`), + ); + }, + }, render(createElement) { return createElement('performance-bar-app', { props: { diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue index 56fdb858088..c7df69c69ed 100644 --- a/app/assets/javascripts/pipelines/components/stage.vue +++ b/app/assets/javascripts/pipelines/components/stage.vue @@ -175,6 +175,7 @@ export default { <span :aria-label="stage.title" aria-hidden="true" + class="no-pointer-events" > <icon :name="borderlessIcon" /> </span> diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js index 8cf7f2f23d0..e49c67ffb5c 100644 --- a/app/assets/javascripts/profile/profile.js +++ b/app/assets/javascripts/profile/profile.js @@ -49,13 +49,15 @@ export default class Profile { saveForm() { const self = this; - const formData = new FormData(this.form[0]); + const formData = new FormData(this.form.get(0)); const avatarBlob = this.avatarGlCrop.getBlob(); if (avatarBlob != null) { formData.append('user[avatar]', avatarBlob, 'avatar.png'); } + formData.delete('user[avatar]-trigger'); + axios({ method: this.form.attr('method'), url: this.form.attr('action'), diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue index c18b74743e4..a4c2289c590 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue @@ -1,7 +1,7 @@ <script> import tooltip from '~/vue_shared/directives/tooltip'; import { n__ } from '~/locale'; -import { webIDEUrl } from '~/lib/utils/url_utility'; +import { mergeUrlParams, webIDEUrl } from '~/lib/utils/url_utility'; import Icon from '~/vue_shared/components/icon.vue'; import clipboardButton from '~/vue_shared/components/clipboard_button.vue'; @@ -43,7 +43,10 @@ export default { return this.isBranchTitleLong(this.mr.targetBranch); }, webIdePath() { - return webIDEUrl(this.mr.statusPath.replace('.json', '')); + return mergeUrlParams({ + target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ? + this.mr.targetProjectFullPath : '', + }, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`)); }, }, methods: { diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index c881cd496d1..e84c436905d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -16,10 +16,11 @@ export default class MergeRequestStore { const pipelineStatus = data.pipeline ? data.pipeline.details.status : null; this.squash = data.squash; - this.squashBeforeMergeHelpPath = this.squashBeforeMergeHelpPath || - data.squash_before_merge_help_path; + this.squashBeforeMergeHelpPath = + this.squashBeforeMergeHelpPath || data.squash_before_merge_help_path; this.enableSquashBeforeMerge = this.enableSquashBeforeMerge || true; + this.iid = data.iid; this.title = data.title; this.targetBranch = data.target_branch; this.sourceBranch = data.source_branch; @@ -85,6 +86,8 @@ export default class MergeRequestStore { this.isMergeAllowed = data.mergeable || false; this.mergeOngoing = data.merge_ongoing; this.allowCollaboration = data.allow_collaboration; + this.targetProjectFullPath = data.target_project_full_path; + this.sourceProjectFullPath = data.source_project_full_path; // Cherry-pick and Revert actions related this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false; @@ -97,7 +100,8 @@ export default class MergeRequestStore { this.hasCI = data.has_ci; this.ciStatus = data.ci_status; this.isPipelineFailed = this.ciStatus === 'failed' || this.ciStatus === 'canceled'; - this.isPipelinePassing = this.ciStatus === 'success' || this.ciStatus === 'success_with_warnings'; + this.isPipelinePassing = + this.ciStatus === 'success' || this.ciStatus === 'success_with_warnings'; this.isPipelineSkipped = this.ciStatus === 'skipped'; this.pipelineDetailedStatus = pipelineStatus; this.isPipelineActive = data.pipeline ? data.pipeline.active : false; diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue index c42c4a1fbe7..e7ff76c8218 100644 --- a/app/assets/javascripts/vue_shared/components/icon.vue +++ b/app/assets/javascripts/vue_shared/components/icon.vue @@ -1,24 +1,40 @@ <script> -/* This is a re-usable vue component for rendering a svg sprite - icon - Sample configuration: - - <icon - name="retry" - :size="32" - css-classes="top" - /> - -*/ // only allow classes in images.scss e.g. s12 const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; +let iconValidator = () => true; + +/* + During development/tests we want to validate that we are just using icons that are actually defined +*/ +if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line global-require + const data = require('@gitlab-org/gitlab-svgs/dist/icons.json'); + const { icons } = data; + iconValidator = value => { + if (icons.includes(value)) { + return true; + } + // eslint-disable-next-line no-console + console.warn(`Icon '${value}' is not a known icon of @gitlab/gitlab-svg`); + return false; + }; +} +/** This is a re-usable vue component for rendering a svg sprite icon + * @example + * <icon + * name="retry" + * :size="32" + * css-classes="top" + * /> + */ export default { props: { name: { type: String, required: true, + validator: iconValidator, }, size: { @@ -83,6 +99,6 @@ export default { :x="x" :y="y" > - <use v-bind="{ 'xlink:href':spriteHref }" /> + <use v-bind="{ 'xlink:href':spriteHref }"/> </svg> </template> diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.vue b/app/assets/javascripts/vue_shared/components/memory_graph.vue index 522091ea889..552a92541be 100644 --- a/app/assets/javascripts/vue_shared/components/memory_graph.vue +++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue @@ -126,7 +126,7 @@ export default { :cx="dotX" :cy="dotY" r="1.5" - tranform="translate(0 -1)" + transform="translate(0 -1)" /> </svg> </div> diff --git a/app/assets/javascripts/vue_shared/components/reports/help_popover.vue b/app/assets/javascripts/vue_shared/components/reports/help_popover.vue new file mode 100644 index 00000000000..c5faa29fd2a --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/help_popover.vue @@ -0,0 +1,48 @@ +<script> +import $ from 'jquery'; +import Icon from '~/vue_shared/components/icon.vue'; +import { inserted } from '~/feature_highlight/feature_highlight_helper'; +import { mouseenter, debouncedMouseleave, togglePopover } from '~/shared/popover'; + +export default { + name: 'ReportsHelpPopover', + components: { + Icon, + }, + props: { + options: { + type: Object, + required: true, + }, + }, + mounted() { + const $el = $(this.$el); + + $el + .popover({ + html: true, + trigger: 'focus', + container: 'body', + placement: 'top', + template: + '<div class="popover" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>', + ...this.options, + }) + .on('mouseenter', mouseenter) + .on('mouseleave', debouncedMouseleave(300)) + .on('inserted.bs.popover', inserted) + .on('show.bs.popover', () => { + window.addEventListener('scroll', togglePopover.bind($el, false), { once: true }); + }); + }, +}; +</script> +<template> + <button + type="button" + class="btn btn-blank btn-transparent btn-help" + tabindex="0" + > + <icon name="question" /> + </button> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/issues_list.vue b/app/assets/javascripts/vue_shared/components/reports/issues_list.vue new file mode 100644 index 00000000000..e1e03e39ee0 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/issues_list.vue @@ -0,0 +1,99 @@ +<script> +import IssuesBlock from './report_issues.vue'; + +/** + * Renders block of issues + */ + +export default { + components: { + IssuesBlock, + }, + props: { + unresolvedIssues: { + type: Array, + required: false, + default: () => [], + }, + resolvedIssues: { + type: Array, + required: false, + default: () => [], + }, + neutralIssues: { + type: Array, + required: false, + default: () => [], + }, + allIssues: { + type: Array, + required: false, + default: () => [], + }, + type: { + type: String, + required: true, + }, + }, + data() { + return { + isFullReportVisible: false, + }; + }, + computed: { + unresolvedIssuesStatus() { + return this.type === 'license' ? 'neutral' : 'failed'; + }, + }, + methods: { + openFullReport() { + this.isFullReportVisible = true; + }, + }, +}; +</script> +<template> + <div class="report-block-container"> + + <issues-block + v-if="unresolvedIssues.length" + :type="type" + :status="unresolvedIssuesStatus" + :issues="unresolvedIssues" + class="js-mr-code-new-issues" + /> + + <issues-block + v-if="isFullReportVisible" + :type="type" + :issues="allIssues" + class="js-mr-code-all-issues" + status="failed" + /> + + <issues-block + v-if="neutralIssues.length" + :type="type" + :issues="neutralIssues" + class="js-mr-code-non-issues" + status="neutral" + /> + + <issues-block + v-if="resolvedIssues.length" + :type="type" + :issues="resolvedIssues" + class="js-mr-code-resolved-issues" + status="success" + /> + + <button + v-if="allIssues.length && !isFullReportVisible" + type="button" + class="btn-link btn-blank prepend-left-10 js-expand-full-list break-link" + @click="openFullReport" + > + {{ s__("ciReport|Show complete code vulnerabilities report") }} + </button> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue b/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue new file mode 100644 index 00000000000..4f81cee2a38 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue @@ -0,0 +1,33 @@ +<script> +import { mapActions } from 'vuex'; + +export default { + props: { + issue: { + type: Object, + required: true, + }, + // failed || success + status: { + type: String, + required: true, + }, + }, + methods: { + ...mapActions(['openModal']), + handleIssueClick() { + const { issue, status, openModal } = this; + openModal({ issue, status }); + }, + }, +}; +</script> +<template> + <button + type="button" + class="btn-link btn-blank text-left break-link vulnerability-name-button" + @click="handleIssueClick()" + > + {{ issue.title }} + </button> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/report_issues.vue b/app/assets/javascripts/vue_shared/components/reports/report_issues.vue new file mode 100644 index 00000000000..ecffb02a3a0 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/report_issues.vue @@ -0,0 +1,72 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + name: 'ReportIssues', + components: { + Icon, + }, + props: { + issues: { + type: Array, + required: true, + }, + type: { + type: String, + required: true, + }, + // failed || success + status: { + type: String, + required: true, + }, + }, + computed: { + iconName() { + if (this.isStatusFailed) { + return 'status_failed_borderless'; + } else if (this.isStatusSuccess) { + return 'status_success_borderless'; + } + + return 'status_created_borderless'; + }, + isStatusFailed() { + return this.status === 'failed'; + }, + isStatusSuccess() { + return this.status === 'success'; + }, + isStatusNeutral() { + return this.status === 'neutral'; + }, + }, +}; +</script> +<template> + <div> + <ul class="report-block-list"> + <li + v-for="(issue, index) in issues" + :class="{ 'is-dismissed': issue.isDismissed }" + :key="index" + class="report-block-list-issue" + > + <div + :class="{ + failed: isStatusFailed, + success: isStatusSuccess, + neutral: isStatusNeutral, + }" + class="report-block-list-icon append-right-5" + > + <icon + :name="iconName" + :size="32" + /> + </div> + + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/report_link.vue b/app/assets/javascripts/vue_shared/components/reports/report_link.vue new file mode 100644 index 00000000000..74d68f9f439 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/report_link.vue @@ -0,0 +1,29 @@ +<script> +export default { + name: 'ReportIssueLink', + props: { + issue: { + type: Object, + required: true, + }, + }, +}; +</script> +<template> + <div class="report-block-list-issue-description-link"> + in + + <a + v-if="issue.urlPath" + :href="issue.urlPath" + target="_blank" + rel="noopener noreferrer nofollow" + class="break-link" + > + {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template> + </a> + <template v-else> + {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template> + </template> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/report_section.vue b/app/assets/javascripts/vue_shared/components/reports/report_section.vue new file mode 100644 index 00000000000..d383ed99a0c --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/report_section.vue @@ -0,0 +1,192 @@ +<script> +import { __ } from '~/locale'; +import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue'; +import IssuesList from './issues_list.vue'; +import Popover from './help_popover.vue'; + +const LOADING = 'LOADING'; +const ERROR = 'ERROR'; +const SUCCESS = 'SUCCESS'; + +export default { + name: 'ReportSection', + components: { + IssuesList, + StatusIcon, + Popover, + }, + props: { + alwaysOpen: { + type: Boolean, + required: false, + default: false, + }, + type: { + type: String, + required: false, + default: '', + }, + status: { + type: String, + required: true, + }, + loadingText: { + type: String, + required: false, + default: '', + }, + errorText: { + type: String, + required: false, + default: '', + }, + successText: { + type: String, + required: true, + }, + unresolvedIssues: { + type: Array, + required: false, + default: () => [], + }, + resolvedIssues: { + type: Array, + required: false, + default: () => [], + }, + neutralIssues: { + type: Array, + required: false, + default: () => [], + }, + allIssues: { + type: Array, + required: false, + default: () => [], + }, + infoText: { + type: [String, Boolean], + required: false, + default: false, + }, + hasIssues: { + type: Boolean, + required: true, + }, + popoverOptions: { + type: Object, + default: () => ({}), + required: false, + }, + }, + + data() { + return { + isCollapsed: true, + }; + }, + + computed: { + collapseText() { + return this.isCollapsed ? __('Expand') : __('Collapse'); + }, + isLoading() { + return this.status === LOADING; + }, + loadingFailed() { + return this.status === ERROR; + }, + isSuccess() { + return this.status === SUCCESS; + }, + isCollapsible() { + return !this.alwaysOpen && this.hasIssues; + }, + isExpanded() { + return this.alwaysOpen || !this.isCollapsed; + }, + statusIconName() { + if (this.isLoading) { + return 'loading'; + } + if (this.loadingFailed || this.unresolvedIssues.length || this.neutralIssues.length) { + return 'warning'; + } + return 'success'; + }, + headerText() { + if (this.isLoading) { + return this.loadingText; + } + + if (this.isSuccess) { + return this.successText; + } + + if (this.loadingFailed) { + return this.errorText; + } + + return ''; + }, + hasPopover() { + return Object.keys(this.popoverOptions).length > 0; + }, + }, + methods: { + toggleCollapsed() { + this.isCollapsed = !this.isCollapsed; + }, + }, +}; +</script> +<template> + <section class="media-section"> + <div + class="media" + > + <status-icon + :status="statusIconName" + /> + <div + class="media-body space-children d-flex" + > + <span + class="js-code-text code-text" + > + {{ headerText }} + + <popover + v-if="hasPopover" + :options="popoverOptions" + class="prepend-left-5" + /> + </span> + + <button + v-if="isCollapsible" + type="button" + class="js-collapse-btn btn bt-default float-right btn-sm" + @click="toggleCollapsed" + > + {{ collapseText }} + </button> + </div> + </div> + + <div + v-if="hasIssues" + v-show="isExpanded" + class="js-report-section-container" + > + <slot name="body"> + <issues-list + :unresolved-issues="unresolvedIssues" + :resolved-issues="resolvedIssues" + :all-issues="allIssues" + :type="type" + /> + </slot> + </div> + </section> +</template> diff --git a/app/assets/javascripts/vue_shared/components/reports/summary_row.vue b/app/assets/javascripts/vue_shared/components/reports/summary_row.vue new file mode 100644 index 00000000000..997bad960e2 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/reports/summary_row.vue @@ -0,0 +1,66 @@ +<script> +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import LoadingIcon from '~/vue_shared/components/loading_icon.vue'; +import Popover from './help_popover.vue'; + +/** + * Renders the summary row for each report + * + * Used both in MR widget and Pipeline's view for: + * - Unit tests reports + * - Security reports + */ + +export default { + name: 'ReportSummaryRow', + components: { + CiIcon, + LoadingIcon, + Popover, + }, + props: { + summary: { + type: String, + required: true, + }, + statusIcon: { + type: String, + required: true, + }, + popoverOptions: { + type: Object, + required: true, + }, + }, + computed: { + iconStatus() { + return { + group: this.statusIcon, + icon: `status_${this.statusIcon}`, + }; + }, + }, +}; +</script> +<template> + <div class="report-block-list-issue report-block-list-issue-parent"> + <div class="report-block-list-icon append-right-10 prepend-left-5"> + <loading-icon + v-if="statusIcon === 'loading'" + css-class="report-block-list-loading-icon" + /> + <ci-icon + v-else + :status="iconStatus" + /> + </div> + + <div class="report-block-list-issue-description"> + <div class="report-block-list-issue-description-text"> + {{ summary }} + </div> + + <popover :options="popoverOptions" /> + </div> + </div> +</template> diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss index ded33e8b151..d28ad407734 100644 --- a/app/assets/stylesheets/bootstrap_migration.scss +++ b/app/assets/stylesheets/bootstrap_migration.scss @@ -110,7 +110,7 @@ code { padding: 2px 4px; color: $red-600; background-color: $red-100; - border-radius: 3px; + border-radius: $border-radius-default; .code > & { background-color: inherit; @@ -128,7 +128,8 @@ table { border-spacing: 0; } -.tooltip { +.tooltip, +.no-pointer-events { // Fix bootstrap4 bug whereby tooltips flicker when they are hovered over their borders pointer-events: none; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index c7b5e22c33d..ec4a0f378d0 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -822,7 +822,7 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { display: flex; flex-direction: row; width: 500px; - height: 334px; + height: 354px; .frequent-items-dropdown-sidebar, .frequent-items-dropdown-content { @@ -868,6 +868,7 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { } .frequent-items-list-container { + height: 304px; padding: 8px 0; overflow-y: auto; @@ -897,10 +898,6 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { margin-top: 8px; } - .frequent-items-search-container { - height: 284px; - } - @include media-breakpoint-down(xs) { .frequent-items-list-container { width: auto; diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index a22454c24e2..a10ff3eecb3 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -31,7 +31,7 @@ label { margin: 0; } - &.label-light { + &.label-bold { font-weight: $gl-font-weight-bold; } } diff --git a/app/assets/stylesheets/framework/gfm.scss b/app/assets/stylesheets/framework/gfm.scss index 1cf12b1a015..d2ba76f5160 100644 --- a/app/assets/stylesheets/framework/gfm.scss +++ b/app/assets/stylesheets/framework/gfm.scss @@ -9,12 +9,8 @@ .gfm-project_member { padding: 0 2px; - border-radius: #{$border-radius-default / 2}; - background-color: $user-mention-bg; - - &:hover { - background-color: $user-mention-bg-hover; - } + background-color: $blue-100; + border-radius: $border-radius-default; } .gfm-color_chip { diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index a8e28104a94..5ca4d944d73 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -47,7 +47,6 @@ .card-body { padding: $gl-padding; - background-color: $white-light; .form-actions { margin: -$gl-padding; diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss index 9dbb04e5443..8bab8cf36b1 100644 --- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss +++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss @@ -321,11 +321,18 @@ } &.activities { + display: flex; border-bottom: 1px solid $border-color; + overflow: hidden; .nav-links { border-bottom: 0; } + + @include media-breakpoint-down(xs) { + display: block; + overflow: visible; + } } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 6cfa09b56a7..6c2fdbe0608 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -297,7 +297,6 @@ $performance-bar-height: 35px; $flash-height: 52px; $context-header-height: 60px; $breadcrumb-min-height: 48px; -$gcp-signup-offer-icon-max-width: 125px; /* * Common component specific colors diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss index 56beb7718a4..0f22fe21143 100644 --- a/app/assets/stylesheets/pages/clusters.scss +++ b/app/assets/stylesheets/pages/clusters.scss @@ -32,49 +32,23 @@ } .gcp-signup-offer { - background-color: $blue-50; - border: 1px solid $blue-300; - border-radius: $border-radius-default; + border-left-color: $blue-500; - // TODO: To be superceded by cssLab - &.alert { - padding: 24px 16px; - - &-dismissable { - padding-right: 32px; - - .close { - top: -8px; - right: -16px; - color: $blue-500; - opacity: 1; - } - } - } - - .gcp-logo { - margin-bottom: $gl-padding; - text-align: center; - } - - img { - max-width: $gcp-signup-offer-icon-max-width; + svg { + fill: $blue-500; + vertical-align: middle; } - a:not(.btn) { - color: $gl-link-color; - font-weight: normal; - text-decoration: none; - } + .gcp-signup-offer--content { + display: flex; - @include media-breakpoint-up(sm) { - > div { - display: flex; - align-items: center; + h4 { + font-size: 16px; + line-height: 24px; } - .gcp-logo { - margin: 0; + .gcp-signup-offer--icon { + align-self: flex-start; } } } diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 3144dcc4dc0..8915b323b3c 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -293,6 +293,8 @@ .prometheus-graph-flag { display: block; min-width: 160px; + border: 0; + box-shadow: 0 1px 4px 0 $black-transparent; h5 { padding: 0; @@ -312,7 +314,6 @@ &.popover { padding: 0; - border: 1px solid $border-color; &.left { left: auto; @@ -320,12 +321,19 @@ margin-right: 10px; > .arrow { - right: -16px; + right: -14px; border-left-color: $border-color; } > .arrow::after { - border-left-color: $theme-gray-50; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-left: 4px solid $theme-gray-50; + } + + .arrow-shadow { + right: -3px; + box-shadow: 1px 0 9px 0 $black-transparent; } } @@ -335,19 +343,35 @@ margin-left: 10px; > .arrow { - left: -16px; + left: -7px; border-right-color: $border-color; } > .arrow::after { - border-right-color: $theme-gray-50; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 4px solid $theme-gray-50; + } + + .arrow-shadow { + left: -3px; + box-shadow: 1px 0 8px 0 $black-transparent; } } > .arrow { - top: 16px; - margin-top: -8px; - border-width: 8px; + top: 10px; + margin: 0; + } + + .arrow-shadow { + content: ""; + position: absolute; + width: 7px; + height: 7px; + background-color: transparent; + transform: rotate(45deg); + top: 13px; } > .popover-title, @@ -355,10 +379,12 @@ padding: 8px; font-size: 12px; white-space: nowrap; + position: relative; } > .popover-title { background-color: $theme-gray-50; + border-radius: $border-radius-default $border-radius-default 0 0; } } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 5835b8b8c9b..c8349a4ef79 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -551,6 +551,7 @@ @include media-breakpoint-up(lg) { .branch-actions { align-self: center; + margin-left: $gl-padding; } } } diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss new file mode 100644 index 00000000000..ce253ebb71f --- /dev/null +++ b/app/assets/stylesheets/pages/reports.scss @@ -0,0 +1,159 @@ +.split-report-section { + border-bottom: 1px solid $gray-darker; + + .report-block-container { + max-height: 500px; + overflow: auto; + } + + .space-children, + .space-children > span { + display: flex; + align-self: center; + } + + .media { + align-items: center; + padding: 10px; + line-height: 20px; + + /* + This fixes the wrapping div of the icon in the report header. + Apparently the borderless status icons are half the size of the status icons with border. + This means we have to double the size of the wrapping div for borderless icons. + */ + .space-children:first-child { + width: 32px; + height: 32px; + align-items: center; + justify-content: center; + margin-right: 5px; + margin-left: 1px; + } + } + + .code-text { + width: 100%; + flex: 1; + } +} + +.mr-widget-grouped-section { + .report-block-container { + max-height: 170px; + overflow: auto; + } + + .report-block-list-issue-parent { + padding: $gl-padding-top $gl-padding; + border-top: 1px solid $border-color; + } + + .report-block-list-icon .loading-container { + position: relative; + left: -2px; + // needed to make the next element align with the + // elements below that have a svg with 16px width + .fa-spinner { + width: 16px; + } + } +} + +.report-block-container { + border-top: 1px solid $border-color; + padding: $gl-padding-top; + background-color: $gray-light; + + // Clean MR widget CSS + line-height: 20px; +} + +.report-block-list { + list-style: none; + padding: 0 1px; + margin: 0; + + .license-item { + line-height: $gl-padding-24; + + .license-dependencies { + color: $gl-text-color-tertiary; + } + + .btn-show-all-packages { + line-height: $gl-btn-line-height; + margin-bottom: 2px; + } + } +} + +.report-block-list-icon { + display: flex; + + &.failed { + color: $red-500; + } + + &.success { + color: $green-500; + } + + &.neutral { + color: $theme-gray-700; + } + + .ci-status-icon { + svg { + width: 16px; + height: 16px; + left: -2px; + } + } +} + +.report-block-list-issue { + display: flex; + align-items: flex-start; + align-content: flex-start; +} + +.is-dismissed .report-block-list-issue-description, +.is-dismissed .vulnerability-name-button { + text-decoration: line-through; +} + +.report-block-list-issue-description-text::after { + content: '\00a0'; +} + +.report-block-list-issue-description { + align-content: space-around; + align-items: flex-start; + flex-wrap: wrap; + display: flex; + align-self: center; +} + +.report-block { + .break-link { + word-wrap: break-word; + word-break: break-all; + } +} + +.report-block-issue-code { + width: 600px; +} + +.modal-security-report-dast { + .modal-dialog { + width: $modal-lg; + max-width: $modal-lg; + } + + // This is temporary till we get the new modals hooked up + &.modal-hide-footer .modal-footer { + display: none; + } +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f45fcd4d900..eeceb99c8d2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base include EnforcesTwoFactorAuthentication include WithPerformanceBar + before_action :limit_unauthenticated_session_times before_action :authenticate_sessionless_user! before_action :authenticate_user! before_action :enforce_terms!, if: :should_enforce_terms? @@ -85,6 +86,24 @@ class ApplicationController < ActionController::Base end end + # By default, all sessions are given the same expiration time configured in + # the session store (e.g. 1 week). However, unauthenticated users can + # generate a lot of sessions, primarily for CSRF verification. It makes + # sense to reduce the TTL for unauthenticated to something much lower than + # the default (e.g. 1 hour) to limit Redis memory. In addition, Rails + # creates a new session after login, so the short TTL doesn't even need to + # be extended. + def limit_unauthenticated_session_times + return if current_user + + # Rack sets this header, but not all tests may have it: https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L251-L259 + return unless request.env['rack.session.options'] + + # This works because Rack uses these options every time a request is handled: + # https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L342 + request.env['rack.session.options'][:expire_after] = Settings.gitlab['unauthenticated_session_expire_delay'] + end + protected def append_info_to_payload(payload) diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb index 79ee5b2f91e..4584ff782a3 100644 --- a/app/controllers/concerns/lfs_request.rb +++ b/app/controllers/concerns/lfs_request.rb @@ -71,7 +71,22 @@ module LfsRequest def lfs_download_access? return false unless project.lfs_enabled? - ci? || lfs_deploy_token? || user_can_download_code? || build_can_download_code? + ci? || lfs_deploy_token? || user_can_download_code? || build_can_download_code? || deploy_token_can_download_code? + end + + def deploy_token_can_download_code? + deploy_token_present? && + deploy_token.project == project && + deploy_token.active? && + deploy_token.read_repository? + end + + def deploy_token_present? + user && user.is_a?(DeployToken) + end + + def deploy_token + user end def lfs_upload_access? @@ -86,7 +101,7 @@ module LfsRequest end def user_can_download_code? - has_authentication_ability?(:download_code) && can?(user, :download_code, project) + has_authentication_ability?(:download_code) && can?(user, :download_code, project) && !deploy_token_present? end def build_can_download_code? diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb index fccbdbca0f6..53f70446d95 100644 --- a/app/controllers/import/gitlab_controller.rb +++ b/app/controllers/import/gitlab_controller.rb @@ -1,4 +1,7 @@ class Import::GitlabController < Import::BaseController + MAX_PROJECT_PAGES = 15 + PER_PAGE_PROJECTS = 100 + before_action :verify_gitlab_import_enabled before_action :gitlab_auth, except: :callback @@ -10,7 +13,7 @@ class Import::GitlabController < Import::BaseController end def status - @repos = client.projects + @repos = client.projects(starting_page: 1, page_limit: MAX_PROJECT_PAGES, per_page: PER_PAGE_PROJECTS) @already_added_projects = find_already_added_projects('gitlab') already_added_projects_names = @already_added_projects.pluck(:import_source) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 9bc774b7636..1cba0011304 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -10,7 +10,6 @@ class Projects::RawController < Projects::ApplicationController def show @blob = @repository.blob_at(@commit.id, @path) - if @blob headers['X-Content-Type-Options'] = 'nosniff' @@ -19,7 +18,7 @@ class Projects::RawController < Projects::ApplicationController if @blob.stored_externally? send_lfs_object else - send_git_blob @repository, @blob + send_git_blob @repository, @blob, inline: (params[:inline] != 'false') end else render_404 diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index c01066c688a..9dc0c31be49 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -116,7 +116,12 @@ class Projects::WikisController < Projects::ApplicationController # Call #wiki to make sure the Wiki Repo is initialized @project_wiki.wiki - @sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages(limit: 15)) + + @sidebar_page = @project_wiki.find_sidebar(params[:version_id]) + + unless @sidebar_page # Fallback to default sidebar + @sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages(limit: 15)) + end rescue ProjectWiki::CouldNotCreateWikiError flash[:notice] = "Could not create Wiki Repository at this time. Please try again later." redirect_to project_path(@project) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 9dd652206fe..4ca42e2d4a2 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -157,6 +157,8 @@ class SessionsController < Devise::SessionsController end def auto_sign_in_with_provider + return unless Gitlab::Auth.omniauth_enabled? + provider = Gitlab.config.omniauth.auto_sign_in_with_provider return unless provider.present? diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb index c7d6bc6cfdc..b06595081e7 100644 --- a/app/finders/projects_finder.rb +++ b/app/finders/projects_finder.rb @@ -16,6 +16,7 @@ # personal: boolean # search: string # non_archived: boolean +# archived: 'only' or boolean # class ProjectsFinder < UnionFinder include CustomAttributesFilter @@ -130,7 +131,7 @@ class ProjectsFinder < UnionFinder def by_archived(projects) if params[:non_archived] projects.non_archived - elsif params.key?(:archived) # Back-compatibility with the places where `params[:archived]` can be set explicitly to `false` + elsif params.key?(:archived) if params[:archived] == 'only' projects.archived elsif Gitlab::Utils.to_boolean(params[:archived]) diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index d2daee22aba..18f0979fc86 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -7,7 +7,7 @@ module AuthHelper end def omniauth_enabled? - Gitlab.config.omniauth.enabled + Gitlab::Auth.omniauth_enabled? end def provider_has_icon?(name) diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 3db28fd6da3..7eb45ddd117 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -114,22 +114,22 @@ module BlobHelper icon("#{file_type_icon_class('file', mode, name)} fw") end - def blob_raw_url(only_path: false) + def blob_raw_url(**kwargs) if @build && @entry - raw_project_job_artifacts_url(@project, @build, path: @entry.path, only_path: only_path) + raw_project_job_artifacts_url(@project, @build, path: @entry.path, **kwargs) elsif @snippet if @snippet.project_id - raw_project_snippet_url(@project, @snippet, only_path: only_path) + raw_project_snippet_url(@project, @snippet, **kwargs) else - raw_snippet_url(@snippet, only_path: only_path) + raw_snippet_url(@snippet, **kwargs) end elsif @blob - project_raw_url(@project, @id, only_path: only_path) + project_raw_url(@project, @id, **kwargs) end end - def blob_raw_path - blob_raw_url(only_path: true) + def blob_raw_path(**kwargs) + blob_raw_url(**kwargs, only_path: true) end # SVGs can contain malicious JavaScript; only include whitelisted @@ -226,16 +226,17 @@ module BlobHelper def open_raw_blob_button(blob) return if blob.empty? + return if blob.raw_binary? || blob.stored_externally? - if blob.raw_binary? || blob.stored_externally? - icon = sprite_icon('download') - title = 'Download' - else - icon = icon('file-code-o') - title = 'Open raw' - end + title = 'Open raw' + link_to icon('file-code-o'), blob_raw_path, class: 'btn btn-sm has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: title, data: { container: 'body' } + end + + def download_blob_button(blob) + return if blob.empty? - link_to icon, blob_raw_path, class: 'btn btn-sm has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: title, data: { container: 'body' } + title = 'Download' + link_to sprite_icon('download'), blob_raw_path(inline: false), download: @path, class: 'btn btn-sm has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: title, data: { container: 'body' } end def blob_render_error_reason(viewer) diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 2f304b040c7..41084ec686f 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -1,3 +1,5 @@ +require 'json' + module IconsHelper extend self include FontAwesome::Rails::IconHelper @@ -38,6 +40,13 @@ module IconsHelper end def sprite_icon(icon_name, size: nil, css_class: nil) + if Gitlab::Sentry.should_raise? + unless known_sprites.include?(icon_name) + exception = ArgumentError.new("#{icon_name} is not a known icon in @gitlab-org/gitlab-svg") + raise exception + end + end + css_classes = size ? "s#{size}" : "" css_classes << " #{css_class}" unless css_class.blank? content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes) @@ -134,4 +143,10 @@ module IconsHelper icon_class end + + private + + def known_sprites + @known_sprites ||= JSON.parse(File.read(Rails.root.join('node_modules/@gitlab-org/gitlab-svgs/dist/icons.json')))['icons'] + end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index b0f381db5ab..221f1aa9dd8 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -413,20 +413,6 @@ module ProjectsHelper @ref || @repository.try(:root_ref) end - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1235 - def sanitize_repo_path(project, message) - return '' unless message.present? - - exports_path = File.join(Settings.shared['path'], 'tmp/project_exports') - filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]") - - disk_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path - end - - filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]") - end - def project_child_container_class(view_path) view_path == "projects/issues/issues" ? "prepend-top-default" : "project-show-#{view_path}" end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index f7dafca7834..cadb88ba632 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -105,7 +105,8 @@ module SearchHelper category: "Groups", id: group.id, label: "#{search_result_sanitize(group.full_name)}", - url: group_path(group) + url: group_path(group), + avatar_url: group.avatar_url || '' } end end @@ -119,7 +120,8 @@ module SearchHelper id: p.id, value: "#{search_result_sanitize(p.name)}", label: "#{search_result_sanitize(p.full_name)}", - url: project_path(p) + url: project_path(p), + avatar_url: p.avatar_url || '' } end end diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 9151543dfdc..ebfde993456 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -8,7 +8,7 @@ module SubmoduleHelper url = repository.submodule_url_for(ref, submodule_item.path) if url == '.' || url == './' - url = File.join(Gitlab.config.gitlab.url, @project.full_path) + url = File.join(Gitlab.config.gitlab.url, repository.project.full_path) end if url =~ %r{([^/:]+)/([^/]+(?:\.git)?)\Z} @@ -31,7 +31,7 @@ module SubmoduleHelper [namespace_project_path(namespace, project), namespace_project_tree_path(namespace, project, submodule_item.id)] elsif relative_self_url?(url) - relative_self_links(url, submodule_item.id) + relative_self_links(url, submodule_item.id, repository.project) elsif github_dot_com_url?(url) standard_links('github.com', namespace, project, submodule_item.id) elsif gitlab_dot_com_url?(url) @@ -73,7 +73,7 @@ module SubmoduleHelper [base, [base, '/tree/', commit].join('')] end - def relative_self_links(url, commit) + def relative_self_links(url, commit, project) url.rstrip! # Map relative links to a namespace and project # For example: @@ -85,7 +85,7 @@ module SubmoduleHelper namespace = components.pop.gsub(/^\.\.$/, '') if namespace.empty? - namespace = @project.namespace.full_path + namespace = project.namespace.full_path end begin diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb index e395cda03d3..cf2fe5a2019 100644 --- a/app/helpers/visibility_level_helper.rb +++ b/app/helpers/visibility_level_helper.rb @@ -126,10 +126,9 @@ module VisibilityLevelHelper end def visibility_icon_description(form_model) - case form_model - when Project + if form_model.respond_to?(:visibility_level_allowed_as_fork?) project_visibility_icon_description(form_model.visibility_level) - when Group + elsif form_model.respond_to?(:visibility_level_allowed_by_sub_groups?) group_visibility_icon_description(form_model.visibility_level) end end diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb index a82271ce0ee..fd1d78bd9b8 100644 --- a/app/helpers/workhorse_helper.rb +++ b/app/helpers/workhorse_helper.rb @@ -2,9 +2,9 @@ # Workhorse will also serve files when using `send_file`. module WorkhorseHelper # Send a Git blob through Workhorse - def send_git_blob(repository, blob) + def send_git_blob(repository, blob, inline: true) headers.store(*Gitlab::Workhorse.send_git_blob(repository, blob)) - headers['Content-Disposition'] = 'inline' + headers['Content-Disposition'] = inline ? 'inline' : 'attachment' headers['Content-Type'] = safe_content_type(blob) render plain: "" end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d8ddb4bc667..db86400128c 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -653,6 +653,7 @@ module Ci variables.append(key: 'CI_JOB_NAME', value: name) variables.append(key: 'CI_JOB_STAGE', value: stage) variables.append(key: 'CI_COMMIT_SHA', value: sha) + variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha) variables.append(key: 'CI_COMMIT_REF_NAME', value: ref) variables.append(key: 'CI_COMMIT_REF_SLUG', value: ref_slug) variables.append(key: "CI_COMMIT_TAG", value: ref) if tag? diff --git a/app/models/concerns/protected_ref_access.rb b/app/models/concerns/protected_ref_access.rb index 71b0c3468b9..5ff7b41b82b 100644 --- a/app/models/concerns/protected_ref_access.rb +++ b/app/models/concerns/protected_ref_access.rb @@ -17,6 +17,11 @@ module ProtectedRefAccess scope :master, -> { maintainer } # @deprecated scope :maintainer, -> { where(access_level: Gitlab::Access::MAINTAINER) } scope :developer, -> { where(access_level: Gitlab::Access::DEVELOPER) } + scope :by_user, -> (user) { where(user_id: user ) } + scope :by_group, -> (group) { where(group_id: group ) } + scope :for_role, -> { where(user_id: nil, group_id: nil) } + scope :for_user, -> { where.not(user_id: nil) } + scope :for_group, -> { where.not(group_id: nil) } validates :access_level, presence: true, if: :role?, inclusion: { in: ALLOWED_ACCESS_LEVELS diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb index 5082dc45368..7ab647abe93 100644 --- a/app/models/deploy_token.rb +++ b/app/models/deploy_token.rb @@ -27,7 +27,7 @@ class DeployToken < ActiveRecord::Base end def active? - !revoked + !revoked && expires_at > Date.today end def scopes @@ -58,6 +58,10 @@ class DeployToken < ActiveRecord::Base write_attribute(:expires_at, value.presence || Forever.date) end + def admin? + false + end + private def ensure_at_least_one_scope diff --git a/app/models/deployment.rb b/app/models/deployment.rb index ac86e9e8de0..687246b47b2 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -92,10 +92,6 @@ class Deployment < ActiveRecord::Base @stop_action ||= manual_actions.find_by(name: on_stop) end - def stop_action? - stop_action.present? - end - def formatted_deployment_time created_at.to_time.in_time_zone.to_s(:medium) end diff --git a/app/models/environment.rb b/app/models/environment.rb index 8d523dae324..4856d313318 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -117,7 +117,7 @@ class Environment < ActiveRecord::Base external_url.gsub(%r{\A.*?://}, '') end - def stop_action? + def stop_action_available? available? && stop_action.present? end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 3d72c447b4b..a073bbfad20 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -182,7 +182,7 @@ class MergeRequestDiff < ActiveRecord::Base end def diffs(diff_options = nil) - if without_files? && comparison = diff_refs.compare_in(project) + if without_files? && comparison = diff_refs&.compare_in(project) # It should fetch the repository when diffs are cleaned by the system. # We don't keep these for storage overload purposes. # See https://gitlab.com/gitlab-org/gitlab-ce/issues/37639 diff --git a/app/models/note.rb b/app/models/note.rb index abc40d9016e..fe3507adcb3 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -202,7 +202,7 @@ class Note < ActiveRecord::Base end def hook_attrs - attributes + Gitlab::HookData::NoteBuilder.new(self).build end def for_commit? diff --git a/app/models/project.rb b/app/models/project.rb index 1894de6ceed..7d37c3b3893 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -154,6 +154,7 @@ class Project < ActiveRecord::Base has_one :mock_monitoring_service has_one :microsoft_teams_service has_one :packagist_service + has_one :hangouts_chat_service # TODO: replace these relations with the fork network versions has_one :forked_project_link, foreign_key: "forked_to_project_id" @@ -368,8 +369,10 @@ class Project < ActiveRecord::Base chronic_duration_attr :build_timeout_human_readable, :build_timeout, default: 3600 validates :build_timeout, allow_nil: true, - numericality: { greater_than_or_equal_to: 600, - message: 'needs to be at least 10 minutes' } + numericality: { greater_than_or_equal_to: 10.minutes, + less_than: 1.month, + only_integer: true, + message: 'needs to be beetween 10 minutes and 1 month' } # Returns a collection of projects that is either public or visible to the # logged in user. @@ -2169,10 +2172,13 @@ class Project < ActiveRecord::Base merge_requests = source_of_merge_requests.opened .where(allow_collaboration: true) - if branch_name - merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user) - else - merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) } + # Issue for N+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/49322 + Gitlab::GitalyClient.allow_n_plus_1_calls do + if branch_name + merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user) + else + merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) } + end end end diff --git a/app/models/project_services/hangouts_chat_service.rb b/app/models/project_services/hangouts_chat_service.rb new file mode 100644 index 00000000000..a8512c5f57c --- /dev/null +++ b/app/models/project_services/hangouts_chat_service.rb @@ -0,0 +1,67 @@ +require 'hangouts_chat' + +class HangoutsChatService < ChatNotificationService + def title + 'Hangouts Chat' + end + + def description + 'Receive event notifications in Google Hangouts Chat' + end + + def self.to_param + 'hangouts_chat' + end + + def help + 'This service sends notifications about projects events to Google Hangouts Chat room.<br /> + To set up this service: + <ol> + <li><a href="https://developers.google.com/hangouts/chat/how-tos/webhooks">Set up an incoming webhook for your room</a>. All notifications will come to this room.</li> + <li>Paste the <strong>Webhook URL</strong> into the field below.</li> + <li>Select events below to enable notifications.</li> + </ol>' + end + + def event_field(event) + end + + def default_channel_placeholder + end + + def webhook_placeholder + 'https://chat.googleapis.com/v1/spaces…' + end + + def default_fields + [ + { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" }, + { type: 'checkbox', name: 'notify_only_broken_pipelines' }, + { type: 'checkbox', name: 'notify_only_default_branch' } + ] + end + + private + + def notify(message, opts) + simple_text = parse_simple_text_message(message) + HangoutsChat::Sender.new(webhook).simple(simple_text) + end + + def parse_simple_text_message(message) + header = message.pretext + return header if message.attachments.empty? + + attachment = message.attachments.first + title = format_attachment_title(attachment) + body = attachment[:text] + + [header, title, body].compact.join("\n") + end + + def format_attachment_title(attachment) + return attachment[:title] unless attachment[:title_link] + + "<#{attachment[:title_link]}|#{attachment[:title]}>" + end +end diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 9ae2fb0013a..3aa56b3983f 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProjectWiki include Gitlab::ShellAdapter include Storage::LegacyProjectWiki @@ -9,6 +11,7 @@ class ProjectWiki }.freeze unless defined?(MARKUPS) CouldNotCreateWikiError = Class.new(StandardError) + SIDEBAR = '_sidebar' # Returns a string describing what went wrong after # an operation fails. @@ -98,6 +101,10 @@ class ProjectWiki end end + def find_sidebar(version = nil) + find_page(SIDEBAR, version) + end + def find_file(name, version = nil) wiki.file(name, version) end diff --git a/app/models/repository.rb b/app/models/repository.rb index a96c73e6ab7..e248f94cbd8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -154,12 +154,9 @@ class Repository # Returns a list of commits that are not present in any reference def new_commits(newrev) - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233 - refs = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - ::Gitlab::Git::RevList.new(raw, newrev: newrev).new_refs - end + commits = raw.new_commits(newrev) - refs.map { |sha| commit(sha.strip) } + ::Commit.decorate(commits, project) end # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/384 diff --git a/app/models/service.rb b/app/models/service.rb index ad835293b46..cbfe0c6eedd 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -254,6 +254,7 @@ class Service < ActiveRecord::Base emails_on_push external_wiki flowdock + hangouts_chat hipchat irker jira diff --git a/app/models/user.rb b/app/models/user.rb index 4987d01aac6..58429f8d607 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,7 +14,6 @@ class User < ActiveRecord::Base include IgnorableColumn include FeatureGate include CreatedAtFilterable - include IgnorableColumn include BulkMemberAccessLoad include BlocksJsonSerialization include WithUploads diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 4b49edb01a5..55243136140 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -60,7 +60,7 @@ class WikiPage attr_accessor :attributes def hook_attrs - attributes + Gitlab::HookData::WikiPageBuilder.new(self).build end def initialize(wiki, page = nil, persisted = false) diff --git a/app/policies/environment_policy.rb b/app/policies/environment_policy.rb index 978dc3a7c81..2d07311db72 100644 --- a/app/policies/environment_policy.rb +++ b/app/policies/environment_policy.rb @@ -2,11 +2,12 @@ class EnvironmentPolicy < BasePolicy delegate { @subject.project } condition(:stop_with_deployment_allowed) do - @subject.stop_action? && can?(:create_deployment) && can?(:update_build, @subject.stop_action) + @subject.stop_action_available? && + can?(:create_deployment) && can?(:update_build, @subject.stop_action) end condition(:stop_with_update_allowed) do - !@subject.stop_action? && can?(:update_environment, @subject) + !@subject.stop_action_available? && can?(:update_environment, @subject) end rule { stop_with_deployment_allowed | stop_with_update_allowed }.enable :stop_environment diff --git a/app/serializers/discussion_entity.rb b/app/serializers/discussion_entity.rb index 8a39a4950f5..7505bbdeb3d 100644 --- a/app/serializers/discussion_entity.rb +++ b/app/serializers/discussion_entity.rb @@ -4,6 +4,7 @@ class DiscussionEntity < Grape::Entity expose :id, :reply_id expose :position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? } + expose :original_position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? } expose :line_code, if: -> (d, _) { d.diff_discussion? } expose :expanded?, as: :expanded expose :active?, as: :active, if: -> (d, _) { d.diff_discussion? } diff --git a/app/serializers/environment_entity.rb b/app/serializers/environment_entity.rb index 0fc3f92b151..83558fc6659 100644 --- a/app/serializers/environment_entity.rb +++ b/app/serializers/environment_entity.rb @@ -7,7 +7,7 @@ class EnvironmentEntity < Grape::Entity expose :external_url expose :environment_type expose :last_deployment, using: DeploymentEntity - expose :stop_action?, as: :has_stop_action + expose :stop_action_available?, as: :has_stop_action expose :metrics_path, if: -> (environment, _) { environment.has_metrics? } do |environment| metrics_project_environment_path(environment.project, environment) diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index 5d72ebdd7fd..a78bd77cf7c 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -10,9 +10,15 @@ class MergeRequestWidgetEntity < IssuableEntity expose :merge_when_pipeline_succeeds expose :source_branch expose :source_project_id + expose :source_project_full_path do |merge_request| + merge_request.source_project&.full_path + end expose :squash expose :target_branch expose :target_project_id + expose :target_project_full_path do |merge_request| + merge_request.project&.full_path + end expose :allow_collaboration expose :should_be_rebased?, as: :should_be_rebased diff --git a/app/services/access_token_validation_service.rb b/app/services/access_token_validation_service.rb index 46e19230328..2a337918d21 100644 --- a/app/services/access_token_validation_service.rb +++ b/app/services/access_token_validation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AccessTokenValidationService # Results: VALID = :valid diff --git a/app/services/after_branch_delete_service.rb b/app/services/after_branch_delete_service.rb index 227e9ea9c6d..e7eb74d3e7d 100644 --- a/app/services/after_branch_delete_service.rb +++ b/app/services/after_branch_delete_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # Branch can be deleted either by DeleteBranchService # or by GitPushService. diff --git a/app/services/akismet_service.rb b/app/services/akismet_service.rb index 0521393dd27..82ae66ab0f5 100644 --- a/app/services/akismet_service.rb +++ b/app/services/akismet_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AkismetService attr_accessor :owner, :text, :options diff --git a/app/services/application_settings/base_service.rb b/app/services/application_settings/base_service.rb index 2bcc7d7c08b..ebe067536ca 100644 --- a/app/services/application_settings/base_service.rb +++ b/app/services/application_settings/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationSettings class BaseService < ::BaseService def initialize(application_setting, user, params = {}) diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb index 7bcb8f49d0d..19cf34e2ac4 100644 --- a/app/services/application_settings/update_service.rb +++ b/app/services/application_settings/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationSettings class UpdateService < ApplicationSettings::BaseService attr_reader :params, :application_setting diff --git a/app/services/applications/create_service.rb b/app/services/applications/create_service.rb index 94a434b95dd..7db90c0b3c6 100644 --- a/app/services/applications/create_service.rb +++ b/app/services/applications/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Applications class CreateService def initialize(current_user, params) diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb index 5ad9a50687c..4c5e22bdd7e 100644 --- a/app/services/audit_event_service.rb +++ b/app/services/audit_event_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AuditEventService def initialize(author, entity, details = {}) @author, @entity, @details = author, entity, details diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index f28cddb2af3..81857d0cb4c 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Auth class ContainerRegistryAuthenticationService < BaseService AUDIENCE = 'container_registry'.freeze diff --git a/app/services/badges/base_service.rb b/app/services/badges/base_service.rb index 4f87426bd38..45fc9ac4373 100644 --- a/app/services/badges/base_service.rb +++ b/app/services/badges/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Badges class BaseService protected diff --git a/app/services/badges/build_service.rb b/app/services/badges/build_service.rb index 6267e571838..e5ede1586b6 100644 --- a/app/services/badges/build_service.rb +++ b/app/services/badges/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Badges class BuildService < Badges::BaseService # returns the created badge diff --git a/app/services/badges/create_service.rb b/app/services/badges/create_service.rb index aafb87f7dcd..4a55a00daeb 100644 --- a/app/services/badges/create_service.rb +++ b/app/services/badges/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Badges class CreateService < Badges::BaseService # returns the created badge diff --git a/app/services/badges/update_service.rb b/app/services/badges/update_service.rb index 495a4a2c99d..a653b7903dd 100644 --- a/app/services/badges/update_service.rb +++ b/app/services/badges/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Badges class UpdateService < Badges::BaseService # returns the updated badge diff --git a/app/services/base_count_service.rb b/app/services/base_count_service.rb index 975e288301c..ad1647842b8 100644 --- a/app/services/base_count_service.rb +++ b/app/services/base_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for services that count a single resource such as the number of # issues for a project. class BaseCountService diff --git a/app/services/base_renderer.rb b/app/services/base_renderer.rb index d6e30bd7008..30a6e8c62dd 100644 --- a/app/services/base_renderer.rb +++ b/app/services/base_renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BaseRenderer attr_reader :current_user diff --git a/app/services/base_service.rb b/app/services/base_service.rb index 3519b7c5e7d..3e968c8f707 100644 --- a/app/services/base_service.rb +++ b/app/services/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BaseService include Gitlab::Allowable diff --git a/app/services/boards/base_service.rb b/app/services/boards/base_service.rb index 72822ffffa1..205db47888e 100644 --- a/app/services/boards/base_service.rb +++ b/app/services/boards/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards class BaseService < ::BaseService # Parent can either a group or a project diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb index bd0bb387662..4caf5ffa3cb 100644 --- a/app/services/boards/create_service.rb +++ b/app/services/boards/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards class CreateService < Boards::BaseService def execute diff --git a/app/services/boards/issues/create_service.rb b/app/services/boards/issues/create_service.rb index 3025029755c..bd045e18b8d 100644 --- a/app/services/boards/issues/create_service.rb +++ b/app/services/boards/issues/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Issues class CreateService < Boards::BaseService diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index b1dbe73cdf7..50c11be0d15 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Issues class ListService < Boards::BaseService diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb index ee3112c7571..6fd8a23b2a1 100644 --- a/app/services/boards/issues/move_service.rb +++ b/app/services/boards/issues/move_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Issues class MoveService < Boards::BaseService diff --git a/app/services/boards/list_service.rb b/app/services/boards/list_service.rb index 9269b8d2620..edd1cc7c2e1 100644 --- a/app/services/boards/list_service.rb +++ b/app/services/boards/list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards class ListService < Boards::BaseService def execute diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb index 6fd9885d4f3..48d2d5abaec 100644 --- a/app/services/boards/lists/create_service.rb +++ b/app/services/boards/lists/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Lists class CreateService < Boards::BaseService diff --git a/app/services/boards/lists/destroy_service.rb b/app/services/boards/lists/destroy_service.rb index d75c5fd3dc6..e12d4f46e19 100644 --- a/app/services/boards/lists/destroy_service.rb +++ b/app/services/boards/lists/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Lists class DestroyService < Boards::BaseService diff --git a/app/services/boards/lists/generate_service.rb b/app/services/boards/lists/generate_service.rb index 05d4ab5dbcc..4fbf1026019 100644 --- a/app/services/boards/lists/generate_service.rb +++ b/app/services/boards/lists/generate_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Lists class GenerateService < Boards::BaseService diff --git a/app/services/boards/lists/list_service.rb b/app/services/boards/lists/list_service.rb index e57c95294af..e10eb52e041 100644 --- a/app/services/boards/lists/list_service.rb +++ b/app/services/boards/lists/list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Lists class ListService < Boards::BaseService diff --git a/app/services/boards/lists/move_service.rb b/app/services/boards/lists/move_service.rb index 7d0730e8332..27a36051662 100644 --- a/app/services/boards/lists/move_service.rb +++ b/app/services/boards/lists/move_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Boards module Lists class MoveService < Boards::BaseService diff --git a/app/services/chat_names/authorize_user_service.rb b/app/services/chat_names/authorize_user_service.rb index 7256466c9e8..78b53cb3637 100644 --- a/app/services/chat_names/authorize_user_service.rb +++ b/app/services/chat_names/authorize_user_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatNames class AuthorizeUserService include Gitlab::Routing diff --git a/app/services/chat_names/find_user_service.rb b/app/services/chat_names/find_user_service.rb index d458b814183..854b191c45c 100644 --- a/app/services/chat_names/find_user_service.rb +++ b/app/services/chat_names/find_user_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatNames class FindUserService def initialize(service, params) diff --git a/app/services/ci/create_pipeline_schedule_service.rb b/app/services/ci/create_pipeline_schedule_service.rb index cd40deb6187..0d5f50c26a1 100644 --- a/app/services/ci/create_pipeline_schedule_service.rb +++ b/app/services/ci/create_pipeline_schedule_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class CreatePipelineScheduleService < BaseService def execute diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 17a53b6a8fd..85df8bcff8c 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class CreatePipelineService < BaseService attr_reader :pipeline diff --git a/app/services/ci/ensure_stage_service.rb b/app/services/ci/ensure_stage_service.rb index b8c7be2d350..3d0e39d1b9f 100644 --- a/app/services/ci/ensure_stage_service.rb +++ b/app/services/ci/ensure_stage_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci ## # We call this service everytime we persist a CI/CD job. diff --git a/app/services/ci/extract_sections_from_build_trace_service.rb b/app/services/ci/extract_sections_from_build_trace_service.rb index 75f9e0f897d..693f6d55be3 100644 --- a/app/services/ci/extract_sections_from_build_trace_service.rb +++ b/app/services/ci/extract_sections_from_build_trace_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class ExtractSectionsFromBuildTraceService < BaseService def execute(build) diff --git a/app/services/ci/fetch_kubernetes_token_service.rb b/app/services/ci/fetch_kubernetes_token_service.rb index bca883ec0a0..15eda56cac6 100644 --- a/app/services/ci/fetch_kubernetes_token_service.rb +++ b/app/services/ci/fetch_kubernetes_token_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # TODO: # Almost components in this class were copied from app/models/project_services/kubernetes_service.rb diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index 85533a1cbdb..f54574b026b 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class PipelineTriggerService < BaseService include Gitlab::Utils::StrongMemoize diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb index e24f48c2d16..eb0b070657d 100644 --- a/app/services/ci/play_build_service.rb +++ b/app/services/ci/play_build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class PlayBuildService < ::BaseService def execute(build) diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb index 55af193d717..cda9bbff3b4 100644 --- a/app/services/ci/process_pipeline_service.rb +++ b/app/services/ci/process_pipeline_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class ProcessPipelineService < BaseService attr_reader :pipeline diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 6eb1c4f52de..f7ccec3a700 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci # This class responsible for assigning # proper pending build to runner on runner API request diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb index 6128b2a8fbb..6ceb59e4780 100644 --- a/app/services/ci/retry_build_service.rb +++ b/app/services/ci/retry_build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class RetryBuildService < ::BaseService CLONE_ACCESSORS = %i[pipeline project ref tag options commands name diff --git a/app/services/ci/retry_pipeline_service.rb b/app/services/ci/retry_pipeline_service.rb index c5a43869990..42a13367a99 100644 --- a/app/services/ci/retry_pipeline_service.rb +++ b/app/services/ci/retry_pipeline_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class RetryPipelineService < ::BaseService include Gitlab::OptimisticLocking diff --git a/app/services/ci/stop_environments_service.rb b/app/services/ci/stop_environments_service.rb index 43c9a065fcf..973ae5ce5aa 100644 --- a/app/services/ci/stop_environments_service.rb +++ b/app/services/ci/stop_environments_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class StopEnvironmentsService < BaseService attr_reader :ref @@ -8,7 +10,7 @@ module Ci return unless @ref.present? environments.each do |environment| - next unless environment.stop_action? + next unless environment.stop_action_available? next unless can?(current_user, :stop_environment, environment) environment.stop_with_action!(current_user) diff --git a/app/services/ci/update_build_queue_service.rb b/app/services/ci/update_build_queue_service.rb index 41b1c144c3e..9c589d910eb 100644 --- a/app/services/ci/update_build_queue_service.rb +++ b/app/services/ci/update_build_queue_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class UpdateBuildQueueService def execute(build) diff --git a/app/services/ci/update_runner_service.rb b/app/services/ci/update_runner_service.rb index 450ee7da1c9..e4117a51fe6 100644 --- a/app/services/ci/update_runner_service.rb +++ b/app/services/ci/update_runner_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class UpdateRunnerService attr_reader :runner diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb index cba1b920f7c..270a8eb24f4 100644 --- a/app/services/clusters/applications/base_helm_service.rb +++ b/app/services/clusters/applications/base_helm_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Applications class BaseHelmService diff --git a/app/services/clusters/applications/check_ingress_ip_address_service.rb b/app/services/clusters/applications/check_ingress_ip_address_service.rb index e572b1e5d99..f32e73e8b1c 100644 --- a/app/services/clusters/applications/check_ingress_ip_address_service.rb +++ b/app/services/clusters/applications/check_ingress_ip_address_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Applications class CheckIngressIpAddressService < BaseHelmService diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb index 90393e951a4..4640c5a2d4b 100644 --- a/app/services/clusters/applications/check_installation_progress_service.rb +++ b/app/services/clusters/applications/check_installation_progress_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Applications class CheckInstallationProgressService < BaseHelmService diff --git a/app/services/clusters/applications/install_service.rb b/app/services/clusters/applications/install_service.rb index 7ec3a9baa6e..7e3c0e77a83 100644 --- a/app/services/clusters/applications/install_service.rb +++ b/app/services/clusters/applications/install_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Applications class InstallService < BaseHelmService diff --git a/app/services/clusters/applications/schedule_installation_service.rb b/app/services/clusters/applications/schedule_installation_service.rb index 9c5461e85e1..4ead4f619c8 100644 --- a/app/services/clusters/applications/schedule_installation_service.rb +++ b/app/services/clusters/applications/schedule_installation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Applications class ScheduleInstallationService < ::BaseService diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb index 418888e3293..e3e0cfa462c 100644 --- a/app/services/clusters/create_service.rb +++ b/app/services/clusters/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters class CreateService < BaseService attr_reader :access_token diff --git a/app/services/clusters/gcp/fetch_operation_service.rb b/app/services/clusters/gcp/fetch_operation_service.rb index a4cd3ca5c11..02c96a1e286 100644 --- a/app/services/clusters/gcp/fetch_operation_service.rb +++ b/app/services/clusters/gcp/fetch_operation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Gcp class FetchOperationService diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index 84944e95542..264419501dc 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Gcp class FinalizeCreationService diff --git a/app/services/clusters/gcp/provision_service.rb b/app/services/clusters/gcp/provision_service.rb index 8beea5a8cfb..ab1bf9c64f6 100644 --- a/app/services/clusters/gcp/provision_service.rb +++ b/app/services/clusters/gcp/provision_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Gcp class ProvisionService diff --git a/app/services/clusters/gcp/verify_provision_status_service.rb b/app/services/clusters/gcp/verify_provision_status_service.rb index 7cc4324677e..b24246f5c4b 100644 --- a/app/services/clusters/gcp/verify_provision_status_service.rb +++ b/app/services/clusters/gcp/verify_provision_status_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters module Gcp class VerifyProvisionStatusService diff --git a/app/services/clusters/update_service.rb b/app/services/clusters/update_service.rb index 989218e32a2..98fdeec4fb1 100644 --- a/app/services/clusters/update_service.rb +++ b/app/services/clusters/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Clusters class UpdateService < BaseService def execute(cluster) diff --git a/app/services/cohorts_service.rb b/app/services/cohorts_service.rb index 6781533af28..7a14e97f749 100644 --- a/app/services/cohorts_service.rb +++ b/app/services/cohorts_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CohortsService MONTHS_INCLUDED = 12 diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 1ce6ab36cbf..2fbd442fc2e 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Commits class ChangeService < Commits::CreateService def initialize(*args) diff --git a/app/services/commits/cherry_pick_service.rb b/app/services/commits/cherry_pick_service.rb index 320e229560d..4c5b15b2f95 100644 --- a/app/services/commits/cherry_pick_service.rb +++ b/app/services/commits/cherry_pick_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Commits class CherryPickService < ChangeService def create_commit! diff --git a/app/services/commits/create_service.rb b/app/services/commits/create_service.rb index 4d0578becbe..3ce9acc833c 100644 --- a/app/services/commits/create_service.rb +++ b/app/services/commits/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Commits class CreateService < ::BaseService ValidationError = Class.new(StandardError) diff --git a/app/services/commits/revert_service.rb b/app/services/commits/revert_service.rb index dc27399e047..dddb8b24eac 100644 --- a/app/services/commits/revert_service.rb +++ b/app/services/commits/revert_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Commits class RevertService < ChangeService def create_commit! diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 2a69a205629..3adf8a0c1a1 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'securerandom' # Compare 2 refs for one repo or between repositories diff --git a/app/services/concerns/exclusive_lease_guard.rb b/app/services/concerns/exclusive_lease_guard.rb index f45436370c1..f102e00d150 100644 --- a/app/services/concerns/exclusive_lease_guard.rb +++ b/app/services/concerns/exclusive_lease_guard.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # # Concern that helps with getting an exclusive lease for running a block # of code. diff --git a/app/services/concerns/issues/resolve_discussions.rb b/app/services/concerns/issues/resolve_discussions.rb index 455f761ca9b..1563ed965df 100644 --- a/app/services/concerns/issues/resolve_discussions.rb +++ b/app/services/concerns/issues/resolve_discussions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues module ResolveDiscussions include Gitlab::Utils::StrongMemoize diff --git a/app/services/concerns/update_visibility_level.rb b/app/services/concerns/update_visibility_level.rb index 536fcc6acce..b7a161f5089 100644 --- a/app/services/concerns/update_visibility_level.rb +++ b/app/services/concerns/update_visibility_level.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module UpdateVisibilityLevel def valid_visibility_level_change?(target, new_visibility) # check that user is allowed to set specified visibility_level diff --git a/app/services/concerns/users/new_user_notifier.rb b/app/services/concerns/users/new_user_notifier.rb index 231693ce7a9..11547e4a5b6 100644 --- a/app/services/concerns/users/new_user_notifier.rb +++ b/app/services/concerns/users/new_user_notifier.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users module NewUserNotifier def notify_new_user(user, reset_token) diff --git a/app/services/concerns/users/participable_service.rb b/app/services/concerns/users/participable_service.rb index bf60b96938d..5b408bd96c7 100644 --- a/app/services/concerns/users/participable_service.rb +++ b/app/services/concerns/users/participable_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users module ParticipableService extend ActiveSupport::Concern diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 9b1a4d960e2..65208b07e27 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateBranchService < BaseService def execute(branch_name, ref) create_master_branch if project.empty_repo? diff --git a/app/services/create_deployment_service.rb b/app/services/create_deployment_service.rb index 7e5a77fb056..bb3f605da28 100644 --- a/app/services/create_deployment_service.rb +++ b/app/services/create_deployment_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateDeploymentService attr_reader :job diff --git a/app/services/create_release_service.rb b/app/services/create_release_service.rb index 54ff1f74126..09c68390007 100644 --- a/app/services/create_release_service.rb +++ b/app/services/create_release_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateReleaseService < BaseService def execute(tag_name, release_description) repository = project.repository diff --git a/app/services/create_snippet_service.rb b/app/services/create_snippet_service.rb index 40286dbf3bf..6f1fce4989e 100644 --- a/app/services/create_snippet_service.rb +++ b/app/services/create_snippet_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateSnippetService < BaseService include SpamCheckService diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb index e1499dcee64..44252f7b0a6 100644 --- a/app/services/delete_branch_service.rb +++ b/app/services/delete_branch_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeleteBranchService < BaseService def execute(branch_name) repository = project.repository diff --git a/app/services/delete_merged_branches_service.rb b/app/services/delete_merged_branches_service.rb index c98d1e3c540..ff3e4783fe3 100644 --- a/app/services/delete_merged_branches_service.rb +++ b/app/services/delete_merged_branches_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeleteMergedBranchesService < BaseService def async_execute DeleteMergedBranchesWorker.perform_async(project.id, current_user.id) diff --git a/app/services/deploy_keys/create_service.rb b/app/services/deploy_keys/create_service.rb index 16de3d08df2..a25e73666f8 100644 --- a/app/services/deploy_keys/create_service.rb +++ b/app/services/deploy_keys/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DeployKeys class CreateService < Keys::BaseService def execute diff --git a/app/services/deploy_tokens/create_service.rb b/app/services/deploy_tokens/create_service.rb index 52f545947af..dc0122002e9 100644 --- a/app/services/deploy_tokens/create_service.rb +++ b/app/services/deploy_tokens/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DeployTokens class CreateService < BaseService def execute diff --git a/app/services/discussions/base_service.rb b/app/services/discussions/base_service.rb index e4dfe6e71bb..86b8310f0a6 100644 --- a/app/services/discussions/base_service.rb +++ b/app/services/discussions/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Discussions class BaseService < ::BaseService end diff --git a/app/services/discussions/resolve_service.rb b/app/services/discussions/resolve_service.rb index 0437195f588..816cd45b07a 100644 --- a/app/services/discussions/resolve_service.rb +++ b/app/services/discussions/resolve_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Discussions class ResolveService < Discussions::BaseService def execute(one_or_more_discussions) diff --git a/app/services/discussions/update_diff_position_service.rb b/app/services/discussions/update_diff_position_service.rb index 746f209e20f..c61437fb2e3 100644 --- a/app/services/discussions/update_diff_position_service.rb +++ b/app/services/discussions/update_diff_position_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Discussions class UpdateDiffPositionService < BaseService def execute(discussion) diff --git a/app/services/emails/base_service.rb b/app/services/emails/base_service.rb index 5bbceeb3b3f..ba7b689a9af 100644 --- a/app/services/emails/base_service.rb +++ b/app/services/emails/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails class BaseService def initialize(current_user, params = {}) diff --git a/app/services/emails/confirm_service.rb b/app/services/emails/confirm_service.rb index b5301bf2b82..38204e011dd 100644 --- a/app/services/emails/confirm_service.rb +++ b/app/services/emails/confirm_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails class ConfirmService < ::Emails::BaseService def execute(email) diff --git a/app/services/emails/create_service.rb b/app/services/emails/create_service.rb index 94a841af7c3..acf575e24e5 100644 --- a/app/services/emails/create_service.rb +++ b/app/services/emails/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails class CreateService < ::Emails::BaseService def execute(extra_params = {}) diff --git a/app/services/emails/destroy_service.rb b/app/services/emails/destroy_service.rb index 1ed131fe326..9ca1a03e172 100644 --- a/app/services/emails/destroy_service.rb +++ b/app/services/emails/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails class DestroyService < ::Emails::BaseService def execute(email) diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index 44dc90b3462..e7464fd9d5f 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # EventCreateService class # # Used for creating events feed on dashboard after certain user action diff --git a/app/services/events/render_service.rb b/app/services/events/render_service.rb index bb72d7685dd..50429683902 100644 --- a/app/services/events/render_service.rb +++ b/app/services/events/render_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Events class RenderService < BaseRenderer def execute(events, atom_request: false) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 8d4b9f14780..025f093a428 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class BaseService < Commits::CreateService FileChangedError = Class.new(StandardError) diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index 8ecac6115bd..362b80071ba 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class CreateDirService < Files::BaseService def create_commit! diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index a954564946b..fd5442a6c28 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class CreateService < Files::BaseService def create_commit! diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index 32a57484d4e..0ec1f79d396 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class DeleteService < Files::BaseService def create_commit! diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index 13a1dee4173..08088f8c592 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class MultiService < Files::BaseService UPDATE_FILE_ACTIONS = %w(update move delete).freeze diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index 1902d1cea72..2b3e96e6c53 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Files class UpdateService < Files::BaseService def create_commit! diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index f3bfc53dcd3..29c8ce5fea3 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitPushService < BaseService attr_accessor :push_data, :push_commits include Gitlab::Access diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index 9917a39b795..3ff2d1d107d 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitTagPushService < BaseService attr_accessor :push_data diff --git a/app/services/gpg_keys/create_service.rb b/app/services/gpg_keys/create_service.rb index e822a89c4d3..e41444b2a82 100644 --- a/app/services/gpg_keys/create_service.rb +++ b/app/services/gpg_keys/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GpgKeys class CreateService < Keys::BaseService def execute diff --git a/app/services/gravatar_service.rb b/app/services/gravatar_service.rb index c6e52c3bb91..2a7a5dae291 100644 --- a/app/services/gravatar_service.rb +++ b/app/services/gravatar_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GravatarService def execute(email, size = nil, scale = 2, username: nil) return unless Gitlab::CurrentSettings.gravatar_enabled? diff --git a/app/services/groups/base_service.rb b/app/services/groups/base_service.rb index a8fa098246a..8c8acce5ca5 100644 --- a/app/services/groups/base_service.rb +++ b/app/services/groups/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class BaseService < ::BaseService attr_accessor :group, :current_user, :params diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb index 70e50aa0f12..24d8400c625 100644 --- a/app/services/groups/create_service.rb +++ b/app/services/groups/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class CreateService < Groups::BaseService def initialize(user, params = {}) diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb index 58e88688dfa..c4554ce45fb 100644 --- a/app/services/groups/destroy_service.rb +++ b/app/services/groups/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class DestroyService < Groups::BaseService def async_execute diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb index c2dfbac5414..50d34d8cb91 100644 --- a/app/services/groups/nested_create_service.rb +++ b/app/services/groups/nested_create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class NestedCreateService < Groups::BaseService attr_reader :group_path, :visibility_level diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb index e591c820cff..ea7576077f3 100644 --- a/app/services/groups/transfer_service.rb +++ b/app/services/groups/transfer_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class TransferService < Groups::BaseService ERROR_MESSAGES = { diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb index 08e3efb96e3..436a6b18cb1 100644 --- a/app/services/groups/update_service.rb +++ b/app/services/groups/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Groups class UpdateService < Groups::BaseService include UpdateVisibilityLevel diff --git a/app/services/ham_service.rb b/app/services/ham_service.rb index b0e1799b489..794eb34d9ca 100644 --- a/app/services/ham_service.rb +++ b/app/services/ham_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class HamService attr_accessor :spam_log diff --git a/app/services/import_export_clean_up_service.rb b/app/services/import_export_clean_up_service.rb index 3702c3742ef..e75a951944e 100644 --- a/app/services/import_export_clean_up_service.rb +++ b/app/services/import_export_clean_up_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ImportExportCleanUpService LAST_MODIFIED_TIME_IN_MINUTES = 1440 diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb index 5d42a89fced..051d5ba881d 100644 --- a/app/services/issuable/bulk_update_service.rb +++ b/app/services/issuable/bulk_update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issuable class BulkUpdateService < IssuableBaseService def execute(type) diff --git a/app/services/issuable/common_system_notes_service.rb b/app/services/issuable/common_system_notes_service.rb index 3da21bd8b8f..028b350ca07 100644 --- a/app/services/issuable/common_system_notes_service.rb +++ b/app/services/issuable/common_system_notes_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issuable class CommonSystemNotesService < ::BaseService attr_reader :issuable diff --git a/app/services/issuable/destroy_service.rb b/app/services/issuable/destroy_service.rb index 0b1a33518c6..4c64655a622 100644 --- a/app/services/issuable/destroy_service.rb +++ b/app/services/issuable/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issuable class DestroyService < IssuableBaseService def execute(issuable) diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 5e06e0c61cf..7d60c65bb79 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class IssuableBaseService < BaseService private diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index cbfef175af0..25389a946bb 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class BaseService < ::IssuableBaseService def hook_data(issue, action, old_associations: {}) diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb index 3a4f7b159f1..52b45f1b2ce 100644 --- a/app/services/issues/build_service.rb +++ b/app/services/issues/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class BuildService < Issues::BaseService include ResolveDiscussions @@ -44,14 +46,14 @@ module Issues other_note_count = discussion.notes.size - 1 - discussion_info = "- [ ] #{first_note_to_resolve.author.to_reference} #{action} a [discussion](#{note_url}): " - discussion_info << " (+#{other_note_count} #{'comment'.pluralize(other_note_count)})" if other_note_count > 0 + discussion_info = ["- [ ] #{first_note_to_resolve.author.to_reference} #{action} a [discussion](#{note_url}): "] + discussion_info << "(+#{other_note_count} #{'comment'.pluralize(other_note_count)})" if other_note_count > 0 note_without_block_quotes = Banzai::Filter::BlockquoteFenceFilter.new(first_note_to_resolve.note).call spaces = ' ' * 4 quote = note_without_block_quotes.lines.map { |line| "#{spaces}> #{line}" }.join - [discussion_info, quote].join("\n\n") + [discussion_info.join(' '), quote].join("\n\n") end def issue_params diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index 4a99367c575..e5cc12e6082 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class CloseService < Issues::BaseService # Closes the supplied issue if the current user is able to do so. diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index 0307634c0b6..5793a15e1bc 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class CreateService < Issues::BaseService include SpamCheckService diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb index 5c0854e664d..9b22f5e7914 100644 --- a/app/services/issues/duplicate_service.rb +++ b/app/services/issues/duplicate_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class DuplicateService < Issues::BaseService def execute(duplicate_issue, canonical_issue) diff --git a/app/services/issues/fetch_referenced_merge_requests_service.rb b/app/services/issues/fetch_referenced_merge_requests_service.rb index 39c8ded9df4..5e84f3c81c9 100644 --- a/app/services/issues/fetch_referenced_merge_requests_service.rb +++ b/app/services/issues/fetch_referenced_merge_requests_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class FetchReferencedMergeRequestsService < Issues::BaseService def execute(issue) diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb index 6e5c29a5c40..841bce9949e 100644 --- a/app/services/issues/move_service.rb +++ b/app/services/issues/move_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class MoveService < Issues::BaseService MoveError = Class.new(StandardError) diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index 02224f3357a..3bd53f9ccdc 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class ReopenService < Issues::BaseService def execute(issue) diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index 1000e1842b6..c02dddf67b2 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Issues class UpdateService < Issues::BaseService include SpamCheckService diff --git a/app/services/keys/base_service.rb b/app/services/keys/base_service.rb index df8e82f5f60..113e22b01ce 100644 --- a/app/services/keys/base_service.rb +++ b/app/services/keys/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Keys class BaseService attr_accessor :user, :params diff --git a/app/services/keys/create_service.rb b/app/services/keys/create_service.rb index e2e5a6c46c5..d9fa69a88d7 100644 --- a/app/services/keys/create_service.rb +++ b/app/services/keys/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Keys class CreateService < ::Keys::BaseService def execute diff --git a/app/services/keys/destroy_service.rb b/app/services/keys/destroy_service.rb index 785cfa3a1d8..e2ae4047941 100644 --- a/app/services/keys/destroy_service.rb +++ b/app/services/keys/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Keys class DestroyService < ::Keys::BaseService def execute(key) diff --git a/app/services/keys/last_used_service.rb b/app/services/keys/last_used_service.rb index dbd79f7da55..daef544bac0 100644 --- a/app/services/keys/last_used_service.rb +++ b/app/services/keys/last_used_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Keys class LastUsedService TIMEOUT = 1.day.to_i diff --git a/app/services/labels/base_service.rb b/app/services/labels/base_service.rb index 91d72a57b4e..ead7f2ea607 100644 --- a/app/services/labels/base_service.rb +++ b/app/services/labels/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Labels class BaseService < ::BaseService COLOR_NAME_TO_HEX = { diff --git a/app/services/labels/create_service.rb b/app/services/labels/create_service.rb index 6c399c92377..fe34be41ac1 100644 --- a/app/services/labels/create_service.rb +++ b/app/services/labels/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Labels class CreateService < Labels::BaseService def initialize(params = {}) diff --git a/app/services/labels/find_or_create_service.rb b/app/services/labels/find_or_create_service.rb index a72da3c637f..e4486764a4d 100644 --- a/app/services/labels/find_or_create_service.rb +++ b/app/services/labels/find_or_create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Labels class FindOrCreateService def initialize(current_user, parent, params = {}) diff --git a/app/services/labels/promote_service.rb b/app/services/labels/promote_service.rb index 74a85e5c9f0..c0463052821 100644 --- a/app/services/labels/promote_service.rb +++ b/app/services/labels/promote_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Labels class PromoteService < BaseService BATCH_SIZE = 1000 diff --git a/app/services/labels/transfer_service.rb b/app/services/labels/transfer_service.rb index 9b7486cf53b..1bd8d9fc325 100644 --- a/app/services/labels/transfer_service.rb +++ b/app/services/labels/transfer_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Labels::TransferService class # # User for recreate the missing group labels at project level diff --git a/app/services/labels/update_service.rb b/app/services/labels/update_service.rb index 28dcabf9541..c3a720a1c66 100644 --- a/app/services/labels/update_service.rb +++ b/app/services/labels/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Labels class UpdateService < Labels::BaseService def initialize(params = {}) diff --git a/app/services/lfs/file_transformer.rb b/app/services/lfs/file_transformer.rb index 69281ee3137..c8eccb8e6cd 100644 --- a/app/services/lfs/file_transformer.rb +++ b/app/services/lfs/file_transformer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lfs # Usage: Calling `new_file` check to see if a file should be in LFS and # return a transformed result with `content` and `encoding` to commit. diff --git a/app/services/lfs/lock_file_service.rb b/app/services/lfs/lock_file_service.rb index bbe10f84ef4..78434909d68 100644 --- a/app/services/lfs/lock_file_service.rb +++ b/app/services/lfs/lock_file_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lfs class LockFileService < BaseService def execute diff --git a/app/services/lfs/locks_finder_service.rb b/app/services/lfs/locks_finder_service.rb index 13c6cc6f81c..d52cf0e3cc4 100644 --- a/app/services/lfs/locks_finder_service.rb +++ b/app/services/lfs/locks_finder_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lfs class LocksFinderService < BaseService def execute diff --git a/app/services/lfs/unlock_file_service.rb b/app/services/lfs/unlock_file_service.rb index 7e3edf21d54..4d1443bf772 100644 --- a/app/services/lfs/unlock_file_service.rb +++ b/app/services/lfs/unlock_file_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Lfs class UnlockFileService < BaseService def execute diff --git a/app/services/mattermost/create_team_service.rb b/app/services/mattermost/create_team_service.rb index e3206810f3a..afcd6439a14 100644 --- a/app/services/mattermost/create_team_service.rb +++ b/app/services/mattermost/create_team_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Mattermost class CreateTeamService < ::BaseService def initialize(group, current_user) diff --git a/app/services/members/approve_access_request_service.rb b/app/services/members/approve_access_request_service.rb index 6be08b590bc..52b890d1821 100644 --- a/app/services/members/approve_access_request_service.rb +++ b/app/services/members/approve_access_request_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class ApproveAccessRequestService < Members::BaseService def execute(access_requester, skip_authorization: false, skip_log_audit_event: false) diff --git a/app/services/members/base_service.rb b/app/services/members/base_service.rb index 74556fb20cf..8248f1441d7 100644 --- a/app/services/members/base_service.rb +++ b/app/services/members/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class BaseService < ::BaseService # current_user - The user that performs the action diff --git a/app/services/members/create_service.rb b/app/services/members/create_service.rb index bc6a9405aac..714b8586737 100644 --- a/app/services/members/create_service.rb +++ b/app/services/members/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class CreateService < Members::BaseService DEFAULT_LIMIT = 100 diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb index 5b51e1982f1..aca0ba66646 100644 --- a/app/services/members/destroy_service.rb +++ b/app/services/members/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class DestroyService < Members::BaseService def execute(member, skip_authorization: false) diff --git a/app/services/members/request_access_service.rb b/app/services/members/request_access_service.rb index 24293b30005..b9b0550e290 100644 --- a/app/services/members/request_access_service.rb +++ b/app/services/members/request_access_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class RequestAccessService < Members::BaseService def execute(source) diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb index cb19cf01dd7..1f5618dae53 100644 --- a/app/services/members/update_service.rb +++ b/app/services/members/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Members class UpdateService < Members::BaseService # returns the updated member diff --git a/app/services/merge_request_metrics_service.rb b/app/services/merge_request_metrics_service.rb index 9248de14a53..4e88b77c855 100644 --- a/app/services/merge_request_metrics_service.rb +++ b/app/services/merge_request_metrics_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MergeRequestMetricsService delegate :update!, to: :@merge_request_metrics diff --git a/app/services/merge_requests/add_todo_when_build_fails_service.rb b/app/services/merge_requests/add_todo_when_build_fails_service.rb index 6805b2f7d1c..79c43b8e7d5 100644 --- a/app/services/merge_requests/add_todo_when_build_fails_service.rb +++ b/app/services/merge_requests/add_todo_when_build_fails_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class AddTodoWhenBuildFailsService < MergeRequests::BaseService # Adds a todo to the parent merge_request when a CI build fails diff --git a/app/services/merge_requests/assign_issues_service.rb b/app/services/merge_requests/assign_issues_service.rb index 8c6c4841020..e9107b9998e 100644 --- a/app/services/merge_requests/assign_issues_service.rb +++ b/app/services/merge_requests/assign_issues_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class AssignIssuesService < BaseService def assignable_issues diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 4c420b38258..e6dd0e12a3a 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class BaseService < ::IssuableBaseService def create_note(merge_request, state = merge_request.state) diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb index a98bbdf74dd..bc988eb2a26 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class BuildService < MergeRequests::BaseService include Gitlab::Utils::StrongMemoize @@ -140,7 +142,8 @@ module MergeRequests closes_issue = "Closes #{issue.to_reference}" if description.present? - merge_request.description += closes_issue.prepend("\n\n") + descr_parts = [merge_request.description, closes_issue] + merge_request.description = descr_parts.join("\n\n") else merge_request.description = closes_issue end @@ -164,9 +167,11 @@ module MergeRequests return if merge_request.title.present? if issue_iid.present? - merge_request.title = "Resolve #{issue.to_reference}" + title_parts = ["Resolve #{issue.to_reference}"] branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize - merge_request.title += " \"#{branch_title}\"" if branch_title.present? + + title_parts << "\"#{branch_title}\"" if branch_title.present? + merge_request.title = title_parts.join(' ') end end diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb index db701c1145d..04527bb9713 100644 --- a/app/services/merge_requests/close_service.rb +++ b/app/services/merge_requests/close_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class CloseService < MergeRequests::BaseService def execute(merge_request, commit = nil) diff --git a/app/services/merge_requests/conflicts/base_service.rb b/app/services/merge_requests/conflicts/base_service.rb index b50875347d9..402f6c4e4c0 100644 --- a/app/services/merge_requests/conflicts/base_service.rb +++ b/app/services/merge_requests/conflicts/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests module Conflicts class BaseService diff --git a/app/services/merge_requests/conflicts/list_service.rb b/app/services/merge_requests/conflicts/list_service.rb index 72cbc49adb2..c6b3a6a1a69 100644 --- a/app/services/merge_requests/conflicts/list_service.rb +++ b/app/services/merge_requests/conflicts/list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests module Conflicts class ListService < MergeRequests::Conflicts::BaseService diff --git a/app/services/merge_requests/conflicts/resolve_service.rb b/app/services/merge_requests/conflicts/resolve_service.rb index 27cafd2d7d9..b9f734310be 100644 --- a/app/services/merge_requests/conflicts/resolve_service.rb +++ b/app/services/merge_requests/conflicts/resolve_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests module Conflicts class ResolveService < MergeRequests::Conflicts::BaseService diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb index 3407b312700..fd91dc4acd0 100644 --- a/app/services/merge_requests/create_from_issue_service.rb +++ b/app/services/merge_requests/create_from_issue_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class CreateFromIssueService < MergeRequests::CreateService def initialize(project, user, params) diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index fe1ac70781e..c36a2ecbfe3 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class CreateService < MergeRequests::BaseService def execute diff --git a/app/services/merge_requests/delete_non_latest_diffs_service.rb b/app/services/merge_requests/delete_non_latest_diffs_service.rb index 40079b21189..2a8ea316921 100644 --- a/app/services/merge_requests/delete_non_latest_diffs_service.rb +++ b/app/services/merge_requests/delete_non_latest_diffs_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class DeleteNonLatestDiffsService BATCH_SIZE = 10 diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb index bffc09c34f0..479e0fe6699 100644 --- a/app/services/merge_requests/ff_merge_service.rb +++ b/app/services/merge_requests/ff_merge_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests # MergeService class # diff --git a/app/services/merge_requests/get_urls_service.rb b/app/services/merge_requests/get_urls_service.rb index 668a1741736..7c88c9abb41 100644 --- a/app/services/merge_requests/get_urls_service.rb +++ b/app/services/merge_requests/get_urls_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class GetUrlsService < BaseService attr_reader :project diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 3d587f97906..fb44f809c41 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests # MergeService class # diff --git a/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb index 9a4e6eb2e88..973e5b64e88 100644 --- a/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class MergeWhenPipelineSucceedsService < MergeRequests::BaseService # Marks the passed `merge_request` to be merged when the pipeline succeeds or diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index 7606d68ff29..3d2aea4e9b6 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests # PostMergeService class # diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb index c741e913860..31b3ebf311e 100644 --- a/app/services/merge_requests/rebase_service.rb +++ b/app/services/merge_requests/rebase_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class RebaseService < MergeRequests::WorkingCopyBaseService REBASE_ERROR = 'Rebase failed. Please rebase locally'.freeze diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 0127d781686..48da796505f 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class RefreshService < MergeRequests::BaseService def execute(oldrev, newrev, ref) diff --git a/app/services/merge_requests/reload_diffs_service.rb b/app/services/merge_requests/reload_diffs_service.rb index 2ec7b403903..8d85dc9eb5f 100644 --- a/app/services/merge_requests/reload_diffs_service.rb +++ b/app/services/merge_requests/reload_diffs_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class ReloadDiffsService def initialize(merge_request, current_user) diff --git a/app/services/merge_requests/reopen_service.rb b/app/services/merge_requests/reopen_service.rb index 8f1c95ac1b7..f2fc13ad028 100644 --- a/app/services/merge_requests/reopen_service.rb +++ b/app/services/merge_requests/reopen_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class ReopenService < MergeRequests::BaseService def execute(merge_request) diff --git a/app/services/merge_requests/resolved_discussion_notification_service.rb b/app/services/merge_requests/resolved_discussion_notification_service.rb index 66a0cbc81d4..03ded1512f9 100644 --- a/app/services/merge_requests/resolved_discussion_notification_service.rb +++ b/app/services/merge_requests/resolved_discussion_notification_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class ResolvedDiscussionNotificationService < MergeRequests::BaseService def execute(merge_request) diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb index a40fb2786bd..a439a380255 100644 --- a/app/services/merge_requests/squash_service.rb +++ b/app/services/merge_requests/squash_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class SquashService < MergeRequests::WorkingCopyBaseService def execute(merge_request) diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 7350725e223..b112edbce7f 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class UpdateService < MergeRequests::BaseService def execute(merge_request) diff --git a/app/services/merge_requests/working_copy_base_service.rb b/app/services/merge_requests/working_copy_base_service.rb index 186e05bf966..2d2be1f4c25 100644 --- a/app/services/merge_requests/working_copy_base_service.rb +++ b/app/services/merge_requests/working_copy_base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequests class WorkingCopyBaseService < MergeRequests::BaseService attr_reader :merge_request diff --git a/app/services/metrics_service.rb b/app/services/metrics_service.rb index c237d2ae8c9..222a5c8c79c 100644 --- a/app/services/metrics_service.rb +++ b/app/services/metrics_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'prometheus/client/formats/text' class MetricsService diff --git a/app/services/milestones/base_service.rb b/app/services/milestones/base_service.rb index cce0863d611..f30194c0bfe 100644 --- a/app/services/milestones/base_service.rb +++ b/app/services/milestones/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class BaseService < ::BaseService # Parent can either a group or a project diff --git a/app/services/milestones/close_service.rb b/app/services/milestones/close_service.rb index 5b06c4b601d..a252f5c144e 100644 --- a/app/services/milestones/close_service.rb +++ b/app/services/milestones/close_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class CloseService < Milestones::BaseService def execute(milestone) diff --git a/app/services/milestones/create_service.rb b/app/services/milestones/create_service.rb index ed2e833d833..6c3edd2e147 100644 --- a/app/services/milestones/create_service.rb +++ b/app/services/milestones/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class CreateService < Milestones::BaseService def execute diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb index b18651476a8..15c04525075 100644 --- a/app/services/milestones/destroy_service.rb +++ b/app/services/milestones/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class DestroyService < Milestones::BaseService def execute(milestone) diff --git a/app/services/milestones/promote_service.rb b/app/services/milestones/promote_service.rb index 2187f26d1ed..37aa6d3a9bc 100644 --- a/app/services/milestones/promote_service.rb +++ b/app/services/milestones/promote_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class PromoteService < Milestones::BaseService PromoteMilestoneError = Class.new(StandardError) diff --git a/app/services/milestones/reopen_service.rb b/app/services/milestones/reopen_service.rb index 3efb33157c5..125a3ec1367 100644 --- a/app/services/milestones/reopen_service.rb +++ b/app/services/milestones/reopen_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class ReopenService < Milestones::BaseService def execute(milestone) diff --git a/app/services/milestones/update_service.rb b/app/services/milestones/update_service.rb index 74edbf9b41d..81b20943bab 100644 --- a/app/services/milestones/update_service.rb +++ b/app/services/milestones/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Milestones class UpdateService < Milestones::BaseService def execute(milestone) diff --git a/app/services/note_summary.rb b/app/services/note_summary.rb index a6f6320d573..81f6f92f75c 100644 --- a/app/services/note_summary.rb +++ b/app/services/note_summary.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NoteSummary attr_reader :note attr_reader :metadata diff --git a/app/services/notes/build_service.rb b/app/services/notes/build_service.rb index 77e7b8a5ea7..df5fe65de3c 100644 --- a/app/services/notes/build_service.rb +++ b/app/services/notes/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class BuildService < ::BaseService def execute diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index 9ea28733f5f..049e6c5a871 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class CreateService < ::BaseService def execute diff --git a/app/services/notes/destroy_service.rb b/app/services/notes/destroy_service.rb index fb78420d324..64e9accd97f 100644 --- a/app/services/notes/destroy_service.rb +++ b/app/services/notes/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class DestroyService < BaseService def execute(note) diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb index 199b8028dbc..48722cc2a79 100644 --- a/app/services/notes/post_process_service.rb +++ b/app/services/notes/post_process_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class PostProcessService attr_accessor :note diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb index 0a33d5f3f3d..7280449bb1c 100644 --- a/app/services/notes/quick_actions_service.rb +++ b/app/services/notes/quick_actions_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class QuickActionsService < BaseService UPDATE_SERVICES = { diff --git a/app/services/notes/render_service.rb b/app/services/notes/render_service.rb index efc9d6da2aa..0e1a55ae2ff 100644 --- a/app/services/notes/render_service.rb +++ b/app/services/notes/render_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class RenderService < BaseRenderer # Renders a collection of Note instances. diff --git a/app/services/notes/resolve_service.rb b/app/services/notes/resolve_service.rb index 0db8ee809a9..cf24795f050 100644 --- a/app/services/notes/resolve_service.rb +++ b/app/services/notes/resolve_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class ResolveService < ::BaseService def execute(note) diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb index e16ef398184..35db409eb27 100644 --- a/app/services/notes/update_service.rb +++ b/app/services/notes/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Notes class UpdateService < BaseService def execute(note) diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb index d9834fd0ccc..4389fd89538 100644 --- a/app/services/notification_recipient_service.rb +++ b/app/services/notification_recipient_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # # Used by NotificationService to determine who should receive notification # diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index d7be9a925b5..4511c500fca 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable GitlabSecurity/PublicSend # NotificationService class diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb index 6da4d9523cf..a15ee4911ef 100644 --- a/app/services/preview_markdown_service.rb +++ b/app/services/preview_markdown_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PreviewMarkdownService < BaseService def execute text, commands = explain_quick_actions(params[:text]) diff --git a/app/services/projects/after_import_service.rb b/app/services/projects/after_import_service.rb index 3047268b2d1..bbdde4408d2 100644 --- a/app/services/projects/after_import_service.rb +++ b/app/services/projects/after_import_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class AfterImportService RESERVED_REF_PREFIXES = Repository::RESERVED_REFS_NAMES.map { |n| File.join('refs', n, '/') } diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb index 9d0eaaf3152..10eb2cea4a2 100644 --- a/app/services/projects/autocomplete_service.rb +++ b/app/services/projects/autocomplete_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class AutocompleteService < BaseService def issues diff --git a/app/services/projects/base_move_relations_service.rb b/app/services/projects/base_move_relations_service.rb index e8fd3ef57e5..78cc2869b72 100644 --- a/app/services/projects/base_move_relations_service.rb +++ b/app/services/projects/base_move_relations_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class BaseMoveRelationsService < BaseService attr_reader :source_project diff --git a/app/services/projects/batch_count_service.rb b/app/services/projects/batch_count_service.rb index 178ebc5a143..aec3b32da89 100644 --- a/app/services/projects/batch_count_service.rb +++ b/app/services/projects/batch_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Service class for getting and caching the number of elements of several projects # Warning: do not user this service with a really large set of projects # because the service use maps to retrieve the project ids. diff --git a/app/services/projects/batch_forks_count_service.rb b/app/services/projects/batch_forks_count_service.rb index e61fe6c86b2..9bf369df999 100644 --- a/app/services/projects/batch_forks_count_service.rb +++ b/app/services/projects/batch_forks_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Service class for getting and caching the number of forks of several projects # Warning: do not user this service with a really large set of projects # because the service use maps to retrieve the project ids diff --git a/app/services/projects/batch_open_issues_count_service.rb b/app/services/projects/batch_open_issues_count_service.rb index 3b0ade2419b..d375fcf9dbd 100644 --- a/app/services/projects/batch_open_issues_count_service.rb +++ b/app/services/projects/batch_open_issues_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Service class for getting and caching the number of issues of several projects # Warning: do not user this service with a really large set of projects # because the service use maps to retrieve the project ids diff --git a/app/services/projects/count_service.rb b/app/services/projects/count_service.rb index 4c8e000928f..3cee80c7bbc 100644 --- a/app/services/projects/count_service.rb +++ b/app/services/projects/count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects # Base class for the various service classes that count project data (e.g. # issues or forks). diff --git a/app/services/projects/create_from_template_service.rb b/app/services/projects/create_from_template_service.rb index 29b133cc466..f5c48e56880 100644 --- a/app/services/projects/create_from_template_service.rb +++ b/app/services/projects/create_from_template_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class CreateFromTemplateService < BaseService def initialize(user, params) diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 85491089d8e..02a3a3eb096 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class CreateService < BaseService def initialize(user, params) diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 87173cc79ec..46a8a5e4d98 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class DestroyService < BaseService include Gitlab::ShellAdapter diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb index 604747e39d0..dd297c9ba43 100644 --- a/app/services/projects/download_service.rb +++ b/app/services/projects/download_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class DownloadService < BaseService WHITELIST = [ diff --git a/app/services/projects/enable_deploy_key_service.rb b/app/services/projects/enable_deploy_key_service.rb index 121385afca3..b7c172028e9 100644 --- a/app/services/projects/enable_deploy_key_service.rb +++ b/app/services/projects/enable_deploy_key_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class EnableDeployKeyService < BaseService def execute diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index a8aafa9fb4f..33ad2120a75 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class ForkService < BaseService def execute(fork_to_project = nil) diff --git a/app/services/projects/forks_count_service.rb b/app/services/projects/forks_count_service.rb index dc6eb19affd..b570c6d4754 100644 --- a/app/services/projects/forks_count_service.rb +++ b/app/services/projects/forks_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects # Service class for getting and caching the number of forks of a project. class ForksCountService < Projects::CountService diff --git a/app/services/projects/gitlab_projects_import_service.rb b/app/services/projects/gitlab_projects_import_service.rb index a16268f4fd2..bc6e9caebb8 100644 --- a/app/services/projects/gitlab_projects_import_service.rb +++ b/app/services/projects/gitlab_projects_import_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This service is an adapter used to for the GitLab Import feature, and # creating a project from a template. # The latter will under the hood just import an archive supplied by GitLab. diff --git a/app/services/projects/group_links/create_service.rb b/app/services/projects/group_links/create_service.rb index 35624577024..1392775f805 100644 --- a/app/services/projects/group_links/create_service.rb +++ b/app/services/projects/group_links/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects module GroupLinks class CreateService < BaseService diff --git a/app/services/projects/group_links/destroy_service.rb b/app/services/projects/group_links/destroy_service.rb index e3a20b4c1e4..8aefad048ce 100644 --- a/app/services/projects/group_links/destroy_service.rb +++ b/app/services/projects/group_links/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects module GroupLinks class DestroyService < BaseService diff --git a/app/services/projects/hashed_storage/migrate_attachments_service.rb b/app/services/projects/hashed_storage/migrate_attachments_service.rb index bc897d891d5..649c916a593 100644 --- a/app/services/projects/hashed_storage/migrate_attachments_service.rb +++ b/app/services/projects/hashed_storage/migrate_attachments_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects module HashedStorage AttachmentMigrationError = Class.new(StandardError) diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb index 68c1af2396b..70f00b7fdeb 100644 --- a/app/services/projects/hashed_storage/migrate_repository_service.rb +++ b/app/services/projects/hashed_storage/migrate_repository_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects module HashedStorage class MigrateRepositoryService < BaseService diff --git a/app/services/projects/hashed_storage_migration_service.rb b/app/services/projects/hashed_storage_migration_service.rb index 662702c1db5..1828c99a65e 100644 --- a/app/services/projects/hashed_storage_migration_service.rb +++ b/app/services/projects/hashed_storage_migration_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class HashedStorageMigrationService < BaseService attr_reader :logger diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 120d57a188d..2f6dc4207dd 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Projects::HousekeepingService class # # Used for git housekeeping diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb index 7bf0b90b491..e3491282a8a 100644 --- a/app/services/projects/import_export/export_service.rb +++ b/app/services/projects/import_export/export_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects module ImportExport class ExportService < BaseService diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index 1781a01cbd4..e560d40371e 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class ImportService < BaseService include Gitlab::ShellAdapter @@ -65,7 +67,7 @@ module Projects else gitlab_shell.import_repository(project.repository_storage, project.disk_path, project.import_url) end - rescue Gitlab::Shell::Error, Gitlab::Git::RepositoryMirroring::RemoteError => e + rescue Gitlab::Shell::Error => e # Expire cache to prevent scenarios such as: # 1. First import failed, but the repo was imported successfully, so +exists?+ returns true # 2. Retried import, repo is broken or not imported but +exists?+ still returns true diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb index d9fb74b090e..a837ea82e38 100644 --- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb +++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This service lists the download link from a remote source based on the # oids provided module Projects diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb index 618c30b971f..7d4fa4e08df 100644 --- a/app/services/projects/lfs_pointers/lfs_download_service.rb +++ b/app/services/projects/lfs_pointers/lfs_download_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This service downloads and links lfs objects from a remote URL module Projects module LfsPointers diff --git a/app/services/projects/lfs_pointers/lfs_import_service.rb b/app/services/projects/lfs_pointers/lfs_import_service.rb index b6b0dec142f..97ce681a911 100644 --- a/app/services/projects/lfs_pointers/lfs_import_service.rb +++ b/app/services/projects/lfs_pointers/lfs_import_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This service manages the whole worflow of discovering the Lfs files in a # repository, linking them to the project and downloading (and linking) the non # existent ones. diff --git a/app/services/projects/lfs_pointers/lfs_link_service.rb b/app/services/projects/lfs_pointers/lfs_link_service.rb index d20bdf86c58..a2eba8e124e 100644 --- a/app/services/projects/lfs_pointers/lfs_link_service.rb +++ b/app/services/projects/lfs_pointers/lfs_link_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Given a list of oids, this services links the existent Lfs Objects to the project module Projects module LfsPointers diff --git a/app/services/projects/lfs_pointers/lfs_list_service.rb b/app/services/projects/lfs_pointers/lfs_list_service.rb index b770982cbc0..22160017f4f 100644 --- a/app/services/projects/lfs_pointers/lfs_list_service.rb +++ b/app/services/projects/lfs_pointers/lfs_list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This service list all existent Lfs objects in a repository module Projects module LfsPointers diff --git a/app/services/projects/move_access_service.rb b/app/services/projects/move_access_service.rb index 3af3a22d486..8e2c3ad2f69 100644 --- a/app/services/projects/move_access_service.rb +++ b/app/services/projects/move_access_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveAccessService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/move_deploy_keys_projects_service.rb b/app/services/projects/move_deploy_keys_projects_service.rb index dde420655b0..40a22837eaf 100644 --- a/app/services/projects/move_deploy_keys_projects_service.rb +++ b/app/services/projects/move_deploy_keys_projects_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveDeployKeysProjectsService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/move_forks_service.rb b/app/services/projects/move_forks_service.rb index d2901ea1457..076a7a50aa9 100644 --- a/app/services/projects/move_forks_service.rb +++ b/app/services/projects/move_forks_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveForksService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/move_lfs_objects_projects_service.rb b/app/services/projects/move_lfs_objects_projects_service.rb index 298da5f1a82..a5099519594 100644 --- a/app/services/projects/move_lfs_objects_projects_service.rb +++ b/app/services/projects/move_lfs_objects_projects_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveLfsObjectsProjectsService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/move_notification_settings_service.rb b/app/services/projects/move_notification_settings_service.rb index f7be461a5da..746605d56f1 100644 --- a/app/services/projects/move_notification_settings_service.rb +++ b/app/services/projects/move_notification_settings_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveNotificationSettingsService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/move_project_authorizations_service.rb b/app/services/projects/move_project_authorizations_service.rb index 5ef12fc49e5..60f2af88e99 100644 --- a/app/services/projects/move_project_authorizations_service.rb +++ b/app/services/projects/move_project_authorizations_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # NOTE: This service cannot be used directly because it is part of a # a bigger process. Instead, use the service MoveAccessService which moves # project memberships, project group links, authorizations and refreshes diff --git a/app/services/projects/move_project_group_links_service.rb b/app/services/projects/move_project_group_links_service.rb index dbeffd7dae9..d9038030f7e 100644 --- a/app/services/projects/move_project_group_links_service.rb +++ b/app/services/projects/move_project_group_links_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # NOTE: This service cannot be used directly because it is part of a # a bigger process. Instead, use the service MoveAccessService which moves # project memberships, project group links, authorizations and refreshes diff --git a/app/services/projects/move_project_members_service.rb b/app/services/projects/move_project_members_service.rb index 22a5f0a3fe6..bb0c0d10242 100644 --- a/app/services/projects/move_project_members_service.rb +++ b/app/services/projects/move_project_members_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # NOTE: This service cannot be used directly because it is part of a # a bigger process. Instead, use the service MoveAccessService which moves # project memberships, project group links, authorizations and refreshes diff --git a/app/services/projects/move_users_star_projects_service.rb b/app/services/projects/move_users_star_projects_service.rb index 079fd5b9685..20121d429e2 100644 --- a/app/services/projects/move_users_star_projects_service.rb +++ b/app/services/projects/move_users_star_projects_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class MoveUsersStarProjectsService < BaseMoveRelationsService def execute(source_project, remove_remaining_elements: true) diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb index 78b1477186a..5d6620c3c54 100644 --- a/app/services/projects/open_issues_count_service.rb +++ b/app/services/projects/open_issues_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects # Service class for counting and caching the number of open issues of a # project. diff --git a/app/services/projects/open_merge_requests_count_service.rb b/app/services/projects/open_merge_requests_count_service.rb index 77e6448fd5e..76ec13952ab 100644 --- a/app/services/projects/open_merge_requests_count_service.rb +++ b/app/services/projects/open_merge_requests_count_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects # Service class for counting and caching the number of open merge requests of # a project. diff --git a/app/services/projects/overwrite_project_service.rb b/app/services/projects/overwrite_project_service.rb index ce94f147aa9..696e1b665b2 100644 --- a/app/services/projects/overwrite_project_service.rb +++ b/app/services/projects/overwrite_project_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class OverwriteProjectService < BaseService def execute(source_project) diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb index 21741913385..7080f388e53 100644 --- a/app/services/projects/participants_service.rb +++ b/app/services/projects/participants_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class ParticipantsService < BaseService include Users::ParticipableService diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb index a8ef2108492..fdfa91801ab 100644 --- a/app/services/projects/propagate_service_template.rb +++ b/app/services/projects/propagate_service_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class PropagateServiceTemplate BATCH_SIZE = 100 diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 61acdd58021..a4a66330546 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Projects::TransferService class # # Used for transfer project to another namespace diff --git a/app/services/projects/unlink_fork_service.rb b/app/services/projects/unlink_fork_service.rb index 842fe4e09c4..2c0d91fe34f 100644 --- a/app/services/projects/unlink_fork_service.rb +++ b/app/services/projects/unlink_fork_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class UnlinkForkService < BaseService def execute diff --git a/app/services/projects/update_pages_configuration_service.rb b/app/services/projects/update_pages_configuration_service.rb index 25017c5cbe3..efbd4c7b323 100644 --- a/app/services/projects/update_pages_configuration_service.rb +++ b/app/services/projects/update_pages_configuration_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class UpdatePagesConfigurationService < BaseService attr_reader :project diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index 1d8caec9c6f..eb2478be3cf 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class UpdatePagesService < BaseService InvalidStateError = Class.new(StandardError) diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb index 8183a2f26d7..4651f7c4f8f 100644 --- a/app/services/projects/update_remote_mirror_service.rb +++ b/app/services/projects/update_remote_mirror_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class UpdateRemoteMirrorService < BaseService attr_reader :errors diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index f4fbaacc08b..d3dc11435fe 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Projects class UpdateService < BaseService include UpdateVisibilityLevel diff --git a/app/services/prometheus/adapter_service.rb b/app/services/prometheus/adapter_service.rb index 4504d2ccfe6..cbba79690c5 100644 --- a/app/services/prometheus/adapter_service.rb +++ b/app/services/prometheus/adapter_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Prometheus class AdapterService def initialize(project, deployment_platform = nil) diff --git a/app/services/protected_branches/access_level_params.rb b/app/services/protected_branches/access_level_params.rb index 4658b0e850d..a7ef573ff0b 100644 --- a/app/services/protected_branches/access_level_params.rb +++ b/app/services/protected_branches/access_level_params.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedBranches class AccessLevelParams attr_reader :type, :params diff --git a/app/services/protected_branches/api_service.rb b/app/services/protected_branches/api_service.rb index 4b40200644b..4340d3e8260 100644 --- a/app/services/protected_branches/api_service.rb +++ b/app/services/protected_branches/api_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedBranches class ApiService < BaseService def create diff --git a/app/services/protected_branches/create_service.rb b/app/services/protected_branches/create_service.rb index 9d947f73af1..87aaf4672a4 100644 --- a/app/services/protected_branches/create_service.rb +++ b/app/services/protected_branches/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedBranches class CreateService < BaseService def execute(skip_authorization: false) diff --git a/app/services/protected_branches/destroy_service.rb b/app/services/protected_branches/destroy_service.rb index 8172c896e76..7190bc2001b 100644 --- a/app/services/protected_branches/destroy_service.rb +++ b/app/services/protected_branches/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedBranches class DestroyService < BaseService def execute(protected_branch) diff --git a/app/services/protected_branches/legacy_api_create_service.rb b/app/services/protected_branches/legacy_api_create_service.rb index bb7656489c5..aef99a860a0 100644 --- a/app/services/protected_branches/legacy_api_create_service.rb +++ b/app/services/protected_branches/legacy_api_create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # The branches#protect API still uses the `developers_can_push` and `developers_can_merge` # flags for backward compatibility, and so performs translation between that format and the # internal data model (separate access levels). The translation code is non-trivial, and so diff --git a/app/services/protected_branches/legacy_api_update_service.rb b/app/services/protected_branches/legacy_api_update_service.rb index 1df38de0e4a..1f6bbe72f85 100644 --- a/app/services/protected_branches/legacy_api_update_service.rb +++ b/app/services/protected_branches/legacy_api_update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # The branches#protect API still uses the `developers_can_push` and `developers_can_merge` # flags for backward compatibility, and so performs translation between that format and the # internal data model (separate access levels). The translation code is non-trivial, and so diff --git a/app/services/protected_branches/update_service.rb b/app/services/protected_branches/update_service.rb index 95e46645374..4d7d498b8ca 100644 --- a/app/services/protected_branches/update_service.rb +++ b/app/services/protected_branches/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedBranches class UpdateService < BaseService def execute(protected_branch) diff --git a/app/services/protected_tags/create_service.rb b/app/services/protected_tags/create_service.rb index faba7865a17..9aff55986b2 100644 --- a/app/services/protected_tags/create_service.rb +++ b/app/services/protected_tags/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedTags class CreateService < BaseService attr_reader :protected_tag diff --git a/app/services/protected_tags/destroy_service.rb b/app/services/protected_tags/destroy_service.rb index c868d7ad8e6..dc4a1b39848 100644 --- a/app/services/protected_tags/destroy_service.rb +++ b/app/services/protected_tags/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedTags class DestroyService < BaseService def execute(protected_tag) diff --git a/app/services/protected_tags/update_service.rb b/app/services/protected_tags/update_service.rb index aea6a48968d..3eb5f4955ee 100644 --- a/app/services/protected_tags/update_service.rb +++ b/app/services/protected_tags/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProtectedTags class UpdateService < BaseService def execute(protected_tag) diff --git a/app/services/push_event_payload_service.rb b/app/services/push_event_payload_service.rb index b0a389c85f9..bb1259787af 100644 --- a/app/services/push_event_payload_service.rb +++ b/app/services/push_event_payload_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Service class for creating push event payloads as stored in the # "push_event_payloads" table. # diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 9ac8fdb4cff..cdc8514c47c 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module QuickActions class InterpretService < BaseService include Gitlab::QuickActions::Dsl diff --git a/app/services/repair_ldap_blocked_user_service.rb b/app/services/repair_ldap_blocked_user_service.rb index 863cef7ff61..6ed42054ac3 100644 --- a/app/services/repair_ldap_blocked_user_service.rb +++ b/app/services/repair_ldap_blocked_user_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepairLdapBlockedUserService attr_accessor :user diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb index ba7be4b3f89..99a9c834352 100644 --- a/app/services/repository_archive_clean_up_service.rb +++ b/app/services/repository_archive_clean_up_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryArchiveCleanUpService LAST_MODIFIED_TIME_IN_MINUTES = 120 diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb index a162a6eedb9..676d367a1c1 100644 --- a/app/services/reset_project_cache_service.rb +++ b/app/services/reset_project_cache_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ResetProjectCacheService < BaseService def execute @project.increment!(:jobs_cache_index) diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index 92a32e703af..cb1bf0a03a5 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Search class GlobalService attr_accessor :current_user, :params diff --git a/app/services/search/group_service.rb b/app/services/search/group_service.rb index b4efba68715..34803d005e3 100644 --- a/app/services/search/group_service.rb +++ b/app/services/search/group_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Search class GroupService < Search::GlobalService attr_accessor :group diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb index 9a22abae635..f223c8be103 100644 --- a/app/services/search/project_service.rb +++ b/app/services/search/project_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Search class ProjectService attr_accessor :project, :current_user, :params diff --git a/app/services/search/snippet_service.rb b/app/services/search/snippet_service.rb index 85da0be6fff..e899a36f468 100644 --- a/app/services/search/snippet_service.rb +++ b/app/services/search/snippet_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Search class SnippetService attr_accessor :current_user, :params diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 1d4d03a8b7d..1b707d79b43 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SearchService include Gitlab::Allowable diff --git a/app/services/spam_check_service.rb b/app/services/spam_check_service.rb index d4ade869777..895261925ba 100644 --- a/app/services/spam_check_service.rb +++ b/app/services/spam_check_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # SpamCheckService # # Provide helper methods for checking if a given spammable object has diff --git a/app/services/spam_service.rb b/app/services/spam_service.rb index 73ea3018fbd..f2f133dae28 100644 --- a/app/services/spam_service.rb +++ b/app/services/spam_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SpamService attr_accessor :spammable, :request, :options attr_reader :spam_log diff --git a/app/services/submit_usage_ping_service.rb b/app/services/submit_usage_ping_service.rb index ac029fad7ea..93c2e222963 100644 --- a/app/services/submit_usage_ping_service.rb +++ b/app/services/submit_usage_ping_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SubmitUsagePingService URL = 'https://version.gitlab.com/usage_data'.freeze diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index ba7946fd23c..bd3907cdf8e 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SystemHooksService def execute_hooks_for(model, event) data = build_event_data(model, event) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 00bf5434b7f..77494295f14 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # SystemNoteService # # Used for creating system notes (e.g., when a user references a merge request @@ -21,9 +23,11 @@ module SystemNoteService total_count = new_commits.length + existing_commits.length commits_text = "#{total_count} commit".pluralize(total_count) - body = "added #{commits_text}\n\n" - body << commits_list(noteable, new_commits, existing_commits, oldrev) - body << "\n\n[Compare with previous version](#{diff_comparison_url(noteable, project, oldrev)})" + text_parts = ["added #{commits_text}"] + text_parts << commits_list(noteable, new_commits, existing_commits, oldrev) + text_parts << "[Compare with previous version](#{diff_comparison_url(noteable, project, oldrev)})" + + body = text_parts.join("\n\n") create_note(NoteSummary.new(noteable, project, author, body, action: 'commit', commit_count: total_count)) end @@ -103,18 +107,19 @@ module SystemNoteService added_labels = added_labels.map(&references).join(' ') removed_labels = removed_labels.map(&references).join(' ') - body = '' + text_parts = [] if added_labels.present? - body << "added #{added_labels}" - body << ' and ' if removed_labels.present? + text_parts << "added #{added_labels}" + text_parts << 'and' if removed_labels.present? end if removed_labels.present? - body << "removed #{removed_labels}" + text_parts << "removed #{removed_labels}" end - body << ' ' << 'label'.pluralize(labels_count) + text_parts << 'label'.pluralize(labels_count) + body = text_parts.join(' ') create_note(NoteSummary.new(noteable, project, author, body, action: 'label')) end @@ -188,8 +193,10 @@ module SystemNoteService spent_at = noteable.spent_at parsed_time = Gitlab::TimeTrackingFormatter.output(time_spent.abs) action = time_spent > 0 ? 'added' : 'subtracted' - body = "#{action} #{parsed_time} of time spent" - body << " at #{spent_at}" if spent_at + + text_parts = ["#{action} #{parsed_time} of time spent"] + text_parts << "at #{spent_at}" if spent_at + body = text_parts.join(' ') end create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking')) @@ -268,17 +275,19 @@ module SystemNoteService diff_refs = change_position.diff_refs version_index = merge_request.merge_request_diffs.viewable.count - body = "changed this line in" + text_parts = ["changed this line in"] if version_params = merge_request.version_params_for(diff_refs) line_code = change_position.line_code(project.repository) url = url_helpers.diffs_project_merge_request_url(project, merge_request, version_params.merge(anchor: line_code)) - body << " [version #{version_index} of the diff](#{url})" + text_parts << "[version #{version_index} of the diff](#{url})" else - body << " version #{version_index} of the diff" + text_parts << "version #{version_index} of the diff" end + body = text_parts.join(' ') note_attributes = discussion.reply_attributes.merge(project: project, author: author, note: body) + note = Note.create(note_attributes.merge(system: true)) note.system_note_metadata = SystemNoteMetadata.new(action: 'outdated') diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb index 3cc88d77ba1..329722df747 100644 --- a/app/services/tags/create_service.rb +++ b/app/services/tags/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Tags class CreateService < BaseService def execute(tag_name, target, message, release_description = nil) diff --git a/app/services/tags/destroy_service.rb b/app/services/tags/destroy_service.rb index b84b061e460..800268485a4 100644 --- a/app/services/tags/destroy_service.rb +++ b/app/services/tags/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Tags class DestroyService < BaseService def execute(tag_name) diff --git a/app/services/test_hooks/base_service.rb b/app/services/test_hooks/base_service.rb index aadc1ea644b..8b5439c00bf 100644 --- a/app/services/test_hooks/base_service.rb +++ b/app/services/test_hooks/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TestHooks class BaseService attr_accessor :hook, :current_user, :trigger diff --git a/app/services/test_hooks/project_service.rb b/app/services/test_hooks/project_service.rb index 65183e84cce..45e0e61e5c4 100644 --- a/app/services/test_hooks/project_service.rb +++ b/app/services/test_hooks/project_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TestHooks class ProjectService < TestHooks::BaseService attr_writer :project diff --git a/app/services/test_hooks/system_service.rb b/app/services/test_hooks/system_service.rb index 9016c77b7f0..082830c5538 100644 --- a/app/services/test_hooks/system_service.rb +++ b/app/services/test_hooks/system_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TestHooks class SystemService < TestHooks::BaseService private diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index f91cd03bf5c..0bcd53c76a9 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # TodoService class # # Used for creating/updating todos after certain user actions diff --git a/app/services/update_release_service.rb b/app/services/update_release_service.rb index dc696e9c440..422ba668e35 100644 --- a/app/services/update_release_service.rb +++ b/app/services/update_release_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UpdateReleaseService < BaseService def execute(tag_name, release_description) repository = project.repository diff --git a/app/services/update_snippet_service.rb b/app/services/update_snippet_service.rb index 358bca73aec..15bc1046a4e 100644 --- a/app/services/update_snippet_service.rb +++ b/app/services/update_snippet_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UpdateSnippetService < BaseService include SpamCheckService diff --git a/app/services/upload_service.rb b/app/services/upload_service.rb index d5a9b344905..39909ee4f82 100644 --- a/app/services/upload_service.rb +++ b/app/services/upload_service.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + class UploadService - def initialize(model, file, uploader_class = FileUploader) - @model, @file, @uploader_class = model, file, uploader_class + def initialize(model, file, uploader_class = FileUploader, **uploader_context) + @model, @file, @uploader_class, @uploader_context = model, file, uploader_class, uploader_context end def execute return nil unless @file && @file.size <= max_attachment_size - uploader = @uploader_class.new(@model) + uploader = @uploader_class.new(@model, nil, @uploader_context) uploader.store!(@file) uploader.to_h diff --git a/app/services/user_agent_detail_service.rb b/app/services/user_agent_detail_service.rb index a1ee3df5fe1..5cb42e879a0 100644 --- a/app/services/user_agent_detail_service.rb +++ b/app/services/user_agent_detail_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UserAgentDetailService attr_accessor :spammable, :request diff --git a/app/services/user_project_access_changed_service.rb b/app/services/user_project_access_changed_service.rb index 8630e572624..adca43660e8 100644 --- a/app/services/user_project_access_changed_service.rb +++ b/app/services/user_project_access_changed_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UserProjectAccessChangedService def initialize(user_ids) @user_ids = Array.wrap(user_ids) diff --git a/app/services/users/activity_service.rb b/app/services/users/activity_service.rb index 5803404c3c8..822df6c646a 100644 --- a/app/services/users/activity_service.rb +++ b/app/services/users/activity_service.rb @@ -1,12 +1,21 @@ +# frozen_string_literal: true + module Users class ActivityService + LEASE_TIMEOUT = 1.minute.to_i + def initialize(author, activity) - @author = author.respond_to?(:user) ? author.user : author + @user = if author.respond_to?(:username) + author + elsif author.respond_to?(:user) + author.user + end + @activity = activity end def execute - return unless @author && @author.is_a?(User) + return unless @user record_activity end @@ -14,9 +23,14 @@ module Users private def record_activity - Gitlab::UserActivities.record(@author.id) if Gitlab::Database.read_write? + return if Gitlab::Database.read_only? + + lease = Gitlab::ExclusiveLease.new("acitvity_service:#{@user.id}", + timeout: LEASE_TIMEOUT) + return unless lease.try_obtain - Rails.logger.debug("Recorded activity: #{@activity} for User ID: #{@author.id} (username: #{@author.username})") + @user.update_attribute(:last_activity_on, Date.today) + Rails.logger.debug("Recorded activity: #{@activity} for User ID: #{@user.id} (username: #{@user.username})") end end end diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index 4fb6d221909..c69b46cab5a 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class BuildService < BaseService def initialize(current_user, params = {}) diff --git a/app/services/users/create_service.rb b/app/services/users/create_service.rb index c8a3c461d60..2ac6dfd90fa 100644 --- a/app/services/users/create_service.rb +++ b/app/services/users/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class CreateService < BaseService include NewUserNotifier diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb index 06b604dad4d..4bc78b5b64e 100644 --- a/app/services/users/destroy_service.rb +++ b/app/services/users/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class DestroyService attr_accessor :current_user diff --git a/app/services/users/last_push_event_service.rb b/app/services/users/last_push_event_service.rb index 57e446d7f30..a9c9497520b 100644 --- a/app/services/users/last_push_event_service.rb +++ b/app/services/users/last_push_event_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users # Service class for caching and retrieving the last push event of a user. class LastPushEventService diff --git a/app/services/users/migrate_to_ghost_user_service.rb b/app/services/users/migrate_to_ghost_user_service.rb index a2833b1e051..4d47078bf43 100644 --- a/app/services/users/migrate_to_ghost_user_service.rb +++ b/app/services/users/migrate_to_ghost_user_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # When a user is destroyed, some of their associated records are # moved to a "Ghost User", to prevent these associated records from # being destroyed. diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb index f028f5eb0d4..23b63aaabdf 100644 --- a/app/services/users/refresh_authorized_projects_service.rb +++ b/app/services/users/refresh_authorized_projects_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users # Service for refreshing the authorized projects of a user. # diff --git a/app/services/users/respond_to_terms_service.rb b/app/services/users/respond_to_terms_service.rb index 06d660186cf..9efa3b285a8 100644 --- a/app/services/users/respond_to_terms_service.rb +++ b/app/services/users/respond_to_terms_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class RespondToTermsService def initialize(user, term) diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb index 15ca1a55a5b..6dadb5a4eac 100644 --- a/app/services/users/update_service.rb +++ b/app/services/users/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Users class UpdateService < BaseService include NewUserNotifier diff --git a/app/services/validate_new_branch_service.rb b/app/services/validate_new_branch_service.rb index 643f2ce1481..c19e2ec2043 100644 --- a/app/services/validate_new_branch_service.rb +++ b/app/services/validate_new_branch_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'base_service' class ValidateNewBranchService < BaseService diff --git a/app/services/verify_pages_domain_service.rb b/app/services/verify_pages_domain_service.rb index 13cb53dee01..07f7391f877 100644 --- a/app/services/verify_pages_domain_service.rb +++ b/app/services/verify_pages_domain_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'resolv' class VerifyPagesDomainService < BaseService diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb index 8a86e47f0ea..34724e0250d 100644 --- a/app/services/web_hook_service.rb +++ b/app/services/web_hook_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WebHookService class InternalErrorResponse attr_reader :body, :headers, :code diff --git a/app/services/wiki_pages/base_service.rb b/app/services/wiki_pages/base_service.rb index 260c04a8b94..e259f5bd1bc 100644 --- a/app/services/wiki_pages/base_service.rb +++ b/app/services/wiki_pages/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiPages class BaseService < ::BaseService private diff --git a/app/services/wiki_pages/create_service.rb b/app/services/wiki_pages/create_service.rb index 24a817c06c9..2e2e0fd9033 100644 --- a/app/services/wiki_pages/create_service.rb +++ b/app/services/wiki_pages/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiPages class CreateService < WikiPages::BaseService def execute diff --git a/app/services/wiki_pages/destroy_service.rb b/app/services/wiki_pages/destroy_service.rb index 6b93fb2f6d7..3f9343339cd 100644 --- a/app/services/wiki_pages/destroy_service.rb +++ b/app/services/wiki_pages/destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiPages class DestroyService < WikiPages::BaseService def execute(page) diff --git a/app/services/wiki_pages/update_service.rb b/app/services/wiki_pages/update_service.rb index 93cbd9a509f..2159dd91e9c 100644 --- a/app/services/wiki_pages/update_service.rb +++ b/app/services/wiki_pages/update_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiPages class UpdateService < WikiPages::BaseService def execute(page) diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index 21292ddcf44..b1365659834 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -15,7 +15,7 @@ class FileUploader < GitlabUploader prepend ObjectStorage::Extension::RecordsUploads MARKDOWN_PATTERN = %r{\!?\[.*?\]\(/uploads/(?<secret>[0-9a-f]{32})/(?<file>.*?)\)} - DYNAMIC_PATH_PATTERN = %r{(?<secret>\h{32})/(?<identifier>.*)} + DYNAMIC_PATH_PATTERN = %r{.*(?<secret>\h{32})/(?<identifier>.*)} after :remove, :prune_store_dir @@ -67,6 +67,10 @@ class FileUploader < GitlabUploader SecureRandom.hex end + def self.extract_dynamic_path(path) + DYNAMIC_PATH_PATTERN.match(path) + end + def upload_paths(identifier) [ File.join(secret, identifier), @@ -132,10 +136,6 @@ class FileUploader < GitlabUploader } end - def filename - self.file.filename - end - def upload=(value) super @@ -143,7 +143,7 @@ class FileUploader < GitlabUploader return if apply_context!(value.uploader_context) # fallback to the regex based extraction - if matches = DYNAMIC_PATH_PATTERN.match(value.path) + if matches = self.class.extract_dynamic_path(value.path) @secret = matches[:secret] @identifier = matches[:identifier] end diff --git a/app/views/admin/application_settings/_abuse.html.haml b/app/views/admin/application_settings/_abuse.html.haml index 91993838fc8..4e9465fc75d 100644 --- a/app/views/admin/application_settings/_abuse.html.haml +++ b/app/views/admin/application_settings/_abuse.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :admin_notification_email, 'Abuse reports notification email', class: 'label-light' + = f.label :admin_notification_email, 'Abuse reports notification email', class: 'label-bold' = f.text_field :admin_notification_email, class: 'form-control' .form-text.text-muted Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area. diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml index f40939747f4..ca242b0ede9 100644 --- a/app/views/admin/application_settings/_account_and_limit.html.haml +++ b/app/views/admin/application_settings/_account_and_limit.html.haml @@ -8,23 +8,23 @@ = f.label :gravatar_enabled, class: 'form-check-label' do Gravatar enabled .form-group - = f.label :default_projects_limit, class: 'label-light' + = f.label :default_projects_limit, class: 'label-bold' = f.number_field :default_projects_limit, class: 'form-control' .form-group - = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'label-light' + = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'label-bold' = f.number_field :max_attachment_size, class: 'form-control' .form-group - = f.label :session_expire_delay, 'Session duration (minutes)', class: 'label-light' + = f.label :session_expire_delay, 'Session duration (minutes)', class: 'label-bold' = f.number_field :session_expire_delay, class: 'form-control' %span.form-text.text-muted#session_expire_delay_help_block GitLab restart is required to apply changes .form-group - = f.label :user_oauth_applications, 'User OAuth applications', class: 'label-light' + = f.label :user_oauth_applications, 'User OAuth applications', class: 'label-bold' .form-check = f.check_box :user_oauth_applications, class: 'form-check-input' = f.label :user_oauth_applications, class: 'form-check-label' do Allow users to register any application to use GitLab as an OAuth provider .form-group - = f.label :user_default_external, 'New users set to external', class: 'label-light' + = f.label :user_default_external, 'New users set to external', class: 'label-bold' .form-check = f.check_box :user_default_external, class: 'form-check-input' = f.label :user_default_external, class: 'form-check-label' do diff --git a/app/views/admin/application_settings/_background_jobs.html.haml b/app/views/admin/application_settings/_background_jobs.html.haml index fd8e695ed49..02d761576e3 100644 --- a/app/views/admin/application_settings/_background_jobs.html.haml +++ b/app/views/admin/application_settings/_background_jobs.html.haml @@ -14,12 +14,12 @@ .form-text.text-muted Limit the amount of resources slow running jobs are assigned. .form-group - = f.label :sidekiq_throttling_queues, 'Sidekiq queues to throttle', class: 'label-light' + = f.label :sidekiq_throttling_queues, 'Sidekiq queues to throttle', class: 'label-bold' = f.select :sidekiq_throttling_queues, sidekiq_queue_options_for_select, { include_hidden: false }, multiple: true, class: 'select2 select-wide', data: { field: 'sidekiq_throttling_queues' } .form-text.text-muted Choose which queues you wish to throttle. .form-group - = f.label :sidekiq_throttling_factor, 'Throttling Factor', class: 'label-light' + = f.label :sidekiq_throttling_factor, 'Throttling Factor', class: 'label-bold' = f.number_field :sidekiq_throttling_factor, class: 'form-control', min: '0.01', max: '0.99', step: '0.01' .form-text.text-muted The factor by which the queues should be throttled. A value between 0.0 and 1.0, exclusive. diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml index 7c16cafe13f..7a304ef2884 100644 --- a/app/views/admin/application_settings/_ci_cd.html.haml +++ b/app/views/admin/application_settings/_ci_cd.html.haml @@ -11,7 +11,7 @@ It will automatically build, test, and deploy applications based on a predefined CI/CD configuration = link_to icon('question-circle'), help_page_path('topics/autodevops/index.md') .form-group - = f.label :auto_devops_domain, class: 'label-light' + = f.label :auto_devops_domain, class: 'label-bold' = f.text_field :auto_devops_domain, class: 'form-control', placeholder: 'domain.com' .form-text.text-muted = s_("AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages.") @@ -21,17 +21,17 @@ = f.label :shared_runners_enabled, class: 'form-check-label' do Enable shared runners for new projects .form-group - = f.label :shared_runners_text, class: 'label-light' + = f.label :shared_runners_text, class: 'label-bold' = f.text_area :shared_runners_text, class: 'form-control', rows: 4 .form-text.text-muted Markdown enabled .form-group - = f.label :max_artifacts_size, 'Maximum artifacts size (MB)', class: 'label-light' + = f.label :max_artifacts_size, 'Maximum artifacts size (MB)', class: 'label-bold' = f.number_field :max_artifacts_size, class: 'form-control' .form-text.text-muted Set the maximum file size for each job's artifacts = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size') .form-group - = f.label :default_artifacts_expire_in, 'Default artifacts expiration', class: 'label-light' + = f.label :default_artifacts_expire_in, 'Default artifacts expiration', class: 'label-bold' = f.text_field :default_artifacts_expire_in, class: 'form-control' .form-text.text-muted Set the default expiration time for each job's artifacts. diff --git a/app/views/admin/application_settings/_gitaly.html.haml b/app/views/admin/application_settings/_gitaly.html.haml index 0b4001c0824..4ade9ee975a 100644 --- a/app/views/admin/application_settings/_gitaly.html.haml +++ b/app/views/admin/application_settings/_gitaly.html.haml @@ -3,20 +3,20 @@ %fieldset .form-group - = f.label :gitaly_timeout_default, 'Default Timeout Period', class: 'label-light' + = f.label :gitaly_timeout_default, 'Default Timeout Period', class: 'label-bold' = f.number_field :gitaly_timeout_default, class: 'form-control' .form-text.text-muted Timeout for Gitaly calls from the GitLab application (in seconds). This timeout is not enforced for git fetch/push operations or Sidekiq jobs. .form-group - = f.label :gitaly_timeout_fast, 'Fast Timeout Period', class: 'label-light' + = f.label :gitaly_timeout_fast, 'Fast Timeout Period', class: 'label-bold' = f.number_field :gitaly_timeout_fast, class: 'form-control' .form-text.text-muted Fast operation timeout (in seconds). Some Gitaly operations are expected to be fast. If they exceed this threshold, there may be a problem with a storage shard and 'failing fast' can help maintain the stability of the GitLab instance. .form-group - = f.label :gitaly_timeout_medium, 'Medium Timeout Period', class: 'label-light' + = f.label :gitaly_timeout_medium, 'Medium Timeout Period', class: 'label-bold' = f.number_field :gitaly_timeout_medium, class: 'form-control' .form-text.text-muted Medium operation timeout (in seconds). This should be a value between the Fast and the Default timeout. diff --git a/app/views/admin/application_settings/_help_page.html.haml b/app/views/admin/application_settings/_help_page.html.haml index 1f402fcb786..73f8d7bb77c 100644 --- a/app/views/admin/application_settings/_help_page.html.haml +++ b/app/views/admin/application_settings/_help_page.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :help_page_text, class: 'label-light' + = f.label :help_page_text, class: 'label-bold' = f.text_area :help_page_text, class: 'form-control', rows: 4 .form-text.text-muted Markdown enabled .form-group @@ -12,7 +12,7 @@ = f.label :help_page_hide_commercial_content, class: 'form-check-label' do Hide marketing-related entries from help .form-group - = f.label :help_page_support_url, 'Support page URL', class: 'label-light' + = f.label :help_page_support_url, 'Support page URL', class: 'label-bold' = f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block' %span.form-text.text-muted#support_help_block Alternate support URL for help page diff --git a/app/views/admin/application_settings/_influx.html.haml b/app/views/admin/application_settings/_influx.html.haml index 61e8e3199a9..2f6d6ddf23d 100644 --- a/app/views/admin/application_settings/_influx.html.haml +++ b/app/views/admin/application_settings/_influx.html.haml @@ -14,10 +14,10 @@ = f.label :metrics_enabled, class: 'form-check-label' do Enable InfluxDB Metrics .form-group - = f.label :metrics_host, 'InfluxDB host', class: 'label-light' + = f.label :metrics_host, 'InfluxDB host', class: 'label-bold' = f.text_field :metrics_host, class: 'form-control', placeholder: 'influxdb.example.com' .form-group - = f.label :metrics_port, 'InfluxDB port', class: 'label-light' + = f.label :metrics_port, 'InfluxDB port', class: 'label-bold' = f.text_field :metrics_port, class: 'form-control', placeholder: '8089' .form-text.text-muted The UDP port to use for connecting to InfluxDB. InfluxDB requires that @@ -25,7 +25,7 @@ sending messages to this port, without it metrics data will not be saved. .form-group - = f.label :metrics_pool_size, 'Connection pool size', class: 'label-light' + = f.label :metrics_pool_size, 'Connection pool size', class: 'label-bold' = f.number_field :metrics_pool_size, class: 'form-control' .form-text.text-muted The amount of InfluxDB connections to open. Connections are opened @@ -33,25 +33,25 @@ enough connections are available (at minimum the amount of application server threads). .form-group - = f.label :metrics_timeout, 'Connection timeout', class: 'label-light' + = f.label :metrics_timeout, 'Connection timeout', class: 'label-bold' = f.number_field :metrics_timeout, class: 'form-control' .form-text.text-muted The amount of seconds after which an InfluxDB connection will time out. .form-group - = f.label :metrics_method_call_threshold, 'Method Call Threshold (ms)', class: 'label-light' + = f.label :metrics_method_call_threshold, 'Method Call Threshold (ms)', class: 'label-bold' = f.number_field :metrics_method_call_threshold, class: 'form-control' .form-text.text-muted A method call is only tracked when it takes longer to complete than the given amount of milliseconds. .form-group - = f.label :metrics_sample_interval, 'Sampler Interval (sec)', class: 'label-light' + = f.label :metrics_sample_interval, 'Sampler Interval (sec)', class: 'label-bold' = f.number_field :metrics_sample_interval, class: 'form-control' .form-text.text-muted The sampling interval in seconds. Sampled data includes memory usage, retained Ruby objects, file descriptors and so on. .form-group - = f.label :metrics_packet_size, 'Metrics per packet', class: 'label-light' + = f.label :metrics_packet_size, 'Metrics per packet', class: 'label-bold' = f.number_field :metrics_packet_size, class: 'form-control' .form-text.text-muted The amount of points to store in a single UDP packet. More points diff --git a/app/views/admin/application_settings/_ip_limits.html.haml b/app/views/admin/application_settings/_ip_limits.html.haml index 73d570a5fee..44118777467 100644 --- a/app/views/admin/application_settings/_ip_limits.html.haml +++ b/app/views/admin/application_settings/_ip_limits.html.haml @@ -10,10 +10,10 @@ %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) .form-group - = f.label :throttle_unauthenticated_requests_per_period, 'Max requests per period per IP', class: 'label-light' + = f.label :throttle_unauthenticated_requests_per_period, 'Max requests per period per IP', class: 'label-bold' = f.number_field :throttle_unauthenticated_requests_per_period, class: 'form-control' .form-group - = f.label :throttle_unauthenticated_period_in_seconds, 'Rate limit period in seconds', class: 'label-light' + = f.label :throttle_unauthenticated_period_in_seconds, 'Rate limit period in seconds', class: 'label-bold' = f.number_field :throttle_unauthenticated_period_in_seconds, class: 'form-control' .form-group .form-check @@ -23,10 +23,10 @@ %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) .form-group - = f.label :throttle_authenticated_api_requests_per_period, 'Max requests per period per user', class: 'label-light' + = f.label :throttle_authenticated_api_requests_per_period, 'Max requests per period per user', class: 'label-bold' = f.number_field :throttle_authenticated_api_requests_per_period, class: 'form-control' .form-group - = f.label :throttle_authenticated_api_period_in_seconds, 'Rate limit period in seconds', class: 'label-light' + = f.label :throttle_authenticated_api_period_in_seconds, 'Rate limit period in seconds', class: 'label-bold' = f.number_field :throttle_authenticated_api_period_in_seconds, class: 'form-control' .form-group .form-check @@ -36,10 +36,10 @@ %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) .form-group - = f.label :throttle_authenticated_web_requests_per_period, 'Max requests per period per user', class: 'label-light' + = f.label :throttle_authenticated_web_requests_per_period, 'Max requests per period per user', class: 'label-bold' = f.number_field :throttle_authenticated_web_requests_per_period, class: 'form-control' .form-group - = f.label :throttle_authenticated_web_period_in_seconds, 'Rate limit period in seconds', class: 'label-light' + = f.label :throttle_authenticated_web_period_in_seconds, 'Rate limit period in seconds', class: 'label-bold' = f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control' = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/_koding.html.haml b/app/views/admin/application_settings/_koding.html.haml index ae60f68f5fe..798a061feb6 100644 --- a/app/views/admin/application_settings/_koding.html.haml +++ b/app/views/admin/application_settings/_koding.html.haml @@ -10,7 +10,7 @@ .form-text.text-muted Koding integration has been deprecated since GitLab 10.0. If you disable your Koding integration, you will not be able to enable it again. .form-group - = f.label :koding_url, 'Koding URL', class: 'label-light' + = f.label :koding_url, 'Koding URL', class: 'label-bold' = f.text_field :koding_url, class: 'form-control', placeholder: 'http://gitlab.your-koding-instance.com:8090' .form-text.text-muted Koding has integration enabled out of the box for the diff --git a/app/views/admin/application_settings/_logging.html.haml b/app/views/admin/application_settings/_logging.html.haml index a6e549cd1f0..f13df885997 100644 --- a/app/views/admin/application_settings/_logging.html.haml +++ b/app/views/admin/application_settings/_logging.html.haml @@ -13,7 +13,7 @@ %a{ href: 'https://getsentry.com', target: '_blank', rel: 'noopener noreferrer' } https://getsentry.com .form-group - = f.label :sentry_dsn, 'Sentry DSN', class: 'label-light' + = f.label :sentry_dsn, 'Sentry DSN', class: 'label-bold' = f.text_field :sentry_dsn, class: 'form-control' .form-group @@ -26,7 +26,7 @@ %a{ href: 'https://sentry.io/for/javascript/', target: '_blank', rel: 'noopener noreferrer' } https://sentry.io/for/javascript/ .form-group - = f.label :clientside_sentry_dsn, 'Clientside Sentry DSN', class: 'label-light' + = f.label :clientside_sentry_dsn, 'Clientside Sentry DSN', class: 'label-bold' = f.text_field :clientside_sentry_dsn, class: 'form-control' = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml index f168ec62ffd..cf4b4c000b5 100644 --- a/app/views/admin/application_settings/_pages.html.haml +++ b/app/views/admin/application_settings/_pages.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :max_pages_size, 'Maximum size of pages (MB)', class: 'label-light' + = f.label :max_pages_size, 'Maximum size of pages (MB)', class: 'label-bold' = f.number_field :max_pages_size, class: 'form-control' .form-text.text-muted 0 for unlimited .form-group diff --git a/app/views/admin/application_settings/_performance_bar.html.haml b/app/views/admin/application_settings/_performance_bar.html.haml index ddbfcc6b77b..c4e14ffb8af 100644 --- a/app/views/admin/application_settings/_performance_bar.html.haml +++ b/app/views/admin/application_settings/_performance_bar.html.haml @@ -8,7 +8,7 @@ = f.label :performance_bar_enabled, class: 'form-check-label' do Enable the Performance Bar .form-group - = f.label :performance_bar_allowed_group_path, 'Allowed group', class: 'label-light' + = f.label :performance_bar_allowed_group_path, 'Allowed group', class: 'label-bold' = f.text_field :performance_bar_allowed_group_path, class: 'form-control', placeholder: 'my-org/my-group', value: @application_setting.performance_bar_allowed_group&.full_path = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/_plantuml.html.haml b/app/views/admin/application_settings/_plantuml.html.haml index 259f18b3b96..07ffcc9e73a 100644 --- a/app/views/admin/application_settings/_plantuml.html.haml +++ b/app/views/admin/application_settings/_plantuml.html.haml @@ -8,7 +8,7 @@ = f.label :plantuml_enabled, class: 'form-check-label' do Enable PlantUML .form-group - = f.label :plantuml_url, 'PlantUML URL', class: 'label-light' + = f.label :plantuml_url, 'PlantUML URL', class: 'label-bold' = f.text_field :plantuml_url, class: 'form-control', placeholder: 'http://gitlab.your-plantuml-instance.com:8080' .form-text.text-muted Allow rendering of diff --git a/app/views/admin/application_settings/_realtime.html.haml b/app/views/admin/application_settings/_realtime.html.haml index 120cf4909b2..4d224d7dd51 100644 --- a/app/views/admin/application_settings/_realtime.html.haml +++ b/app/views/admin/application_settings/_realtime.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :polling_interval_multiplier, 'Polling interval multiplier', class: 'label-light' + = f.label :polling_interval_multiplier, 'Polling interval multiplier', class: 'label-bold' = f.text_field :polling_interval_multiplier, class: 'form-control' .form-text.text-muted Change this value to influence how frequently the GitLab UI polls for updates. diff --git a/app/views/admin/application_settings/_registry.html.haml b/app/views/admin/application_settings/_registry.html.haml index beac70482e5..c511b1ee08a 100644 --- a/app/views/admin/application_settings/_registry.html.haml +++ b/app/views/admin/application_settings/_registry.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :container_registry_token_expire_delay, 'Authorization token duration (minutes)', class: 'label-light' + = f.label :container_registry_token_expire_delay, 'Authorization token duration (minutes)', class: 'label-bold' = f.number_field :container_registry_token_expire_delay, class: 'form-control' = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml index 57facc380eb..cacbcf65845 100644 --- a/app/views/admin/application_settings/_repository_check.html.haml +++ b/app/views/admin/application_settings/_repository_check.html.haml @@ -38,17 +38,17 @@ Creating pack file bitmaps makes housekeeping take a little longer but bitmaps should accelerate 'git clone' performance. .form-group - = f.label :housekeeping_incremental_repack_period, 'Incremental repack period', class: 'label-light' + = f.label :housekeeping_incremental_repack_period, 'Incremental repack period', class: 'label-bold' = f.number_field :housekeeping_incremental_repack_period, class: 'form-control' .form-text.text-muted Number of Git pushes after which an incremental 'git repack' is run. .form-group - = f.label :housekeeping_full_repack_period, 'Full repack period', class: 'label-light' + = f.label :housekeeping_full_repack_period, 'Full repack period', class: 'label-bold' = f.number_field :housekeeping_full_repack_period, class: 'form-control' .form-text.text-muted Number of Git pushes after which a full 'git repack' is run. .form-group - = f.label :housekeeping_gc_period, 'Git GC period', class: 'label-light' + = f.label :housekeeping_gc_period, 'Git GC period', class: 'label-bold' = f.number_field :housekeeping_gc_period, class: 'form-control' .form-text.text-muted Number of Git pushes after which 'git gc' is run. diff --git a/app/views/admin/application_settings/_repository_mirrors_form.html.haml b/app/views/admin/application_settings/_repository_mirrors_form.html.haml index beeb5169361..dbc1e9e3a71 100644 --- a/app/views/admin/application_settings/_repository_mirrors_form.html.haml +++ b/app/views/admin/application_settings/_repository_mirrors_form.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :mirror_available, 'Enable mirror configuration', class: 'label-light' + = f.label :mirror_available, 'Enable mirror configuration', class: 'label-bold' .form-check = f.check_box :mirror_available, class: 'form-check-input' = f.label :mirror_available, class: 'form-check-label' do diff --git a/app/views/admin/application_settings/_repository_storage.html.haml b/app/views/admin/application_settings/_repository_storage.html.haml index 5a303666353..685de99917e 100644 --- a/app/views/admin/application_settings/_repository_storage.html.haml +++ b/app/views/admin/application_settings/_repository_storage.html.haml @@ -13,7 +13,7 @@ repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. %em (EXPERIMENTAL) .form-group - = f.label :repository_storages, 'Storage paths for new projects', class: 'label-light' + = f.label :repository_storages, 'Storage paths for new projects', class: 'label-bold' = f.select :repository_storages, repository_storages_options_for_select(@application_setting.repository_storages), {include_hidden: false}, multiple: true, class: 'form-control' .form-text.text-muted @@ -23,27 +23,27 @@ .sub-section %h4 Circuit breaker .form-group - = f.label :circuitbreaker_check_interval, _('Check interval'), class: 'label-light' + = f.label :circuitbreaker_check_interval, _('Check interval'), class: 'label-bold' = f.number_field :circuitbreaker_check_interval, class: 'form-control' .form-text.text-muted = circuitbreaker_check_interval_help_text .form-group - = f.label :circuitbreaker_access_retries, _('Number of access attempts'), class: 'label-light' + = f.label :circuitbreaker_access_retries, _('Number of access attempts'), class: 'label-bold' = f.number_field :circuitbreaker_access_retries, class: 'form-control' .form-text.text-muted = circuitbreaker_access_retries_help_text .form-group - = f.label :circuitbreaker_storage_timeout, _('Seconds to wait for a storage access attempt'), class: 'label-light' + = f.label :circuitbreaker_storage_timeout, _('Seconds to wait for a storage access attempt'), class: 'label-bold' = f.number_field :circuitbreaker_storage_timeout, class: 'form-control' .form-text.text-muted = circuitbreaker_storage_timeout_help_text .form-group - = f.label :circuitbreaker_failure_count_threshold, _('Maximum git storage failures'), class: 'label-light' + = f.label :circuitbreaker_failure_count_threshold, _('Maximum git storage failures'), class: 'label-bold' = f.number_field :circuitbreaker_failure_count_threshold, class: 'form-control' .form-text.text-muted = circuitbreaker_failure_count_help_text .form-group - = f.label :circuitbreaker_failure_reset_time, _('Seconds before reseting failure information'), class: 'label-light' + = f.label :circuitbreaker_failure_reset_time, _('Seconds before reseting failure information'), class: 'label-bold' = f.number_field :circuitbreaker_failure_reset_time, class: 'form-control' .form-text.text-muted = circuitbreaker_failure_reset_time_help_text diff --git a/app/views/admin/application_settings/_signin.html.haml b/app/views/admin/application_settings/_signin.html.haml index 69d1a43c511..344ed2339fb 100644 --- a/app/views/admin/application_settings/_signin.html.haml +++ b/app/views/admin/application_settings/_signin.html.haml @@ -21,31 +21,31 @@ must be used to authenticate. - if omniauth_enabled? && button_based_providers.any? .form-group - = f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'label-light' + = f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'label-bold' = hidden_field_tag 'application_setting[enabled_oauth_sign_in_sources][]' .btn-group{ data: { toggle: 'buttons' } } - oauth_providers_checkboxes.each do |source| = source .form-group - = f.label :two_factor_authentication, 'Two-factor authentication', class: 'label-light' + = f.label :two_factor_authentication, 'Two-factor authentication', class: 'label-bold' .form-check = f.check_box :require_two_factor_authentication, class: 'form-check-input' = f.label :require_two_factor_authentication, class: 'form-check-label' do Require all users to setup Two-factor authentication .form-group - = f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'label-light' + = f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'label-bold' = f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0' .form-text.text-muted Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication .form-group - = f.label :home_page_url, 'Home page URL', class: 'label-light' + = f.label :home_page_url, 'Home page URL', class: 'label-bold' = f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block' %span.form-text.text-muted#home_help_block We will redirect non-logged in users to this page .form-group - = f.label :after_sign_out_path, class: 'label-light' + = f.label :after_sign_out_path, class: 'label-bold' = f.text_field :after_sign_out_path, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'after_sign_out_path_help_block' %span.form-text.text-muted#after_sign_out_path_help_block We will redirect users to this page after they sign out .form-group - = f.label :sign_in_text, class: 'label-light' + = f.label :sign_in_text, class: 'label-bold' = f.text_area :sign_in_text, class: 'form-control', rows: 4 .form-text.text-muted Markdown enabled diff --git a/app/views/admin/application_settings/_signup.html.haml b/app/views/admin/application_settings/_signup.html.haml index b9ba9128cc9..2b5ff5a38e3 100644 --- a/app/views/admin/application_settings/_signup.html.haml +++ b/app/views/admin/application_settings/_signup.html.haml @@ -13,11 +13,11 @@ = f.label :send_user_confirmation_email, class: 'form-check-label' do Send confirmation email on sign-up .form-group - = f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'label-light' + = f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'label-bold' = f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8 .form-text.text-muted ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com .form-group - = f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'label-light' + = f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'label-bold' .form-check = f.check_box :domain_blacklist_enabled, class: 'form-check-input' = f.label :domain_blacklist_enabled, class: 'form-check-label' do @@ -34,16 +34,16 @@ .option-title Enter blacklist manually .form-group.blacklist-file - = f.label :domain_blacklist_file, 'Blacklist file', class: 'label-light' + = f.label :domain_blacklist_file, 'Blacklist file', class: 'label-bold' = f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf' .form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries. .form-group.blacklist-raw - = f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'label-light' + = f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'label-bold' = f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8 .form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com .form-group - = f.label :after_sign_up_text, class: 'label-light' + = f.label :after_sign_up_text, class: 'label-bold' = f.text_area :after_sign_up_text, class: 'form-control', rows: 4 .form-text.text-muted Markdown enabled diff --git a/app/views/admin/application_settings/_spam.html.haml b/app/views/admin/application_settings/_spam.html.haml index 8f0dce962a9..691b56e8a8e 100644 --- a/app/views/admin/application_settings/_spam.html.haml +++ b/app/views/admin/application_settings/_spam.html.haml @@ -10,14 +10,14 @@ %span.form-text.text-muted#recaptcha_help_block Helps prevent bots from creating accounts .form-group - = f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'label-light' + = f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'label-bold' = f.text_field :recaptcha_site_key, class: 'form-control' .form-text.text-muted Generate site and private keys at %a{ href: 'http://www.google.com/recaptcha', target: 'blank' } http://www.google.com/recaptcha .form-group - = f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'label-light' + = f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'label-bold' = f.text_field :recaptcha_private_key, class: 'form-control' .form-group @@ -28,7 +28,7 @@ %span.form-text.text-muted#akismet_help_block Helps prevent bots from creating issues .form-group - = f.label :akismet_api_key, 'Akismet API Key', class: 'label-light' + = f.label :akismet_api_key, 'Akismet API Key', class: 'label-bold' = f.text_field :akismet_api_key, class: 'form-control' .form-text.text-muted Generate API key at @@ -43,13 +43,13 @@ Helps prevent malicious users hide their activity .form-group - = f.label :unique_ips_limit_per_user, 'IPs per user', class: 'label-light' + = f.label :unique_ips_limit_per_user, 'IPs per user', class: 'label-bold' = f.number_field :unique_ips_limit_per_user, class: 'form-control' .form-text.text-muted Maximum number of unique IPs per user .form-group - = f.label :unique_ips_limit_time_window, 'IP expiration time', class: 'label-light' + = f.label :unique_ips_limit_time_window, 'IP expiration time', class: 'label-bold' = f.number_field :unique_ips_limit_time_window, class: 'form-control' .form-text.text-muted How many seconds an IP will be counted towards the limit diff --git a/app/views/admin/application_settings/_terminal.html.haml b/app/views/admin/application_settings/_terminal.html.haml index 543628ff0ee..dc88a9885c8 100644 --- a/app/views/admin/application_settings/_terminal.html.haml +++ b/app/views/admin/application_settings/_terminal.html.haml @@ -3,7 +3,7 @@ %fieldset .form-group - = f.label :terminal_max_session_time, 'Max session time', class: 'label-light' + = f.label :terminal_max_session_time, 'Max session time', class: 'label-bold' = f.number_field :terminal_max_session_time, class: 'form-control' .form-text.text-muted Maximum time for web terminal websocket connection (in seconds). diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml index 4cc3e6a7d03..cec65f70e9d 100644 --- a/app/views/admin/application_settings/_visibility_and_access.html.haml +++ b/app/views/admin/application_settings/_visibility_and_access.html.haml @@ -3,19 +3,19 @@ %fieldset .form-group - = f.label :default_branch_protection, class: 'label-light' + = f.label :default_branch_protection, class: 'label-bold' = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control' .form-group.visibility-level-setting - = f.label :default_project_visibility, class: 'label-light' + = f.label :default_project_visibility, class: 'label-bold' = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new) .form-group.visibility-level-setting - = f.label :default_snippet_visibility, class: 'label-light' + = f.label :default_snippet_visibility, class: 'label-bold' = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new) .form-group.visibility-level-setting - = f.label :default_group_visibility, class: 'label-light' + = f.label :default_group_visibility, class: 'label-bold' = render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new) .form-group - = f.label :restricted_visibility_levels, class: 'label-light' + = f.label :restricted_visibility_levels, class: 'label-bold' - checkbox_name = 'application_setting[restricted_visibility_levels][]' = hidden_field_tag(checkbox_name) - restricted_level_checkboxes('restricted-visibility-help', checkbox_name, class: 'form-check-input').each do |level| @@ -25,7 +25,7 @@ Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users. .form-group - = f.label :import_sources, class: 'label-light' + = f.label :import_sources, class: 'label-bold' = hidden_field_tag 'application_setting[import_sources][]' - import_sources_checkboxes('import-sources-help', class: 'form-check-input').each do |source| .form-check= source @@ -44,7 +44,7 @@ Project export enabled .form-group - %label.label-light Enabled Git access protocols + %label.label-bold Enabled Git access protocols = select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control') %span.form-text.text-muted#clone-protocol-help Allow only the selected protocols to be used for Git access. @@ -52,7 +52,7 @@ - ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type| - field_name = :"#{type}_key_restriction" .form-group - = f.label field_name, "#{type.upcase} SSH keys", class: 'label-light' + = f.label field_name, "#{type.upcase} SSH keys", class: 'label-bold' = f.select field_name, key_restriction_options_for_select(type), {}, class: 'form-control' = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 18f2c1a509f..fac61f9d249 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -91,10 +91,10 @@ %span.light.float-right = boolean_to_icon gravatar_enabled? - omniauth = "OmniAuth" - %p{ "aria-label" => "#{omniauth}: status " + (Gitlab.config.omniauth.enabled ? "on" : "off") } + %p{ "aria-label" => "#{omniauth}: status " + (Gitlab::Auth.omniauth_enabled? ? "on" : "off") } = omniauth %span.light.float-right - = boolean_to_icon Gitlab.config.omniauth.enabled + = boolean_to_icon Gitlab::Auth.omniauth_enabled? - reply_email = "Reply by email" %p{ "aria-label" => "#{reply_email}: status " + (Gitlab::IncomingEmail.enabled? ? "on" : "off") } = reply_email diff --git a/app/views/admin/hooks/_form.html.haml b/app/views/admin/hooks/_form.html.haml index 3abde755f0f..072f80b56b9 100644 --- a/app/views/admin/hooks/_form.html.haml +++ b/app/views/admin/hooks/_form.html.haml @@ -1,15 +1,15 @@ = form_errors(hook) .form-group - = form.label :url, 'URL', class: 'label-light' + = form.label :url, 'URL', class: 'label-bold' = form.text_field :url, class: 'form-control' .form-group - = form.label :token, 'Secret Token', class: 'label-light' + = form.label :token, 'Secret Token', class: 'label-bold' = form.text_field :token, class: 'form-control' %p.form-text.text-muted Use this token to validate received payloads .form-group - = form.label :url, 'Trigger', class: 'label-light' + = form.label :url, 'Trigger', class: 'label-bold' %ul.list-unstyled %li .form-text.text-muted @@ -45,7 +45,7 @@ %p.light This URL will be triggered when a merge request is created/updated/merged .form-group - = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox' + = form.label :enable_ssl_verification, 'SSL verification', class: 'label-bold checkbox' .form-check = form.check_box :enable_ssl_verification, class: 'form-check-input' = form.label :enable_ssl_verification, class: 'form-check-label' do diff --git a/app/views/admin/identities/edit.html.haml b/app/views/admin/identities/edit.html.haml index 1ad6ce969cb..fa09138c502 100644 --- a/app/views/admin/identities/edit.html.haml +++ b/app/views/admin/identities/edit.html.haml @@ -1,3 +1,6 @@ +- add_to_breadcrumbs "Users", admin_users_path +- add_to_breadcrumbs @user.name, admin_user_identities_path(@user) +- breadcrumb_title "Edit Identity" - page_title _("Edit"), @identity.provider, _("Identities"), @user.name, _("Users") %h3.page-title = _('Edit identity for %{user_name}') % { user_name: @user.name } diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml index 59373ee6752..df3df159947 100644 --- a/app/views/admin/identities/index.html.haml +++ b/app/views/admin/identities/index.html.haml @@ -1,3 +1,5 @@ +- add_to_breadcrumbs "Users", admin_users_path +- breadcrumb_title @user.name - page_title _("Identities"), @user.name, _("Users") = render 'admin/users/head' diff --git a/app/views/admin/identities/new.html.haml b/app/views/admin/identities/new.html.haml index ee743b0fd3c..c28d22625b5 100644 --- a/app/views/admin/identities/new.html.haml +++ b/app/views/admin/identities/new.html.haml @@ -1,3 +1,6 @@ +- add_to_breadcrumbs "Users", admin_users_path +- add_to_breadcrumbs @user.name, admin_user_identities_path(@user) +- breadcrumb_title "New Identity" - page_title _("New Identity") %h3.page-title= _('New identity') %hr diff --git a/app/views/admin/impersonation_tokens/index.html.haml b/app/views/admin/impersonation_tokens/index.html.haml index 1378dde52ab..9e490713ef3 100644 --- a/app/views/admin/impersonation_tokens/index.html.haml +++ b/app/views/admin/impersonation_tokens/index.html.haml @@ -1,3 +1,5 @@ +- add_to_breadcrumbs "Users", admin_users_path +- breadcrumb_title @user.name - page_title "Impersonation Tokens", @user.name, "Users" = render 'admin/users/head' diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 62b7a4cbd07..62be38e9dd2 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -11,7 +11,6 @@ - add_to_breadcrumbs _("Runners"), admin_runners_path - breadcrumb_title "##{@runner.id}" -- @no_container = true - if @runner.instance_type? .bs-callout.bs-callout-success diff --git a/app/views/admin/users/keys.html.haml b/app/views/admin/users/keys.html.haml index 0f644121e62..103bbb3b063 100644 --- a/app/views/admin/users/keys.html.haml +++ b/app/views/admin/users/keys.html.haml @@ -1,3 +1,5 @@ +- add_to_breadcrumbs "Users", admin_users_path +- breadcrumb_title @user.name - page_title "SSH Keys", @user.name, "Users" = render 'admin/users/head' = render 'profiles/keys/key_table', admin: true diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml index cf50d45f755..3d39c1da408 100644 --- a/app/views/admin/users/projects.html.haml +++ b/app/views/admin/users/projects.html.haml @@ -1,3 +1,5 @@ +- add_to_breadcrumbs "Users", admin_users_path +- breadcrumb_title @user.name - page_title "Groups and projects", @user.name, "Users" = render 'admin/users/head' diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index b0562226f5f..f730fd05176 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -149,8 +149,8 @@ %br = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' } - else - .card.bg-warning - .card-header + .card.border-warning + .card-header.bg-warning.text-white Block this user .card-body %p Blocking user has the following effects: @@ -170,8 +170,8 @@ %br = link_to 'Unlock user', unlock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' } - .card.bg-danger - .card-header + .card.border-danger + .card-header.bg-danger.text-white = s_('AdminUsers|Delete user') .card-body - if @user.can_be_removed? && can?(current_user, :destroy_user, @user) @@ -196,8 +196,8 @@ %p You don't have access to delete this user. - .card.bg-danger - .card-header + .card.border-danger + .card-header.bg-danger.text-white = s_('AdminUsers|Delete user and contributions') .card-body - if can?(current_user, :destroy_user, @user) diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml index 3ae9ce6c11f..13f96b9747c 100644 --- a/app/views/ci/runner/_how_to_setup_runner.html.haml +++ b/app/views/ci/runner/_how_to_setup_runner.html.haml @@ -1,16 +1,17 @@ -- link = link_to _("GitLab Runner section"), 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank' +- link = link_to _("Install GitLab Runner"), 'https://docs.gitlab.com/runner/install/', target: '_blank' .append-bottom-10 %h4= _("Setup a #{type} Runner manually") %ol %li - = _("Install a Runner compatible with GitLab CI") - = (_("(check out the %{link} for information on how to install it).") % { link: link }).html_safe + = link.html_safe %li = _("Specify the following URL during the Runner setup:") %code#coordinator_address= root_url(only_path: false) + = clipboard_button(target: '#coordinator_address', title: _("Copy URL to clipboard"), class: "btn-transparent btn-clipboard") %li = _("Use the following registration token during setup:") %code#registration_token= registration_token + = clipboard_button(target: '#registration_token', title: _("Copy token to clipboard"), class: "btn-transparent btn-clipboard") %li = _("Start the Runner!") diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index a676eba2aee..9c246e19faa 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -1,8 +1,8 @@ .nav-block.activities + = render 'shared/event_filter' .controls = link_to dashboard_projects_path(rss_url_options), class: 'btn rss-btn has-tooltip', title: 'Subscribe' do %i.fa.fa-rss - = render 'shared/event_filter' .content_list = spinner diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml index 84b4ce5b606..ac5cac50699 100644 --- a/app/views/doorkeeper/applications/_delete_form.html.haml +++ b/app/views/doorkeeper/applications/_delete_form.html.haml @@ -2,9 +2,9 @@ = form_tag oauth_application_path(application) do %input{ :name => "_method", :type => "hidden", :value => "delete" }/ - if defined? small - = button_tag type: "submit", class: "btn btn-transparent", data: { confirm: "Are you sure?" } do + = button_tag type: "submit", class: "btn btn-transparent", data: { confirm: _("Are you sure?") } do %span.sr-only - Destroy + = _('Destroy') = icon('trash') - else - = submit_tag 'Destroy', data: { confirm: "Are you sure?" }, class: submit_btn_css + = submit_tag _('Destroy'), data: { confirm: _("Are you sure?") }, class: submit_btn_css diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index be0935b8313..0bc057a8864 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -2,24 +2,22 @@ = form_errors(application) .form-group - = f.label :name, class: 'label-light' + = f.label :name, class: 'label-bold' = f.text_field :name, class: 'form-control', required: true .form-group - = f.label :redirect_uri, class: 'label-light' + = f.label :redirect_uri, class: 'label-bold' = f.text_area :redirect_uri, class: 'form-control', required: true %span.form-text.text-muted - Use one line per URI + = _('Use one line per URI') - if Doorkeeper.configuration.native_redirect_uri %span.form-text.text-muted - Use - %code= Doorkeeper.configuration.native_redirect_uri - for local tests + = _('Use <code>%{native_redirect_uri}</code> for local tests').html_safe % { native_redirect_uri: Doorkeeper.configuration.native_redirect_uri } .form-group - = f.label :scopes, class: 'label-light' + = f.label :scopes, class: 'label-bold' = render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes .prepend-top-default - = f.submit 'Save application', class: "btn btn-create" + = f.submit _('Save application'), class: "btn btn-create" diff --git a/app/views/doorkeeper/applications/edit.html.haml b/app/views/doorkeeper/applications/edit.html.haml index 49f90298a50..aad4200f240 100644 --- a/app/views/doorkeeper/applications/edit.html.haml +++ b/app/views/doorkeeper/applications/edit.html.haml @@ -1,4 +1,4 @@ -- page_title "Edit", @application.name, "Applications" +- page_title _("Edit"), @application.name, _("Applications") - @content_class = "limit-container-width" unless fluid_layout -%h3.page-title Edit application +%h3.page-title= _('Edit application') = render 'form', application: @application diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml index cdf3ff81bd9..ab3a1b100ce 100644 --- a/app/views/doorkeeper/applications/index.html.haml +++ b/app/views/doorkeeper/applications/index.html.haml @@ -1,4 +1,4 @@ -- page_title "Applications" +- page_title _("Applications") - @content_class = "limit-container-width" unless fluid_layout .row.prepend-top-default @@ -7,28 +7,27 @@ = page_title %p - if user_oauth_applications? - Manage applications that can use GitLab as an OAuth provider, - and applications that you've authorized to use your account. + = _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.") - else - Manage applications that you've authorized to use your account. + = _("Manage applications that you've authorized to use your account.") .col-lg-8 - if user_oauth_applications? %h5.prepend-top-0 - Add new application + = _('Add new application') = render 'form', application: @application %hr - if user_oauth_applications? .oauth-applications %h5 - Your applications (#{@applications.size}) + = _("Your applications (%{size})") % { size: @applications.size } - if @applications.any? .table-responsive %table.table %thead %tr - %th Name - %th Callback URL - %th Clients + %th= _('Name') + %th= _('Callback URL') + %th= _('Clients') %th.last-heading %tbody - @applications.each do |application| @@ -41,25 +40,25 @@ %td = link_to edit_oauth_application_path(application), class: "btn btn-transparent append-right-5" do %span.sr-only - Edit + = _('Edit') = icon('pencil') = render 'delete_form', application: application, small: true - else .settings-message.text-center - You don't have any applications + = _("You don't have any applications") .oauth-authorized-applications.prepend-top-20.append-bottom-default - if user_oauth_applications? %h5 - Authorized applications (#{@authorized_tokens.size}) + = _("Authorized applications (%{size})") % { size: @authorized_tokens.size } - if @authorized_tokens.any? .table-responsive %table.table.table-striped %thead %tr - %th Name - %th Authorized At - %th Scope + %th= _('Name') + %th= _('Authorized At') + %th= _('Scope') %th %tbody - @authorized_apps.each do |app| @@ -72,12 +71,12 @@ - @authorized_anonymous_tokens.each do |token| %tr %td - Anonymous + = _('Anonymous') .form-text.text-muted - %em Authorization was granted by entering your username and password in the application. + %em= _("Authorization was granted by entering your username and password in the application.") %td= token.created_at %td= token.scopes %td= render 'doorkeeper/authorized_applications/delete_form', token: token - else .settings-message.text-center - You don't have any authorized applications + = _("You don't have any authorized applications") diff --git a/app/views/doorkeeper/applications/new.html.haml b/app/views/doorkeeper/applications/new.html.haml index d3692d1f759..a66fab20d7c 100644 --- a/app/views/doorkeeper/applications/new.html.haml +++ b/app/views/doorkeeper/applications/new.html.haml @@ -1,6 +1,6 @@ -- page_title "New Application" +- page_title _("New Application") -%h3.page-title New Application +%h3.page-title= _("New Application") %hr diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml index 89ad626f73f..bb76ac6d5f6 100644 --- a/app/views/doorkeeper/applications/show.html.haml +++ b/app/views/doorkeeper/applications/show.html.haml @@ -1,27 +1,27 @@ -- add_to_breadcrumbs "Applications", oauth_applications_path +- add_to_breadcrumbs _("Applications"), oauth_applications_path - breadcrumb_title @application.name -- page_title @application.name, "Applications" +- page_title @application.name, _("Applications") - @content_class = "limit-container-width" unless fluid_layout %h3.page-title - Application: #{@application.name} + = _("Application: %{name}") % { name: @application.name } .table-holder.oauth-application-show %table.table %tr %td - Application Id + = _('Application Id') %td %code#application_id= @application.uid %tr %td - Secret: + = _('Secret:') %td %code#secret= @application.secret %tr %td - Callback url + = _('Callback url') %td - @application.redirect_uri.split.each do |uri| %div @@ -30,5 +30,5 @@ = render "shared/tokens/scopes_list", token: @application .form-actions - = link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide float-left' + = link_to _('Edit'), edit_oauth_application_path(@application), class: 'btn btn-primary wide float-left' = render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10' diff --git a/app/views/doorkeeper/authorizations/error.html.haml b/app/views/doorkeeper/authorizations/error.html.haml index 6117b00149f..32b4ccb0fe6 100644 --- a/app/views/doorkeeper/authorizations/error.html.haml +++ b/app/views/doorkeeper/authorizations/error.html.haml @@ -1,3 +1,3 @@ -%h3.page-title An error has occurred +%h3.page-title= _("An error has occurred") %main{ :role => "main" } %pre= @pre_auth.error_response.body[:error_description] diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index 28cdc7607e0..ca62a59d909 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -3,34 +3,28 @@ .modal-content .modal-header %h3.page-title - Authorize - = link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' - to use your account? + - link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer') + = _("Authorize %{link_to_client} to use your account?") .modal-body - if current_user.admin? .text-warning %p = icon("exclamation-triangle fw") - You are an admin, which means granting access to - %strong= @pre_auth.client.name - will allow them to interact with GitLab as an admin as well. Proceed with caution. + = _('You are an admin, which means granting access to <strong>%{client_name}</strong> will allow them to interact with GitLab as an admin as well. Proceed with caution.').html_safe % { client_name: @pre_auth.client.name } %p - An application called - = link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' - is requesting access to your GitLab account. + - link_to_client = link_to(@pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer') + = _("An application called %{link_to_client} is requesting access to your GitLab account.").html_safe % { link_to_client: link_to_client } - auth_app_owner = @pre_auth.client.application.owner - if auth_app_owner - This application was created by - = succeed "." do - = link_to auth_app_owner.name, user_path(auth_app_owner) + - link_to_owner = link_to(auth_app_owner.name, user_path(auth_app_owner)) + = _("This application was created by %{link_to_owner}.").html_safe % { link_to_owner: link_to_owner } - Please note that this application is not provided by GitLab and you should verify its authenticity before - allowing access. + = _("Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access.") - if @pre_auth.scopes %p - This application will be able to: + = _("This application will be able to:") %ul - @pre_auth.scopes.each do |scope| %li @@ -44,7 +38,7 @@ = hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :nonce, @pre_auth.nonce - = submit_tag "Deny", class: "btn btn-danger" + = submit_tag _("Deny"), class: "btn btn-danger" = form_tag oauth_authorization_path, method: :post, class: 'inline' do = hidden_field_tag :client_id, @pre_auth.client.uid = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri @@ -52,4 +46,4 @@ = hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :scope, @pre_auth.scope = hidden_field_tag :nonce, @pre_auth.nonce - = submit_tag "Authorize", class: "btn btn-success prepend-left-10" + = submit_tag _("Authorize"), class: "btn btn-success prepend-left-10" diff --git a/app/views/doorkeeper/authorizations/show.html.haml b/app/views/doorkeeper/authorizations/show.html.haml index 44e868e6782..e4bfd69e7f8 100644 --- a/app/views/doorkeeper/authorizations/show.html.haml +++ b/app/views/doorkeeper/authorizations/show.html.haml @@ -1,3 +1,3 @@ -%h3.page-title Authorization code: +%h3.page-title= _("Authorization code:") %main{ :role => "main" } %code#authorization_code= params[:code] diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml index 11c1e67878e..08f2442f025 100644 --- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml +++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml @@ -6,4 +6,4 @@ = form_tag path do %input{ :name => "_method", :type => "hidden", :value => "delete" }/ - = submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-remove btn-sm' + = submit_tag _('Revoke'), onclick: "return confirm('#{_('Are you sure?')}')", class: 'btn btn-remove btn-sm' diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml index 30c9d02b72e..8e73298b250 100644 --- a/app/views/doorkeeper/authorized_applications/index.html.haml +++ b/app/views/doorkeeper/authorized_applications/index.html.haml @@ -1,12 +1,12 @@ %header - %h1 Your authorized applications + %h1= _("Your authorized applications") %main{ :role => "main" } .table-holder %table.table.table-striped %thead %tr - %th Application - %th Created At + %th= _('Application') + %th= _('Created At') %th %th %tbody diff --git a/app/views/groups/_activities.html.haml b/app/views/groups/_activities.html.haml index 577c63503a8..82a497289f3 100644 --- a/app/views/groups/_activities.html.haml +++ b/app/views/groups/_activities.html.haml @@ -1,8 +1,8 @@ .nav-block.activities + = render 'shared/event_filter' .controls = link_to group_path(@group, rss_url_options), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do %i.fa.fa-rss - = render 'shared/event_filter' .content_list = spinner diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml index 64786d24266..ab8263533be 100644 --- a/app/views/groups/settings/_general.html.haml +++ b/app/views/groups/settings/_general.html.haml @@ -4,17 +4,17 @@ %fieldset .row .form-group.col-md-9 - = f.label :name, class: 'label-light' do + = f.label :name, class: 'label-bold' do Group name = f.text_field :name, class: 'form-control' .form-group.col-md-3 - = f.label :id, class: 'label-light' do + = f.label :id, class: 'label-bold' do Group ID = f.text_field :id, class: 'form-control', readonly: true .form-group - = f.label :description, class: 'label-light' do + = f.label :description, class: 'label-bold' do Group description %span.light (optional) = f.text_area :description, class: 'form-control', rows: 3, maxlength: 250 diff --git a/app/views/import/bitbucket/deploy_key.js.haml b/app/views/import/bitbucket/deploy_key.js.haml index 81b34ab5c9d..99e8ac1afa1 100644 --- a/app/views/import/bitbucket/deploy_key.js.haml +++ b/app/views/import/bitbucket/deploy_key.js.haml @@ -1,3 +1,3 @@ :plain job = $("tr#repo_#{@repo_id}") - job.find(".import-actions").html("<p class='alert alert-danger'>Access denied! Please verify you can add deploy keys to this repository.</p>") + job.find(".import-actions").html("<p class='alert alert-danger'>#{_('Access denied! Please verify you can add deploy keys to this repository.')}</p>") diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 4e8f715db4f..a75b7aa9dd2 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -1,22 +1,22 @@ -- page_title 'Bitbucket import' -- header_title 'Projects', root_path +- page_title _('Bitbucket import') +- header_title _('Projects'), root_path %h3.page-title %i.fa.fa-bitbucket - Import projects from Bitbucket + = _('Import projects from Bitbucket') - if @repos.any? %p.light - Select projects you want to import. + = _('Select projects you want to import.') %hr %p - if @incompatible_repos.any? = button_tag class: 'btn btn-import btn-success js-import-all' do - Import all compatible projects + = _('Import all compatible projects') = icon('spinner spin', class: 'loading-icon') - else = button_tag class: 'btn btn-import btn-success js-import-all' do - Import all projects + = _('Import all projects') = icon('spinner spin', class: 'loading-icon') .table-responsive @@ -26,9 +26,9 @@ %colgroup.import-jobs-status-col %thead %tr - %th From Bitbucket - %th To GitLab - %th Status + %th= _('From Bitbucket') + %th= _('To GitLab') + %th= _('Status') %tbody - @already_added_projects.each do |project| %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } @@ -40,10 +40,10 @@ - if project.import_status == 'finished' %span %i.fa.fa-check - done + = _('done') - elsif project.import_status == 'started' %i.fa.fa-spinner.fa-spin - started + = _('started') - else = project.human_import_status_name @@ -66,7 +66,7 @@ = text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true %td.import-actions.job-status = button_tag class: 'btn btn-import js-add-to-import' do - Import + = _('Import') = icon('spinner spin', class: 'loading-icon') - @incompatible_repos.each do |repo| %tr{ id: "repo_#{repo.owner}___#{repo.slug}" } @@ -74,16 +74,13 @@ = link_to repo.full_name, "https://bitbucket.org/#{repo.full_name}", target: '_blank', rel: 'noopener noreferrer' %td.import-target %td.import-actions-job-status - = label_tag 'Incompatible Project', nil, class: 'label badge-danger' + = label_tag _('Incompatible Project'), nil, class: 'label badge-danger' - if @incompatible_repos.any? %p - One or more of your Bitbucket projects cannot be imported into GitLab - directly because they use Subversion or Mercurial for version control, - rather than Git. Please convert - = link_to 'them to Git,', 'https://www.atlassian.com/git/tutorials/migrating-overview' - and go through the - = link_to 'import flow', status_import_bitbucket_path - again. + = _("One or more of your Bitbucket projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git.") + - link_to_git = link_to(_('Git'), 'https://www.atlassian.com/git/tutorials/migrating-overview') + - link_to_import_flow = link_to(_('import flow'), status_import_bitbucket_path) + = _("Please convert them to %{link_to_git}, and go through the %{link_to_import_flow} again.").html_safe % { link_to_git: link_to_git, link_to_import_flow: link_to_import_flow } .js-importer-status{ data: { jobs_import_path: "#{jobs_import_bitbucket_path}", import_path: "#{import_bitbucket_path}" } } diff --git a/app/views/import/fogbugz/new.html.haml b/app/views/import/fogbugz/new.html.haml index 74d686b6703..b54b1af1e0c 100644 --- a/app/views/import/fogbugz/new.html.haml +++ b/app/views/import/fogbugz/new.html.haml @@ -1,26 +1,24 @@ -- page_title "FogBugz Import" -- header_title "Projects", root_path +- page_title _("FogBugz Import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-bug - Import projects from FogBugz + = _('Import projects from FogBugz') %hr = form_tag callback_import_fogbugz_path do %p - To get started you enter your FogBugz URL and login information below. - In the next steps, you'll be able to map users and select the projects - you want to import. + = _("To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import.") .form-group.row - = label_tag :uri, 'FogBugz URL', class: 'col-form-label col-md-2' + = label_tag :uri, _('FogBugz URL'), class: 'col-form-label col-md-2' .col-md-4 = text_field_tag :uri, nil, placeholder: 'https://mycompany.fogbugz.com', class: 'form-control' .form-group.row - = label_tag :email, 'FogBugz Email', class: 'col-form-label col-md-2' + = label_tag :email, _('FogBugz Email'), class: 'col-form-label col-md-2' .col-md-4 = text_field_tag :email, nil, class: 'form-control' .form-group.row - = label_tag :password, 'FogBugz Password', class: 'col-form-label col-md-2' + = label_tag :password, _('FogBugz Password'), class: 'col-form-label col-md-2' .col-md-4 = password_field_tag :password, nil, class: 'form-control' .form-actions - = submit_tag 'Continue to the next step', class: 'btn btn-create' + = submit_tag _('Continue to the next step'), class: 'btn btn-create' diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml index d27c5d3c36d..ff2f989c509 100644 --- a/app/views/import/fogbugz/new_user_map.html.haml +++ b/app/views/import/fogbugz/new_user_map.html.haml @@ -1,39 +1,33 @@ -- page_title 'User map', 'FogBugz import' -- header_title "Projects", root_path +- page_title _('User map'), _('FogBugz import') +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-bug - Import projects from FogBugz + = _('Import projects from FogBugz') %hr = form_tag create_user_map_import_fogbugz_path do %p - Customize how FogBugz email addresses and usernames are imported into GitLab. - In the next step, you'll be able to select the projects you want to import. + = _("Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import.") %p - The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below. + = _("The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below.") %ul %li - %strong Default: Map a FogBugz account ID to a full name + %strong= _("Default: Map a FogBugz account ID to a full name") %p - An empty GitLab User field will add the FogBugz user's full name - (e.g. "By John Smith") in the description of all issues and comments. - It will also associate and/or assign these issues and comments with - the project creator. + = _("An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator.") %li - %strong Map a FogBugz account ID to a GitLab user + %strong= _("Map a FogBugz account ID to a GitLab user") %p - Selecting a GitLab user will add a link to the GitLab user in the descriptions - of issues and comments (e.g. "By <a href="#">@johnsmith</a>"). It will also - associate and/or assign these issues and comments with the selected user. + = _('Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. "By <a href="#">@johnsmith</a>"). It will also associate and/or assign these issues and comments with the selected user.').html_safe .table-holder %table.table %thead %tr - %th ID - %th Name - %th Email - %th GitLab User + %th= _("ID") + %th= _("Name") + %th= _("Email") + %th= _("GitLab User") %tbody - @user_map.each do |id, user| %tr @@ -45,4 +39,4 @@ scope: :all, email_user: true, selected: user[:gitlab_user]) .form-actions - = submit_tag 'Continue to the next step', class: 'btn btn-create' + = submit_tag _('Continue to the next step'), class: 'btn btn-create' diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index 7b832c6a23a..830d141ebea 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -1,20 +1,19 @@ -- page_title "FogBugz import" -- header_title "Projects", root_path +- page_title _("FogBugz import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-bug - Import projects from FogBugz + = _('Import projects from FogBugz') - if @repos.any? %p.light - Select projects you want to import. + = _('Select projects you want to import.') %p.light - Optionally, you can - = link_to 'customize', new_user_map_import_fogbugz_path - how FogBugz email addresses and usernames are imported into GitLab. + - link_to_customize = link_to('customize', new_user_map_import_fogbugz_path) + = _('Optionally, you can %{link_to_customize} how FogBugz email addresses and usernames are imported into GitLab.').html_safe % { link_to_customize: link_to_customize } %hr %p = button_tag class: 'btn btn-import btn-success js-import-all' do - Import all projects + = _('Import all projects') = icon("spinner spin", class: "loading-icon") .table-responsive @@ -24,9 +23,9 @@ %colgroup.import-jobs-status-col %thead %tr - %th From FogBugz - %th To GitLab - %th Status + %th= _("From FogBugz") + %th= _("To GitLab") + %th= _("Status") %tbody - @already_added_projects.each do |project| %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } @@ -38,10 +37,10 @@ - if project.import_status == 'finished' %span %i.fa.fa-check - done + = _("done") - elsif project.import_status == 'started' %i.fa.fa-spinner.fa-spin - started + = _("started") - else = project.human_import_status_name @@ -53,7 +52,7 @@ #{current_user.username}/#{repo.name} %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - Import + = _("Import") = icon("spinner spin", class: "loading-icon") .js-importer-status{ data: { jobs_import_path: "#{jobs_import_fogbugz_path}", import_path: "#{import_fogbugz_path}" } } diff --git a/app/views/import/gitea/new.html.haml b/app/views/import/gitea/new.html.haml index 581576a8a3d..2b3102f9af9 100644 --- a/app/views/import/gitea/new.html.haml +++ b/app/views/import/gitea/new.html.haml @@ -1,23 +1,22 @@ -- page_title "Gitea Import" -- header_title "Projects", root_path +- page_title _("Gitea Import") +- header_title _("Projects"), root_path %h3.page-title = custom_icon('go_logo') - Import Projects from Gitea + = _('Import Projects from Gitea') %p - To get started, please enter your Gitea Host URL and a - = succeed '.' do - = link_to 'Personal Access Token', 'https://github.com/gogits/go-gogs-client/wiki#access-token' + - link_to_personal_token = link_to(_('Personal Access Token'), 'https://github.com/gogits/go-gogs-client/wiki#access-token') + = _('To get started, please enter your Gitea Host URL and a %{link_to_personal_token}.').html_safe % { link_to_personal_token: link_to_personal_token } = form_tag personal_access_token_import_gitea_path do .form-group.row - = label_tag :gitea_host_url, 'Gitea Host URL', class: 'col-form-label col-sm-2' + = label_tag :gitea_host_url, _('Gitea Host URL'), class: 'col-form-label col-sm-2' .col-sm-4 = text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control' .form-group.row - = label_tag :personal_access_token, 'Personal Access Token', class: 'col-form-label col-sm-2' + = label_tag :personal_access_token, _('Personal Access Token'), class: 'col-form-label col-sm-2' .col-sm-4 = text_field_tag :personal_access_token, nil, class: 'form-control' .form-actions - = submit_tag 'List Your Gitea Repositories', class: 'btn btn-create' + = submit_tag _('List Your Gitea Repositories'), class: 'btn btn-create' diff --git a/app/views/import/gitea/status.html.haml b/app/views/import/gitea/status.html.haml index 589ca27e45d..88244fde16b 100644 --- a/app/views/import/gitea/status.html.haml +++ b/app/views/import/gitea/status.html.haml @@ -1,7 +1,7 @@ -- page_title "Gitea Import" -- header_title "Projects", root_path +- page_title _("Gitea Import") +- header_title _("Projects"), root_path %h3.page-title = custom_icon('go_logo') - Import Projects from Gitea + = _('Import Projects from Gitea') = render 'import/githubish_status', provider: 'gitea' diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml index b9ebb1a39d9..6ff25f2c842 100644 --- a/app/views/import/github/new.html.haml +++ b/app/views/import/github/new.html.haml @@ -1,7 +1,7 @@ - title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import') - page_title title - breadcrumb_title title -- header_title "Projects", root_path +- header_title _("Projects"), root_path %h3.page-title = icon 'github', text: import_github_title diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index b00b972d9c9..be057be6d1a 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -1,7 +1,7 @@ - title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import') - page_title title - breadcrumb_title title -- header_title "Projects", root_path +- header_title _("Projects"), root_path %h3.page-title = icon 'github', text: import_github_title diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 37734414835..b7bfbae5edf 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -1,15 +1,15 @@ -- page_title "GitLab.com import" -- header_title "Projects", root_path +- page_title _("GitLab.com import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-heart - Import projects from GitLab.com + = _('Import projects from GitLab.com') %p.light - Select projects you want to import. + = _('Select projects you want to import.') %hr %p = button_tag class: "btn btn-import btn-success js-import-all" do - Import all projects + = _('Import all projects') = icon("spinner spin", class: "loading-icon") .table-responsive @@ -19,9 +19,9 @@ %colgroup.import-jobs-status-col %thead %tr - %th From GitLab.com - %th To this GitLab instance - %th Status + %th= _('From GitLab.com') + %th= _('To this GitLab instance') + %th= _('Status') %tbody - @already_added_projects.each do |project| %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } @@ -33,10 +33,10 @@ - if project.import_status == 'finished' %span %i.fa.fa-check - done + = _('done') - elsif project.import_status == 'started' %i.fa.fa-spinner.fa-spin - started + = _('started') - else = project.human_import_status_name @@ -48,7 +48,7 @@ = import_project_target(repo['namespace']['path'], repo['name']) %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - Import + = _('Import') = icon("spinner spin", class: "loading-icon") .js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitlab_path}", import_path: "#{import_gitlab_path}" } } diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml index cc672a5ea7c..4225ee19217 100644 --- a/app/views/import/gitlab_projects/new.html.haml +++ b/app/views/import/gitlab_projects/new.html.haml @@ -1,15 +1,15 @@ -- page_title "GitLab Import" -- header_title "Projects", root_path +- page_title _("GitLab Import") +- header_title _("Projects"), root_path %h3.page-title = icon('gitlab') - Import an exported GitLab project + = _('Import an exported GitLab project') %hr = form_tag import_gitlab_project_path, class: 'new_project', multipart: true do .row .form-group.col-12.col-sm-6 - = label_tag :namespace_id, 'Project path', class: 'label-light' + = label_tag :namespace_id, 'Project path', class: 'label-bold' .form-group .input-group - if current_user.can_select_namespace? @@ -24,19 +24,19 @@ #{user_url(current_user.username)}/ = hidden_field_tag :namespace_id, value: current_user.namespace_id .form-group.col-12.col-sm-6.project-path - = label_tag :path, 'Project name', class: 'label-light' + = label_tag :path, _('Project name'), class: 'label-bold' = text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true .row .form-group.col-md-12 - To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here. + = _("To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here.") .row .form-group.col-sm-12 = hidden_field_tag :namespace_id, @namespace.id - = label_tag :file, 'GitLab project export', class: 'label-light' + = label_tag :file, _('GitLab project export'), class: 'label-bold' .form-group = file_field_tag :file, class: '' .row .form-actions.col-sm-12 - = submit_tag 'Import project', class: 'btn btn-create' - = link_to 'Cancel', new_project_path, class: 'btn btn-cancel' + = submit_tag _('Import project'), class: 'btn btn-create' + = link_to _('Cancel'), new_project_path, class: 'btn btn-cancel' diff --git a/app/views/import/google_code/new.html.haml b/app/views/import/google_code/new.html.haml index 2f1fb8d9c56..fd6e4726fc5 100644 --- a/app/views/import/google_code/new.html.haml +++ b/app/views/import/google_code/new.html.haml @@ -1,62 +1,62 @@ -- page_title "Google Code import" -- header_title "Projects", root_path +- page_title _("Google Code import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-google - Import projects from Google Code + = _('Import projects from Google Code') %hr = form_tag callback_import_google_code_path, multipart: true do %p - Follow the steps below to export your Google Code project data. - In the next step, you'll be able to select the projects you want to import. + = _('Follow the steps below to export your Google Code project data.') + = _("In the next step, you'll be able to select the projects you want to import.") %ol %li %p - Go to - #{link_to "Google Takeout", "https://www.google.com/settings/takeout", target: '_blank', rel: 'noopener noreferrer'}. + - link_to_google_takeout = link_to(_("Google Takeout"), "https://www.google.com/settings/takeout", target: '_blank', rel: 'noopener noreferrer') + = _("Go to %{link_to_google_takeout}.").html_safe % { link_to_google_takeout: link_to_google_takeout } %li %p - Make sure you're logged into the account that owns the projects you'd like to import. + = _("Make sure you're logged into the account that owns the projects you'd like to import.") %li %p - Click the <strong>Select none</strong> button on the right, since we only need "Google Code Project Hosting". + = _('Click the <strong>Select none</strong> button on the right, since we only need "Google Code Project Hosting".').html_safe %li %p - Scroll down to <strong>Google Code Project Hosting</strong> and enable the switch on the right. + = _('Scroll down to <strong>Google Code Project Hosting</strong> and enable the switch on the right.').html_safe %li %p - Choose <strong>Next</strong> at the bottom of the page. + = _('Choose <strong>Next</strong> at the bottom of the page.').html_safe %li %p - Leave the "File type" and "Delivery method" options on their default values. + = _('Leave the "File type" and "Delivery method" options on their default values.') %li %p - Choose <strong>Create archive</strong> and wait for archiving to complete. + = _('Choose <strong>Create archive</strong> and wait for archiving to complete.').html_safe %li %p - Click the <strong>Download</strong> button and wait for downloading to complete. + = _('Click the <strong>Download</strong> button and wait for downloading to complete.').html_safe %li %p - Find the downloaded ZIP file and decompress it. + = _('Find the downloaded ZIP file and decompress it.') %li %p - Find the newly extracted <code>Takeout/Google Code Project Hosting/GoogleCodeProjectHosting.json</code> file. + = _('Find the newly extracted <code>Takeout/Google Code Project Hosting/GoogleCodeProjectHosting.json</code> file.').html_safe %li %p - Upload <code>GoogleCodeProjectHosting.json</code> here: + = _('Upload <code>GoogleCodeProjectHosting.json</code> here:').html_safe %p %input{ type: "file", name: "dump_file", id: "dump_file" } %li %p - Do you want to customize how Google Code email addresses and usernames are imported into GitLab? + = _('Do you want to customize how Google Code email addresses and usernames are imported into GitLab?') %p = label_tag :create_user_map_0 do = radio_button_tag :create_user_map, 0, true - No, directly import the existing email addresses and usernames. + = _('No, directly import the existing email addresses and usernames.') %p = label_tag :create_user_map_1 do = radio_button_tag :create_user_map, 1, false - Yes, let me map Google Code users to full names or GitLab users. + = _('Yes, let me map Google Code users to full names or GitLab users.') %li %p - = submit_tag 'Continue to the next step', class: "btn btn-create" + = submit_tag _('Continue to the next step'), class: "btn btn-create" diff --git a/app/views/import/google_code/new_user_map.html.haml b/app/views/import/google_code/new_user_map.html.haml index 91c774f575c..baaaf6bdc63 100644 --- a/app/views/import/google_code/new_user_map.html.haml +++ b/app/views/import/google_code/new_user_map.html.haml @@ -1,44 +1,36 @@ -- page_title "User map", "Google Code import" -- header_title "Projects", root_path +- page_title _("User map"), _("Google Code import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-google - Import projects from Google Code + = _('Import projects from Google Code') %hr = form_tag create_user_map_import_google_code_path do %p - Customize how Google Code email addresses and usernames are imported into GitLab. - In the next step, you'll be able to select the projects you want to import. + = _("Customize how Google Code email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import.") %p - The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side. + = _("The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side.").html_safe %ul %li - %strong Default: Directly import the Google Code email address or username + %strong= _("Default: Directly import the Google Code email address or username") %p - <code>"johnsmith@example.com": "johnsm...@example.com"</code> - will add "By johnsm...@example.com" to all issues and comments originally created by johnsmith@example.com. - The email address or username is masked to ensure the user's privacy. + = _('<code>"johnsmith@example.com": "johnsm...@example.com"</code> will add "By johnsm...@example.com" to all issues and comments originally created by johnsmith@example.com. The email address or username is masked to ensure the user\'s privacy.').html_safe %li - %strong Map a Google Code user to a GitLab user + %strong= _("Map a Google Code user to a GitLab user") %p - <code>"johnsmith@example.com": "@johnsmith"</code> - will add "By <a href="#">@johnsmith</a>" to all issues and comments originally created by johnsmith@example.com, - and will set <a href="#">@johnsmith</a> as the assignee on all issues originally assigned to johnsmith@example.com. + = _('<code>"johnsmith@example.com": "@johnsmith"</code> will add "By <a href="#">@johnsmith</a>" to all issues and comments originally created by johnsmith@example.com, and will set <a href="#">@johnsmith</a> as the assignee on all issues originally assigned to johnsmith@example.com.').html_safe %li - %strong Map a Google Code user to a full name + %strong= _("Map a Google Code user to a full name") %p - <code>"johnsmith@example.com": "John Smith"</code> - will add "By John Smith" to all issues and comments originally created by johnsmith@example.com. + = _('<code>"johnsmith@example.com": "John Smith"</code> will add "By John Smith" to all issues and comments originally created by johnsmith@example.com.').html_safe %li - %strong Map a Google Code user to a full email address + %strong= _("Map a Google Code user to a full email address") %p - <code>"johnsmith@example.com": "johnsmith@example.com"</code> - will add "By <a href="#">johnsmith@example.com</a>" to all issues and comments originally created by johnsmith@example.com. - By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address. + = _('<code>"johnsmith@example.com": "johnsmith@example.com"</code> will add "By <a href="#">johnsmith@example.com</a>" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user\'s privacy. Use this option if you want to show the full email address.').html_safe .form-group.row .col-sm-12 = text_area_tag :user_map, JSON.pretty_generate(@user_map), class: 'form-control', rows: 15 .form-actions - = submit_tag 'Continue to the next step', class: "btn btn-create" + = submit_tag _('Continue to the next step'), class: "btn btn-create" diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index acf7a108cb0..347e2820f94 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -1,25 +1,24 @@ -- page_title "Google Code import" -- header_title "Projects", root_path +- page_title _("Google Code import") +- header_title _("Projects"), root_path %h3.page-title %i.fa.fa-google - Import projects from Google Code + = _('Import projects from Google Code') - if @repos.any? %p.light - Select projects you want to import. + = _('Select projects you want to import.') %p.light - Optionally, you can - = link_to "customize", new_user_map_import_google_code_path - how Google Code email addresses and usernames are imported into GitLab. + - link_to_customize = link_to(_("customize"), new_user_map_import_google_code_path) + = _("Optionally, you can %{link_to_customize} how Google Code email addresses and usernames are imported into GitLab.").html_safe % { link_to_customize: link_to_customize } %hr %p - if @incompatible_repos.any? = button_tag class: "btn btn-import btn-success js-import-all" do - Import all compatible projects + = _("Import all compatible projects") = icon("spinner spin", class: "loading-icon") - else = button_tag class: "btn btn-import btn-success js-import-all" do - Import all projects + = _("Import all projects") = icon("spinner spin", class: "loading-icon") .table-responsive @@ -29,9 +28,9 @@ %colgroup.import-jobs-status-col %thead %tr - %th From Google Code - %th To GitLab - %th Status + %th= _("From Google Code") + %th= _("To GitLab") + %th= _("Status") %tbody - @already_added_projects.each do |project| %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } @@ -43,10 +42,10 @@ - if project.import_status == 'finished' %span %i.fa.fa-check - done + = _("done") - elsif project.import_status == 'started' %i.fa.fa-spinner.fa-spin - started + = _("started") - else = project.human_import_status_name @@ -58,7 +57,7 @@ #{current_user.username}/#{repo.name} %td.import-actions.job-status = button_tag class: "btn btn-import js-add-to-import" do - Import + = _("Import") = icon("spinner spin", class: "loading-icon") - @incompatible_repos.each do |repo| %tr{ id: "repo_#{repo.id}" } @@ -66,15 +65,12 @@ = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank", rel: 'noopener noreferrer' %td.import-target %td.import-actions-job-status - = label_tag "Incompatible Project", nil, class: "label badge-danger" + = label_tag _("Incompatible Project"), nil, class: "label badge-danger" - if @incompatible_repos.any? %p - One or more of your Google Code projects cannot be imported into GitLab - directly because they use Subversion or Mercurial for version control, - rather than Git. Please convert them to Git on Google Code, and go - through the - = link_to "import flow", new_import_google_code_path - again. + = _("One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git.") + - link_to_import_flow = link_to(_("import flow"), new_import_google_code_path) + = _("Please convert them to Git on Google Code, and go through the %{link_to_import_flow} again.").html_safe % { link_to_import_flow: link_to_import_flow } .js-importer-status{ data: { jobs_import_path: "#{jobs_import_google_code_path}", import_path: "#{import_google_code_path}" } } diff --git a/app/views/import/manifest/_form.html.haml b/app/views/import/manifest/_form.html.haml index 763beb5958f..78c7fadb019 100644 --- a/app/views/import/manifest/_form.html.haml +++ b/app/views/import/manifest/_form.html.haml @@ -1,6 +1,6 @@ = form_tag upload_import_manifest_path, multipart: true do .form-group - = label_tag :group_id, nil, class: 'label-light' do + = label_tag :group_id, nil, class: 'label-bold' do = _('Group') .input-group .input-group-prepend.has-tooltip{ title: root_url } @@ -11,7 +11,7 @@ = _('Choose the top-level group for your repository imports.') .form-group - = label_tag :manifest, class: 'label-light' do + = label_tag :manifest, class: 'label-bold' do = _('Manifest') = file_field_tag :manifest, class: 'form-control-file', required: true .form-text.text-muted diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 9c95b6281ba..2220b4eee96 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -29,7 +29,7 @@ %p Activate signin with one of the following services .col-lg-8 - %label.label-light + %label.label-bold Connected Accounts %p Click on icon to activate signin with one of the following services - button_based_providers.each do |provider| diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index a5db9dbe7f8..04a19ab14dd 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -12,7 +12,7 @@ Add email address = form_for 'email', url: profile_emails_path do |f| .form-group - = f.label :email, class: 'label-light' + = f.label :email, class: 'label-bold' = f.text_field :email, class: 'form-control' .prepend-top-default = f.submit 'Add email address', class: 'btn btn-create' diff --git a/app/views/profiles/gpg_keys/_form.html.haml b/app/views/profiles/gpg_keys/_form.html.haml index 3fcf563d970..aa9b0aad034 100644 --- a/app/views/profiles/gpg_keys/_form.html.haml +++ b/app/views/profiles/gpg_keys/_form.html.haml @@ -3,7 +3,7 @@ = form_errors(@gpg_key) .form-group - = f.label :key, class: 'label-light' + = f.label :key, class: 'label-bold' = f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'." .prepend-top-default diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml index 43a2d53b84d..5207921d6fe 100644 --- a/app/views/profiles/keys/_form.html.haml +++ b/app/views/profiles/keys/_form.html.haml @@ -3,11 +3,11 @@ = form_errors(@key) .form-group - = f.label :key, class: 'label-light' + = f.label :key, class: 'label-bold' %p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_rsa.pub' and begins with 'ssh-rsa'. Don't use your private SSH key.") = f.text_area :key, class: "form-control js-add-ssh-key-validation-input", rows: 8, required: true, placeholder: s_('Profiles|Typically starts with "ssh-rsa …"') .form-group - = f.label :title, class: 'label-light' + = f.label :title, class: 'label-bold' = f.text_field :title, class: "form-control input-lg", required: true, placeholder: s_('Profiles|e.g. My MacBook key') %p.form-text.text-muted= _('Name your individual key via a title') diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index 71ea625e5d5..712eb2a4573 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -23,10 +23,10 @@ = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| .form-group - = f.label :notification_email, class: "label-light" + = f.label :notification_email, class: "label-bold" = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" - = label_tag :global_notification_level, "Global notification level", class: "label-light" + = label_tag :global_notification_level, "Global notification level", class: "label-bold" %br .clearfix .form-group.float-left.global-notification-setting diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index 8a51a30191a..9c8cc9c059b 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -18,15 +18,15 @@ - unless @user.password_automatically_set? .form-group - = f.label :current_password, class: 'label-light' + = f.label :current_password, class: 'label-bold' = f.password_field :current_password, required: true, class: 'form-control' %p.form-text.text-muted You must provide your current password in order to change it. .form-group - = f.label :password, 'New password', class: 'label-light' + = f.label :password, 'New password', class: 'label-bold' = f.password_field :password, required: true, class: 'form-control' .form-group - = f.label :password_confirmation, class: 'label-light' + = f.label :password_confirmation, class: 'label-bold' = f.password_field :password_confirmation, required: true, class: 'form-control' .prepend-top-default.append-bottom-default = f.submit 'Save password', class: "btn btn-create append-right-10" diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml index d111113c646..c10d4ea1a4d 100644 --- a/app/views/profiles/personal_access_tokens/index.html.haml +++ b/app/views/profiles/personal_access_tokens/index.html.haml @@ -40,7 +40,7 @@ %p It cannot be used to access any other data. .col-lg-8.feed-token-reset - = label_tag :feed_token, 'Feed token', class: "label-light" + = label_tag :feed_token, 'Feed token', class: "label-bold" = text_field_tag :feed_token, current_user.feed_token, class: 'form-control', readonly: true, onclick: 'this.select()' %p.form-text.text-muted Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. @@ -59,7 +59,7 @@ %p It cannot be used to access any other data. .col-lg-8.incoming-email-token-reset - = label_tag :incoming_email_token, 'Incoming email token', class: "label-light" + = label_tag :incoming_email_token, 'Incoming email token', class: "label-bold" = text_field_tag :incoming_email_token, current_user.incoming_email_token, class: 'form-control', readonly: true, onclick: 'this.select()' %p.form-text.text-muted Keep this token secret. Anyone who gets ahold of it can create issues as if they were you. diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 8f1078bd41d..fd6dd74e1c5 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -42,17 +42,17 @@ = link_to 'Learn more', help_page_path('user/profile/preferences', anchor: 'behavior'), target: '_blank' .col-lg-8 .form-group - = f.label :layout, class: 'label-light' do + = f.label :layout, class: 'label-bold' do Layout width = f.select :layout, layout_choices, {}, class: 'form-control' .form-text.text-muted Choose between fixed (max. 1200px) and fluid (100%) application layout. .form-group - = f.label :dashboard, class: 'label-light' do + = f.label :dashboard, class: 'label-bold' do Default dashboard = f.select :dashboard, dashboard_choices, {}, class: 'form-control' .form-group - = f.label :project_view, class: 'label-light' do + = f.label :project_view, class: 'label-bold' do Project overview content = f.select :project_view, project_view_choices, {}, class: 'form-control' .form-text.text-muted diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index e35ebdea435..cd10b8758f6 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -13,10 +13,16 @@ - if current_user.two_factor_otp_enabled? %p You've already enabled two-factor authentication using mobile authenticator applications. In order to register a different device, you must first disable two-factor authentication. + %p + If you lose your recovery codes you can generate new ones, invalidating all previous codes. + %div = link_to 'Disable two-factor authentication', profile_two_factor_auth_path, method: :delete, data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." }, - class: 'btn btn-danger' + class: 'btn btn-danger append-right-10' + = form_tag codes_profile_two_factor_auth_path, {style: 'display: inline-block', method: :post} do |f| + = submit_tag 'Regenerate recovery codes', class: 'btn' + - else %p Download the Google Authenticator application from App Store or Google Play Store and scan this code. @@ -43,7 +49,7 @@ .alert.alert-danger = @error .form-group - = label_tag :pin_code, nil, class: "label-light" + = label_tag :pin_code, nil, class: "label-bold" = text_field_tag :pin_code, nil, class: "form-control", required: true .prepend-top-default = submit_tag 'Register with two-factor app', class: 'btn btn-success' diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index 1f701f2aa1b..6bf21570d41 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -1,10 +1,9 @@ %div{ class: container_class } .nav-block.activity-filter-block.activities + = render 'shared/event_filter' .controls = link_to project_path(@project, rss_url_options), title: s_("ProjectActivityRSS|Subscribe"), class: 'btn rss-btn has-tooltip' do = icon('rss') - = render 'shared/event_filter' - .content_list.project-activity{ :"data-href" => activity_project_path(@project) } = spinner diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 89940512bc6..74ab8cf8250 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -12,6 +12,9 @@ .project-home-desc - if @project.description.present? = markdown_field(@project, :description) + - if can?(current_user, :read_project, @project) + .text-secondary.prepend-top-8 + = s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id } - if @project.forked? %p diff --git a/app/views/projects/_merge_request_merge_method_settings.html.haml b/app/views/projects/_merge_request_merge_method_settings.html.haml index 3bb220ac6d0..540e996e4d8 100644 --- a/app/views/projects/_merge_request_merge_method_settings.html.haml +++ b/app/views/projects/_merge_request_merge_method_settings.html.haml @@ -2,7 +2,7 @@ - project = local_assigns.fetch(:project) .form-group - = label_tag :merge_method_merge, class: 'label-light' do + = label_tag :merge_method_merge, class: 'label-bold' do Merge method .form-check = form.radio_button :merge_method, :merge, class: "js-merge-method-radio form-check-input" diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index f4994f5459b..c78baa5dfe4 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -4,7 +4,7 @@ .row{ id: project_name_id } = f.hidden_field :ci_cd_only, value: ci_cd_only .form-group.project-path.col-sm-6 - = f.label :namespace_id, class: 'label-light' do + = f.label :namespace_id, class: 'label-bold' do %span Project path .input-group @@ -20,7 +20,7 @@ #{user_url(current_user.username)}/ = f.hidden_field :namespace_id, value: current_user.namespace_id .form-group.project-path.col-sm-6 - = f.label :path, class: 'label-light' do + = f.label :path, class: 'label-bold' do %span Project name = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true @@ -30,12 +30,12 @@ = link_to "Create a group", new_group_path .form-group - = f.label :description, class: 'label-light' do + = f.label :description, class: 'label-bold' do Project description %span (optional) = f.text_area :description, placeholder: 'Description format', class: "form-control", rows: 3, maxlength: 250 -= f.label :visibility_level, class: 'label-light' do += f.label :visibility_level, class: 'label-bold' do Visibility Level = link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: 'Documentation for Visibility Level' }, target: '_blank', rel: 'noopener noreferrer' = render 'shared/visibility_level', f: f, visibility_level: visibility_level.to_i, can_change_visibility_level: true, form_model: @project, with_label: false diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml index d08807b5135..9d8627c9eb1 100644 --- a/app/views/projects/_project_templates.html.haml +++ b/app/views/projects/_project_templates.html.haml @@ -12,7 +12,7 @@ .project-fields-form .row .form-group.col-sm-12 - %label.label-light + %label.label-bold Template .input-group.template-input-group .input-group-prepend diff --git a/app/views/projects/artifacts/file.html.haml b/app/views/projects/artifacts/file.html.haml index aac7a1870df..f7174d6b2c6 100644 --- a/app/views/projects/artifacts/file.html.haml +++ b/app/views/projects/artifacts/file.html.haml @@ -27,6 +27,6 @@ .btn-group{ role: "group" }< = copy_blob_source_button(blob) - = open_raw_blob_button(blob) + = download_blob_button(blob) = render 'projects/blob/content', blob: blob diff --git a/app/views/projects/blob/_header.html.haml b/app/views/projects/blob/_header.html.haml index 0a0b3ce1d6f..84ccd816d80 100644 --- a/app/views/projects/blob/_header.html.haml +++ b/app/views/projects/blob/_header.html.haml @@ -8,8 +8,8 @@ .btn-group{ role: "group" }< = copy_blob_source_button(blob) unless blame = open_raw_blob_button(blob) + = download_blob_button(blob) = view_on_environment_button(@commit.sha, @path, @environment) if @environment - .btn-group{ role: "group" }< = render_if_exists 'projects/blob/header_file_locks_link' = edit_blob_button diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index d8b4266143e..a2dc2730ecc 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -1,5 +1,5 @@ - if current_user - %button.btn.btn-default.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } } + %button.btn.btn-default.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } }> - if current_user.starred?(@project) = sprite_icon('star') %span.starred= _('Unstar') diff --git a/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml b/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml index 9298d93663d..73b11d509d3 100644 --- a/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml +++ b/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml @@ -1,12 +1,12 @@ - link = link_to(s_('ClusterIntegration|sign up'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer') -.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' } +.bs-callout.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' } %button.close{ type: "button", data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } } × - %div - .col-sm-2.gcp-logo - = image_tag 'illustrations/logos/google-cloud-platform_logo.svg' - .col-sm-10 - %h4= s_('ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform') + .gcp-signup-offer--content + .gcp-signup-offer--icon.append-right-8 + = sprite_icon("information", size: 16) + .gcp-signup-offer--copy + %h4= s_('ClusterIntegration|Did you know?') %p= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link } - %a.btn.btn-info{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' } + %a.btn.btn-default{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' } Apply for credit diff --git a/app/views/projects/clusters/gcp/_form.html.haml b/app/views/projects/clusters/gcp/_form.html.haml index 0a2e320556d..9133de6559d 100644 --- a/app/views/projects/clusters/gcp/_form.html.haml +++ b/app/views/projects/clusters/gcp/_form.html.haml @@ -15,15 +15,15 @@ = form_for @gcp_cluster, html: { class: 'js-gke-cluster-creation prepend-top-20', data: { token: token_in_session } }, url: create_gcp_namespace_project_clusters_path(@project.namespace, @project), as: :cluster do |field| = form_errors(@gcp_cluster) .form-group - = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-light' + = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-bold' = field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Kubernetes cluster name') .form-group - = field.label :environment_scope, s_('ClusterIntegration|Environment scope'), class: 'label-light' + = field.label :environment_scope, s_('ClusterIntegration|Environment scope'), class: 'label-bold' = field.text_field :environment_scope, class: 'form-control', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') = field.fields_for :provider_gcp, @gcp_cluster.provider_gcp do |provider_gcp_field| .form-group - = provider_gcp_field.label :gcp_project_id, s_('ClusterIntegration|Google Cloud Platform project'), class: 'label-light' + = provider_gcp_field.label :gcp_project_id, s_('ClusterIntegration|Google Cloud Platform project'), class: 'label-bold' .js-gcp-project-id-dropdown-entry-point{ data: { docsUrl: 'https://console.cloud.google.com/home/dashboard' } } = provider_gcp_field.hidden_field :gcp_project_id .dropdown @@ -34,7 +34,7 @@ %span.form-text.text-muted .form-group - = provider_gcp_field.label :zone, s_('ClusterIntegration|Zone'), class: 'label-light' + = provider_gcp_field.label :zone, s_('ClusterIntegration|Zone'), class: 'label-bold' .js-gcp-zone-dropdown-entry-point = provider_gcp_field.hidden_field :zone .dropdown @@ -46,11 +46,11 @@ = s_('ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}.').html_safe % { help_link_start: help_link_start % { url: zones_link_url }, help_link_end: help_link_end } .form-group - = provider_gcp_field.label :num_nodes, s_('ClusterIntegration|Number of nodes'), class: 'label-light' + = provider_gcp_field.label :num_nodes, s_('ClusterIntegration|Number of nodes'), class: 'label-bold' = provider_gcp_field.text_field :num_nodes, class: 'form-control', placeholder: '3' .form-group - = provider_gcp_field.label :machine_type, s_('ClusterIntegration|Machine type'), class: 'label-light' + = provider_gcp_field.label :machine_type, s_('ClusterIntegration|Machine type'), class: 'label-bold' .js-gcp-machine-type-dropdown-entry-point = provider_gcp_field.hidden_field :machine_type .dropdown diff --git a/app/views/projects/clusters/user/_form.html.haml b/app/views/projects/clusters/user/_form.html.haml index 3006bb5073e..e8ef0008802 100644 --- a/app/views/projects/clusters/user/_form.html.haml +++ b/app/views/projects/clusters/user/_form.html.haml @@ -1,28 +1,28 @@ = form_for @user_cluster, url: create_user_namespace_project_clusters_path(@project.namespace, @project), as: :cluster do |field| = form_errors(@user_cluster) .form-group - = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-light' + = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-bold' = field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Kubernetes cluster name') - if has_multiple_clusters?(@project) .form-group - = field.label :environment_scope, s_('ClusterIntegration|Environment scope'), class: 'label-light' + = field.label :environment_scope, s_('ClusterIntegration|Environment scope'), class: 'label-bold' = field.text_field :environment_scope, class: 'form-control', placeholder: s_('ClusterIntegration|Environment scope') = field.fields_for :platform_kubernetes, @user_cluster.platform_kubernetes do |platform_kubernetes_field| .form-group - = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL'), class: 'label-light' + = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL'), class: 'label-bold' = platform_kubernetes_field.text_field :api_url, class: 'form-control', placeholder: s_('ClusterIntegration|API URL') .form-group - = platform_kubernetes_field.label :ca_cert, s_('ClusterIntegration|CA Certificate'), class: 'label-light' + = platform_kubernetes_field.label :ca_cert, s_('ClusterIntegration|CA Certificate'), class: 'label-bold' = platform_kubernetes_field.text_area :ca_cert, class: 'form-control', placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)') .form-group - = platform_kubernetes_field.label :token, s_('ClusterIntegration|Token'), class: 'label-light' + = platform_kubernetes_field.label :token, s_('ClusterIntegration|Token'), class: 'label-bold' = platform_kubernetes_field.text_field :token, class: 'form-control', placeholder: s_('ClusterIntegration|Service token'), autocomplete: 'off' .form-group - = platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)'), class: 'label-light' + = platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)'), class: 'label-bold' = platform_kubernetes_field.text_field :namespace, class: 'form-control', placeholder: s_('ClusterIntegration|Project namespace') .form-group diff --git a/app/views/projects/clusters/user/_show.html.haml b/app/views/projects/clusters/user/_show.html.haml index 4d117f435dc..20a07d6695e 100644 --- a/app/views/projects/clusters/user/_show.html.haml +++ b/app/views/projects/clusters/user/_show.html.haml @@ -1,20 +1,20 @@ = form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| = form_errors(@cluster) .form-group - = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-light' + = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-bold' = field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Kubernetes cluster name') = field.fields_for :platform_kubernetes, @cluster.platform_kubernetes do |platform_kubernetes_field| .form-group - = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL'), class: 'label-light' + = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL'), class: 'label-bold' = platform_kubernetes_field.text_field :api_url, class: 'form-control', placeholder: s_('ClusterIntegration|API URL') .form-group - = platform_kubernetes_field.label :ca_cert, s_('ClusterIntegration|CA Certificate'), class: 'label-light' + = platform_kubernetes_field.label :ca_cert, s_('ClusterIntegration|CA Certificate'), class: 'label-bold' = platform_kubernetes_field.text_area :ca_cert, class: 'form-control', placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)') .form-group - = platform_kubernetes_field.label :token, s_('ClusterIntegration|Token'), class: 'label-light' + = platform_kubernetes_field.label :token, s_('ClusterIntegration|Token'), class: 'label-bold' .input-group = platform_kubernetes_field.text_field :token, class: 'form-control js-cluster-token', type: 'password', placeholder: s_('ClusterIntegration|Token'), autocomplete: 'off' %span.input-group-append.clipboard-addon @@ -23,7 +23,7 @@ = s_('ClusterIntegration|Show') .form-group - = platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)'), class: 'label-light' + = platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)'), class: 'label-bold' = platform_kubernetes_field.text_field :namespace, class: 'form-control', placeholder: s_('ClusterIntegration|Project namespace') .form-group diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml index 3d97e93c9e9..afd70ef5774 100644 --- a/app/views/projects/commit/_change.html.haml +++ b/app/views/projects/commit/_change.html.haml @@ -11,7 +11,7 @@ - branch_label = s_('ChangeTypeActionLabel|Pick into branch') - title = commit.merged_merge_request(current_user) ? _('Cherry-pick this merge request') : _('Cherry-pick this commit') -.modal{ id: "modal-#{type}-commit" } +.modal{ id: "modal-#{type}-commit", tabindex: -1 } .modal-dialog .modal-content .modal-header @@ -23,7 +23,7 @@ %p= description = form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "js-#{type}-form js-requires-input" do .form-group.branch - = label_tag 'start_branch', branch_label, class: 'label-light' + = label_tag 'start_branch', branch_label, class: 'label-bold' = hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch' = dropdown_tag(@project.default_branch, options: { title: s_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: s_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: project_branches_path(@project), submit_form_on_click: false } }) diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml index 5ad8091a02b..f8ab0c1ec54 100644 --- a/app/views/projects/deploy_keys/_form.html.haml +++ b/app/views/projects/deploy_keys/_form.html.haml @@ -1,10 +1,10 @@ = form_for [@project.namespace.becomes(Namespace), @project, @deploy_keys.new_key], url: namespace_project_deploy_keys_path, html: { class: "js-requires-input container" } do |f| = form_errors(@deploy_keys.new_key) .form-group.row - = f.label :title, class: "label-light" + = f.label :title, class: "label-bold" = f.text_field :title, class: 'form-control', required: true .form-group.row - = f.label :key, class: "label-light" + = f.label :key, class: "label-bold" = f.text_area :key, class: "form-control", rows: 5, required: true .form-group.row %p.light.append-bottom-0 diff --git a/app/views/projects/deploy_tokens/_form.html.haml b/app/views/projects/deploy_tokens/_form.html.haml index f8db30df7b4..578a9e2f74d 100644 --- a/app/views/projects/deploy_tokens/_form.html.haml +++ b/app/views/projects/deploy_tokens/_form.html.haml @@ -5,25 +5,25 @@ = form_errors(token) .form-group - = f.label :name, class: 'label-light' + = f.label :name, class: 'label-bold' = f.text_field :name, class: 'form-control', required: true .form-group - = f.label :expires_at, class: 'label-light' + = f.label :expires_at, class: 'label-bold' = f.text_field :expires_at, class: 'datepicker form-control', value: f.object.expires_at .form-group - = f.label :scopes, class: 'label-light' - %fieldset - = f.check_box :read_repository - = label_tag ("deploy_token_read_repository"), 'read_repository' - %span= s_('DeployTokens|Allows read-only access to the repository') + = f.label :scopes, class: 'label-bold' + %fieldset.form-group.form-check + = f.check_box :read_repository, class: 'form-check-input' + = label_tag ("deploy_token_read_repository"), 'read_repository', class: 'label-bold form-check-label' + .text-secondary= s_('DeployTokens|Allows read-only access to the repository') - if container_registry_enabled?(project) - %fieldset - = f.check_box :read_registry - = label_tag ("deploy_token_read_registry"), 'read_registry' - %span= s_('DeployTokens|Allows read-only access to the registry images') + %fieldset.form-group.form-check + = f.check_box :read_registry, class: 'form-check-input' + = label_tag ("deploy_token_read_registry"), 'read_registry', class: 'label-bold form-check-label' + .text-secondary= s_('DeployTokens|Allows read-only access to the registry images') .prepend-top-default = f.submit s_('DeployTokens|Create deploy token'), class: 'btn btn-success' diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index c2d900cbcf7..0ff88b82ae6 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -18,17 +18,17 @@ %fieldset .row .form-group.col-md-9 - = f.label :name, class: 'label-light', for: 'project_name_edit' do + = f.label :name, class: 'label-bold', for: 'project_name_edit' do Project name = f.text_field :name, class: "form-control", id: "project_name_edit" .form-group.col-md-3 - = f.label :id, class: 'label-light' do + = f.label :id, class: 'label-bold' do Project ID = f.text_field :id, class: 'form-control', readonly: true .form-group - = f.label :description, class: 'label-light' do + = f.label :description, class: 'label-bold' do Project description %span.light (optional) = f.text_area :description, class: "form-control", rows: 3, maxlength: 250 @@ -37,13 +37,13 @@ - unless @project.empty_repo? .form-group - = f.label :default_branch, "Default Branch", class: 'label-light' + = f.label :default_branch, "Default Branch", class: 'label-bold' = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'}) = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project .form-group - = f.label :tag_list, "Tags", class: 'label-light' + = f.label :tag_list, "Tags", class: 'label-bold' = f.text_field :tag_list, value: @project.tag_list.sort.join(', '), maxlength: 2000, class: "form-control" %p.form-text.text-muted Separate tags with commas. %fieldset.features @@ -144,12 +144,12 @@ = render 'projects/errors' = form_for([@project.namespace.becomes(Namespace), @project]) do |f| .form-group.project_name_holder - = f.label :name, class: 'label-light' do + = f.label :name, class: 'label-bold' do Project name .form-group = f.text_field :name, class: "form-control" .form-group - = f.label :path, class: 'label-light' do + = f.label :path, class: 'label-bold' do %span Path .form-group .input-group @@ -169,7 +169,7 @@ Transfer project = form_for([@project.namespace.becomes(Namespace), @project], url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'js-project-transfer-form' } ) do |f| .form-group - = label_tag :new_namespace_id, nil, class: 'label-light' do + = label_tag :new_namespace_id, nil, class: 'label-bold' do %span Select a new namespace .form-group = select_tag :new_namespace_id, namespaces_options(nil), include_blank: true, class: 'select2' diff --git a/app/views/projects/environments/_form.html.haml b/app/views/projects/environments/_form.html.haml index 1605f3a3351..0586dbdf0e2 100644 --- a/app/views/projects/environments/_form.html.haml +++ b/app/views/projects/environments/_form.html.haml @@ -11,10 +11,10 @@ = form_errors(@environment) .form-group - = f.label :name, 'Name', class: 'label-light' + = f.label :name, 'Name', class: 'label-bold' = f.text_field :name, required: true, class: 'form-control' .form-group - = f.label :external_url, 'External URL', class: 'label-light' + = f.label :external_url, 'External URL', class: 'label-bold' = f.url_field :external_url, class: 'form-control' .form-actions diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index a33bc9d4ce6..c7890b37381 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -16,7 +16,7 @@ ? .modal-body %p= s_('Environments|Are you sure you want to stop this environment?') - - unless @environment.stop_action? + - unless @environment.stop_action_available? .warning_message %p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: '<strong>'.html_safe, emphasis_end: '</strong>'.html_safe, diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index 16c4f21279d..8ce822c43b7 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -5,12 +5,12 @@ %hr - if @project.import_failed? - .card.bg-danger - .card-header The repository could not be imported. + .card.border-danger + .card-header.bg-danger.text-white The repository could not be imported. .card-body %pre :preserve - #{h(sanitize_repo_path(@project, @project.import_error))} + #{h(@project.import_error)} = form_for @project, url: project_import_path(@project), method: :post do |f| = render "shared/import_form", f: f diff --git a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml b/app/views/projects/merge_requests/conflicts/_submit_form.html.haml index 4d84ee2488b..8181267184a 100644 --- a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml +++ b/app/views/projects/merge_requests/conflicts/_submit_form.html.haml @@ -9,7 +9,7 @@ .resolve-info = translation.html_safe .col-md-8 - %label.label-light{ "for" => "commit-message" } + %label.label-bold{ "for" => "commit-message" } #{ _('Commit message') } .commit-message-container .max-width-marker diff --git a/app/views/projects/mirrors/_push.html.haml b/app/views/projects/mirrors/_push.html.haml index 2b2871a81e5..08375e09816 100644 --- a/app/views/projects/mirrors/_push.html.haml +++ b/app/views/projects/mirrors/_push.html.haml @@ -32,11 +32,11 @@ .form-group = rm_form.check_box :enabled, class: "float-left" .prepend-left-20 - = rm_form.label :enabled, "Remote mirror repository", class: "label-light append-bottom-0" + = rm_form.label :enabled, "Remote mirror repository", class: "label-bold append-bottom-0" %p.light.append-bottom-0 Automatically update the remote mirror's branches, tags, and commits from this repository every time someone pushes to it. .form-group.has-feedback - = rm_form.label :url, "Git repository URL", class: "label-light" + = rm_form.label :url, "Git repository URL", class: "label-bold" = rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git' = render "projects/mirrors/instructions" @@ -44,7 +44,7 @@ .form-group = rm_form.check_box :only_protected_branches, class: 'float-left' .prepend-left-20 - = rm_form.label :only_protected_branches, class: 'label-light' + = rm_form.label :only_protected_branches, class: 'label-bold' = link_to icon('question-circle'), help_page_path('user/project/protected_branches') = f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror' diff --git a/app/views/projects/pages/_destroy.haml b/app/views/projects/pages/_destroy.haml index 9b77c4e3494..ae8c801b705 100644 --- a/app/views/projects/pages/_destroy.haml +++ b/app/views/projects/pages/_destroy.haml @@ -1,7 +1,7 @@ - if @project.pages_deployed? - if can?(current_user, :remove_pages, @project) - .card.bg-danger - .card-header Remove pages + .card.border-danger + .card-header.bg-danger.text-white Remove pages .errors-holder .card-body %p diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml index 1cdf981fcb4..9a981d53ab6 100644 --- a/app/views/projects/pipeline_schedules/_form.html.haml +++ b/app/views/projects/pipeline_schedules/_form.html.haml @@ -2,25 +2,25 @@ = form_errors(@schedule) .form-group.row .col-md-9 - = f.label :description, _('Description'), class: 'label-light' + = f.label :description, _('Description'), class: 'label-bold' = f.text_field :description, class: 'form-control', required: true, autofocus: true, placeholder: s_('PipelineSchedules|Provide a short description for this pipeline') .form-group.row .col-md-9 - = f.label :cron, _('Interval Pattern'), class: 'label-light' + = f.label :cron, _('Interval Pattern'), class: 'label-bold' #interval-pattern-input{ data: { initial_interval: @schedule.cron } } .form-group.row .col-md-9 - = f.label :cron_timezone, _('Cron Timezone'), class: 'label-light' + = f.label :cron_timezone, _('Cron Timezone'), class: 'label-bold' = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } ) = f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true .form-group.row .col-md-9 - = f.label :ref, _('Target Branch'), class: 'label-light' + = f.label :ref, _('Target Branch'), class: 'label-bold' = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } ) = f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true .form-group.row.js-ci-variable-list-section .col-md-9 - %label.label-light + %label.label-bold #{ s_('PipelineSchedules|Variables') } %ul.ci-variable-list - @schedule.variables.each do |variable| @@ -34,7 +34,7 @@ = n_('Reveal value', 'Reveal values', @schedule.variables.size) .form-group.row .col-md-9 - = f.label :active, s_('PipelineSchedules|Activated'), class: 'label-light' + = f.label :active, s_('PipelineSchedules|Activated'), class: 'label-bold' %div = f.check_box :active, required: false, value: @schedule.active? = _('Active') diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 5064db8d5cd..6272687be1c 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -2,10 +2,10 @@ .col-sm-12 = form_for @project_member, as: :project_member, url: project_project_members_path(@project), html: { class: 'users-project-form' } do |f| .form-group - = label_tag :user_ids, "Select members to invite", class: "label-light" + = label_tag :user_ids, "Select members to invite", class: "label-bold" = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true, placeholder: "Search for members to update or invite") .form-group - = label_tag :access_level, "Choose a role permission", class: "label-light" + = label_tag :access_level, "Choose a role permission", class: "label-bold" .select-wrapper = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select select-control" = icon('chevron-down') @@ -14,7 +14,7 @@ about role permissions .form-group .clearable-input - = label_tag :expires_at, 'Access expiration date', class: 'label-light' + = label_tag :expires_at, 'Access expiration date', class: 'label-bold' = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' %i.clear-icon.js-clear-input = f.submit "Add to project", class: "btn btn-create" diff --git a/app/views/projects/project_members/_new_shared_group.html.haml b/app/views/projects/project_members/_new_shared_group.html.haml index 684219735e2..d7227c32833 100644 --- a/app/views/projects/project_members/_new_shared_group.html.haml +++ b/app/views/projects/project_members/_new_shared_group.html.haml @@ -2,10 +2,10 @@ .col-sm-12 = form_tag project_group_links_path(@project), class: 'js-requires-input', method: :post do .form-group - = label_tag :link_group_id, "Select a group to share with", class: "label-light" + = label_tag :link_group_id, "Select a group to share with", class: "label-bold" = groups_select_tag(:link_group_id, data: { skip_groups: @skip_groups }, class: "input-clamp", required: true) .form-group - = label_tag :link_group_access, "Max access level", class: "label-light" + = label_tag :link_group_access, "Max access level", class: "label-bold" .select-wrapper = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control select-control" = icon('chevron-down') @@ -13,7 +13,7 @@ = link_to "Read more", help_page_path("user/permissions"), class: "vlink" about role permissions .form-group - = label_tag :expires_at, 'Access expiration date', class: 'label-light' + = label_tag :expires_at, 'Access expiration date', class: 'label-bold' .clearable-input = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date-groups', placeholder: 'Expiration date', id: 'expires_at_groups' %i.clear-icon.js-clear-input diff --git a/app/views/projects/protected_branches/_update_protected_branch.html.haml b/app/views/projects/protected_branches/_update_protected_branch.html.haml index f242459f69b..74bfaa9ff80 100644 --- a/app/views/projects/protected_branches/_update_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_update_protected_branch.html.haml @@ -6,5 +6,5 @@ %td = hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_levels.first.access_level = dropdown_tag( (protected_branch.push_access_levels.first.humanize || 'Select') , - options: { toggle_class: 'js-allowed-to-push qa-allowed-to-push', dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header', + options: { toggle_class: 'js-allowed-to-push', dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header', data: { field_name: "allowed_to_push_#{protected_branch.id}", access_level_id: protected_branch.push_access_levels.first.id }}) diff --git a/app/views/projects/protected_branches/shared/_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_protected_branch.html.haml index 82ef08272d3..05cee483c0e 100644 --- a/app/views/projects/protected_branches/shared/_protected_branch.html.haml +++ b/app/views/projects/protected_branches/shared/_protected_branch.html.haml @@ -2,7 +2,7 @@ %tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch) } } %td - %span.ref-name.qa-protected-branch-name= protected_branch.name + %span.ref-name= protected_branch.name - if @project.root_ref?(protected_branch.name) %span.badge.badge-info.prepend-left-5 default diff --git a/app/views/projects/protected_tags/_protected_tag.html.haml b/app/views/projects/protected_tags/_protected_tag.html.haml index da1f97c8d6a..e0912bf39c0 100644 --- a/app/views/projects/protected_tags/_protected_tag.html.haml +++ b/app/views/projects/protected_tags/_protected_tag.html.haml @@ -1,2 +1,4 @@ = render layout: 'projects/protected_tags/shared/protected_tag', locals: { protected_tag: protected_tag } do - = render partial: 'projects/protected_tags/update_protected_tag', locals: { protected_tag: protected_tag } + %td + = render 'projects/protected_tags/protected_tag_create_access_levels', protected_tag: protected_tag, create_access_level: protected_tag.create_access_levels.for_role.first + = render_if_exists 'projects/protected_tags/protected_tag_extra_create_access_levels', protected_tag: protected_tag diff --git a/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml b/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml new file mode 100644 index 00000000000..1d4e9565156 --- /dev/null +++ b/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml @@ -0,0 +1,8 @@ +- protected_tag = local_assigns.fetch(:protected_tag) +- create_access_level = local_assigns.fetch(:create_access_level) +- dropdown_label = create_access_level&.humanize || 'Select' + += hidden_field_tag "allowed_to_create_#{protected_tag.id}", create_access_level&.access_level += dropdown_tag(dropdown_label, + options: { toggle_class: 'js-allowed-to-create', dropdown_class: 'dropdown-menu-selectable capitalize-header js-allowed-to-create-container', + data: { field_name: "allowed_to_create_#{protected_tag.id}", access_level_id: create_access_level&.id }}) diff --git a/app/views/projects/protected_tags/_update_protected_tag.haml b/app/views/projects/protected_tags/_update_protected_tag.haml deleted file mode 100644 index cc80bd04dd0..00000000000 --- a/app/views/projects/protected_tags/_update_protected_tag.haml +++ /dev/null @@ -1,5 +0,0 @@ -%td - = hidden_field_tag "allowed_to_create_#{protected_tag.id}", protected_tag.create_access_levels.first.access_level - = dropdown_tag( (protected_tag.create_access_levels.first.humanize || 'Select') , - options: { toggle_class: 'js-allowed-to-create', dropdown_class: 'dropdown-menu-selectable capitalize-header js-allowed-to-create-container', - data: { field_name: "allowed_to_create_#{protected_tag.id}", access_level_id: protected_tag.create_access_levels.first.id }}) diff --git a/app/views/projects/services/prometheus/_metrics.html.haml b/app/views/projects/services/prometheus/_metrics.html.haml new file mode 100644 index 00000000000..98d64fafe86 --- /dev/null +++ b/app/views/projects/services/prometheus/_metrics.html.haml @@ -0,0 +1,30 @@ +- project = local_assigns.fetch(:project) + +.card.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/metrics') } } + .card-header + %h3.card-title + = s_('PrometheusService|Common metrics') + %span.badge.badge-pill.js-monitored-count 0 + .card-body + .loading-metrics.js-loading-metrics + %p.prepend-top-10.prepend-left-10 + = icon('spinner spin', class: 'metrics-load-spinner') + = s_('PrometheusService|Finding and configuring metrics...') + .empty-metrics.hidden.js-empty-metrics + %p.text-tertiary.prepend-top-10.prepend-left-10 + = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics') + %ul.list-unstyled.metrics-list.hidden.js-metrics-list + +.card.hidden.js-panel-missing-env-vars + .card-header + %h3.card-title + = icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel') + = s_('PrometheusService|Missing environment variable') + %span.badge.badge-pill.js-env-var-count 0 + .card-body.hidden + .flash-container + .flash-notice + .flash-text + = s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries." % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>" }).html_safe + = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels') + %ul.list-unstyled.metrics-list.js-missing-var-metrics-list diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml index bda597cc02b..9741b783db3 100644 --- a/app/views/projects/services/prometheus/_show.html.haml +++ b/app/views/projects/services/prometheus/_show.html.haml @@ -3,35 +3,8 @@ %h4.prepend-top-0 = s_('PrometheusService|Metrics') %p - = s_('PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters.') - = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus') + = s_('PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters.') + = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus_library/metrics'), target: '_blank', rel: "noopener noreferrer" .col-lg-9 - .card.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(@project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/metrics') } } - .card-header - %h3.card-title - = s_('PrometheusService|Common metrics') - %span.badge.badge-pill.js-monitored-count 0 - .card-body - .loading-metrics.js-loading-metrics - %p.prepend-top-10.prepend-left-10 - = icon('spinner spin', class: 'metrics-load-spinner') - = s_('PrometheusService|Finding and configuring metrics...') - .empty-metrics.hidden.js-empty-metrics - %p.text-tertiary.prepend-top-10.prepend-left-10 - = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics') - %ul.list-unstyled.metrics-list.hidden.js-metrics-list - - .card.hidden.js-panel-missing-env-vars - .card-header - %h3.card-title - = icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel') - = s_('PrometheusService|Missing environment variable') - %span.badge.badge-pill.js-env-var-count 0 - .card-body.hidden - .flash-container - .flash-notice - .flash-text - = s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries." % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>" }).html_safe - = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels') - %ul.list-unstyled.metrics-list.js-missing-var-metrics-list + = render_if_exists 'projects/services/prometheus/metrics', project: @project diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml index fb113aa7639..64751e5616a 100644 --- a/app/views/projects/settings/ci_cd/_form.html.haml +++ b/app/views/projects/settings/ci_cd/_form.html.haml @@ -4,7 +4,7 @@ = form_errors(@project) %fieldset.builds-feature .form-group.append-bottom-default.js-secret-runner-token - = f.label :runners_token, _("Runner token"), class: 'label-light' + = f.label :runners_token, _("Runner token"), class: 'label-bold' .form-control.js-secret-value-placeholder = '*' * 20 = f.text_field :runners_token, class: "form-control hide js-secret-value", placeholder: 'xEeFCaDAB89' @@ -36,7 +36,7 @@ %hr .form-group - = f.label :build_timeout_human_readable, _('Timeout'), class: 'label-light' + = f.label :build_timeout_human_readable, _('Timeout'), class: 'label-bold' = f.text_field :build_timeout_human_readable, class: 'form-control' %p.form-text.text-muted = _("Per job. If a job passes this threshold, it will be marked as failed") @@ -44,7 +44,7 @@ %hr .form-group - = f.label :ci_config_path, _('Custom CI config path'), class: 'label-light' + = f.label :ci_config_path, _('Custom CI config path'), class: 'label-bold' = f.text_field :ci_config_path, class: 'form-control', placeholder: '.gitlab-ci.yml' %p.form-text.text-muted = _("The path to CI config file. Defaults to <code>.gitlab-ci.yml</code>") @@ -83,7 +83,7 @@ %hr .form-group - = f.label :build_coverage_regex, _("Test coverage parsing"), class: 'label-light' + = f.label :build_coverage_regex, _("Test coverage parsing"), class: 'label-bold' .input-group %span.input-group-prepend .input-group-text / diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index 96ecac815c0..dab95ba09f2 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -26,6 +26,8 @@ = link_to new_project_tag_path(@project), class: 'btn btn-create new-tag-btn' do = s_('TagsPage|New tag') + = render_if_exists 'projects/commits/mirror_status' + .tags - if @tags.any? %ul.flex-list.content-list diff --git a/app/views/projects/triggers/_form.html.haml b/app/views/projects/triggers/_form.html.haml index 3539aea3580..1a5fc56f429 100644 --- a/app/views/projects/triggers/_form.html.haml +++ b/app/views/projects/triggers/_form.html.haml @@ -3,9 +3,9 @@ - if @trigger.token .form-group - %label.label-light Token + %label.label-bold Token %p.form-control-plaintext= @trigger.token .form-group - = f.label :key, "Description", class: "label-light" + = f.label :key, "Description", class: "label-bold" = f.text_field :description, class: "form-control", required: true, title: 'Trigger description is required.', placeholder: "Trigger description" = f.submit btn_text, class: "btn btn-save" diff --git a/app/views/projects/wikis/_sidebar.html.haml b/app/views/projects/wikis/_sidebar.html.haml index a23396dc0d8..28353927135 100644 --- a/app/views/projects/wikis/_sidebar.html.haml +++ b/app/views/projects/wikis/_sidebar.html.haml @@ -11,9 +11,11 @@ .blocks-container .block.block-first - %ul.wiki-pages - = render @sidebar_wiki_entries, context: 'sidebar' - + - if @sidebar_page + = render_wiki_content(@sidebar_page) + - else + %ul.wiki-pages + = render @sidebar_wiki_entries, context: 'sidebar' .block = link_to project_wikis_pages_path(@project), class: 'btn btn-block' do = s_("Wiki|More Pages") diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml index ecb5b1c6ebc..7afb7b3a93b 100644 --- a/app/views/shared/_event_filter.html.haml +++ b/app/views/shared/_event_filter.html.haml @@ -1,4 +1,4 @@ -.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller +.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller.flex-fill .fade-left= icon('angle-left') .fade-right= icon('angle-right') %ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml index 356e12cf9f8..7b593ca4f76 100644 --- a/app/views/shared/_import_form.html.haml +++ b/app/views/shared/_import_form.html.haml @@ -1,7 +1,7 @@ - ci_cd_only = local_assigns.fetch(:ci_cd_only, false) .form-group.import-url-data - = f.label :import_url, class: 'label-light' do + = f.label :import_url, class: 'label-bold' do %span = _('Git repository URL') diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml index 28407b543b9..58d310fac16 100644 --- a/app/views/shared/_personal_access_tokens_form.html.haml +++ b/app/views/shared/_personal_access_tokens_form.html.haml @@ -11,18 +11,18 @@ .row .form-group.col-md-6 - = f.label :name, class: 'label-light' + = f.label :name, class: 'label-bold' = f.text_field :name, class: "form-control", required: true .row .form-group.col-md-6 - = f.label :expires_at, class: 'label-light' + = f.label :expires_at, class: 'label-bold' .input-icon-wrapper = f.text_field :expires_at, class: "datepicker form-control", placeholder: 'YYYY-MM-DD' = icon('calendar', { class: 'input-icon-right' }) .form-group - = f.label :scopes, class: 'label-light' + = f.label :scopes, class: 'label-bold' = render 'shared/tokens/scopes_form', prefix: 'personal_access_token', token: token, scopes: scopes .prepend-top-default diff --git a/app/views/shared/tokens/_scopes_form.html.haml b/app/views/shared/tokens/_scopes_form.html.haml index dcb3fca23f2..af9db5f59a8 100644 --- a/app/views/shared/tokens/_scopes_form.html.haml +++ b/app/views/shared/tokens/_scopes_form.html.haml @@ -5,5 +5,5 @@ - scopes.each do |scope| %fieldset.form-group.form-check = check_box_tag "#{prefix}[scopes][]", scope, token.scopes.include?(scope), id: "#{prefix}_scopes_#{scope}", class: 'form-check-input' - = label_tag ("#{prefix}_scopes_#{scope}"), scope, class: 'label-light form-check-label' + = label_tag ("#{prefix}_scopes_#{scope}"), scope, class: 'label-bold form-check-label' .text-secondary= t scope, scope: [:doorkeeper, :scope_desc] diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index 660769fa50d..07ebb8680d2 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -1,15 +1,15 @@ = form_errors(hook) .form-group - = form.label :url, 'URL', class: 'label-light' + = form.label :url, 'URL', class: 'label-bold' = form.text_field :url, class: 'form-control', placeholder: 'http://example.com/trigger-ci.json' .form-group - = form.label :token, 'Secret Token', class: 'label-light' + = form.label :token, 'Secret Token', class: 'label-bold' = form.text_field :token, class: 'form-control', placeholder: '' %p.form-text.text-muted Use this token to validate received payloads. It will be sent with the request in the X-Gitlab-Token HTTP header. .form-group - = form.label :url, 'Trigger', class: 'label-light' + = form.label :url, 'Trigger', class: 'label-bold' %ul.list-unstyled.prepend-left-20 %li = form.check_box :push_events, class: 'form-check-input' @@ -72,7 +72,7 @@ %p.light.ml-1 This URL will be triggered when a wiki page is created/updated .form-group - = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox' + = form.label :enable_ssl_verification, 'SSL verification', class: 'label-bold checkbox' .form-check = form.check_box :enable_ssl_verification, class: 'form-check-input' = form.label :enable_ssl_verification, class: 'form-check-label ml-1' do diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index d4be1ccfcfa..4de35b9bd06 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -13,7 +13,6 @@ - cronjob:repository_archive_cache - cronjob:repository_check_dispatch - cronjob:requests_profiles -- cronjob:schedule_update_user_activity - cronjob:stuck_ci_jobs - cronjob:stuck_import_jobs - cronjob:stuck_merge_jobs @@ -114,7 +113,6 @@ - storage_migrator - system_hook_push - update_merge_requests -- update_user_activity - upload_checksum - web_hook - repository_update_remote_mirror diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index 8d0cfc73ccd..17ad1d5ab88 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -51,7 +51,7 @@ class EmailsOnPushWorker end end - recipients.split.each do |recipient| + valid_recipients(recipients).each do |recipient| begin send_email( recipient, @@ -89,4 +89,10 @@ class EmailsOnPushWorker email.header[:skip_premailer] = true if skip_premailer email.deliver_now end + + def valid_recipients(recipients) + recipients.split.select do |recipient| + recipient.include?('@') + end + end end diff --git a/app/workers/schedule_update_user_activity_worker.rb b/app/workers/schedule_update_user_activity_worker.rb deleted file mode 100644 index ff42fb8f0e5..00000000000 --- a/app/workers/schedule_update_user_activity_worker.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class ScheduleUpdateUserActivityWorker - include ApplicationWorker - include CronjobQueue - - def perform(batch_size = 500) - Gitlab::UserActivities.new.each_slice(batch_size) do |batch| - UpdateUserActivityWorker.perform_async(Hash[batch]) - end - end -end diff --git a/app/workers/update_user_activity_worker.rb b/app/workers/update_user_activity_worker.rb deleted file mode 100644 index 15f01a70337..00000000000 --- a/app/workers/update_user_activity_worker.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -class UpdateUserActivityWorker - include ApplicationWorker - - def perform(pairs) - pairs = cast_data(pairs) - ids = pairs.keys - conditions = 'WHEN id = ? THEN ? ' * ids.length - - User.where(id: ids) - .update_all([ - "last_activity_on = CASE #{conditions} ELSE last_activity_on END", - *pairs.to_a.flatten - ]) - - Gitlab::UserActivities.new.delete(*ids) - end - - private - - def cast_data(pairs) - pairs.each_with_object({}) do |(key, value), new_pairs| - new_pairs[key.to_i] = Time.at(value.to_i).to_s(:db) - end - end -end diff --git a/changelogs/custom_wiki_sidebar.yml b/changelogs/custom_wiki_sidebar.yml new file mode 100644 index 00000000000..988fccc929c --- /dev/null +++ b/changelogs/custom_wiki_sidebar.yml @@ -0,0 +1,5 @@ +--- +title: "Custom Wiki Sidebar Support Issue 14995" +merge_request: +author: Josh Sooter +type: added diff --git a/changelogs/unreleased/18141-osw-use-monospaced-font-on-diffs-commit-ref.yml b/changelogs/unreleased/18141-osw-use-monospaced-font-on-diffs-commit-ref.yml deleted file mode 100644 index 43ff880a8cb..00000000000 --- a/changelogs/unreleased/18141-osw-use-monospaced-font-on-diffs-commit-ref.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use monospaced font for MR diff commit link ref on GFM -merge_request: -author: -type: other diff --git a/changelogs/unreleased/19439-api-file-sha56-and-head.yml b/changelogs/unreleased/19439-api-file-sha56-and-head.yml deleted file mode 100644 index 4bc1e560631..00000000000 --- a/changelogs/unreleased/19439-api-file-sha56-and-head.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add SHA256 and HEAD on File API -merge_request: 19439 -author: ahmet2mir -type: added diff --git a/changelogs/unreleased/19468-add_readme_when_creating_project.yml b/changelogs/unreleased/19468-add_readme_when_creating_project.yml deleted file mode 100644 index f85fc773ef0..00000000000 --- a/changelogs/unreleased/19468-add_readme_when_creating_project.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add option to add README when creating a project -merge_request: 20335 -author: -type: added diff --git a/changelogs/unreleased/20357.yml b/changelogs/unreleased/20357.yml deleted file mode 100644 index b4ce686eece..00000000000 --- a/changelogs/unreleased/20357.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix double "in" in time to artifact deletion message -merge_request: 20357 -author: "@bbodenmiller" -type: fixed diff --git a/changelogs/unreleased/23705-add-single-file-download-in-repo.yml b/changelogs/unreleased/23705-add-single-file-download-in-repo.yml new file mode 100644 index 00000000000..f156bfb1101 --- /dev/null +++ b/changelogs/unreleased/23705-add-single-file-download-in-repo.yml @@ -0,0 +1,5 @@ +--- +title: Add download button for single file (including raw files) in repository +merge_request: 20480 +author: Kia Mei Somabes +type: added diff --git a/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml b/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml new file mode 100644 index 00000000000..55d82c4ee5d --- /dev/null +++ b/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml @@ -0,0 +1,5 @@ +--- +title: Improve feedback when a developer is unable to push to an empty repository +merge_request: 20519 +author: +type: changed diff --git a/changelogs/unreleased/31583-osw-gfm-complete-status-indication.yml b/changelogs/unreleased/31583-osw-gfm-complete-status-indication.yml deleted file mode 100644 index 6f2cf275592..00000000000 --- a/changelogs/unreleased/31583-osw-gfm-complete-status-indication.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Present state indication on GFM preview -merge_request: -author: -type: added diff --git a/changelogs/unreleased/35158-snippets-api-visibility.yml b/changelogs/unreleased/35158-snippets-api-visibility.yml deleted file mode 100644 index f06015dda46..00000000000 --- a/changelogs/unreleased/35158-snippets-api-visibility.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expose visibility via Snippets API -merge_request: 19620 -author: Jan Beckmann -type: added diff --git a/changelogs/unreleased/36234-nav-add-groups-dropdown.yml b/changelogs/unreleased/36234-nav-add-groups-dropdown.yml deleted file mode 100644 index 86a24102665..00000000000 --- a/changelogs/unreleased/36234-nav-add-groups-dropdown.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add dropdown to Groups link in top bar -merge_request: 18280 -author: -type: added diff --git a/changelogs/unreleased/36907-fix-new-issue-link-from-failed-job.yml b/changelogs/unreleased/36907-fix-new-issue-link-from-failed-job.yml deleted file mode 100644 index 80a50734f72..00000000000 --- a/changelogs/unreleased/36907-fix-new-issue-link-from-failed-job.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix link to job when creating a new issue from a failed job -merge_request: 20328 -author: -type: fixed diff --git a/changelogs/unreleased/37561-add-id-settings.yml b/changelogs/unreleased/37561-add-id-settings.yml deleted file mode 100644 index 122ac23cb53..00000000000 --- a/changelogs/unreleased/37561-add-id-settings.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allows settings sections to expand by default when linking to them -merge_request: 20211 -author: -type: other diff --git a/changelogs/unreleased/39543-milestone-page-list-redesign.yml b/changelogs/unreleased/39543-milestone-page-list-redesign.yml deleted file mode 100644 index dcd73c5eddf..00000000000 --- a/changelogs/unreleased/39543-milestone-page-list-redesign.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Milestone page list redesign -merge_request: 19832 -author: Constance Okoghenun -type: changed diff --git a/changelogs/unreleased/39604-update-top-right-avatar-after-changing-avatar.yml b/changelogs/unreleased/39604-update-top-right-avatar-after-changing-avatar.yml deleted file mode 100644 index 17192673996..00000000000 --- a/changelogs/unreleased/39604-update-top-right-avatar-after-changing-avatar.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change avatar image in the header when user updates their avatar. -merge_request: 20119 -author: Jamie Schembri -type: added diff --git a/changelogs/unreleased/40005-u2f-unspported-browsers.yml b/changelogs/unreleased/40005-u2f-unspported-browsers.yml deleted file mode 100644 index eb5ff99246e..00000000000 --- a/changelogs/unreleased/40005-u2f-unspported-browsers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve U2F workflow when using unsupported browsers -merge_request: 19938 -author: Jan Beckmann -type: changed diff --git a/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml b/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml deleted file mode 100644 index f4b34909ae9..00000000000 --- a/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Keep lists ordered when copying only list items -merge_request: 18522 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/41784-monitoring-graph-popovers.yml b/changelogs/unreleased/41784-monitoring-graph-popovers.yml new file mode 100644 index 00000000000..757445d7e0c --- /dev/null +++ b/changelogs/unreleased/41784-monitoring-graph-popovers.yml @@ -0,0 +1,5 @@ +--- +title: Update design for system metrics popovers +merge_request: 20655 +author: +type: fixed diff --git a/changelogs/unreleased/42342-teams-pipeline-notifications.yml b/changelogs/unreleased/42342-teams-pipeline-notifications.yml deleted file mode 100644 index 4ef3a35465b..00000000000 --- a/changelogs/unreleased/42342-teams-pipeline-notifications.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes Microsoft Teams notifications for pipeline events -merge_request: 19632 -author: Jeff Brown -type: fixed diff --git a/changelogs/unreleased/43270-import-with-milestones-failing.yml b/changelogs/unreleased/43270-import-with-milestones-failing.yml deleted file mode 100644 index 13bf8072376..00000000000 --- a/changelogs/unreleased/43270-import-with-milestones-failing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix label and milestone duplicated records and IID errors -merge_request: 19961 -author: -type: fixed diff --git a/changelogs/unreleased/43312-remove_user_activity_workers.yml b/changelogs/unreleased/43312-remove_user_activity_workers.yml new file mode 100644 index 00000000000..6dfd018e350 --- /dev/null +++ b/changelogs/unreleased/43312-remove_user_activity_workers.yml @@ -0,0 +1,5 @@ +--- +title: Delete UserActivities and related workers +merge_request: 20597 +author: +type: performance diff --git a/changelogs/unreleased/43446-new-cluster-page-tabs.yml b/changelogs/unreleased/43446-new-cluster-page-tabs.yml deleted file mode 100644 index e8c73257b16..00000000000 --- a/changelogs/unreleased/43446-new-cluster-page-tabs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create new or add existing Kubernetes cluster from a single page -merge_request: 18963 -author: -type: changed diff --git a/changelogs/unreleased/43472-remove-environment-scope-field-on-cluster-creation-form-for-core-starter-plans.yml b/changelogs/unreleased/43472-remove-environment-scope-field-on-cluster-creation-form-for-core-starter-plans.yml deleted file mode 100644 index 7d2804f0310..00000000000 --- a/changelogs/unreleased/43472-remove-environment-scope-field-on-cluster-creation-form-for-core-starter-plans.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes the environment scope field for users that cannot edit it -merge_request: 19643 -author: -type: changed diff --git a/changelogs/unreleased/44674-use-one-column-form-layout-on-admin-area-settings-page.yml b/changelogs/unreleased/44674-use-one-column-form-layout-on-admin-area-settings-page.yml deleted file mode 100644 index 69733889d5a..00000000000 --- a/changelogs/unreleased/44674-use-one-column-form-layout-on-admin-area-settings-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use one column form layout on Admin Area Settings page -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/44697-when-editing-a-comment-in-an-issue-the-preview-mode-is-toggled-in-the-main-textarea.yml b/changelogs/unreleased/44697-when-editing-a-comment-in-an-issue-the-preview-mode-is-toggled-in-the-main-textarea.yml deleted file mode 100644 index 750e28f1a8d..00000000000 --- a/changelogs/unreleased/44697-when-editing-a-comment-in-an-issue-the-preview-mode-is-toggled-in-the-main-textarea.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fixed bug when editing a comment in an issue,the preview mode is toggled in - the main textarea -merge_request: 20112 -author: Constance Okoghenun -type: fixed diff --git a/changelogs/unreleased/44725-expire_correct_methods_after_change_head.yml b/changelogs/unreleased/44725-expire_correct_methods_after_change_head.yml deleted file mode 100644 index 21a65f142c3..00000000000 --- a/changelogs/unreleased/44725-expire_correct_methods_after_change_head.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expire correct method caches after HEAD changed -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/4525-fix-project-indexes.yml b/changelogs/unreleased/4525-fix-project-indexes.yml new file mode 100644 index 00000000000..930e3b934c2 --- /dev/null +++ b/changelogs/unreleased/4525-fix-project-indexes.yml @@ -0,0 +1,5 @@ +--- +title: Rework some projects table indexes around repository_storage field +merge_request: 20377 +author: +type: fixed diff --git a/changelogs/unreleased/45400-automatically-created-mr-uses-wrong-target-branch-when-branching-from-tag.yml b/changelogs/unreleased/45400-automatically-created-mr-uses-wrong-target-branch-when-branching-from-tag.yml deleted file mode 100644 index 5aba62435ed..00000000000 --- a/changelogs/unreleased/45400-automatically-created-mr-uses-wrong-target-branch-when-branching-from-tag.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Set MR target branch to default branch if target branch is not valid -merge_request: 19067 -author: -type: fixed diff --git a/changelogs/unreleased/45443-unable-to-save-user-profile-update-with-safari.yml b/changelogs/unreleased/45443-unable-to-save-user-profile-update-with-safari.yml new file mode 100644 index 00000000000..b18f7aec546 --- /dev/null +++ b/changelogs/unreleased/45443-unable-to-save-user-profile-update-with-safari.yml @@ -0,0 +1,5 @@ +--- +title: Resolve "Unable to save user profile update with Safari" +merge_request: 20676 +author: +type: fixed diff --git a/changelogs/unreleased/45487-slack-tag-push-notifs.yml b/changelogs/unreleased/45487-slack-tag-push-notifs.yml deleted file mode 100644 index 647000bd97c..00000000000 --- a/changelogs/unreleased/45487-slack-tag-push-notifs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix chat service tag notifications not sending when only default branch enabled -merge_request: 19864 -author: -type: fixed diff --git a/changelogs/unreleased/45557-machine-type-help-links.yml b/changelogs/unreleased/45557-machine-type-help-links.yml deleted file mode 100644 index 870a650e10b..00000000000 --- a/changelogs/unreleased/45557-machine-type-help-links.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Add machine type and pricing documentation links, add class to labels to make - bold -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/45575-invalid-characters-signup.yml b/changelogs/unreleased/45575-invalid-characters-signup.yml deleted file mode 100644 index 679bd13e59b..00000000000 --- a/changelogs/unreleased/45575-invalid-characters-signup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Fix username validation order on signup, resolves #45575' -merge_request: 19610 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/45703-open-web-ide-file-tree.yml b/changelogs/unreleased/45703-open-web-ide-file-tree.yml deleted file mode 100644 index abee9cad2d5..00000000000 --- a/changelogs/unreleased/45703-open-web-ide-file-tree.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update WebIDE to show file in tree on load -merge_request: 19887 -author: -type: changed diff --git a/changelogs/unreleased/45738-add-environment-drop-down-to-metrics-dashboard.yml b/changelogs/unreleased/45738-add-environment-drop-down-to-metrics-dashboard.yml deleted file mode 100644 index 5aaeaaf0448..00000000000 --- a/changelogs/unreleased/45738-add-environment-drop-down-to-metrics-dashboard.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add environment dropdown for the metrics page -merge_request: 19833 -author: -type: changed diff --git a/changelogs/unreleased/45933-webide-fade-uneditable-area.yml b/changelogs/unreleased/45933-webide-fade-uneditable-area.yml deleted file mode 100644 index dfb186122e7..00000000000 --- a/changelogs/unreleased/45933-webide-fade-uneditable-area.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fade uneditable area in Web IDE -merge_request: 20008 -author: -type: changed diff --git a/changelogs/unreleased/46202-webide-file-states.yml b/changelogs/unreleased/46202-webide-file-states.yml deleted file mode 100644 index 8d697b643be..00000000000 --- a/changelogs/unreleased/46202-webide-file-states.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update Web IDE file tree styles -merge_request: 19969 -author: -type: changed diff --git a/changelogs/unreleased/46246-gitlab-project-export-should-use-object-storage.yml b/changelogs/unreleased/46246-gitlab-project-export-should-use-object-storage.yml deleted file mode 100644 index 908c7a238fd..00000000000 --- a/changelogs/unreleased/46246-gitlab-project-export-should-use-object-storage.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add Object Storage to project export -merge_request: 20105 -author: -type: added diff --git a/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key-part-1.yml b/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key-part-1.yml deleted file mode 100644 index d8c7d612c3d..00000000000 --- a/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key-part-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update new SSH key page to improve copy -merge_request: 19994 -author: -type: other diff --git a/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key.yml b/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key.yml deleted file mode 100644 index 64bbecf3405..00000000000 --- a/changelogs/unreleased/46396-recognise-when-a-user-is-trying-to-validate-a-private-ssh-key.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update new SSH key page to improve key input validation -merge_request: 19997 -author: -type: other diff --git a/changelogs/unreleased/46429-creating-a-deploy-token-doesn-t-bring-back-to-the-creation-page.yml b/changelogs/unreleased/46429-creating-a-deploy-token-doesn-t-bring-back-to-the-creation-page.yml deleted file mode 100644 index b564fb0174f..00000000000 --- a/changelogs/unreleased/46429-creating-a-deploy-token-doesn-t-bring-back-to-the-creation-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allows you to create another deploy token dimmediately after creating one -merge_request: 19639 -author: -type: changed diff --git a/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml b/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml deleted file mode 100644 index 7d42d971022..00000000000 --- a/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: CE port gitlab-ee!6112 -merge_request: 19714 -author: -type: other diff --git a/changelogs/unreleased/46571-webhooks-nil-password.yml b/changelogs/unreleased/46571-webhooks-nil-password.yml deleted file mode 100644 index 34c5f09478f..00000000000 --- a/changelogs/unreleased/46571-webhooks-nil-password.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix webhook error when password is not present -merge_request: 19945 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/46783-removed-omniauth-provider-causing-invalid-application-setting.yml b/changelogs/unreleased/46783-removed-omniauth-provider-causing-invalid-application-setting.yml deleted file mode 100644 index d5ecf5163d4..00000000000 --- a/changelogs/unreleased/46783-removed-omniauth-provider-causing-invalid-application-setting.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Ignore unknown OAuth sources in ApplicationSetting -merge_request: 20129 -author: -type: fixed diff --git a/changelogs/unreleased/46831-remove-unused-bootstrap-component-css.yml b/changelogs/unreleased/46831-remove-unused-bootstrap-component-css.yml deleted file mode 100644 index e0e2b481b69..00000000000 --- a/changelogs/unreleased/46831-remove-unused-bootstrap-component-css.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes unused bootstrap 4 scss files -merge_request: 19423 -author: -type: deprecated diff --git a/changelogs/unreleased/46861-issuable-title-with-longer-username.yml b/changelogs/unreleased/46861-issuable-title-with-longer-username.yml deleted file mode 100644 index 9df6879deb6..00000000000 --- a/changelogs/unreleased/46861-issuable-title-with-longer-username.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix CSS for buttons not to be hidden on issues/MR title -merge_request: 19176 -author: Takuya Noguchi -type: fixed diff --git a/changelogs/unreleased/46869-deploy-tokens-failed-to-clone-lfs-repository.yml b/changelogs/unreleased/46869-deploy-tokens-failed-to-clone-lfs-repository.yml new file mode 100644 index 00000000000..d490df58144 --- /dev/null +++ b/changelogs/unreleased/46869-deploy-tokens-failed-to-clone-lfs-repository.yml @@ -0,0 +1,5 @@ +--- +title: Allow cloning LFS repositories through DeployTokens +merge_request: 20729 +author: +type: other diff --git a/changelogs/unreleased/46963-add_readme_button_for_non_empty_project.yml b/changelogs/unreleased/46963-add_readme_button_for_non_empty_project.yml deleted file mode 100644 index fdf41a26c4d..00000000000 --- a/changelogs/unreleased/46963-add_readme_button_for_non_empty_project.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add readme button to non-empty project page -merge_request: 20104 -author: -type: fixed diff --git a/changelogs/unreleased/47040-inconsistent-job-list-in-job-details-view.yml b/changelogs/unreleased/47040-inconsistent-job-list-in-job-details-view.yml deleted file mode 100644 index 5629a40a1f1..00000000000 --- a/changelogs/unreleased/47040-inconsistent-job-list-in-job-details-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show jobs from same pipeline in sidebar in job details view. -merge_request: 20243 -author: -type: fixed diff --git a/changelogs/unreleased/47050-quick-actions-case-insensitive.yml b/changelogs/unreleased/47050-quick-actions-case-insensitive.yml deleted file mode 100644 index 176aba627b9..00000000000 --- a/changelogs/unreleased/47050-quick-actions-case-insensitive.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make quick commands case insensitive -merge_request: 19614 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/47145-quick-actions-confidential.yml b/changelogs/unreleased/47145-quick-actions-confidential.yml deleted file mode 100644 index 7ae4e2268af..00000000000 --- a/changelogs/unreleased/47145-quick-actions-confidential.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add /confidential quick action -merge_request: -author: Jan Beckmann -type: added diff --git a/changelogs/unreleased/47221-explain-what-groups-are-in-the-new-group-page.yml b/changelogs/unreleased/47221-explain-what-groups-are-in-the-new-group-page.yml deleted file mode 100644 index 94c58a3863a..00000000000 --- a/changelogs/unreleased/47221-explain-what-groups-are-in-the-new-group-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update new group page to better explain what groups are -merge_request: 19991 -author: -type: other diff --git a/changelogs/unreleased/47274-help-users-find-our-contributing-page.yml b/changelogs/unreleased/47274-help-users-find-our-contributing-page.yml deleted file mode 100644 index ed13c917a2e..00000000000 --- a/changelogs/unreleased/47274-help-users-find-our-contributing-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add a link to the contributing page in the user dropdown -merge_request: 19708 -author: -type: added diff --git a/changelogs/unreleased/47419-Fix-breadcrumbs.yml b/changelogs/unreleased/47419-Fix-breadcrumbs.yml new file mode 100644 index 00000000000..1a7f8196683 --- /dev/null +++ b/changelogs/unreleased/47419-Fix-breadcrumbs.yml @@ -0,0 +1,5 @@ +--- +title: Fix breadcrumbs in Admin/User interface. +merge_request: 19608 +author: Robin Naundorf +type: fixed diff --git a/changelogs/unreleased/47462-issues-disabled-group-page.yml b/changelogs/unreleased/47462-issues-disabled-group-page.yml deleted file mode 100644 index c8cad608cb3..00000000000 --- a/changelogs/unreleased/47462-issues-disabled-group-page.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Only show new issue / new merge request on group page when issues / merge requests - are enabled -merge_request: 19869 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/47631-operations-kubernetes-option-is-always-visible-when-repository-or-builds-are-disabled.yml b/changelogs/unreleased/47631-operations-kubernetes-option-is-always-visible-when-repository-or-builds-are-disabled.yml deleted file mode 100644 index 5c23b3ef320..00000000000 --- a/changelogs/unreleased/47631-operations-kubernetes-option-is-always-visible-when-repository-or-builds-are-disabled.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Omits operartions and kubernetes item from project sidebar when repository or builds are disabled -merge_request: 19835 -author: -type: fixed diff --git a/changelogs/unreleased/47794-environment-scope-cluster-page.yml b/changelogs/unreleased/47794-environment-scope-cluster-page.yml deleted file mode 100644 index 75eb7ec209c..00000000000 --- a/changelogs/unreleased/47794-environment-scope-cluster-page.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Change environment scope text depending on number of project clusters. Update - form to only include form-groups -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/47865-changelog-for-style-updates.yml b/changelogs/unreleased/47865-changelog-for-style-updates.yml deleted file mode 100644 index 2e4fbbda000..00000000000 --- a/changelogs/unreleased/47865-changelog-for-style-updates.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Minor style changes to personal access token form and scope checkboxes -merge_request: 20052 -author: -type: other diff --git a/changelogs/unreleased/48036-fix-web-ide-blob-crash.yml b/changelogs/unreleased/48036-fix-web-ide-blob-crash.yml new file mode 100644 index 00000000000..6ff209b5181 --- /dev/null +++ b/changelogs/unreleased/48036-fix-web-ide-blob-crash.yml @@ -0,0 +1,5 @@ +--- +title: Fix Web IDE crashing on directories named 'blob' +merge_request: 20712 +author: +type: fixed diff --git a/changelogs/unreleased/48050-add-full-commit-sha.yml b/changelogs/unreleased/48050-add-full-commit-sha.yml deleted file mode 100644 index 30376fe35e0..00000000000 --- a/changelogs/unreleased/48050-add-full-commit-sha.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Uses long sha version of the merged commit in MR widget copy to clipboard button -merge_request: 19955 -author: -type: other diff --git a/changelogs/unreleased/48100-fix-branch-not-shown.yml b/changelogs/unreleased/48100-fix-branch-not-shown.yml deleted file mode 100644 index 917c5c23f67..00000000000 --- a/changelogs/unreleased/48100-fix-branch-not-shown.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix branches are not shown in Merge Request dropdown when preferred language - is not English -merge_request: 20016 -author: Hiroyuki Sato -type: fixed diff --git a/changelogs/unreleased/48153-date-selection-dialog-broken-when-creating-a-new-milestone.yml b/changelogs/unreleased/48153-date-selection-dialog-broken-when-creating-a-new-milestone.yml deleted file mode 100644 index 13ab5b0467d..00000000000 --- a/changelogs/unreleased/48153-date-selection-dialog-broken-when-creating-a-new-milestone.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent browser autocomplete for milestone date fields -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/48237-toggle-file-comments.yml b/changelogs/unreleased/48237-toggle-file-comments.yml deleted file mode 100644 index 2e893aad0b2..00000000000 --- a/changelogs/unreleased/48237-toggle-file-comments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes toggle discussion button not expanding collapsed discussions -merge_request: 20452 -author: -type: fixed diff --git a/changelogs/unreleased/48378-avatar-upload.yml b/changelogs/unreleased/48378-avatar-upload.yml deleted file mode 100644 index 1e359ee72d5..00000000000 --- a/changelogs/unreleased/48378-avatar-upload.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes issue with uploading same image to Profile Avatar twice -merge_request: 20161 -author: Chirag Bhatia -type: fixed diff --git a/changelogs/unreleased/48497-merge-request-refactor-displays-changes-dropdown-incorrectly.yml b/changelogs/unreleased/48497-merge-request-refactor-displays-changes-dropdown-incorrectly.yml deleted file mode 100644 index 41af2f8cc4f..00000000000 --- a/changelogs/unreleased/48497-merge-request-refactor-displays-changes-dropdown-incorrectly.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed Merge request changes dropdown displays incorrectly -merge_request: 20237 -author: Constance Okoghenun -type: fixed diff --git a/changelogs/unreleased/48515-sql-queries-are-not-shown-from-the-performance-bar-in-safari.yml b/changelogs/unreleased/48515-sql-queries-are-not-shown-from-the-performance-bar-in-safari.yml deleted file mode 100644 index 65c59dbf31f..00000000000 --- a/changelogs/unreleased/48515-sql-queries-are-not-shown-from-the-performance-bar-in-safari.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix performance bar modal visibility in Safari -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml b/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml deleted file mode 100644 index 575767df912..00000000000 --- a/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add option to hide third party offers in admin application settings -merge_request: 20379 -author: -type: added diff --git a/changelogs/unreleased/48603-merge-request-refactor-title-and-copy-to-clipboard-button-are-behind-the-action-buttons.yml b/changelogs/unreleased/48603-merge-request-refactor-title-and-copy-to-clipboard-button-are-behind-the-action-buttons.yml deleted file mode 100644 index 792c7814f7e..00000000000 --- a/changelogs/unreleased/48603-merge-request-refactor-title-and-copy-to-clipboard-button-are-behind-the-action-buttons.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix overlapping file title and file actions in MR changes tag -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/48634-header-navbar-line-separator-is-missing.yml b/changelogs/unreleased/48634-header-navbar-line-separator-is-missing.yml deleted file mode 100644 index 92d9295982e..00000000000 --- a/changelogs/unreleased/48634-header-navbar-line-separator-is-missing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Line separator to the left of the 'Admin area' wrench icon had vanished -merge_request: 20282 -author: bitsapien -type: fixed diff --git a/changelogs/unreleased/48661-node-6-and-7-compatibility-broken-by-recent-monaco-editor-upgrade.yml b/changelogs/unreleased/48661-node-6-and-7-compatibility-broken-by-recent-monaco-editor-upgrade.yml deleted file mode 100644 index 36a4b5f754d..00000000000 --- a/changelogs/unreleased/48661-node-6-and-7-compatibility-broken-by-recent-monaco-editor-upgrade.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve compatibility issues with node 6 -merge_request: 20461 -author: -type: fixed diff --git a/changelogs/unreleased/48670-application-settings-may-not-be-invalidated-if-migrations-are-run.yml b/changelogs/unreleased/48670-application-settings-may-not-be-invalidated-if-migrations-are-run.yml deleted file mode 100644 index f4267582f89..00000000000 --- a/changelogs/unreleased/48670-application-settings-may-not-be-invalidated-if-migrations-are-run.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Stop relying on migrations in the CacheableAttributes cache key and cache attributes - for 1 minute instead -merge_request: 20389 -author: -type: fixed diff --git a/changelogs/unreleased/48677-also-check-auto_sign_in_with_provider.yml b/changelogs/unreleased/48677-also-check-auto_sign_in_with_provider.yml deleted file mode 100644 index 3021fe6b9c8..00000000000 --- a/changelogs/unreleased/48677-also-check-auto_sign_in_with_provider.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Load Devise with Omniauth when auto_sign_in_with_provider is configured -merge_request: 20302 -author: -type: fixed diff --git a/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml b/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml new file mode 100644 index 00000000000..7552e0d3878 --- /dev/null +++ b/changelogs/unreleased/48745-project-exports-fail-when-uploads-have-been-migrated-to-object-storage.yml @@ -0,0 +1,5 @@ +--- +title: Add uploader support to Import/Export uploads +merge_request: 20484 +author: +type: added diff --git a/changelogs/unreleased/48789-remove-event-listeners-scroll.yml b/changelogs/unreleased/48789-remove-event-listeners-scroll.yml deleted file mode 100644 index 9cc3f7adc36..00000000000 --- a/changelogs/unreleased/48789-remove-event-listeners-scroll.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Improves performance on Merge Request diff tab by removing the scroll event - listeners being added to every file -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/ide-commit-actions-update.yml b/changelogs/unreleased/48804-redesign-gcp-banner.yml index 35bee94e156..729f959badc 100644 --- a/changelogs/unreleased/ide-commit-actions-update.yml +++ b/changelogs/unreleased/48804-redesign-gcp-banner.yml @@ -1,5 +1,5 @@ --- -title: Improve Web IDE commit flow +title: Redesign GCP offer banner merge_request: author: type: changed diff --git a/changelogs/unreleased/48817-fix-mr-changes-discussion-navigation.yml b/changelogs/unreleased/48817-fix-mr-changes-discussion-navigation.yml new file mode 100644 index 00000000000..ec4b843b863 --- /dev/null +++ b/changelogs/unreleased/48817-fix-mr-changes-discussion-navigation.yml @@ -0,0 +1,5 @@ +--- +title: Fix navigation to First and Next discussion on MR Changes tab +merge_request: 20434 +author: +type: fixed diff --git a/changelogs/unreleased/48825-performance.yml b/changelogs/unreleased/48825-performance.yml deleted file mode 100644 index 428852f6f8b..00000000000 --- a/changelogs/unreleased/48825-performance.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Improves performance of mr code, by fixing the state being mutated outside - of the store in the util function trimFirstCharOfLineContent and in map operations. - Avoids map operation in an empty array. Adds specs to the trimFirstCharOfLineContent - function -merge_request: 20380 -author: filipa -type: performance diff --git a/changelogs/unreleased/48932-disable-saml-if-omniauth-is-disabled.yml b/changelogs/unreleased/48932-disable-saml-if-omniauth-is-disabled.yml new file mode 100644 index 00000000000..0466debea65 --- /dev/null +++ b/changelogs/unreleased/48932-disable-saml-if-omniauth-is-disabled.yml @@ -0,0 +1,5 @@ +--- +title: Disable SAML and Bitbucket if OmniAuth is disabled +merge_request: 20608 +author: +type: fixed diff --git a/changelogs/unreleased/48951-clean-up.yml b/changelogs/unreleased/48951-clean-up.yml deleted file mode 100644 index 0102cd43f96..00000000000 --- a/changelogs/unreleased/48951-clean-up.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes unused vuex code in mr refactor and removes unneeded dependencies -merge_request: 20499 -author: -type: other diff --git a/changelogs/unreleased/48978-fix-helm-installation-on-cluster.yml b/changelogs/unreleased/48978-fix-helm-installation-on-cluster.yml deleted file mode 100644 index f786d9e2235..00000000000 --- a/changelogs/unreleased/48978-fix-helm-installation-on-cluster.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes base command used in Helm installations -merge_request: 20471 -author: -type: fixed diff --git a/changelogs/unreleased/49291-fix-memory-graph-component-typo.yml b/changelogs/unreleased/49291-fix-memory-graph-component-typo.yml new file mode 100644 index 00000000000..f21bd454e84 --- /dev/null +++ b/changelogs/unreleased/49291-fix-memory-graph-component-typo.yml @@ -0,0 +1,5 @@ +--- +title: Fix typo in CSS transform property for Memory Graph component +merge_request: 20650 +author: +type: fixed diff --git a/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml b/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml new file mode 100644 index 00000000000..a87eef3f7f3 --- /dev/null +++ b/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml @@ -0,0 +1,5 @@ +--- +title: Add support for tar.gz AUTO_DEVOPS_CHART charts (#49324) +merge_request: 20691 +author: '@kondi1' +type: added diff --git a/changelogs/unreleased/_acet-fix-expanding-context-lines.yml b/changelogs/unreleased/_acet-fix-expanding-context-lines.yml new file mode 100644 index 00000000000..41b4dbca5d6 --- /dev/null +++ b/changelogs/unreleased/_acet-fix-expanding-context-lines.yml @@ -0,0 +1,5 @@ +--- +title: Fix rendering of the context lines in MR diffs page +merge_request: 20642 +author: +type: fixed diff --git a/changelogs/unreleased/_acet-fix-mr-autosave.yml b/changelogs/unreleased/_acet-fix-mr-autosave.yml new file mode 100644 index 00000000000..f87b32f68e2 --- /dev/null +++ b/changelogs/unreleased/_acet-fix-mr-autosave.yml @@ -0,0 +1,5 @@ +--- +title: Fix autosave and ESC confirmation issues for MR discussions +merge_request: 20569 +author: +type: fixed diff --git a/changelogs/unreleased/_acet-fix-outdated-discussions.yml b/changelogs/unreleased/_acet-fix-outdated-discussions.yml new file mode 100644 index 00000000000..d31483b4765 --- /dev/null +++ b/changelogs/unreleased/_acet-fix-outdated-discussions.yml @@ -0,0 +1,5 @@ +--- +title: Fix showing outdated discussions on Changes tab +merge_request: 20445 +author: +type: fixed diff --git a/changelogs/unreleased/accept-rf3-2822-compliant-addresses.yml b/changelogs/unreleased/accept-rf3-2822-compliant-addresses.yml new file mode 100644 index 00000000000..97d017613ba --- /dev/null +++ b/changelogs/unreleased/accept-rf3-2822-compliant-addresses.yml @@ -0,0 +1,5 @@ +--- +title: Emails on push recipients now accepts formats like John Doe <johndoe@example.com> +merge_request: +author: George Thomas +type: added diff --git a/changelogs/unreleased/add-merge-request-header-branch-details-right-margin.yml b/changelogs/unreleased/add-merge-request-header-branch-details-right-margin.yml new file mode 100644 index 00000000000..4f9a551d13e --- /dev/null +++ b/changelogs/unreleased/add-merge-request-header-branch-details-right-margin.yml @@ -0,0 +1,5 @@ +--- +title: Add merge request header branch actions left margin +merge_request: 20643 +author: George Tsiolis +type: changed diff --git a/changelogs/unreleased/add-missing-index-for-deployments.yml b/changelogs/unreleased/add-missing-index-for-deployments.yml deleted file mode 100644 index 7863c0ee039..00000000000 --- a/changelogs/unreleased/add-missing-index-for-deployments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add index on deployable_type/id for deployments -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/add-more-rebase-logging.yml b/changelogs/unreleased/add-more-rebase-logging.yml deleted file mode 100644 index a7d1c3aa664..00000000000 --- a/changelogs/unreleased/add-more-rebase-logging.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add more detailed logging to githost.log when rebasing -merge_request: -author: -type: other diff --git a/changelogs/unreleased/add-title-placeholder-for-new-issues.yml b/changelogs/unreleased/add-title-placeholder-for-new-issues.yml deleted file mode 100644 index ce9e3b4ac18..00000000000 --- a/changelogs/unreleased/add-title-placeholder-for-new-issues.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add title placeholder for new issues -merge_request: 20271 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/add-total-time-flat-printer-for-profiling.yml b/changelogs/unreleased/add-total-time-flat-printer-for-profiling.yml new file mode 100644 index 00000000000..37a4e31896e --- /dev/null +++ b/changelogs/unreleased/add-total-time-flat-printer-for-profiling.yml @@ -0,0 +1,6 @@ +--- +title: Add a Gitlab::Profiler.print_by_total_time convenience method for profiling + from a Rails console +merge_request: +author: +type: other diff --git a/changelogs/unreleased/an-no-healthcheck-until-brooklyn.yml b/changelogs/unreleased/an-no-healthcheck-until-brooklyn.yml deleted file mode 100644 index 4942688d00f..00000000000 --- a/changelogs/unreleased/an-no-healthcheck-until-brooklyn.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove healthchecks from prometheus endpoint -merge_request: 20565 -author: -type: fixed diff --git a/changelogs/unreleased/author-doc-fix.yml b/changelogs/unreleased/author-doc-fix.yml deleted file mode 100644 index 83521543239..00000000000 --- a/changelogs/unreleased/author-doc-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix fields for author & assignee in MR API docs. -merge_request: 19798 -author: gfyoung -type: fixed diff --git a/changelogs/unreleased/backstage-gb-stages-position-migration-clean-up.yml b/changelogs/unreleased/backstage-gb-stages-position-migration-clean-up.yml deleted file mode 100644 index d2ada88870b..00000000000 --- a/changelogs/unreleased/backstage-gb-stages-position-migration-clean-up.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fully migrate pipeline stages position -merge_request: 19369 -author: -type: performance diff --git a/changelogs/unreleased/bjk-48176_ruby_gc.yml b/changelogs/unreleased/bjk-48176_ruby_gc.yml deleted file mode 100644 index 45c6338df81..00000000000 --- a/changelogs/unreleased/bjk-48176_ruby_gc.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cleanup Prometheus ruby metrics -merge_request: 20039 -author: Ben Kochie -type: fixed diff --git a/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml b/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml deleted file mode 100644 index 69d49f3e3e0..00000000000 --- a/changelogs/unreleased/blackst0ne-add-gemfile-rails5-lock-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add CI job to check Gemfile.rails5.lock -merge_request: 19605 -author: "@blackst0ne" -type: other diff --git a/changelogs/unreleased/blackst0ne-bump-grape-path-helpers-gem-to-1-0-5.yml b/changelogs/unreleased/blackst0ne-bump-grape-path-helpers-gem-to-1-0-5.yml deleted file mode 100644 index 9d975ff81bf..00000000000 --- a/changelogs/unreleased/blackst0ne-bump-grape-path-helpers-gem-to-1-0-5.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump grape-path-helpers to 1.0.5 -merge_request: 19604 -author: "@blackst0ne" -type: other diff --git a/changelogs/unreleased/blackst0ne-fix-protect-from-forgery-in-application-controller.yml b/changelogs/unreleased/blackst0ne-fix-protect-from-forgery-in-application-controller.yml deleted file mode 100644 index da75ea8b09e..00000000000 --- a/changelogs/unreleased/blackst0ne-fix-protect-from-forgery-in-application-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Force the callback run first" -merge_request: 20055 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-activerecord-statementinvalid-mysql2-error-expression-1-of-select-list-is-not-in-group-by-clause.yml b/changelogs/unreleased/blackst0ne-rails5-activerecord-statementinvalid-mysql2-error-expression-1-of-select-list-is-not-in-group-by-clause.yml deleted file mode 100644 index d9cccc49830..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-activerecord-statementinvalid-mysql2-error-expression-1-of-select-list-is-not-in-group-by-clause.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix milestone GROUP BY query" -merge_request: 20256 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-expected-search-search-seed_project-got-nil.yml b/changelogs/unreleased/blackst0ne-rails5-expected-search-search-seed_project-got-nil.yml deleted file mode 100644 index e7bb2703b03..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-expected-search-search-seed_project-got-nil.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix sessions_controller_spec" -merge_request: 19936 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-expected-the-response-to-have-status-code-ok-but-it-was-404.yml b/changelogs/unreleased/blackst0ne-rails5-expected-the-response-to-have-status-code-ok-but-it-was-404.yml deleted file mode 100644 index fad15de2dd5..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-expected-the-response-to-have-status-code-ok-but-it-was-404.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Set request.format for artifacts_controller" -merge_request: 19937 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-fix-blob-requests-format.yml b/changelogs/unreleased/blackst0ne-rails5-fix-blob-requests-format.yml deleted file mode 100644 index a83aa03606a..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-fix-blob-requests-format.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Explicitly set request.format for blob_controller" -merge_request: 19876 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-fix-data-store-spec.yml b/changelogs/unreleased/blackst0ne-rails5-fix-data-store-spec.yml deleted file mode 100644 index 403c3764321..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-fix-data-store-spec.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: '[Rails5] Fix "-1 is not a valid data_store"' -merge_request: 19917 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-fix-optimistic-lock-values.yml b/changelogs/unreleased/blackst0ne-rails5-fix-optimistic-lock-values.yml deleted file mode 100644 index 1915dff73ab..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-fix-optimistic-lock-values.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix optimistic lock value" -merge_request: 19878 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-fix-pipeline-schedules-controller-spec.yml b/changelogs/unreleased/blackst0ne-rails5-fix-pipeline-schedules-controller-spec.yml deleted file mode 100644 index 7a2b19ad681..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-fix-pipeline-schedules-controller-spec.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix pipeline_schedules_controller_spec" -merge_request: 19919 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-fix-snippets-finder.yml b/changelogs/unreleased/blackst0ne-rails5-fix-snippets-finder.yml deleted file mode 100644 index 597b85de26f..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-fix-snippets-finder.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix snippets_finder arel queries" -merge_request: 19796 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-found-new-routes-that-could-cause-conflicts-with-existing-namespaced-routes.yml b/changelogs/unreleased/blackst0ne-rails5-found-new-routes-that-could-cause-conflicts-with-existing-namespaced-routes.yml deleted file mode 100644 index c8d916af824..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-found-new-routes-that-could-cause-conflicts-with-existing-namespaced-routes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Fix ActionCable '/cable' mountpoint conflict" -merge_request: 20015 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-invalid-single-table-inheritance-type-group-is-not-a-subclass-of-namespace.yml b/changelogs/unreleased/blackst0ne-rails5-invalid-single-table-inheritance-type-group-is-not-a-subclass-of-namespace.yml deleted file mode 100644 index 92e6ce35941..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-invalid-single-table-inheritance-type-group-is-not-a-subclass-of-namespace.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "[Rails5] Invalid single-table inheritance type: Group is not a subclass of - Namespace" -merge_request: 19918 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/blackst0ne-rails5-set-request-format-in--commits-controller.yml b/changelogs/unreleased/blackst0ne-rails5-set-request-format-in--commits-controller.yml deleted file mode 100644 index 3f8f8fd5d66..00000000000 --- a/changelogs/unreleased/blackst0ne-rails5-set-request-format-in--commits-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "[Rails5] Set request.format in commits_controller" -merge_request: 20023 -author: "@blackst0ne" -type: fixed diff --git a/changelogs/unreleased/build-chunks-on-object-storage.yml b/changelogs/unreleased/build-chunks-on-object-storage.yml deleted file mode 100644 index 9f36dfee378..00000000000 --- a/changelogs/unreleased/build-chunks-on-object-storage.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Use object storage as the first class persistable store for new live trace - architecture -merge_request: 19515 -author: -type: changed diff --git a/changelogs/unreleased/bump-carrierwave-to-1-2-3.yml b/changelogs/unreleased/bump-carrierwave-to-1-2-3.yml deleted file mode 100644 index 373ac48553e..00000000000 --- a/changelogs/unreleased/bump-carrierwave-to-1-2-3.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump carrierwave gem verion to 1.2.3 -merge_request: 20287 -author: -type: performance diff --git a/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml b/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml deleted file mode 100644 index 54154ad2449..00000000000 --- a/changelogs/unreleased/bvl-fix-maintainer-push-rejected.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix bug where maintainer would not be allowed to push to forks with merge requests - that have `Allow maintainer edits` enabled. -merge_request: 18968 -author: -type: fixed diff --git a/changelogs/unreleased/bvl-graphql-nested-merge-request.yml b/changelogs/unreleased/bvl-graphql-nested-merge-request.yml deleted file mode 100644 index f0f0488d31a..00000000000 --- a/changelogs/unreleased/bvl-graphql-nested-merge-request.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow querying a single merge request within a project -merge_request: 19853 -author: -type: changed diff --git a/changelogs/unreleased/bvl-graphql-permissions.yml b/changelogs/unreleased/bvl-graphql-permissions.yml deleted file mode 100644 index 42d5e24bb15..00000000000 --- a/changelogs/unreleased/bvl-graphql-permissions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Expose permissions of the current user on resources in GraphQL' -merge_request: 20152 -author: -type: added diff --git a/changelogs/unreleased/bvl-graphql-pipeline-lists.yml b/changelogs/unreleased/bvl-graphql-pipeline-lists.yml deleted file mode 100644 index be258dc12ad..00000000000 --- a/changelogs/unreleased/bvl-graphql-pipeline-lists.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add pipeline lists to GraphQL -merge_request: 20249 -author: -type: added diff --git a/changelogs/unreleased/bvl-preload-parents-after-pagination.yml b/changelogs/unreleased/bvl-preload-parents-after-pagination.yml deleted file mode 100644 index ff3d4716d34..00000000000 --- a/changelogs/unreleased/bvl-preload-parents-after-pagination.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reduce the number of queries when searching for groups -merge_request: 20398 -author: -type: performance diff --git a/changelogs/unreleased/bw-enable-commonmark.yml b/changelogs/unreleased/bw-enable-commonmark.yml deleted file mode 100644 index 89252e5063d..00000000000 --- a/changelogs/unreleased/bw-enable-commonmark.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use CommonMark syntax and rendering for new Markdown content -merge_request: 19331 -author: -type: added diff --git a/changelogs/unreleased/cache-doc-fix.yml b/changelogs/unreleased/cache-doc-fix.yml deleted file mode 100644 index db4726a92e9..00000000000 --- a/changelogs/unreleased/cache-doc-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Remove incorrect CI doc re: PowerShell' -merge_request: 19622 -author: gfyoung -type: fixed diff --git a/changelogs/unreleased/ce-5024-filename-search.yml b/changelogs/unreleased/ce-5024-filename-search.yml deleted file mode 100644 index a8bf9b1f802..00000000000 --- a/changelogs/unreleased/ce-5024-filename-search.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add filename filtering to code search -merge_request: 19509 -author: -type: added diff --git a/changelogs/unreleased/close-revert-and-cherry-pick-modal-on-escape-keypress.yml b/changelogs/unreleased/close-revert-and-cherry-pick-modal-on-escape-keypress.yml new file mode 100644 index 00000000000..49648cdfcfc --- /dev/null +++ b/changelogs/unreleased/close-revert-and-cherry-pick-modal-on-escape-keypress.yml @@ -0,0 +1,5 @@ +--- +title: Close revert and cherry pick modal on escape keypress +merge_request: 20341 +author: George Tsiolis +type: changed diff --git a/changelogs/unreleased/close-revoke-deploy-token-modal-on-escape-keypress.yml b/changelogs/unreleased/close-revoke-deploy-token-modal-on-escape-keypress.yml deleted file mode 100644 index 98316cae406..00000000000 --- a/changelogs/unreleased/close-revoke-deploy-token-modal-on-escape-keypress.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Close revoke deploy token modal on escape keypress -merge_request: 20347 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/commits_api_with_stats.yml b/changelogs/unreleased/commits_api_with_stats.yml deleted file mode 100644 index 4357f1a6305..00000000000 --- a/changelogs/unreleased/commits_api_with_stats.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added with_statsoption for GET /projects/:id/repository/commits -merge_request: -author: -type: added diff --git a/changelogs/unreleased/cr-add-locked-state-to-MR.yml b/changelogs/unreleased/cr-add-locked-state-to-MR.yml deleted file mode 100644 index f290ddc0b87..00000000000 --- a/changelogs/unreleased/cr-add-locked-state-to-MR.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds the `locked` state to the merge request API so that it can be used as a search filter. -merge_request: 20186 -author: -type: fixed diff --git a/changelogs/unreleased/cr-keep-issue-labels.yml b/changelogs/unreleased/cr-keep-issue-labels.yml deleted file mode 100644 index 051e7faffea..00000000000 --- a/changelogs/unreleased/cr-keep-issue-labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Keeps the label on an issue when the issue is moved. -merge_request: 20036 -author: -type: fixed diff --git a/changelogs/unreleased/da-port-cte-to-ce.yml b/changelogs/unreleased/da-port-cte-to-ce.yml deleted file mode 100644 index 6fa759fcf7d..00000000000 --- a/changelogs/unreleased/da-port-cte-to-ce.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add Gitlab::SQL:CTE for easily building CTE statements -merge_request: -author: -type: added diff --git a/changelogs/unreleased/db-configure-after-drop-tables.yml b/changelogs/unreleased/db-configure-after-drop-tables.yml deleted file mode 100644 index 00844b334fa..00000000000 --- a/changelogs/unreleased/db-configure-after-drop-tables.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes an issue where migrations instead of schema loading were run -merge_request: 20227 -author: -type: changed diff --git a/changelogs/unreleased/dm-blockquote-trailing-whitespace.yml b/changelogs/unreleased/dm-blockquote-trailing-whitespace.yml deleted file mode 100644 index 98ecdde4f4c..00000000000 --- a/changelogs/unreleased/dm-blockquote-trailing-whitespace.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow trailing whitespace on blockquote fence lines -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-branch-api-can-push.yml b/changelogs/unreleased/dm-branch-api-can-push.yml deleted file mode 100644 index 3be8962089b..00000000000 --- a/changelogs/unreleased/dm-branch-api-can-push.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expose whether current user can push into a branch on branches API -merge_request: -author: -type: added diff --git a/changelogs/unreleased/dm-invalid-active-service-template.yml b/changelogs/unreleased/dm-invalid-active-service-template.yml deleted file mode 100644 index 8b77fac55b9..00000000000 --- a/changelogs/unreleased/dm-invalid-active-service-template.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Deactivate new KubernetesService created from active template to prevent project creation from failing -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-label-reference-period.yml b/changelogs/unreleased/dm-label-reference-period.yml deleted file mode 100644 index 9fdd590641d..00000000000 --- a/changelogs/unreleased/dm-label-reference-period.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Properly detect label reference if followed by period or question mark -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-user-without-projects-performance.yml b/changelogs/unreleased/dm-user-without-projects-performance.yml deleted file mode 100644 index e7fc0ae6d54..00000000000 --- a/changelogs/unreleased/dm-user-without-projects-performance.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve performance of listing users without projects -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/existing-gcp-accounts.yml b/changelogs/unreleased/existing-gcp-accounts.yml deleted file mode 100644 index ce396c70b4a..00000000000 --- a/changelogs/unreleased/existing-gcp-accounts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add back copy for existing gcp accounts within offer banner -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/expose-ci-url.yml b/changelogs/unreleased/expose-ci-url.yml deleted file mode 100644 index b6ad7d18e0d..00000000000 --- a/changelogs/unreleased/expose-ci-url.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add CI_PIPELINE_URL and CI_JOB_URL -merge_request: 19618 -author: -type: added diff --git a/changelogs/unreleased/feature-gb-email-delivery-metrics.yml b/changelogs/unreleased/feature-gb-email-delivery-metrics.yml new file mode 100644 index 00000000000..9d0d08a471d --- /dev/null +++ b/changelogs/unreleased/feature-gb-email-delivery-metrics.yml @@ -0,0 +1,5 @@ +--- +title: Add emails delivery Prometheus metrics +merge_request: 20638 +author: +type: added diff --git a/changelogs/unreleased/feature-oidc-subject-claim.yml b/changelogs/unreleased/feature-oidc-subject-claim.yml deleted file mode 100644 index e995ca26234..00000000000 --- a/changelogs/unreleased/feature-oidc-subject-claim.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't hash user ID in OIDC subject claim -merge_request: 19784 -author: Markus Koller -type: changed diff --git a/changelogs/unreleased/features-show-project-id-on-home-panel.yml b/changelogs/unreleased/features-show-project-id-on-home-panel.yml new file mode 100644 index 00000000000..f592be07a52 --- /dev/null +++ b/changelogs/unreleased/features-show-project-id-on-home-panel.yml @@ -0,0 +1,5 @@ +--- +title: Show Project ID on project home panel +merge_request: 20305 +author: Tuğçe Nur Taş +type: added diff --git a/changelogs/unreleased/fix-boards-issue-highlight.yml b/changelogs/unreleased/fix-boards-issue-highlight.yml deleted file mode 100644 index 0cc3faa81ca..00000000000 --- a/changelogs/unreleased/fix-boards-issue-highlight.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix boards issue highlight -merge_request: 20063 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/fix-br-decode.yml b/changelogs/unreleased/fix-br-decode.yml deleted file mode 100644 index 66ecc3deb35..00000000000 --- a/changelogs/unreleased/fix-br-decode.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: mergeError message has been binded using v-html directive -merge_request: 19058 -author: Murat Dogan -type: fixed diff --git a/changelogs/unreleased/fix-diff-note.yml b/changelogs/unreleased/fix-diff-note.yml new file mode 100644 index 00000000000..6f10f86b9bc --- /dev/null +++ b/changelogs/unreleased/fix-diff-note.yml @@ -0,0 +1,5 @@ +--- +title: Fix serialization of LegacyDiffNote +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-filename-for-direct-uploads.yml b/changelogs/unreleased/fix-filename-for-direct-uploads.yml new file mode 100644 index 00000000000..a1bbf3704c0 --- /dev/null +++ b/changelogs/unreleased/fix-filename-for-direct-uploads.yml @@ -0,0 +1,5 @@ +--- +title: Fix filename for accelerated uploads +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-gb-add-missing-before-sha-predefined-variable.yml b/changelogs/unreleased/fix-gb-add-missing-before-sha-predefined-variable.yml new file mode 100644 index 00000000000..7e9e8c33a71 --- /dev/null +++ b/changelogs/unreleased/fix-gb-add-missing-before-sha-predefined-variable.yml @@ -0,0 +1,5 @@ +--- +title: Add missing predefined variable and fix docs +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-gb-fix-deserializing-ci-yaml-variables.yml b/changelogs/unreleased/fix-gb-fix-deserializing-ci-yaml-variables.yml new file mode 100644 index 00000000000..80b069c9251 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-deserializing-ci-yaml-variables.yml @@ -0,0 +1,5 @@ +--- +title: Fix accessing imported pipeline builds +merge_request: 20713 +author: +type: fixed diff --git a/changelogs/unreleased/fix-gb-fix-project-settings-build-time-validation.yml b/changelogs/unreleased/fix-gb-fix-project-settings-build-time-validation.yml new file mode 100644 index 00000000000..adf582e34a2 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-project-settings-build-time-validation.yml @@ -0,0 +1,5 @@ +--- +title: Limit maximum project build timeout setting to 1 month +merge_request: 20591 +author: +type: fixed diff --git a/changelogs/unreleased/fix-gitaly-mr-creation-limits.yml b/changelogs/unreleased/fix-gitaly-mr-creation-limits.yml deleted file mode 100644 index e903f2e5277..00000000000 --- a/changelogs/unreleased/fix-gitaly-mr-creation-limits.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix merge request diffs when created with gitaly_diff_between enabled -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-groups-api-ordering.yml b/changelogs/unreleased/fix-groups-api-ordering.yml deleted file mode 100644 index 3a6a7f84356..00000000000 --- a/changelogs/unreleased/fix-groups-api-ordering.yml +++ /dev/null @@ -1,4 +0,0 @@ -title: Fixed pagination of groups API -merge_request: 19665 -author: Marko, Peter -type: added diff --git a/changelogs/unreleased/fix-last-commit-author-link-is-blue.yml b/changelogs/unreleased/fix-last-commit-author-link-is-blue.yml deleted file mode 100644 index aaceeaecfb1..00000000000 --- a/changelogs/unreleased/fix-last-commit-author-link-is-blue.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Updated last commit link color -merge_request: 20234 -author: Constance Okoghenun -type: fixed diff --git a/changelogs/unreleased/fix-paragraph-line-height-for-emoji.yml b/changelogs/unreleased/fix-paragraph-line-height-for-emoji.yml deleted file mode 100644 index 5aaf0fac60e..00000000000 --- a/changelogs/unreleased/fix-paragraph-line-height-for-emoji.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix paragraph line height for emoji -merge_request: 20137 -author: George Tsiolis -type: fixed diff --git a/changelogs/unreleased/fix-performance-problem-of-tags-query.yml b/changelogs/unreleased/fix-performance-problem-of-tags-query.yml deleted file mode 100644 index 4649775be9c..00000000000 --- a/changelogs/unreleased/fix-performance-problem-of-tags-query.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix performance problem of accessing tag list for projects api endpoints -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/fix-project-api-archived.yml b/changelogs/unreleased/fix-project-api-archived.yml new file mode 100644 index 00000000000..9d119fd3429 --- /dev/null +++ b/changelogs/unreleased/fix-project-api-archived.yml @@ -0,0 +1,5 @@ +--- +title: Fix archived parameter for projects API +merge_request: 20566 +author: Peter Marko +type: fixed diff --git a/changelogs/unreleased/fix-trace-archive-cron-worker-race-condition.yml b/changelogs/unreleased/fix-trace-archive-cron-worker-race-condition.yml deleted file mode 100644 index ca8f4252008..00000000000 --- a/changelogs/unreleased/fix-trace-archive-cron-worker-race-condition.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Check if archived trace exist before archive it -merge_request: 20297 -author: -type: fixed diff --git a/changelogs/unreleased/fix-web-ide-disable-markdown-autocomplete.yml b/changelogs/unreleased/fix-web-ide-disable-markdown-autocomplete.yml deleted file mode 100644 index 6a4d9b6c8c4..00000000000 --- a/changelogs/unreleased/fix-web-ide-disable-markdown-autocomplete.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disabled Web IDE autocomplete suggestions for Markdown files. -merge_request: -author: Isaac Smith -type: fixed diff --git a/changelogs/unreleased/fj-43565-wrong-role-displayed.yml b/changelogs/unreleased/fj-43565-wrong-role-displayed.yml deleted file mode 100644 index 67ff25bc50c..00000000000 --- a/changelogs/unreleased/fj-43565-wrong-role-displayed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix wrong role badge displayed in projects dashboard -merge_request: 20374 -author: -type: fixed diff --git a/changelogs/unreleased/fj-46278-apply-doorkeeper-scope-patch.yml b/changelogs/unreleased/fj-46278-apply-doorkeeper-scope-patch.yml deleted file mode 100644 index 1f4de2cb490..00000000000 --- a/changelogs/unreleased/fj-46278-apply-doorkeeper-scope-patch.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix OAuth Application Authorization screen to appear with each access -merge_request: 20216 -author: -type: fixed diff --git a/changelogs/unreleased/fj-46278-enable-doorkeeper-reuse-access-token.yml b/changelogs/unreleased/fj-46278-enable-doorkeeper-reuse-access-token.yml deleted file mode 100644 index 0994f4de248..00000000000 --- a/changelogs/unreleased/fj-46278-enable-doorkeeper-reuse-access-token.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Enable Doorkeeper option to avoid generating new tokens when users login via - oauth -merge_request: 20200 -author: -type: fixed diff --git a/changelogs/unreleased/fj-48123-fix-gitlab-import.yml b/changelogs/unreleased/fj-48123-fix-gitlab-import.yml new file mode 100644 index 00000000000..896db2cdcb8 --- /dev/null +++ b/changelogs/unreleased/fj-48123-fix-gitlab-import.yml @@ -0,0 +1,5 @@ +--- +title: Fix GitLab project imports not loading due to API timeouts +merge_request: 20599 +author: +type: fixed diff --git a/changelogs/unreleased/fj-49014-wiki-search-error.yml b/changelogs/unreleased/fj-49014-wiki-search-error.yml new file mode 100644 index 00000000000..a76805cb7f9 --- /dev/null +++ b/changelogs/unreleased/fj-49014-wiki-search-error.yml @@ -0,0 +1,5 @@ +--- +title: Fixed bug with invalid repository reference using the wiki search +merge_request: 20722 +author: +type: fixed diff --git a/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml b/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml deleted file mode 100644 index 3b4d429707f..00000000000 --- a/changelogs/unreleased/fj-bumping-gollum-lib-and-gollum-rugged-adapter.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed bug that allowed to remove other wiki pages if the title had wildcard characters -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fj-web-terminal-ci-build.yml b/changelogs/unreleased/fj-web-terminal-ci-build.yml deleted file mode 100644 index c3608d4203b..00000000000 --- a/changelogs/unreleased/fj-web-terminal-ci-build.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add Web Terminal for Ci Builds -merge_request: -author: Vicky Chijwani -type: added diff --git a/changelogs/unreleased/fl-mr-refactor-performance-improvements.yml b/changelogs/unreleased/fl-mr-refactor-performance-improvements.yml deleted file mode 100644 index 649d1b5da67..00000000000 --- a/changelogs/unreleased/fl-mr-refactor-performance-improvements.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Structure getters for diff Store properly and adds specs -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/frozen-string-app-workers.yml b/changelogs/unreleased/frozen-string-app-workers.yml deleted file mode 100644 index 48b50cc6ca4..00000000000 --- a/changelogs/unreleased/frozen-string-app-workers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable frozen string in app/workers/*.rb -merge_request: 19944 -author: gfyoung -type: other diff --git a/changelogs/unreleased/frozen-string-enable-app-services.yml b/changelogs/unreleased/frozen-string-enable-app-services.yml new file mode 100644 index 00000000000..cfc1f356e3a --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-app-services.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen string in apps/uploaders/*.rb +merge_request: 20401 +author: gfyoung +type: other diff --git a/changelogs/unreleased/frozen-string-enable-app-uploaders.yml b/changelogs/unreleased/frozen-string-enable-app-uploaders.yml deleted file mode 100644 index d43ca8bed8c..00000000000 --- a/changelogs/unreleased/frozen-string-enable-app-uploaders.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable frozen string in apps/validators/*.rb -merge_request: 20382 -author: gfyoung -type: other diff --git a/changelogs/unreleased/frozen-string-enable-app-validators.yml b/changelogs/unreleased/frozen-string-enable-app-validators.yml deleted file mode 100644 index db480b06d9b..00000000000 --- a/changelogs/unreleased/frozen-string-enable-app-validators.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable frozen string in apps/validators/*.rb -merge_request: 20220 -author: gfyoung -type: other diff --git a/changelogs/unreleased/frozen-string-enable-app-workers-2.yml b/changelogs/unreleased/frozen-string-enable-app-workers-2.yml deleted file mode 100644 index 81de6899d76..00000000000 --- a/changelogs/unreleased/frozen-string-enable-app-workers-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Finish enabling frozen string for app/workers/*.rb -merge_request: 20197 -author: gfyoung -type: other diff --git a/changelogs/unreleased/frozen-string-enable-apps-services-inner-even-more.yml b/changelogs/unreleased/frozen-string-enable-apps-services-inner-even-more.yml new file mode 100644 index 00000000000..cee790a07ff --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-apps-services-inner-even-more.yml @@ -0,0 +1,5 @@ +--- +title: Enable even more frozen string in app/services/**/*.rb +merge_request: 20702 +author: gfyoung +type: performance diff --git a/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml b/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml new file mode 100644 index 00000000000..ea962cf8edc --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml @@ -0,0 +1,5 @@ +--- +title: Enable more frozen string in app/services/**/*.rb +merge_request: 20677 +author: gfyoung +type: performance diff --git a/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml b/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml new file mode 100644 index 00000000000..16b8ec3908f --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen string in app/services/**/*.rb +merge_request: 20656 +author: gfyoung +type: performance diff --git a/changelogs/unreleased/gitaly-commit-count-opt-out.yml b/changelogs/unreleased/gitaly-commit-count-opt-out.yml deleted file mode 100644 index fd8298b1d7b..00000000000 --- a/changelogs/unreleased/gitaly-commit-count-opt-out.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move some Gitaly RPC's to opt-out -merge_request: 19591 -author: -type: other diff --git a/changelogs/unreleased/gitaly-ff-branch-nil.yml b/changelogs/unreleased/gitaly-ff-branch-nil.yml new file mode 100644 index 00000000000..e7e689e6053 --- /dev/null +++ b/changelogs/unreleased/gitaly-ff-branch-nil.yml @@ -0,0 +1,5 @@ +--- +title: Add missing Gitaly branch_update nil checks +merge_request: 20711 +author: +type: fixed diff --git a/changelogs/unreleased/gitaly-opt-out-branch-tag.yml b/changelogs/unreleased/gitaly-opt-out-branch-tag.yml deleted file mode 100644 index 750fc863eed..00000000000 --- a/changelogs/unreleased/gitaly-opt-out-branch-tag.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move Gitaly branch/tag/ref RPC's to opt-out -merge_request: 19644 -author: -type: other diff --git a/changelogs/unreleased/gitaly-serverservice-info-timeout.yml b/changelogs/unreleased/gitaly-serverservice-info-timeout.yml deleted file mode 100644 index 7f2fe8b9c93..00000000000 --- a/changelogs/unreleased/gitaly-serverservice-info-timeout.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use appropriate timeout on Gitaly server info checks, avoid error on timeout -merge_request: 20552 -author: -type: fixed diff --git a/changelogs/unreleased/gitaly-timeouts.yml b/changelogs/unreleased/gitaly-timeouts.yml deleted file mode 100644 index ac8008faa2d..00000000000 --- a/changelogs/unreleased/gitaly-timeouts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Updated Gitaly fail-fast timeout values -merge_request: !20259 -author: -type: performance diff --git a/changelogs/unreleased/hangouts_chat_integration.yml b/changelogs/unreleased/hangouts_chat_integration.yml new file mode 100644 index 00000000000..bf3484a6d02 --- /dev/null +++ b/changelogs/unreleased/hangouts_chat_integration.yml @@ -0,0 +1,5 @@ +--- +title: Add Hangouts Chat integration +merge_request: 20290 +author: Kukovskii Vladimir +type: added diff --git a/changelogs/unreleased/highlight-cluster-settings-message.yml b/changelogs/unreleased/highlight-cluster-settings-message.yml deleted file mode 100644 index 4e029941c51..00000000000 --- a/changelogs/unreleased/highlight-cluster-settings-message.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Highlight cluster settings message -merge_request: 19996 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/ide-merge-request-info.yml b/changelogs/unreleased/ide-merge-request-info.yml deleted file mode 100644 index 104f48ae309..00000000000 --- a/changelogs/unreleased/ide-merge-request-info.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Display merge request title & description in Web IDE -merge_request: -author: -type: added diff --git a/changelogs/unreleased/jprovazn-delete-upload-worker.yml b/changelogs/unreleased/jprovazn-delete-upload-worker.yml deleted file mode 100644 index 52916482d32..00000000000 --- a/changelogs/unreleased/jprovazn-delete-upload-worker.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove deprecated object_storage_upload queue. -merge_request: -author: -type: removed diff --git a/changelogs/unreleased/jprovazn-direct-upload.yml b/changelogs/unreleased/jprovazn-direct-upload.yml deleted file mode 100644 index 57f6d1e07c3..00000000000 --- a/changelogs/unreleased/jprovazn-direct-upload.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Support direct_upload for generic uploads -merge_request: -author: -type: added diff --git a/changelogs/unreleased/jprovazn-extra-line.yml b/changelogs/unreleased/jprovazn-extra-line.yml deleted file mode 100644 index 2628620f8ec..00000000000 --- a/changelogs/unreleased/jprovazn-extra-line.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't show context button for diffs of deleted files. -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/jprovazn-fix-mr-caching.yml b/changelogs/unreleased/jprovazn-fix-mr-caching.yml deleted file mode 100644 index 7ad7ed54143..00000000000 --- a/changelogs/unreleased/jprovazn-fix-mr-caching.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Invalidate merge request diffs cache if diff data change. -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/jprovazn-label-links-update.yml b/changelogs/unreleased/jprovazn-label-links-update.yml deleted file mode 100644 index 75fb46ede6b..00000000000 --- a/changelogs/unreleased/jprovazn-label-links-update.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix cross-project label references. -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/jprovazn-upload-symlink.yml b/changelogs/unreleased/jprovazn-upload-symlink.yml deleted file mode 100644 index 265791d332f..00000000000 --- a/changelogs/unreleased/jprovazn-upload-symlink.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add /uploads subdirectory to allowed upload paths. -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/jr-48133-web-ide-commit-ellipsis.yml b/changelogs/unreleased/jr-48133-web-ide-commit-ellipsis.yml deleted file mode 100644 index ac58eaccaaf..00000000000 --- a/changelogs/unreleased/jr-48133-web-ide-commit-ellipsis.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add ellispsis to web ide commit button -merge_request: 20030 -author: -type: other diff --git a/changelogs/unreleased/jupyter-image.yml b/changelogs/unreleased/jupyter-image.yml new file mode 100644 index 00000000000..8aeefd603d8 --- /dev/null +++ b/changelogs/unreleased/jupyter-image.yml @@ -0,0 +1,5 @@ +--- +title: Rubix, scikit-learn, tensorflow & other useful libraries pre-installed with JupyterHub +merge_request: 20714 +author: Amit Rathi +type: changed diff --git a/changelogs/unreleased/limit-metrics-content-type.yml b/changelogs/unreleased/limit-metrics-content-type.yml deleted file mode 100644 index 42cb4347771..00000000000 --- a/changelogs/unreleased/limit-metrics-content-type.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Limit the action suffixes in transaction metrics -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/more-group-api-sorting-options.yml b/changelogs/unreleased/more-group-api-sorting-options.yml deleted file mode 100644 index b29f76a65a9..00000000000 --- a/changelogs/unreleased/more-group-api-sorting-options.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added id sorting option to GET groups and subgroups API -merge_request: 19665 -author: Marko, Peter -type: added diff --git a/changelogs/unreleased/move-boards-modal-empty-state-vue-component.yml b/changelogs/unreleased/move-boards-modal-empty-state-vue-component.yml deleted file mode 100644 index 54a61d7c914..00000000000 --- a/changelogs/unreleased/move-boards-modal-empty-state-vue-component.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move boards modal EmptyState vue component -merge_request: 20068 -author: George Tsiolis -type: performance diff --git a/changelogs/unreleased/no-multi-assign-enable.yml b/changelogs/unreleased/no-multi-assign-enable.yml deleted file mode 100644 index bb9c69b18e7..00000000000 --- a/changelogs/unreleased/no-multi-assign-enable.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable no-multi-assignment in JS files -merge_request: 19808 -author: gfyoung -type: other diff --git a/changelogs/unreleased/no-multi-assign-follow-up.yml b/changelogs/unreleased/no-multi-assign-follow-up.yml deleted file mode 100644 index 817760ff649..00000000000 --- a/changelogs/unreleased/no-multi-assign-follow-up.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve no-multi-assignment fixes after enabling rule -merge_request: 19915 -author: gfyoung -type: other diff --git a/changelogs/unreleased/no-restricted-globals-enable.yml b/changelogs/unreleased/no-restricted-globals-enable.yml deleted file mode 100644 index 1fa2eac0d03..00000000000 --- a/changelogs/unreleased/no-restricted-globals-enable.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable no-restricted globals in JS files -merge_request: 19877 -author: gfyoung -type: other diff --git a/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-migration.yml b/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-migration.yml deleted file mode 100644 index e4cbae1a109..00000000000 --- a/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-migration.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Schedule workers to delete non-latest diffs in post-migration -merge_request: -author: -type: other diff --git a/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-upon-merge.yml b/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-upon-merge.yml deleted file mode 100644 index 3e752125f3a..00000000000 --- a/changelogs/unreleased/osw-delete-non-latest-mr-diff-files-upon-merge.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Delete non-latest merge request diff files upon merge -merge_request: -author: -type: other diff --git a/changelogs/unreleased/osw-mark-as-merged-as-first-post-merge-action.yml b/changelogs/unreleased/osw-mark-as-merged-as-first-post-merge-action.yml deleted file mode 100644 index 2049afc3d44..00000000000 --- a/changelogs/unreleased/osw-mark-as-merged-as-first-post-merge-action.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Mark MR as merged regardless of errors when closing issues -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/perf-wiki-pattern-once.yml b/changelogs/unreleased/perf-wiki-pattern-once.yml deleted file mode 100644 index fb4085a06ae..00000000000 --- a/changelogs/unreleased/perf-wiki-pattern-once.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve render performance of large wiki pages -merge_request: 20465 -author: Peter Leitzen -type: performance diff --git a/changelogs/unreleased/pr-importer-io-extra-error-handling.yml b/changelogs/unreleased/pr-importer-io-extra-error-handling.yml deleted file mode 100644 index 2f7121b2840..00000000000 --- a/changelogs/unreleased/pr-importer-io-extra-error-handling.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Ensure MR diffs always exist in the PR importer -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/prefer-destructuring-fix.yml b/changelogs/unreleased/prefer-destructuring-fix.yml deleted file mode 100644 index 452e04f553e..00000000000 --- a/changelogs/unreleased/prefer-destructuring-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable prefer-structuring in JS files -merge_request: 19943 -author: gfyoung -type: other diff --git a/changelogs/unreleased/project-dropdown-list-overflow.yml b/changelogs/unreleased/project-dropdown-list-overflow.yml new file mode 100644 index 00000000000..9b74a68291b --- /dev/null +++ b/changelogs/unreleased/project-dropdown-list-overflow.yml @@ -0,0 +1,5 @@ +--- +title: Don't overflow project/group dropdown results +merge_request: 20704 +author: gfyoung +type: fixed diff --git a/changelogs/unreleased/project-visibility-tooltip.yml b/changelogs/unreleased/project-visibility-tooltip.yml new file mode 100644 index 00000000000..806c93e493a --- /dev/null +++ b/changelogs/unreleased/project-visibility-tooltip.yml @@ -0,0 +1,5 @@ +--- +title: Fix project visibility tooltip +merge_request: 20535 +author: Jamie Schembri +type: fixed diff --git a/changelogs/unreleased/prune-web-hook-logs.yml b/changelogs/unreleased/prune-web-hook-logs.yml deleted file mode 100644 index e8c805b2a92..00000000000 --- a/changelogs/unreleased/prune-web-hook-logs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prune web hook logs older than 90 days -merge_request: -author: -type: added diff --git a/changelogs/unreleased/rails5-fix-46276.yml b/changelogs/unreleased/rails5-fix-46276.yml deleted file mode 100644 index cdca91a755d..00000000000 --- a/changelogs/unreleased/rails5-fix-46276.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix format in uploads actions -merge_request: 19907 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47366.yml b/changelogs/unreleased/rails5-fix-47366.yml deleted file mode 100644 index 7ea03d2b95e..00000000000 --- a/changelogs/unreleased/rails5-fix-47366.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix expected `issuable.reload.updated_at` to have changed -merge_request: 19733 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47370.yml b/changelogs/unreleased/rails5-fix-47370.yml deleted file mode 100644 index 90c19593b7d..00000000000 --- a/changelogs/unreleased/rails5-fix-47370.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use same gem versions for rails5 as for rails4 where possible -merge_request: 19498 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47804.yml b/changelogs/unreleased/rails5-fix-47804.yml deleted file mode 100644 index 3332ed3bbaa..00000000000 --- a/changelogs/unreleased/rails5-fix-47804.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix stack level too deep -merge_request: 19762 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47805.yml b/changelogs/unreleased/rails5-fix-47805.yml deleted file mode 100644 index 8bd8ad5488c..00000000000 --- a/changelogs/unreleased/rails5-fix-47805.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Rails5 ActionController::ParameterMissing: param is missing or the value is - empty: application_setting' -merge_request: 19763 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47835.yml b/changelogs/unreleased/rails5-fix-47835.yml deleted file mode 100644 index fe9cbf1a03a..00000000000 --- a/changelogs/unreleased/rails5-fix-47835.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Rails5 fix no implicit conversion of Hash into String. ActionController::Parameters - no longer returns an hash in Rails 5 -merge_request: 19792 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47836.yml b/changelogs/unreleased/rails5-fix-47836.yml deleted file mode 100644 index 2aef2db607a..00000000000 --- a/changelogs/unreleased/rails5-fix-47836.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Rails5 fix passing Group objects array into for_projects_and_groups milestone - scope -merge_request: 19863 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-47960.yml b/changelogs/unreleased/rails5-fix-47960.yml deleted file mode 100644 index 2229511ccd6..00000000000 --- a/changelogs/unreleased/rails5-fix-47960.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix update_attribute usage not causing a save -merge_request: 19881 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48009.yml b/changelogs/unreleased/rails5-fix-48009.yml deleted file mode 100644 index 7ade9ef2b7d..00000000000 --- a/changelogs/unreleased/rails5-fix-48009.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 update Gemfile.rails5.lock -merge_request: 19921 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48012.yml b/changelogs/unreleased/rails5-fix-48012.yml deleted file mode 100644 index 953ccbd8af7..00000000000 --- a/changelogs/unreleased/rails5-fix-48012.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Rails5 fix passing Group objects array into for_projects_and_groups milestone - scope -merge_request: 19920 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48104.yml b/changelogs/unreleased/rails5-fix-48104.yml deleted file mode 100644 index 6cf519ad791..00000000000 --- a/changelogs/unreleased/rails5-fix-48104.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Rails5 fix expected: 1 time with arguments: (97, anything, {"squash"=>false}) - received: 0 times' -merge_request: 20004 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48140.yml b/changelogs/unreleased/rails5-fix-48140.yml deleted file mode 100644 index a6992803e5a..00000000000 --- a/changelogs/unreleased/rails5-fix-48140.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Rails 5 fix Capybara::ElementNotFound: Unable to find visible css #modal-revert-commit - and expected: "/bar" got: "/foo"' -merge_request: 20044 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48141.yml b/changelogs/unreleased/rails5-fix-48141.yml deleted file mode 100644 index 5e2aa23b8fb..00000000000 --- a/changelogs/unreleased/rails5-fix-48141.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Rails5 fix expected: 0 times with any arguments received: 1 time with arguments: - DashboardController' -merge_request: 20018 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48142.yml b/changelogs/unreleased/rails5-fix-48142.yml deleted file mode 100644 index bfd95cfbe8b..00000000000 --- a/changelogs/unreleased/rails5-fix-48142.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix Admin::HooksController -merge_request: 20017 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48430.yml b/changelogs/unreleased/rails5-fix-48430.yml deleted file mode 100644 index 16495615395..00000000000 --- a/changelogs/unreleased/rails5-fix-48430.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix MySQL milliseconds problem in specs -merge_request: 20221 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-48432.yml b/changelogs/unreleased/rails5-fix-48432.yml deleted file mode 100644 index 732294447a9..00000000000 --- a/changelogs/unreleased/rails5-fix-48432.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix Mysql comparison failure caused by milliseconds problem -merge_request: 20222 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-db-check.yml b/changelogs/unreleased/rails5-fix-db-check.yml deleted file mode 100644 index ccac4619ea7..00000000000 --- a/changelogs/unreleased/rails5-fix-db-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix connection execute return integer instead of string -merge_request: 19901 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-mysql-arel-from.yml b/changelogs/unreleased/rails5-fix-mysql-arel-from.yml deleted file mode 100644 index 9883ff306f1..00000000000 --- a/changelogs/unreleased/rails5-fix-mysql-arel-from.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix arel from in mysql_median_datetime_sql -merge_request: 20167 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-pages-controller.yml b/changelogs/unreleased/rails5-fix-pages-controller.yml deleted file mode 100644 index eeb3747c4eb..00000000000 --- a/changelogs/unreleased/rails5-fix-pages-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rails5 fix Projects::PagesController spec -merge_request: 20007 -author: Jasper Maes -type: fixed diff --git a/changelogs/unreleased/rails5-fix-revert-modal-spec.yml b/changelogs/unreleased/rails5-fix-revert-modal-spec.yml new file mode 100644 index 00000000000..0637e503ca9 --- /dev/null +++ b/changelogs/unreleased/rails5-fix-revert-modal-spec.yml @@ -0,0 +1,5 @@ +--- +title: Rails5 fix user sees revert modal spec +merge_request: 20706 +author: Jasper Maes +type: fixed diff --git a/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml b/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml new file mode 100644 index 00000000000..fd5a6521882 --- /dev/null +++ b/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml @@ -0,0 +1,5 @@ +--- +title: "Cleans up display of Deploy Tokens to match Personal Access Tokens" +merge_request: 20578 +author: Marcel Amirault +type: added
\ No newline at end of file diff --git a/changelogs/unreleased/rd-33733-showing-created-date-instead-of-updated-date-in-project-lists.yml b/changelogs/unreleased/rd-33733-showing-created-date-instead-of-updated-date-in-project-lists.yml deleted file mode 100644 index 3934381b0cf..00000000000 --- a/changelogs/unreleased/rd-33733-showing-created-date-instead-of-updated-date-in-project-lists.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Invalidate cache with project details when repository is updated -merge_request: 19774 -author: -type: fixed diff --git a/changelogs/unreleased/regen-2fa-codes.yml b/changelogs/unreleased/regen-2fa-codes.yml new file mode 100644 index 00000000000..596f759df0f --- /dev/null +++ b/changelogs/unreleased/regen-2fa-codes.yml @@ -0,0 +1,5 @@ +--- +title: Added button to regenerate 2FA codes +merge_request: +author: Luke Picciau +type: added diff --git a/changelogs/unreleased/remove-allocations-gem.yml b/changelogs/unreleased/remove-allocations-gem.yml deleted file mode 100644 index e809fd26701..00000000000 --- a/changelogs/unreleased/remove-allocations-gem.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove remaining traces of the Allocations Gem -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/remove-ci_job_request_with_tags_matcher.yml b/changelogs/unreleased/remove-ci_job_request_with_tags_matcher.yml deleted file mode 100644 index b86512445d5..00000000000 --- a/changelogs/unreleased/remove-ci_job_request_with_tags_matcher.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove the ci_job_request_with_tags_matcher -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/remove-is-shared-from-ci-runners.yml b/changelogs/unreleased/remove-is-shared-from-ci-runners.yml deleted file mode 100644 index a6917431a53..00000000000 --- a/changelogs/unreleased/remove-is-shared-from-ci-runners.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove the use of `is_shared` of `Ci::Runner` -merge_request: -author: -type: other diff --git a/changelogs/unreleased/remove-link-label-vertical-alignment-property.yml b/changelogs/unreleased/remove-link-label-vertical-alignment-property.yml deleted file mode 100644 index 40ec3998b05..00000000000 --- a/changelogs/unreleased/remove-link-label-vertical-alignment-property.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change label link vertical alignment property -merge_request: 18777 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/remove-small-container-width.yml b/changelogs/unreleased/remove-small-container-width.yml deleted file mode 100644 index 1af8aafa87e..00000000000 --- a/changelogs/unreleased/remove-small-container-width.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove small container width -merge_request: 19893 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/remove-trace-efficiently.yml b/changelogs/unreleased/remove-trace-efficiently.yml deleted file mode 100644 index a6ba6d28dce..00000000000 --- a/changelogs/unreleased/remove-trace-efficiently.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove redundant query when removing trace -merge_request: 20324 -author: -type: performance diff --git a/changelogs/unreleased/revert-merge-request-discussion-buttons-padding.yml b/changelogs/unreleased/revert-merge-request-discussion-buttons-padding.yml deleted file mode 100644 index 9f11dd3dc3f..00000000000 --- a/changelogs/unreleased/revert-merge-request-discussion-buttons-padding.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Revert merge request discussion buttons padding -merge_request: 20060 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/safari-scrollbar-bug.yml b/changelogs/unreleased/safari-scrollbar-bug.yml deleted file mode 100644 index 792a66d1ada..00000000000 --- a/changelogs/unreleased/safari-scrollbar-bug.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove scrollbar in Safari in repo settings page -merge_request: 19809 -author: gfyoung -type: fixed diff --git a/changelogs/unreleased/satishperala-gitlab-ce-20720_webhooks_full_image_url.yml b/changelogs/unreleased/satishperala-gitlab-ce-20720_webhooks_full_image_url.yml new file mode 100644 index 00000000000..7bfe1b5778f --- /dev/null +++ b/changelogs/unreleased/satishperala-gitlab-ce-20720_webhooks_full_image_url.yml @@ -0,0 +1,5 @@ +--- +title: Include full image URL in webhooks for uploaded images +merge_request: 18109 +author: Satish Perala +type: changed diff --git a/changelogs/unreleased/security-2682-fix-xss-for-markdown-toc.yml b/changelogs/unreleased/security-2682-fix-xss-for-markdown-toc.yml deleted file mode 100644 index f595678c3c2..00000000000 --- a/changelogs/unreleased/security-2682-fix-xss-for-markdown-toc.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix XSS vulnerability for table of content generation -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-fj-bumping-sanitize-gem.yml b/changelogs/unreleased/security-fj-bumping-sanitize-gem.yml deleted file mode 100644 index bec1033425d..00000000000 --- a/changelogs/unreleased/security-fj-bumping-sanitize-gem.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update sanitize gem to 4.6.5 to fix HTML injection vulnerability -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-html_escape_branch_name.yml b/changelogs/unreleased/security-html_escape_branch_name.yml deleted file mode 100644 index 02d1065348f..00000000000 --- a/changelogs/unreleased/security-html_escape_branch_name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: HTML escape branch name in project graphs page -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-html_escape_usernames.yml b/changelogs/unreleased/security-html_escape_usernames.yml deleted file mode 100644 index 7e69e4ae266..00000000000 --- a/changelogs/unreleased/security-html_escape_usernames.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: HTML escape the name of the user in ProjectsHelper#link_to_member -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-rd-do-not-show-internal-info-in-public-feed.yml b/changelogs/unreleased/security-rd-do-not-show-internal-info-in-public-feed.yml deleted file mode 100644 index ff78c162dff..00000000000 --- a/changelogs/unreleased/security-rd-do-not-show-internal-info-in-public-feed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't show events from internal projects for anonymous users in public feed -merge_request: -author: -type: security diff --git a/changelogs/unreleased/sh-bump-rugged-0-27-2.yml b/changelogs/unreleased/sh-bump-rugged-0-27-2.yml deleted file mode 100644 index 6c519648b51..00000000000 --- a/changelogs/unreleased/sh-bump-rugged-0-27-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump rugged to 0.27.2 -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-bamboo-change-set.yml b/changelogs/unreleased/sh-fix-bamboo-change-set.yml deleted file mode 100644 index 85e79e17dee..00000000000 --- a/changelogs/unreleased/sh-fix-bamboo-change-set.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Bamboo CI status not showing for branch plans -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-49133.yml b/changelogs/unreleased/sh-fix-issue-49133.yml new file mode 100644 index 00000000000..847220d88b2 --- /dev/null +++ b/changelogs/unreleased/sh-fix-issue-49133.yml @@ -0,0 +1,5 @@ +--- +title: Fix symlink vulnerability in project import +merge_request: +author: +type: security diff --git a/changelogs/unreleased/sh-fix-stderr-pipe-consumption.yml b/changelogs/unreleased/sh-fix-stderr-pipe-consumption.yml new file mode 100644 index 00000000000..b7366cf2569 --- /dev/null +++ b/changelogs/unreleased/sh-fix-stderr-pipe-consumption.yml @@ -0,0 +1,5 @@ +--- +title: Avoid process deadlock in popen by consuming input pipes +merge_request: 20600 +author: +type: fixed diff --git a/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml b/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml new file mode 100644 index 00000000000..44a46b4115e --- /dev/null +++ b/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml @@ -0,0 +1,5 @@ +--- +title: Limit the TTL for anonymous sessions to 1 hour +merge_request: 20700 +author: +type: performance diff --git a/changelogs/unreleased/sh-normalize-urls.yml b/changelogs/unreleased/sh-normalize-urls.yml new file mode 100644 index 00000000000..b0d1120e10b --- /dev/null +++ b/changelogs/unreleased/sh-normalize-urls.yml @@ -0,0 +1,5 @@ +--- +title: Escape username and password in UrlSanitizer#full_url +merge_request: 20684 +author: +type: fixed diff --git a/changelogs/unreleased/sh-optimize-locks-check-ce.yml b/changelogs/unreleased/sh-optimize-locks-check-ce.yml deleted file mode 100644 index 933ec9b79bf..00000000000 --- a/changelogs/unreleased/sh-optimize-locks-check-ce.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Eliminate N+1 queries in LFS file locks checks during a push -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/straight-comparision-mode.yml b/changelogs/unreleased/straight-comparision-mode.yml deleted file mode 100644 index 2f6a0c0b54d..00000000000 --- a/changelogs/unreleased/straight-comparision-mode.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow straight diff in Compare API -merge_request: 20120 -author: Maciej Nowak -type: added diff --git a/changelogs/unreleased/tc-repo-check-per-shard.yml b/changelogs/unreleased/tc-repo-check-per-shard.yml deleted file mode 100644 index 227b6b0b93b..00000000000 --- a/changelogs/unreleased/tc-repo-check-per-shard.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Run repository checks in parallel for each shard -merge_request: 20179 -author: -type: added diff --git a/changelogs/unreleased/text-expander-icon-update.yml b/changelogs/unreleased/text-expander-icon-update.yml deleted file mode 100644 index be9dc98728f..00000000000 --- a/changelogs/unreleased/text-expander-icon-update.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Updated the icon for expand buttons to ellipsis -merge_request: 18793 -author: Constance Okoghenun -type: changed
\ No newline at end of file diff --git a/changelogs/unreleased/toggle-password-cluster.yml b/changelogs/unreleased/toggle-password-cluster.yml new file mode 100644 index 00000000000..1a43c4baa25 --- /dev/null +++ b/changelogs/unreleased/toggle-password-cluster.yml @@ -0,0 +1,5 @@ +--- +title: Toggle Show / Hide Button for Kubernetes Password +merge_request: 20659 +author: gfyoung +type: fixed diff --git a/changelogs/unreleased/transfer_project_api_endpoint.yml b/changelogs/unreleased/transfer_project_api_endpoint.yml deleted file mode 100644 index 60c704c62a0..00000000000 --- a/changelogs/unreleased/transfer_project_api_endpoint.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add transfer project API endpoint -merge_request: 20122 -author: Aram Visser -type: added diff --git a/changelogs/unreleased/tweak-sql-buckets.yml b/changelogs/unreleased/tweak-sql-buckets.yml new file mode 100644 index 00000000000..00a0f733ee1 --- /dev/null +++ b/changelogs/unreleased/tweak-sql-buckets.yml @@ -0,0 +1,5 @@ +--- +title: Add a 10 ms bucket for SQL timings +merge_request: +author: +type: changed diff --git a/changelogs/unreleased/tz-diff-blob-image-viewer.yml b/changelogs/unreleased/tz-diff-blob-image-viewer.yml deleted file mode 100644 index 81d87bc71f5..00000000000 --- a/changelogs/unreleased/tz-diff-blob-image-viewer.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Web IDE supports now Image + Download Diff Viewing -merge_request: 18768 -author: -type: added diff --git a/changelogs/unreleased/unify-views-search-results.yml b/changelogs/unreleased/unify-views-search-results.yml deleted file mode 100644 index 81ad3616648..00000000000 --- a/changelogs/unreleased/unify-views-search-results.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Hide project name if searching against a project -merge_request: 19595 -author: -type: changed diff --git a/changelogs/unreleased/update-bcrypt-to-support-libxcrypt.yml b/changelogs/unreleased/update-bcrypt-to-support-libxcrypt.yml deleted file mode 100644 index c18a0f75d22..00000000000 --- a/changelogs/unreleased/update-bcrypt-to-support-libxcrypt.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: update bcrypt to also support libxcrypt -merge_request: 20260 -author: muhammadn -type: other diff --git a/changelogs/unreleased/update-card-body-style.yml b/changelogs/unreleased/update-card-body-style.yml new file mode 100644 index 00000000000..d9197c18502 --- /dev/null +++ b/changelogs/unreleased/update-card-body-style.yml @@ -0,0 +1,5 @@ +--- +title: Remove background color from card-body style +merge_request: 20689 +author: George Tsiolis +type: fixed diff --git a/changelogs/unreleased/update-environments-nav-controls.yml b/changelogs/unreleased/update-environments-nav-controls.yml deleted file mode 100644 index 639dadd0cdf..00000000000 --- a/changelogs/unreleased/update-environments-nav-controls.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update environments nav controls icons -merge_request: 20199 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/update-external-link-icon-in-header-user-dropdown.yml b/changelogs/unreleased/update-external-link-icon-in-header-user-dropdown.yml deleted file mode 100644 index ee769f06379..00000000000 --- a/changelogs/unreleased/update-external-link-icon-in-header-user-dropdown.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update external link icon in header user dropdown -merge_request: 20150 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/update-external-link-icon-in-merge-request-widget.yml b/changelogs/unreleased/update-external-link-icon-in-merge-request-widget.yml deleted file mode 100644 index c650c32f884..00000000000 --- a/changelogs/unreleased/update-external-link-icon-in-merge-request-widget.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update external link icon in merge request widget -merge_request: 20154 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/update-integrations-external-link-icons.yml b/changelogs/unreleased/update-integrations-external-link-icons.yml deleted file mode 100644 index 9972744bd00..00000000000 --- a/changelogs/unreleased/update-integrations-external-link-icons.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update integrations external link icons -merge_request: 20205 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/update-issue-closing-pattern.yml b/changelogs/unreleased/update-issue-closing-pattern.yml new file mode 100644 index 00000000000..95488adf449 --- /dev/null +++ b/changelogs/unreleased/update-issue-closing-pattern.yml @@ -0,0 +1,5 @@ +--- +title: Update issue closing pattern +merge_request: 20554 +author: George Tsiolis +type: changed diff --git a/changelogs/unreleased/update-pipeline-icon-in-web-ide-sidebar.yml b/changelogs/unreleased/update-pipeline-icon-in-web-ide-sidebar.yml deleted file mode 100644 index 3f1f3c643e2..00000000000 --- a/changelogs/unreleased/update-pipeline-icon-in-web-ide-sidebar.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update pipeline icon in web ide sidebar -merge_request: 20058 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/update-specific-runners-help-url.yml b/changelogs/unreleased/update-specific-runners-help-url.yml new file mode 100644 index 00000000000..0ccbc3b2d65 --- /dev/null +++ b/changelogs/unreleased/update-specific-runners-help-url.yml @@ -0,0 +1,5 @@ +--- +title: Update specific runners help URL +merge_request: 20213 +author: George Tsiolis +type: other diff --git a/changelogs/unreleased/upgrade-gitlab-markup.yml b/changelogs/unreleased/upgrade-gitlab-markup.yml deleted file mode 100644 index 9b0eaa7068d..00000000000 --- a/changelogs/unreleased/upgrade-gitlab-markup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix extra blank line at start of rendered reStructuredText code block -merge_request: 19596 -author: -type: fixed diff --git a/changelogs/unreleased/use-backup-custom-hooks-gitaly.yml b/changelogs/unreleased/use-backup-custom-hooks-gitaly.yml deleted file mode 100644 index 4b9766332c3..00000000000 --- a/changelogs/unreleased/use-backup-custom-hooks-gitaly.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: migrate backup rake task to gitaly -merge_request: -author: -type: added diff --git a/changelogs/unreleased/use-tooltip-component-in-mr-widget-author-time-component.yml b/changelogs/unreleased/use-tooltip-component-in-mr-widget-author-time-component.yml deleted file mode 100644 index 4ab9b6dadc0..00000000000 --- a/changelogs/unreleased/use-tooltip-component-in-mr-widget-author-time-component.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use Tooltip component in MrWidgetAuthorTime vue comonent -merge_request: 19635 -author: George Tsiolis -type: performance diff --git a/changelogs/unreleased/web-hooks-log-pagination.yml b/changelogs/unreleased/web-hooks-log-pagination.yml deleted file mode 100644 index fd9e4f9ca13..00000000000 --- a/changelogs/unreleased/web-hooks-log-pagination.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed pagination of web hook logs -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/winh-new-branch-url-encode.yml b/changelogs/unreleased/winh-new-branch-url-encode.yml deleted file mode 100644 index f3554d0d4a1..00000000000 --- a/changelogs/unreleased/winh-new-branch-url-encode.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix branch name encoding for dropdown on issue page -merge_request: 19634 -author: -type: fixed diff --git a/changelogs/unreleased/zj-gitaly-read-write-check.yml b/changelogs/unreleased/zj-gitaly-read-write-check.yml deleted file mode 100644 index 43951d20e8f..00000000000 --- a/changelogs/unreleased/zj-gitaly-read-write-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Gitaly metrics check for read/writeability -merge_request: 20022 -author: -type: other diff --git a/config/boot.rb b/config/boot.rb index 84f390f3228..655c54ddb84 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -9,3 +9,8 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../#{gemfile}", __dir__) # Set up gems listed in the Gemfile. require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +begin + require 'bootsnap/setup' +rescue LoadError + # bootsnap is optional dependency, so if we don't have it it's fine +end diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index ab109f5d04f..561ff57c9fb 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -78,15 +78,15 @@ production: &base # username_changing_enabled: false # default: true - User can change her username/namespace ## Default theme ID ## 1 - Indigo - ## 2 - Light Indigo - ## 3 - Blue - ## 4 - Light Blue + ## 2 - Dark + ## 3 - Light + ## 4 - Blue ## 5 - Green - ## 6 - Light Green - ## 7 - Red - ## 8 - Light Red - ## 9 - Dark - ## 10 - Light + ## 6 - Light Indigo + ## 7 - Light Blue + ## 8 - Light Green + ## 9 - Red + ## 10 - Light Red # default_theme: 1 # default: 1 ## Automatic issue closing diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 693a2934a1b..c3122827a6b 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -135,11 +135,12 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled']. Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? -Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?: *,? +and +| *, *)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil? +Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?: *,? +and +| *,? *)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['max_attachment_size'] ||= 10 Settings.gitlab['session_expire_delay'] ||= 10080 +Settings.gitlab['unauthenticated_session_expire_delay'] ||= 1.hour.to_i Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.gitlab.default_projects_features['merge_requests'].nil? Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil? @@ -318,10 +319,6 @@ Settings.cron_jobs['gitlab_usage_ping_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['gitlab_usage_ping_worker']['cron'] ||= Settings.__send__(:cron_for_usage_ping) Settings.cron_jobs['gitlab_usage_ping_worker']['job_class'] = 'GitlabUsagePingWorker' -Settings.cron_jobs['schedule_update_user_activity_worker'] ||= Settingslogic.new({}) -Settings.cron_jobs['schedule_update_user_activity_worker']['cron'] ||= '30 0 * * *' -Settings.cron_jobs['schedule_update_user_activity_worker']['job_class'] = 'ScheduleUpdateUserActivityWorker' - Settings.cron_jobs['remove_old_web_hook_logs_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['remove_old_web_hook_logs_worker']['cron'] ||= '40 0 * * *' Settings.cron_jobs['remove_old_web_hook_logs_worker']['job_class'] = 'RemoveOldWebHookLogsWorker' diff --git a/config/initializers/action_mailer_hooks.rb b/config/initializers/action_mailer_hooks.rb new file mode 100644 index 00000000000..f1b3c1f8ae8 --- /dev/null +++ b/config/initializers/action_mailer_hooks.rb @@ -0,0 +1,12 @@ +unless Gitlab.config.gitlab.email_enabled + ActionMailer::Base.register_interceptor(::Gitlab::Email::Hook::DisableEmailInterceptor) + ActionMailer::Base.logger = nil +end + +ActionMailer::Base.register_interceptors( + ::Gitlab::Email::Hook::AdditionalHeadersInterceptor, + ::Gitlab::Email::Hook::EmailTemplateInterceptor, + ::Gitlab::Email::Hook::DeliveryMetricsObserver +) + +ActionMailer::Base.register_observer(::Gitlab::Email::Hook::DeliveryMetricsObserver) diff --git a/config/initializers/additional_headers_interceptor.rb b/config/initializers/additional_headers_interceptor.rb deleted file mode 100644 index b9159e7c06c..00000000000 --- a/config/initializers/additional_headers_interceptor.rb +++ /dev/null @@ -1 +0,0 @@ -ActionMailer::Base.register_interceptor(AdditionalEmailHeadersInterceptor) diff --git a/config/initializers/bootstrap_form.rb b/config/initializers/bootstrap_form.rb index 11171b38a85..bbc1d83a63f 100644 --- a/config/initializers/bootstrap_form.rb +++ b/config/initializers/bootstrap_form.rb @@ -1,6 +1,6 @@ module BootstrapFormBuilderCustomization def label_class - "label-light" + "label-bold" end end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index e5772c33307..c41b2db722c 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -219,7 +219,7 @@ Devise.setup do |config| end end - if Gitlab::OmniauthInitializer.enabled? + if Gitlab::Auth.omniauth_enabled? Gitlab::OmniauthInitializer.new(config).execute(Gitlab.config.omniauth.providers) end end diff --git a/config/initializers/disable_email_interceptor.rb b/config/initializers/disable_email_interceptor.rb deleted file mode 100644 index e8770c8d460..00000000000 --- a/config/initializers/disable_email_interceptor.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Interceptor in lib/disable_email_interceptor.rb -unless Gitlab.config.gitlab.email_enabled - ActionMailer::Base.register_interceptor(DisableEmailInterceptor) - ActionMailer::Base.logger = nil -end diff --git a/config/initializers/email_template_interceptor.rb b/config/initializers/email_template_interceptor.rb deleted file mode 100644 index f195ca9bcd6..00000000000 --- a/config/initializers/email_template_interceptor.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Interceptor in lib/email_template_interceptor.rb -ActionMailer::Base.register_interceptor(EmailTemplateInterceptor) diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index c558eb28ced..ef23ca065c6 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -16,8 +16,3 @@ OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_s OmniAuth.config.before_request_phase do |env| Gitlab::RequestForgeryProtection.call(env) end - -if Gitlab::OmniauthInitializer.enabled? - provider_names = Gitlab.config.omniauth.providers.map(&:name) - Gitlab::Auth.omniauth_setup_providers(provider_names) -end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 3400142db36..70b584ff9e9 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -62,7 +62,6 @@ - [default, 1] - [pages, 1] - [system_hook_push, 1] - - [update_user_activity, 1] - [propagate_service_template, 1] - [background_migration, 1] - [gcp_cluster, 1] @@ -77,4 +76,3 @@ - [repository_remove_remote, 1] - [create_note_diff_file, 1] - [delete_diff_files, 1] - diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile index 2424e650d07..a1f94dc6004 100644 --- a/danger/changelog/Dangerfile +++ b/danger/changelog/Dangerfile @@ -2,15 +2,13 @@ require 'yaml' -NO_CHANGELOG_LABELS = %w[backstage QA test].freeze +NO_CHANGELOG_LABELS = %w[backstage Documentation QA test].freeze SEE_DOC = "See [the documentation](https://docs.gitlab.com/ce/development/changelog.html).".freeze -MISSING_CHANGELOG_MESSAGE = <<~MSG.freeze -**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html).** - +CREATE_CHANGELOG_MESSAGE = <<~MSG.freeze You can create one with: ``` -bin/changelog -m %<mr_iid>s +bin/changelog -m %<mr_iid>s "%<mr_title>s" ``` If your merge request doesn't warrant a CHANGELOG entry, @@ -38,12 +36,14 @@ def check_changelog(path) if yaml["merge_request"].nil? message "Consider setting `merge_request` to #{gitlab.mr_json["iid"]} in #{gitlab.html_link(path)}. #{SEE_DOC}" - elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !ce_port_changelog?(changelog_path) + elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !ce_port_changelog?(path) fail "Merge request ID was not set to #{gitlab.mr_json["iid"]}! #{SEE_DOC}" end -rescue StandardError +rescue Psych::SyntaxError, Psych::DisallowedClass, Psych::BadAlias # YAML could not be parsed, fail the build. fail "#{gitlab.html_link(path)} isn't valid YAML! #{SEE_DOC}" +rescue StandardError => e + warn "There was a problem trying to check the Changelog. Exception: #{e.name} - #{e.message}" end def presented_no_changelog_labels @@ -54,13 +54,15 @@ changelog_needed = (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty? changelog_found = git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} } if git.modified_files.include?("CHANGELOG.md") - fail "CHANGELOG.md was edited. Please remove the additions and create an entry with `bin/changelog -m #{gitlab.mr_json["iid"]}` instead." + fail "**CHANGELOG.md was edited.** Please remove the additions and create a CHANGELOG entry.\n\n" + + format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: gitlab.mr_json["title"], labels: presented_no_changelog_labels) end if changelog_needed if changelog_found check_changelog(changelog_found) else - warn format(MISSING_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], labels: presented_no_changelog_labels) + warn "**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html).**\n\n" + + format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: gitlab.mr_json["title"], labels: presented_no_changelog_labels) end end diff --git a/danger/specs/Dangerfile b/danger/specs/Dangerfile index 934ea0beadb..97188df8785 100644 --- a/danger/specs/Dangerfile +++ b/danger/specs/Dangerfile @@ -1,12 +1,18 @@ +NO_SPECS_LABELS = %w[backstage Documentation QA].freeze NO_NEW_SPEC_MESSAGE = <<~MSG.freeze You've made some app changes, but didn't add any tests. That's OK as long as you're refactoring existing code, -but please consider adding the ~backstage label in that case. +but please consider adding any of the %<labels>s labels. MSG +def presented_no_changelog_labels + NO_SPECS_LABELS.map { |label| "~#{label}" }.join(', ') +end + has_app_changes = !git.modified_files.grep(%r{\A(ee/)?(app|lib|db/(geo/)?(post_)?migrate)/}).empty? -has_spec_changes = !git.modified_files.grep(/spec/).empty? +has_spec_changes = !git.modified_files.grep(%r{\A(ee/)?spec/}).empty? +new_specs_needed = (gitlab.mr_labels & NO_SPECS_LABELS).empty? -if has_app_changes && !has_spec_changes - warn NO_NEW_SPEC_MESSAGE, sticky: false +if has_app_changes && !has_spec_changes && new_specs_needed + warn format(NO_NEW_SPEC_MESSAGE, labels: presented_no_changelog_labels), sticky: false end diff --git a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb index dc16d5c5169..1eb6a8fa5df 100644 --- a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb +++ b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb @@ -1,9 +1,19 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers + class Repository + attr_reader :storage + + def initialize(storage, relative_path) + @storage = storage + @relative_path = relative_path + end + + def gitaly_repository + Gitaly::Repository.new(storage_name: @storage, relative_path: @relative_path) + end + end + class Project < ActiveRecord::Base def self.find_including_path(id) select("projects.*, CONCAT(namespaces.path, '/', projects.path) AS path_with_namespace") @@ -11,19 +21,12 @@ class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration .find_by(id: id) end - def repository_storage_path - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - Gitlab.config.repositories.storages[repository_storage].legacy_disk_path - end - end - - def repository_path - # TODO: review if the change from Legacy storage needs to reflect here as well. - File.join(repository_storage_path, read_attribute(:path_with_namespace) + '.git') + def commit(rev) + Gitlab::GitalyClient::CommitService.new(repository).find_commit(rev) end def repository - @repository ||= Rugged::Repository.new(repository_path) + @repository ||= Repository.new(repository_storage, read_attribute(:path_with_namespace) + '.git') end end @@ -42,22 +45,19 @@ class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration next unless project - begin - commit = project.repository.lookup(payload['args'][2]) - rescue Rugged::OdbError - next - end + commit = project.commit(payload['args'][2]) + next unless commit hash = { - id: commit.oid, - message: encode(commit.message), - parent_ids: commit.parent_ids, - authored_date: commit.author[:time], - author_name: encode(commit.author[:name]), - author_email: encode(commit.author[:email]), - committed_date: commit.committer[:time], - committer_email: encode(commit.committer[:email]), - committer_name: encode(commit.committer[:name]) + id: commit.id, + message: encode(commit.body), + parent_ids: commit.parent_ids.to_a, + authored_date: Time.at(commit.author.date.seconds).utc, + author_name: encode(commit.author.name), + author_email: encode(commit.author.email), + committed_date: Time.at(commit.committer.date.seconds).utc, + committer_email: encode(commit.committer.email), + committer_name: encode(commit.committer.name) } payload['args'][2] = hash diff --git a/db/migrate/20161226122833_remove_dot_git_from_usernames.rb b/db/migrate/20161226122833_remove_dot_git_from_usernames.rb index 133435523e1..db10426b483 100644 --- a/db/migrate/20161226122833_remove_dot_git_from_usernames.rb +++ b/db/migrate/20161226122833_remove_dot_git_from_usernames.rb @@ -1,11 +1,7 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - class RemoveDotGitFromUsernames < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers include Gitlab::ShellAdapter - # Set this constant to true if this migration requires downtime. DOWNTIME = false def up @@ -64,16 +60,14 @@ class RemoveDotGitFromUsernames < ActiveRecord::Migration # we rename suffix instead of removing it path = path.sub(/\.git\z/, '_git') - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - check_routes(path.dup, 0, path) - end + check_routes(path.dup, 0, path) end def check_routes(base, counter, path) route_exists = route_exists?(path) - Gitlab.config.repositories.storages.each do |shard, storage| - if route_exists || path_exists?(shard, storage.legacy_disk_path) + Gitlab.config.repositories.storages.each do |shard, _storage| + if route_exists || path_exists?(shard, path) counter += 1 path = "#{base}#{counter}" diff --git a/db/post_migrate/20180704145007_update_project_indexes.rb b/db/post_migrate/20180704145007_update_project_indexes.rb new file mode 100644 index 00000000000..193563b36db --- /dev/null +++ b/db/post_migrate/20180704145007_update_project_indexes.rb @@ -0,0 +1,23 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class UpdateProjectIndexes < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + NEW_INDEX_NAME = 'idx_project_repository_check_partial' + + disable_ddl_transaction! + + def up + add_concurrent_index(:projects, + [:repository_storage, :created_at], + name: NEW_INDEX_NAME, + where: 'last_repository_check_at IS NULL' + ) + end + + def down + remove_concurrent_index_by_name(:projects, NEW_INDEX_NAME) + end +end diff --git a/db/schema.rb b/db/schema.rb index d2aa31fae30..1a5555fb3a4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1674,6 +1674,7 @@ ActiveRecord::Schema.define(version: 20180704204006) do add_index "projects", ["path"], name: "index_projects_on_path", using: :btree add_index "projects", ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} add_index "projects", ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree + add_index "projects", ["repository_storage", "created_at"], name: "idx_project_repository_check_partial", where: "(last_repository_check_at IS NULL)", using: :btree add_index "projects", ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree add_index "projects", ["runners_token"], name: "index_projects_on_runners_token", using: :btree add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md index c0e98099e42..7bc92ae77ee 100644 --- a/doc/administration/monitoring/prometheus/gitlab_metrics.md +++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md @@ -22,7 +22,7 @@ collect metrics from this endpoint. We recommend setting up another Prometheus server, because the embedded server configuration is overwritten once every [reconfigure of GitLab][reconfigure]. In the future this will not be required. -## Metrics available +## Unicorn Metrics available The following metrics are available: diff --git a/doc/api/jobs.md b/doc/api/jobs.md index cfa5e9a3e95..9a950097675 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -50,6 +50,7 @@ Example of response "started_at": "2015-12-24T17:54:24.729Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/6", "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, @@ -82,7 +83,7 @@ Example of response "size": 1000 }, "finished_at": "2015-12-24T17:54:27.895Z", - "artifacts_expire_at": "2016-01-23T17:54:27.895Z" + "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, "name": "teaspoon", "pipeline": { @@ -97,6 +98,7 @@ Example of response "started_at": "2015-12-24T17:54:27.722Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/7", "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, @@ -151,7 +153,7 @@ Example of response "created_at": "2015-12-24T15:51:21.727Z", "artifacts_file": null, "finished_at": "2015-12-24T17:54:24.921Z", - "artifacts_expire_at": "2016-01-23T17:54:24.921Z" + "artifacts_expire_at": "2016-01-23T17:54:24.921Z", "id": 6, "name": "rspec:other", "pipeline": { @@ -166,6 +168,7 @@ Example of response "started_at": "2015-12-24T17:54:24.729Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/6", "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, @@ -198,7 +201,7 @@ Example of response "size": 1000 }, "finished_at": "2015-12-24T17:54:27.895Z", - "artifacts_expire_at": "2016-01-23T17:54:27.895Z" + "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, "name": "teaspoon", "pipeline": { @@ -213,6 +216,7 @@ Example of response "started_at": "2015-12-24T17:54:27.722Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/7", "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, @@ -280,6 +284,7 @@ Example of response "started_at": "2015-12-24T17:54:30.733Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/8", "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, @@ -455,7 +460,7 @@ Example of response "created_at": "2016-01-11T10:13:33.506Z", "artifacts_file": null, "finished_at": "2016-01-11T10:14:09.526Z", - "id": 69, + "id": 42, "name": "rubocop", "ref": "master", "runner": null, @@ -463,6 +468,7 @@ Example of response "started_at": null, "status": "canceled", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/42", "user": null } ``` @@ -501,7 +507,7 @@ Example of response "created_at": "2016-01-11T10:13:33.506Z", "artifacts_file": null, "finished_at": null, - "id": 69, + "id": 42, "name": "rubocop", "ref": "master", "runner": null, @@ -509,6 +515,7 @@ Example of response "started_at": null, "status": "pending", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/42", "user": null } ``` @@ -549,7 +556,7 @@ Example of response }, "coverage": null, "download_url": null, - "id": 69, + "id": 42, "name": "rubocop", "ref": "master", "runner": null, @@ -559,6 +566,7 @@ Example of response "finished_at": "2016-01-11T10:15:10.506Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/42", "user": null } ``` @@ -599,7 +607,7 @@ Example response: }, "coverage": null, "download_url": null, - "id": 69, + "id": 42, "name": "rubocop", "ref": "master", "runner": null, @@ -609,6 +617,7 @@ Example response: "finished_at": "2016-01-11T10:15:10.506Z", "status": "failed", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/42", "user": null } ``` @@ -647,7 +656,7 @@ Example of response "created_at": "2016-01-11T10:13:33.506Z", "artifacts_file": null, "finished_at": null, - "id": 69, + "id": 42, "name": "rubocop", "ref": "master", "runner": null, @@ -655,6 +664,7 @@ Example of response "started_at": null, "status": "started", "tag": false, + "web_url": "https://example.com/foo/bar/-/jobs/42", "user": null } ``` diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md index ebae68fe389..574be52801c 100644 --- a/doc/api/pipelines.md +++ b/doc/api/pipelines.md @@ -33,13 +33,15 @@ Example of response "id": 47, "status": "pending", "ref": "new-pipeline", - "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a" + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "web_url": "https://example.com/foo/bar/pipelines/47" }, { "id": 48, "status": "pending", "ref": "new-pipeline", - "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a" + "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", + "web_url": "https://example.com/foo/bar/pipelines/48" } ] ``` @@ -86,7 +88,8 @@ Example of response "finished_at": "2016-08-11T11:32:35.145Z", "committed_at": null, "duration": null, - "coverage": "30.0" + "coverage": "30.0", + "web_url": "https://example.com/foo/bar/pipelines/46" } ``` @@ -133,7 +136,8 @@ Example of response "finished_at": null, "committed_at": null, "duration": null, - "coverage": null + "coverage": null, + "web_url": "https://example.com/foo/bar/pipelines/61" } ``` @@ -151,7 +155,7 @@ POST /projects/:id/pipelines/:pipeline_id/retry | `pipeline_id` | integer | yes | The ID of a pipeline | ``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/retry" +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/retry" ``` Response: @@ -179,7 +183,8 @@ Response: "finished_at": "2016-08-11T11:32:35.145Z", "committed_at": null, "duration": null, - "coverage": null + "coverage": null, + "web_url": "https://example.com/foo/bar/pipelines/46" } ``` @@ -197,7 +202,7 @@ POST /projects/:id/pipelines/:pipeline_id/cancel | `pipeline_id` | integer | yes | The ID of a pipeline | ``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/cancel" +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/pipelines/46/cancel" ``` Response: @@ -225,7 +230,8 @@ Response: "finished_at": "2016-08-11T11:32:35.145Z", "committed_at": null, "duration": null, - "coverage": null + "coverage": null, + "web_url": "https://example.com/foo/bar/pipelines/46" } ``` diff --git a/doc/api/projects.md b/doc/api/projects.md index a35c2a56992..9409afc88a8 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -55,6 +55,8 @@ GET /projects | `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) | | `with_issues_enabled` | boolean | no | Limit by enabled issues feature | | `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | +| `wiki_checksum_failed` | boolean | no | Limit projects where the wiki checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ | +| `repository_checksum_failed` | boolean | no | Limit projects where the repository checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ | When `simple=true` or the user is unauthenticated this returns something like: @@ -571,7 +573,15 @@ If the project is a fork, and you provide a valid token to authenticate, the "avatar_url":"https://assets.gitlab-static.net/uploads/-/system/project/avatar/13083/logo-extra-whitespace.png", "star_count":3812, "forks_count":3561, - "last_activity_at":"2018-01-02T11:40:26.570Z" + "last_activity_at":"2018-01-02T11:40:26.570Z", + "namespace": { + "id": 72, + "name": "GitLab.org", + "path": "gitlab-org", + "kind": "group", + "full_path": "gitlab-org", + "parent_id": null + } } ... @@ -1509,3 +1519,6 @@ GET /projects/:id/snapshot | --------- | ---- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `wiki` | boolean | no | Whether to download the wiki, rather than project, repository | + +[eep]: https://about.gitlab.com/pricing/ "Available only in GitLab Premium" +[ee-6137]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137 diff --git a/doc/api/services.md b/doc/api/services.md index aeb48ccc36c..efa173180bb 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -443,6 +443,54 @@ Get Gemnasium service settings for a project. GET /projects/:id/services/gemnasium ``` +## Hangouts Chat + +Google GSuite team collaboration tool. + +>**Note:** This service was [introduced in v11.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20290) + +### Create/Edit Hangouts Chat service + +Set Hangouts Chat service for a project. + +``` +PUT /projects/:id/services/hangouts_chat +``` + +>**Note:** Specific event parameters (e.g. `push_events` flag) were [introduced in v10.4][11435] + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | true | The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces... | +| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines | +| `notify_only_default_branch` | boolean | false | Send notifications only for the default branch | +| `push_events` | boolean | false | Enable notifications for push events | +| `issues_events` | boolean | false | Enable notifications for issue events | +| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events | +| `merge_requests_events` | boolean | false | Enable notifications for merge request events | +| `tag_push_events` | boolean | false | Enable notifications for tag push events | +| `note_events` | boolean | false | Enable notifications for note events | +| `pipeline_events` | boolean | false | Enable notifications for pipeline events | +| `wiki_page_events` | boolean | false | Enable notifications for wiki page events | + +### Delete Hangouts Chat service + +Delete Hangouts Chat service for a project. + +``` +DELETE /projects/:id/services/hangouts_chat +``` + +### Get Hangouts Chat service settings + +Get Hangouts Chat service settings for a project. + +``` +GET /projects/:id/services/hangouts_chat +``` + ## HipChat Private group chat and IM diff --git a/doc/api/users.md b/doc/api/users.md index ca5afa04687..72fdaaa2c74 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -33,6 +33,20 @@ GET /users ] ``` +You can also search for users by email or username with: `/users?search=John` + +In addition, you can lookup users by username: + +``` +GET /users?username=:username +``` + +For example: + +``` +GET /users?username=jack_smith +``` + In addition, you can filter users based on states eg. `blocked`, `active` This works only to filter users who are `blocked` or `active`. It does not support `active=false` or `blocked=false`. @@ -126,21 +140,7 @@ GET /users ] ``` -You can search for users by email or username with: `/users?search=John` - -In addition, you can lookup users by username: - -``` -GET /users?username=:username -``` - -For example: - -``` -GET /users?username=jack_smith -``` - -You can also lookup users by external UID and provider: +You can lookup users by external UID and provider: ``` GET /users?extern_uid=:extern_uid&provider=:provider diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 7751f128d8e..115e6e390c9 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -47,6 +47,7 @@ future GitLab releases.** | **CI_COMMIT_REF_NAME** | 9.0 | all | The branch or tag name for which project is built | | **CI_COMMIT_REF_SLUG** | 9.0 | all | `$CI_COMMIT_REF_NAME` lowercased, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in URLs, host names and domain names. | | **CI_COMMIT_SHA** | 9.0 | all | The commit revision for which project is built | +| **CI_COMMIT_BEFORE_SHA** | 11.2 | all | The previous latest commit present on a branch before a push request. | | **CI_COMMIT_TAG** | 9.0 | 0.5 | The commit tag name. Present only when building tags. | | **CI_COMMIT_MESSAGE** | 10.8 | all | The full commit message. | | **CI_COMMIT_TITLE** | 10.8 | all | The title of the commit - the full first line of the message | @@ -118,6 +119,7 @@ future GitLab releases.** | `CI_BUILD_ID` | `CI_JOB_ID` | | `CI_BUILD_REF` | `CI_COMMIT_SHA` | | `CI_BUILD_TAG` | `CI_COMMIT_TAG` | +| `CI_BUILD_BEFORE_SHA` | `CI_COMMIT_BEFORE_SHA` | | `CI_BUILD_REF_NAME` | `CI_COMMIT_REF_NAME` | | `CI_BUILD_REF_SLUG` | `CI_COMMIT_REF_SLUG` | | `CI_BUILD_NAME` | `CI_JOB_NAME` | diff --git a/doc/development/README.md b/doc/development/README.md index 5d6fed5bc72..fed3903c771 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -40,6 +40,7 @@ description: 'Learn how to contribute to GitLab.' - [View sent emails or preview mailers](emails.md) - [Shell commands](shell_commands.md) in the GitLab codebase - [`Gemfile` guidelines](gemfile.md) +- [Pry debugging](pry_debugging.md) - [Sidekiq debugging](sidekiq_debugging.md) - [Gotchas](gotchas.md) to avoid - [Avoid modules with instance variables](module_with_instance_variables.md) if possible diff --git a/doc/development/architecture.md b/doc/development/architecture.md index 6ca3e9e5a0a..3e417a44ec1 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -197,4 +197,4 @@ Note: It is recommended to log into the `git` user using `sudo -i -u git` or `su ## GitLab.com -We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/handbook/infrastructure/production-architecture/) but this is probably over the top unless you have millions of users. +We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/) but this is probably over the top unless you have millions of users. diff --git a/doc/development/profiling.md b/doc/development/profiling.md index 11878b4009b..0ca8bb67a77 100644 --- a/doc/development/profiling.md +++ b/doc/development/profiling.md @@ -42,6 +42,36 @@ Passing a `logger:` keyword argument to `Gitlab::Profiler.profile` will send ActiveRecord and ActionController log output to that logger. Further options are documented with the method source. +There is also a RubyProf printer available: +`Gitlab::Profiler::TotalTimeFlatPrinter`. This acts like +`RubyProf::FlatPrinter`, but its `min_percent` option works on the method's +total time, not its self time. (This is because we often spend most of our time +in library code, but this comes from calls in our application.) It also offers a +`max_percent` option to help filter out outer calls that aren't useful (like +`ActionDispatch::Integration::Session#process`). + +There is a convenience method for using this, +`Gitlab::Profiler.print_by_total_time`: + +```ruby +result = Gitlab::Profiler.profile('/my-user') +Gitlab::Profiler.print_by_total_time(result, max_percent: 60, min_percent: 2) +# Measure Mode: wall_time +# Thread ID: 70005223698240 +# Fiber ID: 70004894952580 +# Total: 1.768912 +# Sort by: total_time +# +# %self total self wait child calls name +# 0.00 1.017 0.000 0.000 1.017 14 *ActionView::Helpers::RenderingHelper#render +# 0.00 1.017 0.000 0.000 1.017 14 *ActionView::Renderer#render_partial +# 0.00 1.017 0.000 0.000 1.017 14 *ActionView::PartialRenderer#render +# 0.00 1.007 0.000 0.000 1.007 14 *ActionView::PartialRenderer#render_partial +# 0.00 0.930 0.000 0.000 0.930 14 Hamlit::TemplateHandler#call +# 0.00 0.928 0.000 0.000 0.928 14 Temple::Engine#call +# 0.02 0.865 0.000 0.000 0.864 638 *Enumerable#inject +``` + [GitLab-Profiler](https://gitlab.com/gitlab-com/gitlab-profiler) is a project that builds on this to add some additional niceties, such as allowing configuration with a single Yaml file for multiple URLs, and uploading of the diff --git a/doc/development/pry_debugging.md b/doc/development/pry_debugging.md new file mode 100644 index 00000000000..de5e1323e6a --- /dev/null +++ b/doc/development/pry_debugging.md @@ -0,0 +1,130 @@ +# Pry debugging + +## Invoking pry debugging + +To invoke the debugger, place `binding.pry` somewhere in your +code. When the Ruby interpreter hits that code, execution will stop, +and you can type in commands to debug the state of the program + +## `byebug` vs `binding.pry` + +`byebug` has a very similar interface as `gdb`, but `byebug` does not +use the powerful Pry REPL. + +`binding.pry` uses Pry, but lacks some of the `byebug` +features. GitLab uses the [`pry-byebug`](https://github.com/deivid-rodriguez/pry-byebug) +gem. This gem brings some capabilities `byebug` to `binding.pry`, so +using that, will give you the most debugging powers. + +## `byebug` + +Check out [the docs](https://github.com/deivid-rodriguez/byebug) for the full list of commands. + +You can start the Pry REPL with the `pry` command. + +## `pry` + +There are **a lot** of features present in `pry`, too much to cover in +this document, so for the full documentation head over to the [Pry wiki](https://github.com/pry/pry/wiki). + +Below are a few features definitely worth checking out, also run +`help` in a pry session to see what else you can do. + +### State navigation + +With the [state navigation](https://github.com/pry/pry/wiki/State-navigation) +you can move around in the code to discover methods and such: + +```ruby +# Change context +[1] pry(main)> cd Pry +[2] pry(Pry):1> + +# Print methods +[2] pry(Pry):1> ls -m + +# Find a method +[3] pry(Pry):1> find-method to_yaml +``` + +### Source browsing + +You [look at the source code](https://github.com/pry/pry/wiki/Source-browsing) +from your `pry` session: + +```ruby +[1] pry(main)> $ Array#first +# The above is equivalent to +[2] pry(main)> cd Array +[3] pry(Array):1> show-source first +``` + +`$` is an alias for `show-source`. + +### Documentation browsing + +Similar to source browsing, is [Documentation browsing](https://github.com/pry/pry/wiki/Documentation-browsing). + +```ruby +[1] pry(main)> show-doc Array#first +``` + +`?` is an alias for `show-doc`. + +### Command history + +With <kdb>Ctrl+R</kbd> you can search your [command history](https://github.com/pry/pry/wiki/History). + +## Stepping + +To step through the code, you can use the following commands: + +- `break`: Manage breakpoints. +- `step`: Step execution into the next line or method. Takes an + optional numeric argument to step multiple times. +- `next`: Step over to the next line within the same frame. Also takes + an optional numeric argument to step multiple lines. +- `finish`: Execute until current stack frame returns. +- `continue`: Continue program execution and end the Pry session. + +## Callstack navigation + +You also can move around in the callstack with these commands: + +- `backtrace`: Shows the current stack. You can use the numbers on the + left side with the frame command to navigate the stack. +- `up`: Moves the stack frame up. Takes an optional numeric argument + to move multiple frames. +- `down`: Moves the stack frame down. Takes an optional numeric + argument to move multiple frames. +- `frame <n>`: Moves to a specific frame. Called without arguments + will show the current frame. + +## Short commands + +When you use `binding.pry` instead of `byebug`, the short commands +like `s`, `n`, `f`, and `c` do not work. To reinstall them, add this +to `~/.pryrc`: + +```ruby +if defined?(PryByebug) + Pry.commands.alias_command 's', 'step' + Pry.commands.alias_command 'n', 'next' + Pry.commands.alias_command 'f', 'finish' + Pry.commands.alias_command 'c', 'continue' +end +``` + +## Repeat last command + +You can repeat the last command by just hitting the <kbd>Enter</kbd> +key (e.g., with `step` or`next`), if you place the following snippet +in your `~/.pryrc`: + +```ruby +Pry::Commands.command /^$/, "repeat last command" do + _pry_.run_command Pry.history.to_a.last +end +``` + +`byebug` supports this out-of-the-box. diff --git a/doc/development/sql.md b/doc/development/sql.md index 974b1d99dff..e1e1d31a85f 100644 --- a/doc/development/sql.md +++ b/doc/development/sql.md @@ -243,3 +243,45 @@ WHERE EXISTS ( ``` [gin-index]: http://www.postgresql.org/docs/current/static/gin.html + +## `.find_or_create_by` is not atomic + +The inherent pattern with methods like `.find_or_create_by` and +`.first_or_create` and others is that they are not atomic. This means, +it first runs a `SELECT`, and if there are no results an `INSERT` is +performed. With concurrent processes in mind, there is a race condition +which may lead to trying to insert two similar records. This may not be +desired, or may cause one of the queries to fail due to a constraint +violation, for example. + +Using transactions does not solve this problem. + +The following pattern should be used to avoid the problem: + +```ruby +Project.transaction do + begin + User.find_or_create_by(username: "foo") + rescue ActiveRecord::RecordNotUnique + retry + end +end +``` + +If the above block is run inside a transaction and hits the race +condition, the transaction is aborted and we cannot simply retry (any +further queries inside the aborted transaction are going to fail). We +can employ [nested transactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions) +here to only rollback the "inner transaction". Note that `requires_new: true` is required here. + +```ruby +Project.transaction do + begin + User.transaction(requires_new: true) do + User.find_or_create_by(username: "foo") + end + rescue ActiveRecord::RecordNotUnique + retry + end +end +``` diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md index 1a926a660f1..acbfa1850b4 100644 --- a/doc/development/testing_guide/best_practices.md +++ b/doc/development/testing_guide/best_practices.md @@ -101,7 +101,7 @@ CHROME_HEADLESS=0 bundle exec rspec some_spec.rb The test will go by quickly, but this will give you an idea of what's happening. -You can also add `byebug` or `binding.pry` to pause execution and step through +You can also add `byebug` or `binding.pry` to pause execution and [step through](../pry_debugging.md#stepping) the test. #### Screenshots diff --git a/doc/install/installation.md b/doc/install/installation.md index 4b68090f8d3..8c7f80fd8e8 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -92,9 +92,9 @@ Is the system packaged Git too old? Remove it and compile from source. # Download and compile from source cd /tmp - curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.16.3.tar.gz - echo 'dda229e9c73f4fbb7d4324e0d993e11311673df03f73b194c554c2e9451e17cd git-2.16.3.tar.gz' | shasum -a256 -c - && tar -xzf git-2.16.3.tar.gz - cd git-2.16.3/ + curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.18.0.tar.gz + echo '94faf2c0b02a7920b0b46f4961d8e9cad08e81418614102898a55f980fa3e7e4 git-2.18.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.18.0.tar.gz + cd git-2.18.0/ ./configure make prefix=/usr/local all diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md index 48f3df1925a..692f81dd7cd 100644 --- a/doc/install/kubernetes/gitlab_chart.md +++ b/doc/install/kubernetes/gitlab_chart.md @@ -16,16 +16,8 @@ The default deployment includes: ### Limitations -Some features and functions are not currently available in the beta release: -* [GitLab Pages](../../user/project/pages/) -* [Reply by email](../../administration/reply_by_email.html) -* [Project templates](../../gitlab-basics/create-project.html) -* [Project import/export](../../user/project/settings/import_export.html) -* [Geo](https://docs.gitlab.com/ee/administration/geo/replication/) - -Currently out of scope: -* [Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/) -* [MySQL support](https://docs.gitlab.com/omnibus/settings/database.html#using-a-mysql-database-management-server-enterprise-edition-only) +Some features and functions are not currently available in the beta release. +For details, see [known issues and limitations](https://gitlab.com/charts/gitlab/blob/master/doc/architecture/beta.md#known-issues-and-limitations) in the charts repository. ## Prerequisites diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index d04829eaeb8..de1d366adc3 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -527,7 +527,7 @@ repo or by specifying a project variable: - **Bundled chart** - If your project has a `./chart` directory with a `Chart.yaml` file in it, Auto DevOps will detect the chart and use it instead of the [default - one](https://gitlab.com/charts/charts.gitlab.io/tree/master/charts/auto-deploy-app). + one](https://gitlab.com/charts/auto-deploy-app). This can be a great way to control exactly how your application is deployed. - **Project variable** - Create a [project variable](../../ci/variables/README.md#secret-variables) `AUTO_DEVOPS_CHART` with the URL of a custom chart to use. diff --git a/doc/update/10.6-to-10.7.md b/doc/update/10.6-to-10.7.md index 4efbb8c65cf..b9c14395a3a 100644 --- a/doc/update/10.6-to-10.7.md +++ b/doc/update/10.6-to-10.7.md @@ -340,7 +340,7 @@ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production If all items are green, then congratulations, the upgrade is complete! -## Things went south? Revert to previous version (10.5) +## Things went south? Revert to previous version (10.6) ### 1. Revert the code to the previous version diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md index 44e9f6c5516..0b38cde811d 100644 --- a/doc/update/mysql_to_postgresql.md +++ b/doc/update/mysql_to_postgresql.md @@ -194,12 +194,12 @@ sudo apt-get install pgloader 1. Switch database from MySQL to PostgreSQL - ``` bash - cd /home/git/gitlab - sudo -u git mv config/database.yml config/database.yml.bak - sudo -u git cp config/database.yml.postgresql config/database.yml - sudo -u git -H chmod o-rwx config/database.yml - ``` + ``` bash + cd /home/git/gitlab + sudo -u git mv config/database.yml config/database.yml.bak + sudo -u git cp config/database.yml.postgresql config/database.yml + sudo -u git -H chmod o-rwx config/database.yml + ``` 1. Run the following commands to prepare the schema: diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index d054561d5f3..20886faf418 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -64,7 +64,8 @@ Below are the current settings regarding [GitLab CI/CD](../../ci/README.md). ## Repository size limit -The maximum size your Git repository is allowed to be including LFS. +The maximum size your Git repository is allowed to be, including LFS. If you are near +or over the size limit, you can [reduce your repository size with Git](../project/repository/reducing_the_repo_size_using_git.md). | Setting | GitLab.com | Default | | ----------- | ----------------- | ------------- | diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index cc1d65e4e6c..7c552103412 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -167,7 +167,7 @@ twice, which can lead to confusion during deployments. | [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. | | [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | | [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | -| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | +| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | ## Getting the external IP address diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md index 812ecf05faf..06171f11e12 100644 --- a/doc/user/project/import/manifest.md +++ b/doc/user/project/import/manifest.md @@ -1,7 +1,8 @@ # Import multiple repositories by uploading a manifest file GitLab allows you to import all the required git repositories -based a manifest file like the one used by the Android repository. +based a manifest file like the one used by the [Android repository](https://android.googlesource.com/platform/manifest/+/2d6f081a3b05d8ef7a2b1b52b0d536b2b74feab4/default.xml). +This feature can be very handy when you need to import a project with many repositories like Android Open Source Project (AOSP). >**Note:** diff --git a/doc/user/project/integrations/emails_on_push.md b/doc/user/project/integrations/emails_on_push.md index c01da883562..b050c83fb72 100644 --- a/doc/user/project/integrations/emails_on_push.md +++ b/doc/user/project/integrations/emails_on_push.md @@ -6,7 +6,7 @@ every change that is pushed to your project. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) and select the **Emails on push** service to configure it. -In the _Recipients_ area, provide a list of emails separated by commas. +In the _Recipients_ area, provide a list of emails separated by spaces or newlines. You can configure any of the following settings depending on your preference. diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md new file mode 100644 index 00000000000..6ab44420a10 --- /dev/null +++ b/doc/user/project/integrations/hangouts_chat.md @@ -0,0 +1,27 @@ +# Hangouts Chat service + +The Hangouts Chat service sends notifications from GitLab to the room for which the webhook was created. + +## On Hangouts Chat + +1. Open the chat room in which you want to see the notifications. +1. From the chat room menu, select **Configure Webhooks**. +1. Click on **ADD WEBHOOK** and fill in the name of the bot that will post the messages. Optionally define avatar. +1. Click **SAVE** and copy the **Webhook URL** of your webhook. + +See also [the Hangouts Chat documentation for configuring incoming webhooks](https://developers.google.com/hangouts/chat/how-tos/webhooks) + +## On GitLab + +When you have the **Webhook URL** for your Hangouts Chat room webhook, you can setup the GitLab service. + +1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**. +1. Select the **Hangouts Chat** project service to configure it. +1. Check the **Active** checkbox to turn on the service. +1. Check the checkboxes corresponding to the GitLab events you want to receive. +1. Paste the **Webhook URL** that you copied from the Hangouts Chat configuration step. +1. Configure the remaining options and click `Save changes`. + +Your Hangouts Chat room will now start receiving GitLab event notifications as configured. + +![Hangouts Chat configuration](img/hangouts_chat_configuration.png) diff --git a/doc/user/project/integrations/img/hangouts_chat_configuration.png b/doc/user/project/integrations/img/hangouts_chat_configuration.png Binary files differnew file mode 100644 index 00000000000..33fadbe6547 --- /dev/null +++ b/doc/user/project/integrations/img/hangouts_chat_configuration.png diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md index 8c51eb9915e..05ee1b4e6d7 100644 --- a/doc/user/project/integrations/project_services.md +++ b/doc/user/project/integrations/project_services.md @@ -35,6 +35,7 @@ Click on the service links to see further configuration instructions and details | External Wiki | Replaces the link to the internal wiki with a link to an external wiki | | Flowdock | Flowdock is a collaboration web app for technical teams | | Gemnasium _(Has been deprecated in GitLab 11.0)_ | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities | +| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat | | [HipChat](hipchat.md) | Private group chat and IM | | [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | | [JIRA](jira.md) | JIRA issue tracker | diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index 8c09927e2df..8e486318980 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -10,6 +10,13 @@ Starting from GitLab 8.5: Starting from GitLab 11.1, the logs of web hooks are automatically removed after one month. +>**Note** +Starting from GitLab 11.2: +- The `description` field for issues, merge requests, comments, and wiki pages + is rewritten so that simple Markdown image references (like + `![](/uploads/...)`) have their target URL changed to an absolute URL. See + [image URL rewriting](#image-url-rewriting) for more details. + Project webhooks allow you to trigger a URL if for example new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. GitLab will send a POST request with data @@ -1125,6 +1132,27 @@ X-Gitlab-Event: Build Hook } ``` +## Image URL rewriting + +From GitLab 11.2, simple image references are rewritten to use an absolute URL +in webhooks. So if an image, merge request, comment, or wiki page has this in +its description: + +```markdown +![image](/uploads/$sha/image.png) +``` + +It will appear in the webhook body as the below (assuming that GitLab is +installed at gitlab.example.com): + +```markdown +![image](https://gitlab.example.com/uploads/$sha/image.png) +``` + +This will not rewrite URLs that already are pointing to HTTP, HTTPS, or +protocol-relative URLs. It will also not rewrite image URLs using advanced +Markdown features, like link labels. + ## Testing webhooks You can trigger the webhook manually. Sample data from the project will be used.Sample data will take from the project. diff --git a/doc/user/project/merge_requests/img/merge_request.png b/doc/user/project/merge_requests/img/merge_request.png Binary files differindex f9ca6348953..61b61122b11 100644 --- a/doc/user/project/merge_requests/img/merge_request.png +++ b/doc/user/project/merge_requests/img/merge_request.png diff --git a/doc/user/project/milestones/img/milestones_new_group_milestone.png b/doc/user/project/milestones/img/milestones_new_group_milestone.png Binary files differindex 8780394d72e..b6defab101d 100644 --- a/doc/user/project/milestones/img/milestones_new_group_milestone.png +++ b/doc/user/project/milestones/img/milestones_new_group_milestone.png diff --git a/doc/user/project/milestones/img/milestones_new_project_milestone.png b/doc/user/project/milestones/img/milestones_new_project_milestone.png Binary files differindex ba058428dfa..9aaff7dfef1 100644 --- a/doc/user/project/milestones/img/milestones_new_project_milestone.png +++ b/doc/user/project/milestones/img/milestones_new_project_milestone.png diff --git a/doc/user/project/milestones/img/milestones_promote_milestone.png b/doc/user/project/milestones/img/milestones_promote_milestone.png Binary files differindex 99bee1240d4..5e7f94c316f 100644 --- a/doc/user/project/milestones/img/milestones_promote_milestone.png +++ b/doc/user/project/milestones/img/milestones_promote_milestone.png diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md index d084ee41d8a..ad0ef60373c 100644 --- a/doc/user/project/wiki/index.md +++ b/doc/user/project/wiki/index.md @@ -107,3 +107,10 @@ On the right sidebar, click on **Clone repository** and follow the on-screen instructions. [permissions]: ../../permissions.md + +## Customizing sidebar + +By default, the wiki would render a sidebar which lists all the pages for the +wiki. You could as well provide a `_sidebar` page to replace this default +sidebar. When this customized sidebar page is provided, the default sidebar +would not be rendered, but the customized one. diff --git a/lib/additional_email_headers_interceptor.rb b/lib/additional_email_headers_interceptor.rb deleted file mode 100644 index 3cb1694b9f1..00000000000 --- a/lib/additional_email_headers_interceptor.rb +++ /dev/null @@ -1,6 +0,0 @@ -class AdditionalEmailHeadersInterceptor - def self.delivering_email(message) - message.header['Auto-Submitted'] ||= 'auto-generated' - message.header['X-Auto-Response-Suppress'] ||= 'All' - end -end diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 964780cba6a..92329465b2c 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -6,6 +6,18 @@ module API before { authorize! :download_code, user_project } + helpers do + def user_access + @user_access ||= Gitlab::UserAccess.new(current_user, project: user_project) + end + + def authorize_push_to_branch!(branch) + unless user_access.can_push_to_branch?(branch) + forbidden!("You are not allowed to push into this branch") + end + end + end + params do requires :id, type: String, desc: 'The ID of a project' end @@ -67,7 +79,7 @@ module API optional :author_name, type: String, desc: 'Author name for commit' end post ':id/repository/commits' do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) attrs = declared_params attrs[:branch_name] = attrs.delete(:branch) @@ -142,7 +154,7 @@ module API requires :branch, type: String, desc: 'The name of the branch' end post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do - authorize! :push_code, user_project + authorize_push_to_branch!(params[:branch]) commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b256c33c631..464a31ee819 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -132,6 +132,7 @@ module API expose :star_count, :forks_count expose :last_activity_at + expose :namespace, using: 'API::Entities::NamespaceBasic' expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes def self.preload_relation(projects_relation, options = {}) @@ -194,7 +195,6 @@ module API expose :shared_runners_enabled expose :lfs_enabled?, as: :lfs_enabled expose :creator_id - expose :namespace, using: 'API::Entities::NamespaceBasic' expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda { |project, options| project.forked? } expose :import_status expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] } @@ -529,6 +529,10 @@ module API class PipelineBasic < Grape::Entity expose :id, :sha, :ref, :status + + expose :web_url do |pipeline, _options| + Gitlab::Routing.url_helpers.project_pipeline_url(pipeline.project, pipeline) + end end class MergeRequestSimple < ProjectEntity @@ -701,7 +705,7 @@ module API expose :system?, as: :system expose :noteable_id, :noteable_type - expose :position, if: ->(note, options) { note.diff_note? } do |note| + expose :position, if: ->(note, options) { note.is_a?(DiffNote) } do |note| note.position.to_h end @@ -1069,6 +1073,10 @@ module API expose :user, with: User expose :commit, with: Commit expose :pipeline, with: PipelineBasic + + expose :web_url do |job, _options| + Gitlab::Routing.url_helpers.project_job_url(job.project, job) + end end class Job < JobBasic diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 9c53b7c3fe7..f7737468148 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -385,7 +385,7 @@ module API finder_params[:non_public] = true if params[:membership].present? finder_params[:starred] = true if params[:starred].present? finder_params[:visibility_level] = Gitlab::VisibilityLevel.level_value(params[:visibility]) if params[:visibility] - finder_params[:archived] = params[:archived] + finder_params[:archived] = archived_param unless params[:archived].nil? finder_params[:search] = params[:search] if params[:search] finder_params[:user] = params.delete(:user) if params[:user] finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes] @@ -496,5 +496,11 @@ module API exception.status == 500 end + + def archived_param + return 'only' if params[:archived] + + params[:archived] + end end end diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index e95b0dd5267..10c6e565f09 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -54,7 +54,7 @@ module API pipeline = user_project.pipelines.find(params[:pipeline_id]) builds = pipeline.builds builds = filter_builds(builds, params[:scope]) - builds = builds.preload(:job_artifacts_archive) + builds = builds.preload(:job_artifacts_archive, project: [:namespace]) present paginate(builds), with: Entities::Job end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 8273abe48c9..889e3d4f819 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -9,6 +9,21 @@ module API before { authenticate_non_get! } helpers do + params :optional_filter_params_ee do + # EE::API::Projects would override this helper + end + + # EE::API::Projects would override this method + def apply_filters(projects) + projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled] + projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] + projects = projects.with_statistics if params[:statistics] + + projects + end + end + + helpers do params :statistics_params do optional :statistics, type: Boolean, default: false, desc: 'Include project statistics' end @@ -30,7 +45,7 @@ module API end params :filter_params do - optional :archived, type: Boolean, default: false, desc: 'Limit by archived status' + optional :archived, type: Boolean, desc: 'Limit by archived status' optional :visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'Limit by visibility' optional :search, type: String, desc: 'Return list of projects matching the search criteria' @@ -39,6 +54,8 @@ module API optional :membership, type: Boolean, default: false, desc: 'Limit by projects that the current user is a member of' optional :with_issues_enabled, type: Boolean, default: false, desc: 'Limit by enabled issues feature' optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature' + + use :optional_filter_params_ee end params :create_params do @@ -52,9 +69,7 @@ module API def present_projects(projects, options = {}) projects = reorder_projects(projects) - projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled] - projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] - projects = projects.with_statistics if params[:statistics] + projects = apply_filters(projects) projects = paginate(projects) projects, options = with_custom_attributes(projects, options) diff --git a/lib/api/services.rb b/lib/api/services.rb index 553e8dff4b9..1f2bf546cd7 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -368,6 +368,14 @@ module API desc: "The project's slug on gemnasium.com" } ], + 'hangouts-chat' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…' + } + ], 'hipchat' => [ { required: true, @@ -688,6 +696,7 @@ module API ExternalWikiService, FlowdockService, GemnasiumService, + HangoutsChatService, HipchatService, IrkerService, JiraService, diff --git a/lib/banzai/filter/blockquote_fence_filter.rb b/lib/banzai/filter/blockquote_fence_filter.rb index fbfcd72c916..7108e828c6d 100644 --- a/lib/banzai/filter/blockquote_fence_filter.rb +++ b/lib/banzai/filter/blockquote_fence_filter.rb @@ -2,27 +2,7 @@ module Banzai module Filter class BlockquoteFenceFilter < HTML::Pipeline::TextFilter REGEX = %r{ - (?<code> - # Code blocks: - # ``` - # Anything, including `>>>` blocks which are ignored by this filter - # ``` - - ^``` - .+? - \n```\ *$ - ) - | - (?<html> - # HTML block: - # <tag> - # Anything, including `>>>` blocks which are ignored by this filter - # </tag> - - ^<[^>]+?>\ *\n - .+? - \n<\/[^>]+?>\ *$ - ) + #{::Gitlab::Regex.markdown_code_or_html_blocks} | (?: # Blockquote: diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 0d9b874ef85..5dab80dd3eb 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -24,6 +24,17 @@ module Banzai Filter::AutolinkFilter, Filter::ExternalLinkFilter, + *reference_filters, + + Filter::TaskListFilter, + Filter::InlineDiffFilter, + + Filter::SetDirectionFilter + ] + end + + def self.reference_filters + [ Filter::UserReferenceFilter, Filter::IssueReferenceFilter, Filter::ExternalIssueReferenceFilter, @@ -32,12 +43,7 @@ module Banzai Filter::CommitRangeReferenceFilter, Filter::CommitReferenceFilter, Filter::LabelReferenceFilter, - Filter::MilestoneReferenceFilter, - - Filter::TaskListFilter, - Filter::InlineDiffFilter, - - Filter::SetDirectionFilter + Filter::MilestoneReferenceFilter ] end diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb index dcd52bc03c7..0b2e584ef16 100644 --- a/lib/banzai/pipeline/post_process_pipeline.rb +++ b/lib/banzai/pipeline/post_process_pipeline.rb @@ -2,11 +2,17 @@ module Banzai module Pipeline class PostProcessPipeline < BasePipeline def self.filters - FilterArray[ + @filters ||= FilterArray[ + *internal_link_filters, + Filter::AbsoluteLinkFilter + ] + end + + def self.internal_link_filters + [ Filter::RedactorFilter, Filter::RelativeLinkFilter, - Filter::IssuableStateFilter, - Filter::AbsoluteLinkFilter + Filter::IssuableStateFilter ] end diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb index 1929099931b..cd5a6c8875c 100644 --- a/lib/banzai/pipeline/single_line_pipeline.rb +++ b/lib/banzai/pipeline/single_line_pipeline.rb @@ -10,13 +10,19 @@ module Banzai Filter::AutolinkFilter, Filter::ExternalLinkFilter, + *reference_filters + ] + end + + def self.reference_filters + [ Filter::UserReferenceFilter, Filter::IssueReferenceFilter, Filter::ExternalIssueReferenceFilter, Filter::MergeRequestReferenceFilter, Filter::SnippetReferenceFilter, Filter::CommitRangeReferenceFilter, - Filter::CommitReferenceFilter, + Filter::CommitReferenceFilter ] end end diff --git a/lib/disable_email_interceptor.rb b/lib/disable_email_interceptor.rb deleted file mode 100644 index cee664b8951..00000000000 --- a/lib/disable_email_interceptor.rb +++ /dev/null @@ -1,7 +0,0 @@ -# Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails -class DisableEmailInterceptor - def self.delivering_email(message) - message.perform_deliveries = false - Rails.logger.info "Emails disabled! Interceptor prevented sending mail #{message.subject}" - end -end diff --git a/lib/email_template_interceptor.rb b/lib/email_template_interceptor.rb deleted file mode 100644 index 3978a6d9fe4..00000000000 --- a/lib/email_template_interceptor.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails -class EmailTemplateInterceptor - def self.delivering_email(message) - # Remove HTML part if HTML emails are disabled. - unless Gitlab::CurrentSettings.html_emails_enabled - message.parts.delete_if do |part| - part.content_type.start_with?('text/html') - end - end - end -end diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 7de66539848..111e18b2076 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -14,23 +14,8 @@ module Gitlab DEFAULT_SCOPES = [:api].freeze class << self - def omniauth_customized_providers - @omniauth_customized_providers ||= %w[bitbucket jwt] - end - - def omniauth_setup_providers(provider_names) - provider_names.each do |provider| - omniauth_setup_a_provider(provider) - end - end - - def omniauth_setup_a_provider(provider) - case provider - when 'kerberos' - require 'omniauth-kerberos' - when *omniauth_customized_providers - require_dependency "omni_auth/strategies/#{provider}" - end + def omniauth_enabled? + Gitlab.config.omniauth.enabled end def find_for_git_client(login, password, project:, ip:) diff --git a/lib/gitlab/auth/o_auth/provider.rb b/lib/gitlab/auth/o_auth/provider.rb index 5fb61ffe00d..e73743944a9 100644 --- a/lib/gitlab/auth/o_auth/provider.rb +++ b/lib/gitlab/auth/o_auth/provider.rb @@ -30,7 +30,7 @@ module Gitlab def self.enabled?(name) return true if name == 'database' - providers.include?(name.to_sym) + Gitlab::Auth.omniauth_enabled? && providers.include?(name.to_sym) end def self.ldap_provider?(name) diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb index f76a6fb5f17..7a4224e5bbe 100644 --- a/lib/gitlab/checks/change_access.rb +++ b/lib/gitlab/checks/change_access.rb @@ -93,7 +93,7 @@ module Gitlab end else unless user_access.can_push_to_branch?(branch_name) - raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_protected_branch] + raise GitAccess::UnauthorizedError, push_to_protected_branch_rejected_message end end end @@ -140,6 +140,29 @@ module Gitlab private + def push_to_protected_branch_rejected_message + if project.empty_repo? + empty_project_push_message + else + ERROR_MESSAGES[:push_protected_branch] + end + end + + def empty_project_push_message + <<~MESSAGE + + A default branch (e.g. master) does not yet exist for #{project.full_path} + Ask a project Owner or Maintainer to create a default branch: + + #{project_members_url} + + MESSAGE + end + + def project_members_url + Gitlab::Routing.url_helpers.project_project_members_url(project) + end + def should_run_commit_validations? commit_check.validate_lfs_file_locks? end diff --git a/lib/gitlab/ci/variables/collection/item.rb b/lib/gitlab/ci/variables/collection/item.rb index 222aa06b800..7da6d09d440 100644 --- a/lib/gitlab/ci/variables/collection/item.rb +++ b/lib/gitlab/ci/variables/collection/item.rb @@ -34,7 +34,7 @@ module Gitlab def self.fabricate(resource) case resource when Hash - self.new(resource) + self.new(resource.symbolize_keys) when ::HasVariable self.new(resource.to_runner_variable) when self diff --git a/lib/gitlab/email/hook/additional_headers_interceptor.rb b/lib/gitlab/email/hook/additional_headers_interceptor.rb new file mode 100644 index 00000000000..064cb5e659a --- /dev/null +++ b/lib/gitlab/email/hook/additional_headers_interceptor.rb @@ -0,0 +1,12 @@ +module Gitlab + module Email + module Hook + class AdditionalHeadersInterceptor + def self.delivering_email(message) + message.header['Auto-Submitted'] ||= 'auto-generated' + message.header['X-Auto-Response-Suppress'] ||= 'All' + end + end + end + end +end diff --git a/lib/gitlab/email/hook/delivery_metrics_observer.rb b/lib/gitlab/email/hook/delivery_metrics_observer.rb new file mode 100644 index 00000000000..1c2985f6045 --- /dev/null +++ b/lib/gitlab/email/hook/delivery_metrics_observer.rb @@ -0,0 +1,31 @@ +module Gitlab + module Email + module Hook + class DeliveryMetricsObserver + extend Gitlab::Utils::StrongMemoize + + def self.delivering_email(_message) + delivery_attempts_counter.increment + end + + def self.delivered_email(_message) + delivered_emails_counter.increment + end + + def self.delivery_attempts_counter + strong_memoize(:delivery_attempts_counter) do + Gitlab::Metrics.counter(:gitlab_emails_delivery_attempts_total, + 'Counter of total emails delivery attempts') + end + end + + def self.delivered_emails_counter + strong_memoize(:delivered_emails_counter) do + Gitlab::Metrics.counter(:gitlab_emails_delivered_total, + 'Counter of total emails delievered') + end + end + end + end + end +end diff --git a/lib/gitlab/email/hook/disable_email_interceptor.rb b/lib/gitlab/email/hook/disable_email_interceptor.rb new file mode 100644 index 00000000000..7bb8b53f0c8 --- /dev/null +++ b/lib/gitlab/email/hook/disable_email_interceptor.rb @@ -0,0 +1,13 @@ +module Gitlab + module Email + module Hook + class DisableEmailInterceptor + def self.delivering_email(message) + message.perform_deliveries = false + + Rails.logger.info "Emails disabled! Interceptor prevented sending mail #{message.subject}" + end + end + end + end +end diff --git a/lib/gitlab/email/hook/email_template_interceptor.rb b/lib/gitlab/email/hook/email_template_interceptor.rb new file mode 100644 index 00000000000..be0c4dd862e --- /dev/null +++ b/lib/gitlab/email/hook/email_template_interceptor.rb @@ -0,0 +1,18 @@ +module Gitlab + module Email + module Hook + class EmailTemplateInterceptor + ## + # Remove HTML part if HTML emails are disabled. + # + def self.delivering_email(message) + unless Gitlab::CurrentSettings.html_emails_enabled + message.parts.delete_if do |part| + part.content_type.start_with?('text/html') + end + end + end + end + end + end +end diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 4e2d817d12c..5b264868af0 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -1,4 +1,4 @@ -# Gitlab::Git::Commit is a wrapper around native Rugged::Commit object +# Gitlab::Git::Commit is a wrapper around Gitaly::GitCommit module Gitlab module Git class Commit @@ -55,7 +55,6 @@ module Gitlab # A rugged reference? commit_id = Gitlab::Git::Ref.dereference_object(commit_id) - return decorate(repo, commit_id) if commit_id.is_a?(Rugged::Commit) # Some weird thing? return nil unless commit_id.is_a?(String) @@ -68,9 +67,7 @@ module Gitlab end decorate(repo, commit) if commit - rescue Rugged::ReferenceError, Rugged::InvalidError, Rugged::ObjectError, - Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository, - Rugged::OdbError, Rugged::TreeError, ArgumentError + rescue Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository, ArgumentError nil end @@ -142,20 +139,6 @@ module Gitlab Gitlab::Git::Commit.new(repository, commit, ref) end - # Returns the `Rugged` sorting type constant for one or more given - # sort types. Valid keys are `:none`, `:topo`, and `:date`, or an array - # containing more than one of them. `:date` uses a combination of date and - # topological sorting to closer mimic git's native ordering. - def rugged_sort_type(sort_type) - @rugged_sort_types ||= { - none: Rugged::SORT_NONE, - topo: Rugged::SORT_TOPO, - date: Rugged::SORT_DATE | Rugged::SORT_TOPO - } - - @rugged_sort_types.fetch(sort_type, Rugged::SORT_NONE) - end - def shas_with_signatures(repository, shas) Gitlab::GitalyClient::CommitService.new(repository).filter_shas_with_signatures(shas) end @@ -223,8 +206,6 @@ module Gitlab case raw_commit when Hash init_from_hash(raw_commit) - when Rugged::Commit - init_from_rugged(raw_commit) when Gitaly::GitCommit init_from_gitaly(raw_commit) else @@ -265,23 +246,6 @@ module Gitlab @repository.gitaly_commit_client.diff_from_parent(self, options) end - # Not to be called directly, but right now its used for tests and in old - # migrations - def rugged_diff_from_parent(options = {}) - options ||= {} - break_rewrites = options[:break_rewrites] - actual_options = Gitlab::Git::Diff.filter_diff_options(options) - - diff = if rugged_commit.parents.empty? - rugged_commit.diff(actual_options.merge(reverse: true)) - else - rugged_commit.parents[0].diff(rugged_commit, actual_options) - end - - diff.find_similar!(break_rewrites: break_rewrites) - diff - end - def deltas @deltas ||= begin deltas = @repository.gitaly_commit_client.commit_deltas(self) @@ -352,14 +316,6 @@ module Gitlab encode! @committer_email end - def rugged_commit - @rugged_commit ||= if raw_commit.is_a?(Rugged::Commit) - raw_commit - else - @repository.rev_parse_target(id) - end - end - def merge_commit? parent_ids.size > 1 end @@ -405,22 +361,6 @@ module Gitlab end end - def init_from_rugged(commit) - author = commit.author - committer = commit.committer - - @raw_commit = commit - @id = commit.oid - @message = commit.message - @authored_date = author[:time] - @committed_date = committer[:time] - @author_name = author[:name] - @author_email = author[:email] - @committer_name = committer[:name] - @committer_email = committer[:email] - @parent_ids = commit.parents.map(&:oid) - end - def init_from_gitaly(commit) @raw_commit = commit @id = commit.id diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb index 280def182d5..57d748343be 100644 --- a/lib/gitlab/git/operation_service.rb +++ b/lib/gitlab/git/operation_service.rb @@ -8,6 +8,8 @@ module Gitlab alias_method :branch_created?, :branch_created def self.from_gitaly(branch_update) + return if branch_update.nil? + new( branch_update.commit_id, branch_update.repo_created, diff --git a/lib/gitlab/git/popen.rb b/lib/gitlab/git/popen.rb index f9f24ecc48d..7426688fc55 100644 --- a/lib/gitlab/git/popen.rb +++ b/lib/gitlab/git/popen.rb @@ -21,6 +21,10 @@ module Gitlab Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| stdout.set_encoding(Encoding::ASCII_8BIT) + # stderr and stdout pipes can block if stderr/stdout aren't drained: https://bugs.ruby-lang.org/issues/9082 + # Mimic what Ruby does with capture3: https://github.com/ruby/ruby/blob/1ec544695fa02d714180ef9c34e755027b6a2103/lib/open3.rb#L257-L273 + err_reader = Thread.new { stderr.read } + yield(stdin) if block_given? stdin.close @@ -32,7 +36,7 @@ module Gitlab cmd_output << stdout.read end - cmd_output << stderr.read + cmd_output << err_reader.value cmd_status = wait_thr.value.exitstatus end @@ -55,16 +59,20 @@ module Gitlab rerr, werr = IO.pipe pid = Process.spawn(vars, *cmd, out: wout, err: werr, chdir: path, pgroup: true) + # stderr and stdout pipes can block if stderr/stdout aren't drained: https://bugs.ruby-lang.org/issues/9082 + # Mimic what Ruby does with capture3: https://github.com/ruby/ruby/blob/1ec544695fa02d714180ef9c34e755027b6a2103/lib/open3.rb#L257-L273 + out_reader = Thread.new { rout.read } + err_reader = Thread.new { rerr.read } begin - status = process_wait_with_timeout(pid, timeout) - # close write ends so we could read them wout.close werr.close - cmd_output = rout.readlines.join - cmd_output << rerr.readlines.join # Copying the behaviour of `popen` which merges stderr into output + status = process_wait_with_timeout(pid, timeout) + + cmd_output = out_reader.value + cmd_output << err_reader.value # Copying the behaviour of `popen` which merges stderr into output [cmd_output, status.exitstatus] rescue Timeout::Error => e diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index fc4711751b1..21ac43f80fd 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1,4 +1,3 @@ -# Gitlab::Git::Repository is a wrapper around native Rugged::Repository object require 'tempfile' require 'forwardable' require "rubygems/package" @@ -252,14 +251,6 @@ module Gitlab end end - def batch_existence(object_ids, existing: true) - filter_method = existing ? :select : :reject - - object_ids.public_send(filter_method) do |oid| # rubocop:disable GitlabSecurity/PublicSend - rugged.exists?(oid) - end - end - # Returns an Array of branch and tag names def ref_names branch_names + tag_names @@ -280,12 +271,6 @@ module Gitlab end.map(&:name) end - def rugged_head - rugged.head - rescue Rugged::ReferenceError - nil - end - def archive_metadata(ref, storage_path, project_path, format = "tar.gz", append_sha:) ref ||= root_ref commit = Gitlab::Git::Commit.find(self, ref) @@ -395,6 +380,21 @@ module Gitlab end end + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233 + def new_commits(newrev) + gitaly_migrate(:new_commits) do |is_enabled| + if is_enabled + gitaly_ref_client.list_new_commits(newrev) + else + refs = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + rev_list(including: newrev, excluding: :all).split("\n").map(&:strip) + end + + Gitlab::Git::Commit.batch_by_oid(self, refs) + end + end + end + def count_commits(options) options = process_count_commits_options(options.dup) @@ -415,13 +415,6 @@ module Gitlab end end - # Return the object that +revspec+ points to. If +revspec+ is an - # annotated tag, then return the tag's target instead. - def rev_parse_target(revspec) - obj = rugged.rev_parse(revspec) - Ref.dereference_object(obj) - end - # Counts the amount of commits between `from` and `to`. def count_commits_between(from, to, options = {}) count_commits(from: from, to: to, **options) @@ -449,12 +442,8 @@ module Gitlab # Returns the SHA of the most recent common ancestor of +from+ and +to+ def merge_base(from, to) - gitaly_migrate(:merge_base) do |is_enabled| - if is_enabled - gitaly_repository_client.find_merge_base(from, to) - else - rugged_merge_base(from, to) - end + wrapped_gitaly_errors do + gitaly_repository_client.find_merge_base(from, to) end end @@ -470,12 +459,8 @@ module Gitlab return [] unless root_sha - branches = gitaly_migrate(:merged_branch_names) do |is_enabled| - if is_enabled - gitaly_merged_branch_names(branch_names, root_sha) - else - git_merged_branch_names(branch_names, root_sha) - end + branches = wrapped_gitaly_errors do + gitaly_merged_branch_names(branch_names, root_sha) end Set.new(branches) @@ -515,11 +500,6 @@ module Gitlab @refs_hash end - # Lookup for rugged object by oid or ref name - def lookup(oid_or_ref_name) - rugged.rev_parse(oid_or_ref_name) - end - # Returns url for submodule # # Ex. @@ -692,35 +672,17 @@ module Gitlab # If `mirror_refmap` is present the remote is set as mirror with that mapping def add_remote(remote_name, url, mirror_refmap: nil) - gitaly_migrate(:remote_add_remote) do |is_enabled| - if is_enabled - gitaly_remote_client.add_remote(remote_name, url, mirror_refmap) - else - rugged_add_remote(remote_name, url, mirror_refmap) - end + wrapped_gitaly_errors do + gitaly_remote_client.add_remote(remote_name, url, mirror_refmap) end end def remove_remote(remote_name) - gitaly_migrate(:remote_remove_remote) do |is_enabled| - if is_enabled - gitaly_remote_client.remove_remote(remote_name) - else - rugged_remove_remote(remote_name) - end + wrapped_gitaly_errors do + gitaly_remote_client.remove_remote(remote_name) end end - # Update the specified remote using the values in the +options+ hash - # - # Example - # repo.update_remote("origin", url: "path/to/repo") - def remote_update(remote_name, url:) - # TODO: Implement other remote options - rugged.remotes.set_url(remote_name, url) - nil - end - AUTOCRLF_VALUES = { "true" => true, "false" => false, @@ -859,12 +821,8 @@ module Gitlab def write_ref(ref_path, ref, old_ref: nil, shell: true) ref_path = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref_path}" unless ref_path.start_with?("refs/") || ref_path == "HEAD" - gitaly_migrate(:write_ref) do |is_enabled| - if is_enabled - gitaly_repository_client.write_ref(ref_path, ref, old_ref, shell) - else - local_write_ref(ref_path, ref, old_ref: old_ref, shell: shell) - end + wrapped_gitaly_errors do + gitaly_repository_client.write_ref(ref_path, ref, old_ref, shell) end end @@ -898,12 +856,8 @@ module Gitlab end def fetch_repository_as_mirror(repository) - gitaly_migrate(:remote_fetch_internal_remote) do |is_enabled| - if is_enabled - gitaly_remote_client.fetch_internal_remote(repository) - else - rugged_fetch_repository_as_mirror(repository) - end + wrapped_gitaly_errors do + gitaly_remote_client.fetch_internal_remote(repository) end end @@ -916,20 +870,6 @@ module Gitlab Gitlab::Git::Blob.batch(self, items, blob_size_limit: blob_size_limit) end - def commit_index(user, branch_name, index, options) - committer = user_to_committer(user) - - OperationService.new(user, self).with_branch(branch_name) do - commit_params = options.merge( - tree: index.write_tree(rugged), - author: committer, - committer: committer - ) - - create_commit(commit_params) - end - end - def fsck msg, status = gitaly_repository_client.fsck @@ -1169,33 +1109,6 @@ module Gitlab run_git!(args, lazy_block: block) end - def with_worktree(worktree_path, branch, sparse_checkout_files: nil, env:) - base_args = %w(worktree add --detach) - - # Note that we _don't_ want to test for `.present?` here: If the caller - # passes an non nil empty value it means it still wants sparse checkout - # but just isn't interested in any file, perhaps because it wants to - # checkout files in by a changeset but that changeset only adds files. - if sparse_checkout_files - # Create worktree without checking out - run_git!(base_args + ['--no-checkout', worktree_path], env: env) - worktree_git_path = run_git!(%w(rev-parse --git-dir), chdir: worktree_path).chomp - - configure_sparse_checkout(worktree_git_path, sparse_checkout_files) - - # After sparse checkout configuration, checkout `branch` in worktree - run_git!(%W(checkout --detach #{branch}), chdir: worktree_path, env: env) - else - # Create worktree and checkout `branch` in it - run_git!(base_args + [worktree_path, branch], env: env) - end - - yield - ensure - FileUtils.rm_rf(worktree_path) if File.exist?(worktree_path) - FileUtils.rm_rf(worktree_git_path) if worktree_git_path && File.exist?(worktree_git_path) - end - def checksum # The exists? RPC is much cheaper, so we perform this request first raise NoRepository, "Repository does not exists" unless exists? @@ -1213,37 +1126,6 @@ module Gitlab end end - def local_write_ref(ref_path, ref, old_ref: nil, shell: true) - if shell - shell_write_ref(ref_path, ref, old_ref) - else - rugged_write_ref(ref_path, ref) - end - end - - def rugged_write_config(full_path:) - rugged.config['gitlab.fullpath'] = full_path - end - - def shell_write_ref(ref_path, ref, old_ref) - raise ArgumentError, "invalid ref_path #{ref_path.inspect}" if ref_path.include?(' ') - raise ArgumentError, "invalid ref #{ref.inspect}" if ref.include?("\x00") - raise ArgumentError, "invalid old_ref #{old_ref.inspect}" if !old_ref.nil? && old_ref.include?("\x00") - - input = "update #{ref_path}\x00#{ref}\x00#{old_ref}\x00" - run_git!(%w[update-ref --stdin -z]) { |stdin| stdin.write(input) } - end - - def rugged_write_ref(ref_path, ref) - rugged.references.create(ref_path, ref, force: true) - rescue Rugged::ReferenceError => ex - Rails.logger.error "Unable to create #{ref_path} reference for repository #{path}: #{ex}" - rescue Rugged::OSError => ex - raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/ - - Rails.logger.error "Unable to create #{ref_path} reference for repository #{path}: #{ex}" - end - def run_git(args, chdir: path, env: {}, nice: false, lazy_block: nil, &block) cmd = [Gitlab.config.git.bin_path, *args] cmd.unshift("nice") if nice @@ -1272,38 +1154,6 @@ module Gitlab end end - # Adding a worktree means checking out the repository. For large repos, - # this can be very expensive, so set up sparse checkout for the worktree - # to only check out the files we're interested in. - def configure_sparse_checkout(worktree_git_path, files) - run_git!(%w(config core.sparseCheckout true)) - - return if files.empty? - - worktree_info_path = File.join(worktree_git_path, 'info') - FileUtils.mkdir_p(worktree_info_path) - File.write(File.join(worktree_info_path, 'sparse-checkout'), files) - end - - def rugged_fetch_source_branch(source_repository, source_branch, local_ref) - with_repo_branch_commit(source_repository, source_branch) do |commit| - if commit - write_ref(local_ref, commit.sha) - true - else - false - end - end - end - - def worktree_path(prefix, id) - id = id.to_s - raise ArgumentError, "worktree id can't be empty" unless id.present? - raise ArgumentError, "worktree id can't contain slashes " if id.include?("/") - - File.join(path, 'gitlab-worktree', "#{prefix}-#{id}") - end - def git_env_for_user(user) { 'GIT_COMMITTER_NAME' => user.name, @@ -1314,20 +1164,6 @@ module Gitlab } end - def git_merged_branch_names(branch_names, root_sha) - git_arguments = - %W[branch --merged #{root_sha} - --format=%(refname:short)\ %(objectname)] + branch_names - - lines = run_git(git_arguments).first.lines - - lines.each_with_object([]) do |line, branches| - name, sha = line.strip.split(' ', 2) - - branches << name if sha != root_sha - end - end - def gitaly_merged_branch_names(branch_names, root_sha) qualified_branch_names = branch_names.map { |b| "refs/heads/#{b}" } @@ -1356,23 +1192,6 @@ module Gitlab end end - # We are trying to deprecate this method because it does a lot of work - # but it seems to be used only to look up submodule URL's. - # https://gitlab.com/gitlab-org/gitaly/issues/329 - def submodules(ref) - commit = rev_parse_target(ref) - return {} unless commit - - begin - content = blob_content(commit, ".gitmodules") - rescue InvalidBlobName - return {} - end - - parser = GitmodulesParser.new(content) - fill_submodule_ids(commit, parser.parse) - end - def gitaly_submodule_url_for(ref, path) # We don't care about the contents so 1 byte is enough. Can't request 0 bytes, 0 means unlimited. commit_object = gitaly_commit_client.tree_entry(ref, path, 1) @@ -1395,79 +1214,6 @@ module Gitlab Gitlab::Git::HookEnv.all(gl_repository).values_at(*ALLOWED_OBJECT_RELATIVE_DIRECTORIES_VARIABLES).flatten.compact end - # Get the content of a blob for a given commit. If the blob is a commit - # (for submodules) then return the blob's OID. - def blob_content(commit, blob_name) - blob_entry = tree_entry(commit, blob_name) - - unless blob_entry - raise InvalidBlobName.new("Invalid blob name: #{blob_name}") - end - - case blob_entry[:type] - when :commit - blob_entry[:oid] - when :tree - raise InvalidBlobName.new("#{blob_name} is a tree, not a blob") - when :blob - rugged.lookup(blob_entry[:oid]).content - end - end - - # Fill in the 'id' field of a submodule hash from its values - # as-of +commit+. Return a Hash consisting only of entries - # from the submodule hash for which the 'id' field is filled. - def fill_submodule_ids(commit, submodule_data) - submodule_data.each do |path, data| - id = begin - blob_content(commit, path) - rescue InvalidBlobName - nil - end - data['id'] = id - end - submodule_data.select { |path, data| data['id'] } - end - - # Find the entry for +path+ in the tree for +commit+ - def tree_entry(commit, path) - pathname = Pathname.new(path) - first = true - tmp_entry = nil - - pathname.each_filename do |dir| - if first - tmp_entry = commit.tree[dir] - first = false - elsif tmp_entry.nil? - return nil - else - begin - tmp_entry = rugged.lookup(tmp_entry[:oid]) - rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError - return nil - end - - return nil unless tmp_entry.type == :tree - - tmp_entry = tmp_entry[dir] - end - end - - tmp_entry - end - - # Return the Rugged patches for the diff between +from+ and +to+. - def diff_patches(from, to, options = {}, *paths) - options ||= {} - break_rewrites = options[:break_rewrites] - actual_options = Gitlab::Git::Diff.filter_diff_options(options.merge(paths: paths)) - - diff = rugged.diff(from, to, actual_options) - diff.find_similar!(break_rewrites: break_rewrites) - diff.each_patch - end - def sort_branches(branches, sort_by) case sort_by when 'name' @@ -1496,75 +1242,6 @@ module Gitlab gitaly_repository_client.apply_gitattributes(revision) end - def rugged_copy_gitattributes(ref) - begin - commit = lookup(ref) - rescue Rugged::ReferenceError - raise InvalidRef.new("Ref #{ref} is invalid") - end - - # Create the paths - info_dir_path = File.join(path, 'info') - info_attributes_path = File.join(info_dir_path, 'attributes') - - begin - # Retrieve the contents of the blob - gitattributes_content = blob_content(commit, '.gitattributes') - rescue InvalidBlobName - # No .gitattributes found. Should now remove any info/attributes and return - File.delete(info_attributes_path) if File.exist?(info_attributes_path) - return - end - - # Create the info directory if needed - Dir.mkdir(info_dir_path) unless File.directory?(info_dir_path) - - # Write the contents of the .gitattributes file to info/attributes - # Use binary mode to prevent Rails from converting ASCII-8BIT to UTF-8 - File.open(info_attributes_path, "wb") do |file| - file.write(gitattributes_content) - end - end - - def rugged_cherry_pick(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:) - OperationService.new(user, self).with_branch( - branch_name, - start_branch_name: start_branch_name, - start_repository: start_repository - ) do |start_commit| - - Gitlab::Git.check_namespace!(commit, start_repository) - - cherry_pick_tree_id = check_cherry_pick_content(commit, start_commit.sha) - raise CreateTreeError unless cherry_pick_tree_id - - committer = user_to_committer(user) - - create_commit(message: message, - author: { - email: commit.author_email, - name: commit.author_name, - time: commit.authored_date - }, - committer: committer, - tree: cherry_pick_tree_id, - parents: [start_commit.sha]) - end - end - - def check_cherry_pick_content(target_commit, source_sha) - args = [target_commit.sha, source_sha] - args << 1 if target_commit.merge_commit? - - cherry_pick_index = rugged.cherrypick_commit(*args) - return false if cherry_pick_index.conflicts? - - tree_id = cherry_pick_index.write_tree(rugged) - return false unless diff_exists?(source_sha, tree_id) - - tree_id - end - def local_fetch_ref(source_path, source_ref:, target_ref:) args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref}) run_git(args) @@ -1576,70 +1253,17 @@ module Gitlab run_git(args, env: source_repository.fetch_env) end - def rugged_add_remote(remote_name, url, mirror_refmap) - rugged.remotes.create(remote_name, url) - - set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap - rescue Rugged::ConfigError - remote_update(remote_name, url: url) - end - def gitaly_delete_refs(*ref_names) gitaly_ref_client.delete_refs(refs: ref_names) if ref_names.any? end - def rugged_remove_remote(remote_name) - # When a remote is deleted all its remote refs are deleted too, but in - # the case of mirrors we map its refs (that would usualy go under - # [remote_name]/) to the top level namespace. We clean the mapping so - # those don't get deleted. - if rugged.config["remote.#{remote_name}.mirror"] - rugged.config.delete("remote.#{remote_name}.fetch") - end - - rugged.remotes.delete(remote_name) - true - rescue Rugged::ConfigError - false - end - - def rugged_fetch_repository_as_mirror(repository) - remote_name = "tmp-#{SecureRandom.hex}" - repository = RemoteRepository.new(repository) unless repository.is_a?(RemoteRepository) - - add_remote(remote_name, GITALY_INTERNAL_URL, mirror_refmap: :all_refs) - fetch_remote(remote_name, env: repository.fetch_env) - ensure - remove_remote(remote_name) - end - - def fetch_remote(remote_name = 'origin', env: nil) - run_git(['fetch', remote_name], env: env).last.zero? - end - def gitlab_projects_error raise CommandError, @gitlab_projects.output end - def rugged_merge_base(from, to) - rugged.merge_base(from, to) - rescue Rugged::ReferenceError - nil - end - def rev_list_param(spec) spec == :all ? ['--all'] : spec end - - def sha_from_ref(ref) - rev_parse_target(ref).oid - end - - def create_commit(params = {}) - params[:message].delete!("\r") - - Rugged::Commit.create(rugged, params) - end end end end diff --git a/lib/gitlab/git/repository_mirroring.rb b/lib/gitlab/git/repository_mirroring.rb index e35ea5762eb..8835bfb2481 100644 --- a/lib/gitlab/git/repository_mirroring.rb +++ b/lib/gitlab/git/repository_mirroring.rb @@ -1,56 +1,26 @@ module Gitlab module Git module RepositoryMirroring - REFMAPS = { - # With `:all_refs`, the repository is equivalent to the result of `git clone --mirror` - all_refs: '+refs/*:refs/*', - heads: '+refs/heads/*:refs/heads/*', - tags: '+refs/tags/*:refs/tags/*' - }.freeze - - RemoteError = Class.new(StandardError) - - def set_remote_as_mirror(remote_name, refmap: :all_refs) - set_remote_refmap(remote_name, refmap) - - rugged.config["remote.#{remote_name}.mirror"] = true - rugged.config["remote.#{remote_name}.prune"] = true - end - - def remote_tags(remote) - # Each line has this format: "dc872e9fa6963f8f03da6c8f6f264d0845d6b092\trefs/tags/v1.10.0\n" - # We want to convert it to: [{ 'v1.10.0' => 'dc872e9fa6963f8f03da6c8f6f264d0845d6b092' }, ...] - list_remote_tags(remote).map do |line| - target, path = line.strip.split("\t") - - # When the remote repo does not have tags. - if target.nil? || path.nil? - Rails.logger.info "Empty or invalid list of tags for remote: #{remote}. Output: #{output}" - break [] + def remote_branches(remote_name) + gitaly_migrate(:ref_find_all_remote_branches) do |is_enabled| + if is_enabled + gitaly_ref_client.remote_branches(remote_name) + else + rugged_remote_branches(remote_name) end - - name = path.split('/', 3).last - # We're only interested in tag references - # See: http://stackoverflow.com/questions/15472107/when-listing-git-ls-remote-why-theres-after-the-tag-name - next if name =~ /\^\{\}\Z/ - - target_commit = Gitlab::Git::Commit.find(self, target) - Gitlab::Git::Tag.new(self, { - name: name, - target: target, - target_commit: target_commit - }) - end.compact + end end - def remote_branches(remote_name) + private + + def rugged_remote_branches(remote_name) branches = [] rugged.references.each("refs/remotes/#{remote_name}/*").map do |ref| name = ref.name.sub(%r{\Arefs/remotes/#{remote_name}/}, '') begin - target_commit = Gitlab::Git::Commit.find(self, ref.target) + target_commit = Gitlab::Git::Commit.find(self, ref.target.oid) branches << Gitlab::Git::Branch.new(self, name, ref.target, target_commit) rescue Rugged::ReferenceError # Omit invalid branch @@ -59,37 +29,6 @@ module Gitlab branches end - - private - - def set_remote_refmap(remote_name, refmap) - Array(refmap).each_with_index do |refspec, i| - refspec = REFMAPS[refspec] || refspec - - # We need multiple `fetch` entries, but Rugged only allows replacing a config, not adding to it. - # To make sure we start from scratch, we set the first using rugged, and use `git` for any others - if i == 0 - rugged.config["remote.#{remote_name}.fetch"] = refspec - else - run_git(%W[config --add remote.#{remote_name}.fetch #{refspec}]) - end - end - end - - def list_remote_tags(remote) - tag_list, exit_code, error = nil - cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path} ls-remote --tags #{remote}) - - Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr| - tag_list = stdout.read - error = stderr.read - exit_code = wait_thr.value.exitstatus - end - - raise RemoteError, error unless exit_code.zero? - - tag_list.split("\n") - end end end end diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb deleted file mode 100644 index 2ba68343aa5..00000000000 --- a/lib/gitlab/git/rev_list.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Gitlab - module Git - class RevList - include Gitlab::Git::Popen - - attr_reader :oldrev, :newrev, :repository - - def initialize(repository, newrev:, oldrev: nil) - @oldrev = oldrev - @newrev = newrev - @repository = repository - end - - # This method returns an array of new commit references - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233 - # - def new_refs - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - repository.rev_list(including: newrev, excluding: :all).split("\n") - end - end - - private - - def execute(args) - repository.rev_list(args).split("\n") - end - - def get_objects(including: [], excluding: [], options: [], require_path: nil) - opts = { including: including, excluding: excluding, options: options, objects: true } - - repository.rev_list(opts) do |lazy_output| - objects = objects_from_output(lazy_output, require_path: require_path) - - yield(objects) - end - end - - def objects_from_output(object_output, require_path: nil) - object_output.map do |output_line| - sha, path = output_line.split(' ', 2) - - next if require_path && path.to_s.empty? - - sha - end.reject(&:nil?) - end - end - end -end diff --git a/lib/gitlab/git_ref_validator.rb b/lib/gitlab/git_ref_validator.rb index 2e3e4fc3f1f..40636fb204e 100644 --- a/lib/gitlab/git_ref_validator.rb +++ b/lib/gitlab/git_ref_validator.rb @@ -7,11 +7,11 @@ module Gitlab # # Returns true for a valid reference name, false otherwise def validate(ref_name) - return false if ref_name.start_with?('refs/heads/') - return false if ref_name.start_with?('refs/remotes/') + not_allowed_prefixes = %w(refs/heads/ refs/remotes/ -) + return false if ref_name.start_with?(*not_allowed_prefixes) + return false if ref_name == 'HEAD' - Gitlab::Utils.system_silent( - %W(#{Gitlab.config.git.bin_path} check-ref-format --branch #{ref_name})) + Rugged::Reference.valid_name? "refs/heads/#{ref_name}" end end end diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb index 555733d1834..54c78fdb680 100644 --- a/lib/gitlab/gitaly_client/operation_service.rb +++ b/lib/gitlab/gitaly_client/operation_service.rb @@ -144,13 +144,14 @@ module Gitlab branch: encode_binary(target_branch) ) - branch_update = GitalyClient.call( + response = GitalyClient.call( @repository.storage, :operation_service, :user_ff_branch, request - ).branch_update - Gitlab::Git::OperationService::BranchUpdate.from_gitaly(branch_update) + ) + + Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) rescue GRPC::FailedPrecondition => e raise Gitlab::Git::CommitError, e end @@ -306,9 +307,9 @@ module Gitlab raise Gitlab::Git::CommitError, response.commit_error elsif response.create_tree_error.presence raise Gitlab::Git::Repository::CreateTreeError, response.create_tree_error - else - Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) end + + Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) end def user_commit_files_request_header( diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb index 7f4eed9222a..fbe7d4ba1ae 100644 --- a/lib/gitlab/gitaly_client/ref_service.rb +++ b/lib/gitlab/gitaly_client/ref_service.rb @@ -17,6 +17,13 @@ module Gitlab consume_find_all_branches_response(response) end + def remote_branches(remote_name) + request = Gitaly::FindAllRemoteBranchesRequest.new(repository: @gitaly_repo, remote_name: remote_name) + response = GitalyClient.call(@repository.storage, :ref_service, :find_all_remote_branches, request) + + consume_find_all_remote_branches_response(remote_name, response) + end + def merged_branches(branch_names = []) request = Gitaly::FindAllBranchesRequest.new( repository: @gitaly_repo, @@ -56,6 +63,25 @@ module Gitlab encode!(response.name.dup) end + def list_new_commits(newrev) + request = Gitaly::ListNewCommitsRequest.new( + repository: @gitaly_repo, + commit_id: newrev + ) + + response = GitalyClient + .call(@storage, :ref_service, :list_new_commits, request, timeout: GitalyClient.medium_timeout) + + commits = [] + response.each do |msg| + msg.commits.each do |c| + commits << Gitlab::Git::Commit.new(@repository, c) + end + end + + commits + end + def count_tag_names tag_names.count end @@ -224,6 +250,18 @@ module Gitlab end end + def consume_find_all_remote_branches_response(remote_name, response) + remote_name += '/' unless remote_name.ends_with?('/') + + response.flat_map do |message| + message.branches.map do |branch| + target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target_commit) + branch_name = branch.name.sub(remote_name, '') + Gitlab::Git::Branch.new(@repository, branch_name, branch.target_commit.id, target_commit) + end + end + end + def consume_tags_response(response) response.flat_map do |message| message.tags.map { |gitaly_tag| Gitlab::Git::Tag.new(@repository, gitaly_tag) } diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb index 22719e9a003..38ef12491df 100644 --- a/lib/gitlab/gitlab_import/client.rb +++ b/lib/gitlab/gitlab_import/client.rb @@ -32,15 +32,15 @@ module Gitlab api.get("/api/v4/user").parsed end - def issues(project_identifier) - lazy_page_iterator(PER_PAGE) do |page| - api.get("/api/v4/projects/#{project_identifier}/issues?per_page=#{PER_PAGE}&page=#{page}").parsed + def issues(project_identifier, **kwargs) + lazy_page_iterator(**kwargs) do |page, per_page| + api.get("/api/v4/projects/#{project_identifier}/issues?per_page=#{per_page}&page=#{page}").parsed end end - def issue_comments(project_identifier, issue_id) - lazy_page_iterator(PER_PAGE) do |page| - api.get("/api/v4/projects/#{project_identifier}/issues/#{issue_id}/notes?per_page=#{PER_PAGE}&page=#{page}").parsed + def issue_comments(project_identifier, issue_id, **kwargs) + lazy_page_iterator(**kwargs) do |page, per_page| + api.get("/api/v4/projects/#{project_identifier}/issues/#{issue_id}/notes?per_page=#{per_page}&page=#{page}").parsed end end @@ -48,23 +48,27 @@ module Gitlab api.get("/api/v4/projects/#{id}").parsed end - def projects - lazy_page_iterator(PER_PAGE) do |page| - api.get("/api/v4/projects?per_page=#{PER_PAGE}&page=#{page}").parsed + def projects(**kwargs) + lazy_page_iterator(**kwargs) do |page, per_page| + api.get("/api/v4/projects?per_page=#{per_page}&page=#{page}&simple=true&membership=true").parsed end end private - def lazy_page_iterator(per_page) + def lazy_page_iterator(starting_page: 1, page_limit: nil, per_page: PER_PAGE) Enumerator.new do |y| - page = 1 + page = starting_page + page_limit = (starting_page - 1) + page_limit if page_limit + loop do - items = yield(page) + items = yield(page, per_page) + items.each do |item| y << item end - break if items.empty? || items.size < per_page + + break if items.empty? || items.size < per_page || (page_limit && page >= page_limit) page += 1 end diff --git a/lib/gitlab/hook_data/base_builder.rb b/lib/gitlab/hook_data/base_builder.rb new file mode 100644 index 00000000000..4ffca356b29 --- /dev/null +++ b/lib/gitlab/hook_data/base_builder.rb @@ -0,0 +1,38 @@ +module Gitlab + module HookData + class BaseBuilder + attr_accessor :object + + MARKDOWN_SIMPLE_IMAGE = %r{ + #{::Gitlab::Regex.markdown_code_or_html_blocks} + | + (?<image> + ! + \[(?<title>[^\n]*?)\] + \((?<url>(?!(https?://|//))[^\n]+?)\) + ) + }mx.freeze + + def initialize(object) + @object = object + end + + private + + def absolute_image_urls(markdown_text) + return markdown_text unless markdown_text.present? + + markdown_text.gsub(MARKDOWN_SIMPLE_IMAGE) do + if $~[:image] + url = $~[:url] + url = "/#{url}" unless url.start_with?('/') + + "![#{$~[:title]}](#{Gitlab.config.gitlab.url}#{url})" + else + $~[0] + end + end + end + end + end +end diff --git a/lib/gitlab/hook_data/issuable_builder.rb b/lib/gitlab/hook_data/issuable_builder.rb index 6ab36676127..f2eda398b8f 100644 --- a/lib/gitlab/hook_data/issuable_builder.rb +++ b/lib/gitlab/hook_data/issuable_builder.rb @@ -1,13 +1,9 @@ module Gitlab module HookData - class IssuableBuilder + class IssuableBuilder < BaseBuilder CHANGES_KEYS = %i[previous current].freeze - attr_accessor :issuable - - def initialize(issuable) - @issuable = issuable - end + alias_method :issuable, :object def build(user: nil, changes: {}) hook_data = { diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb index f9b1a3caf5e..0d71c748dc6 100644 --- a/lib/gitlab/hook_data/issue_builder.rb +++ b/lib/gitlab/hook_data/issue_builder.rb @@ -1,6 +1,6 @@ module Gitlab module HookData - class IssueBuilder + class IssueBuilder < BaseBuilder SAFE_HOOK_ATTRIBUTES = %i[ assignee_id author_id @@ -30,14 +30,11 @@ module Gitlab total_time_spent ].freeze - attr_accessor :issue - - def initialize(issue) - @issue = issue - end + alias_method :issue, :object def build attrs = { + description: absolute_image_urls(issue.description), url: Gitlab::UrlBuilder.build(issue), total_time_spent: issue.total_time_spent, human_total_time_spent: issue.human_total_time_spent, diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb index aff786864f2..dfbed0597ed 100644 --- a/lib/gitlab/hook_data/merge_request_builder.rb +++ b/lib/gitlab/hook_data/merge_request_builder.rb @@ -1,6 +1,6 @@ module Gitlab module HookData - class MergeRequestBuilder + class MergeRequestBuilder < BaseBuilder SAFE_HOOK_ATTRIBUTES = %i[ assignee_id author_id @@ -35,14 +35,11 @@ module Gitlab total_time_spent ].freeze - attr_accessor :merge_request - - def initialize(merge_request) - @merge_request = merge_request - end + alias_method :merge_request, :object def build attrs = { + description: absolute_image_urls(merge_request.description), url: Gitlab::UrlBuilder.build(merge_request), source: merge_request.source_project.try(:hook_attrs), target: merge_request.target_project.hook_attrs, diff --git a/lib/gitlab/hook_data/note_builder.rb b/lib/gitlab/hook_data/note_builder.rb new file mode 100644 index 00000000000..81873e345d5 --- /dev/null +++ b/lib/gitlab/hook_data/note_builder.rb @@ -0,0 +1,43 @@ +module Gitlab + module HookData + class NoteBuilder < BaseBuilder + SAFE_HOOK_ATTRIBUTES = %i[ + attachment + author_id + change_position + commit_id + created_at + discussion_id + id + line_code + note + noteable_id + noteable_type + original_position + position + project_id + resolved_at + resolved_by_id + resolved_by_push + st_diff + system + type + updated_at + updated_by_id + ].freeze + + alias_method :note, :object + + def build + note + .attributes + .with_indifferent_access + .slice(*SAFE_HOOK_ATTRIBUTES) + .merge( + description: absolute_image_urls(note.note), + url: Gitlab::UrlBuilder.build(note) + ) + end + end + end +end diff --git a/lib/gitlab/hook_data/wiki_page_builder.rb b/lib/gitlab/hook_data/wiki_page_builder.rb new file mode 100644 index 00000000000..59c94a61cf2 --- /dev/null +++ b/lib/gitlab/hook_data/wiki_page_builder.rb @@ -0,0 +1,15 @@ +module Gitlab + module HookData + class WikiPageBuilder < BaseBuilder + alias_method :wiki_page, :object + + def build + wiki_page + .attributes + .merge( + 'content' => absolute_image_urls(wiki_page.content) + ) + end + end + end +end diff --git a/lib/gitlab/import_export/avatar_saver.rb b/lib/gitlab/import_export/avatar_saver.rb index 998c21e2586..31ef0490cb3 100644 --- a/lib/gitlab/import_export/avatar_saver.rb +++ b/lib/gitlab/import_export/avatar_saver.rb @@ -11,7 +11,12 @@ module Gitlab def save return true unless @project.avatar.exists? - copy_files(avatar_path, avatar_export_path) + Gitlab::ImportExport::UploadsManager.new( + project: @project, + shared: @shared, + relative_export_path: 'avatar', + from: avatar_path + ).save rescue => e @shared.error(e) false @@ -19,10 +24,6 @@ module Gitlab private - def avatar_export_path - File.join(@shared.export_path, 'avatar', @project.avatar_identifier) - end - def avatar_path @project.avatar.path end diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb index 0f4c3498036..4c411f4847e 100644 --- a/lib/gitlab/import_export/file_importer.rb +++ b/lib/gitlab/import_export/file_importer.rb @@ -4,6 +4,7 @@ module Gitlab include Gitlab::ImportExport::CommandLineUtil MAX_RETRIES = 8 + IGNORED_FILENAMES = %w(. ..).freeze def self.import(*args) new(*args).import @@ -59,7 +60,7 @@ module Gitlab end def extracted_files - Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| f =~ %r{.*/\.{1,2}$} } + Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| IGNORED_FILENAMES.include?(File.basename(f)) } end end end diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb new file mode 100644 index 00000000000..1110149712d --- /dev/null +++ b/lib/gitlab/import_export/uploads_manager.rb @@ -0,0 +1,101 @@ +module Gitlab + module ImportExport + class UploadsManager + include Gitlab::ImportExport::CommandLineUtil + + UPLOADS_BATCH_SIZE = 100 + + def initialize(project:, shared:, relative_export_path: 'uploads', from: nil) + @project = project + @shared = shared + @relative_export_path = relative_export_path + @from = from || default_uploads_path + end + + def save + copy_files(@from, uploads_export_path) if File.directory?(@from) + + if File.file?(@from) && @relative_export_path == 'avatar' + copy_files(@from, File.join(uploads_export_path, @project.avatar.filename)) + end + + copy_from_object_storage + + true + rescue => e + @shared.error(e) + false + end + + def restore + Dir["#{uploads_export_path}/**/*"].each do |upload| + next if File.directory?(upload) + + add_upload(upload) + end + + true + rescue => e + @shared.error(e) + false + end + + private + + def add_upload(upload) + uploader_context = FileUploader.extract_dynamic_path(upload).named_captures.symbolize_keys + + UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute + end + + def copy_from_object_storage + return unless Gitlab::ImportExport.object_storage? + + each_uploader do |uploader| + next unless uploader.file + next if uploader.upload.local? # Already copied, using the old method + + download_and_copy(uploader) + end + end + + def default_uploads_path + FileUploader.absolute_base_dir(@project) + end + + def uploads_export_path + @uploads_export_path ||= File.join(@shared.export_path, @relative_export_path) + end + + def each_uploader + avatar_path = @project.avatar&.upload&.path + + if @relative_export_path == 'avatar' + yield(@project.avatar) + else + project_uploads_except_avatar(avatar_path).find_each(batch_size: UPLOADS_BATCH_SIZE) do |upload| + yield(upload.build_uploader) + end + end + end + + def project_uploads_except_avatar(avatar_path) + return @project.uploads unless avatar_path + + @project.uploads.where("path != ?", avatar_path) + end + + def download_and_copy(upload) + secret = upload.try(:secret) || '' + upload_path = File.join(uploads_export_path, secret, upload.filename) + + mkdir_p(File.join(uploads_export_path, secret)) + + File.open(upload_path, 'w') do |file| + # Download (stream) file from the uploader's location + IO.copy_stream(URI.parse(upload.file.url).open, file) + end + end + end + end +end diff --git a/lib/gitlab/import_export/uploads_restorer.rb b/lib/gitlab/import_export/uploads_restorer.rb index df19354b76e..25f85936227 100644 --- a/lib/gitlab/import_export/uploads_restorer.rb +++ b/lib/gitlab/import_export/uploads_restorer.rb @@ -2,13 +2,30 @@ module Gitlab module ImportExport class UploadsRestorer < UploadsSaver def restore - return true unless File.directory?(uploads_export_path) + if Gitlab::ImportExport.object_storage? + Gitlab::ImportExport::UploadsManager.new( + project: @project, + shared: @shared + ).restore + elsif File.directory?(uploads_export_path) + copy_files(uploads_export_path, uploads_path) - copy_files(uploads_export_path, uploads_path) + true + else + true # Proceed without uploads + end rescue => e @shared.error(e) false end + + def uploads_path + FileUploader.absolute_base_dir(@project) + end + + def uploads_export_path + @uploads_export_path ||= File.join(@shared.export_path, 'uploads') + end end end end diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb index 2f08dda55fd..b3f17af5661 100644 --- a/lib/gitlab/import_export/uploads_saver.rb +++ b/lib/gitlab/import_export/uploads_saver.rb @@ -9,21 +9,14 @@ module Gitlab end def save - return true unless File.directory?(uploads_path) - - copy_files(uploads_path, uploads_export_path) + Gitlab::ImportExport::UploadsManager.new( + project: @project, + shared: @shared + ).save rescue => e @shared.error(e) false end - - def uploads_path - FileUploader.absolute_base_dir(@project) - end - - def uploads_export_path - File.join(@shared.export_path, 'uploads') - end end end end diff --git a/lib/gitlab/json_logger.rb b/lib/gitlab/json_logger.rb new file mode 100644 index 00000000000..28e258196ca --- /dev/null +++ b/lib/gitlab/json_logger.rb @@ -0,0 +1,22 @@ +module Gitlab + class JsonLogger < ::Gitlab::Logger + def self.file_name_noext + raise NotImplementedError + end + + def format_message(severity, timestamp, progname, message) + data = {} + data[:severity] = severity + data[:time] = timestamp.utc.iso8601(3) + + case message + when String + data[:message] = message + when Hash + data.merge!(message) + end + + data.to_json + "\n" + end + end +end diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb index a42e312b5d3..e58927a40b9 100644 --- a/lib/gitlab/logger.rb +++ b/lib/gitlab/logger.rb @@ -4,10 +4,18 @@ module Gitlab file_name_noext + '.log' end + def self.debug(message) + build.debug(message) + end + def self.error(message) build.error(message) end + def self.warn(message) + build.warn(message) + end + def self.info(message) build.info(message) end diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 38f119cf06d..c205f348023 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -20,7 +20,7 @@ module Gitlab define_histogram :gitlab_sql_duration_seconds do docstring 'SQL time' base_labels Transaction::BASE_LABELS - buckets [0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0] + buckets [0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0] end def current_transaction diff --git a/lib/gitlab/omniauth_initializer.rb b/lib/gitlab/omniauth_initializer.rb index a71acda8701..f33ea0880df 100644 --- a/lib/gitlab/omniauth_initializer.rb +++ b/lib/gitlab/omniauth_initializer.rb @@ -1,23 +1,21 @@ module Gitlab class OmniauthInitializer - def self.enabled? - Gitlab.config.omniauth.enabled || - Gitlab.config.omniauth.auto_sign_in_with_provider.present? - end - def initialize(devise_config) @devise_config = devise_config end def execute(providers) providers.each do |provider| - add_provider(provider['name'].to_sym, *arguments_for(provider)) + name = provider['name'].to_sym + + add_provider_to_devise(name, *arguments_for(provider)) + setup_provider(name) end end private - def add_provider(*args) + def add_provider_to_devise(*args) @devise_config.omniauth(*args) end @@ -76,5 +74,23 @@ module Gitlab end end end + + def omniauth_customized_providers + @omniauth_customized_providers ||= build_omniauth_customized_providers + end + + # We override this in EE + def build_omniauth_customized_providers + %i[bitbucket jwt] + end + + def setup_provider(provider) + case provider + when :kerberos + require 'omniauth-kerberos' + when *omniauth_customized_providers + require_dependency "omni_auth/strategies/#{provider}" + end + end end end diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb index b9832a724c4..d0cb7c1a7cf 100644 --- a/lib/gitlab/popen.rb +++ b/lib/gitlab/popen.rb @@ -34,11 +34,16 @@ module Gitlab start = Time.now Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + # stderr and stdout pipes can block if stderr/stdout aren't drained: https://bugs.ruby-lang.org/issues/9082 + # Mimic what Ruby does with capture3: https://github.com/ruby/ruby/blob/1ec544695fa02d714180ef9c34e755027b6a2103/lib/open3.rb#L257-L273 + out_reader = Thread.new { stdout.read } + err_reader = Thread.new { stderr.read } + yield(stdin) if block_given? stdin.close - cmd_stdout = stdout.read - cmd_stderr = stderr.read + cmd_stdout = out_reader.value + cmd_stderr = err_reader.value cmd_status = wait_thr.value end diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb index ecff6ab5d5e..c5bb4648572 100644 --- a/lib/gitlab/profiler.rb +++ b/lib/gitlab/profiler.rb @@ -146,5 +146,11 @@ module Gitlab logger.info("#{model} total (#{query_count}): #{time.round(2)}ms") end end + + def self.print_by_total_time(result, options = {}) + default_options = { sort_method: :total_time } + + Gitlab::Profiler::TotalTimeFlatPrinter.new(result).print(STDOUT, default_options.merge(options)) + end end end diff --git a/lib/gitlab/profiler/total_time_flat_printer.rb b/lib/gitlab/profiler/total_time_flat_printer.rb new file mode 100644 index 00000000000..2fd0ec10ba8 --- /dev/null +++ b/lib/gitlab/profiler/total_time_flat_printer.rb @@ -0,0 +1,39 @@ +module Gitlab + module Profiler + class TotalTimeFlatPrinter < RubyProf::FlatPrinter + def max_percent + @options[:max_percent] || 100 + end + + # Copied from: + # <https://github.com/ruby-prof/ruby-prof/blob/master/lib/ruby-prof/printers/flat_printer.rb> + # + # The changes are just to filter by total time, not self time, and add a + # max_percent option as well. + def print_methods(thread) + total_time = thread.total_time + methods = thread.methods.sort_by(&sort_method).reverse + + sum = 0 + methods.each do |method| + total_percent = (method.total_time / total_time) * 100 + next if total_percent < min_percent + next if total_percent > max_percent + + sum += method.self_time + + @output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s\n" % [ + method.self_time / total_time * 100, # %self + method.total_time, # total + method.self_time, # self + method.wait_time, # wait + method.children_time, # children + method.called, # calls + method.recursive? ? "*" : " ", # cycle + method_name(method) # name + ] + end + end + end + end +end diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 38bdc61d8ab..62f9e538c04 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -5,7 +5,7 @@ module Gitlab def initialize(current_user, project, query, repository_ref = nil, per_page: 20) @current_user = current_user @project = project - @repository_ref = repository_ref.presence || project.default_branch + @repository_ref = repository_ref.presence @query = query @per_page = per_page end @@ -95,7 +95,7 @@ module Gitlab def blobs return [] unless Ability.allowed?(@current_user, :download_code, @project) - @blobs ||= Gitlab::FileFinder.new(project, repository_ref).find(query) + @blobs ||= Gitlab::FileFinder.new(project, repository_project_ref).find(query) end def wiki_blobs @@ -103,11 +103,8 @@ module Gitlab @wiki_blobs ||= begin if project.wiki_enabled? && query.present? - project_wiki = ProjectWiki.new(project) - - unless project_wiki.empty? - ref = repository_ref || project.wiki.default_branch - Gitlab::WikiFileFinder.new(project, ref).find(query) + unless project.wiki.empty? + Gitlab::WikiFileFinder.new(project, repository_wiki_ref).find(query) else [] end @@ -150,5 +147,13 @@ module Gitlab def project_ids_relation project end + + def repository_project_ref + @repository_project_ref ||= repository_ref || project.default_branch + end + + def repository_wiki_ref + @repository_wiki_ref ||= repository_ref || project.wiki.default_branch + end end end diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index ac3de2a8f71..e1a958c508a 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -73,5 +73,31 @@ module Gitlab def build_trace_section_regex @build_trace_section_regexp ||= /section_((?:start)|(?:end)):(\d+):([a-zA-Z0-9_.-]+)\r\033\[0K/.freeze end + + def markdown_code_or_html_blocks + @markdown_code_or_html_blocks ||= %r{ + (?<code> + # Code blocks: + # ``` + # Anything, including `>>>` blocks which are ignored by this filter + # ``` + + ^``` + .+? + \n```\ *$ + ) + | + (?<html> + # HTML block: + # <tag> + # Anything, including `>>>` blocks which are ignored by this filter + # </tag> + + ^<[^>]+?>\ *\n + .+? + \n<\/[^>]+?>\ *$ + ) + }mx + end end end diff --git a/lib/gitlab/serializer/ci/variables.rb b/lib/gitlab/serializer/ci/variables.rb index c059c454eac..292c8de6229 100644 --- a/lib/gitlab/serializer/ci/variables.rb +++ b/lib/gitlab/serializer/ci/variables.rb @@ -13,8 +13,9 @@ module Gitlab object = YAML.safe_load(string, [Symbol]) object.map do |variable| - variable[:key] = variable[:key].to_s - variable + variable.symbolize_keys.tap do |variable| + variable[:key] = variable[:key].to_s + end end end diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb index de8b6ec69ce..308a95d2f09 100644 --- a/lib/gitlab/url_sanitizer.rb +++ b/lib/gitlab/url_sanitizer.rb @@ -71,12 +71,10 @@ module Gitlab def generate_full_url return @url unless valid_credentials? - @full_url = @url.dup - - @full_url.password = credentials[:password] if credentials[:password].present? - @full_url.user = credentials[:user] if credentials[:user].present? - - @full_url + @url.dup.tap do |generated| + generated.password = encode_percent(credentials[:password]) if credentials[:password].present? + generated.user = encode_percent(credentials[:user]) if credentials[:user].present? + end end def safe_url @@ -89,5 +87,10 @@ module Gitlab def valid_credentials? credentials && credentials.is_a?(Hash) && credentials.any? end + + def encode_percent(string) + # CGI.escape converts spaces to +, but this doesn't work for git clone + CGI.escape(string).gsub('+', '%20') + end end end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index dff0c97eeb4..22c9638ecc0 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -95,7 +95,7 @@ module Gitlab gravatar_enabled: Gitlab::CurrentSettings.gravatar_enabled?, ldap_enabled: Gitlab.config.ldap.enabled, mattermost_enabled: Gitlab.config.mattermost.enabled, - omniauth_enabled: Gitlab.config.omniauth.enabled, + omniauth_enabled: Gitlab::Auth.omniauth_enabled?, reply_by_email_enabled: Gitlab::IncomingEmail.enabled?, signup_enabled: Gitlab::CurrentSettings.allow_signup? } diff --git a/lib/gitlab/user_activities.rb b/lib/gitlab/user_activities.rb deleted file mode 100644 index 125488536e1..00000000000 --- a/lib/gitlab/user_activities.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Gitlab - class UserActivities - include Enumerable - - KEY = 'users:activities'.freeze - BATCH_SIZE = 500 - - def self.record(key, time = Time.now) - Gitlab::Redis::SharedState.with do |redis| - redis.hset(KEY, key, time.to_i) - end - end - - def delete(*keys) - Gitlab::Redis::SharedState.with do |redis| - redis.hdel(KEY, keys) - end - end - - def each - cursor = 0 - loop do - cursor, pairs = - Gitlab::Redis::SharedState.with do |redis| - redis.hscan(KEY, cursor, count: BATCH_SIZE) - end - - Hash[pairs].each { |pair| yield pair } - - break if cursor == '0' - end - end - end -end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index 52ae1330d7f..5e07b12ee1c 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -104,28 +104,5 @@ namespace :gitlab do puts "To block these users run this command with BLOCK=true".color(:yellow) end end - - # This is a rake task which removes faulty refs. These refs where only - # created in the 8.13.RC cycle, and fixed in the stable builds which were - # released. So likely this should only be run once on gitlab.com - # Faulty refs are moved so they are kept around, else some features break. - desc 'GitLab | Cleanup | Remove faulty deployment refs' - task move_faulty_deployment_refs: :gitlab_environment do - projects = Project.where(id: Deployment.select(:project_id).distinct) - - projects.find_each do |project| - rugged = project.repository.rugged - - max_iid = project.deployments.maximum(:iid) - - rugged.references.each('refs/environments/**/*') do |ref| - id = ref.name.split('/').last.to_i - next unless id > max_iid - - project.deployments.find(id).create_ref - project.repository.delete_refs(ref) - end - end - end end end diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index 6de739e9515..e97d77d20e0 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -54,8 +54,8 @@ namespace :gitlab do puts "HTTP Clone URL:\t#{http_clone_url}" puts "SSH Clone URL:\t#{ssh_clone_url}" puts "Using LDAP:\t#{Gitlab.config.ldap.enabled ? "yes".color(:green) : "no"}" - puts "Using Omniauth:\t#{Gitlab.config.omniauth.enabled ? "yes".color(:green) : "no"}" - puts "Omniauth Providers: #{omniauth_providers.join(', ')}" if Gitlab.config.omniauth.enabled + puts "Using Omniauth:\t#{Gitlab::Auth.omniauth_enabled? ? "yes".color(:green) : "no"}" + puts "Omniauth Providers: #{omniauth_providers.join(', ')}" if Gitlab::Auth.omniauth_enabled? # check Gitolite version gitlab_shell_version_file = "#{Gitlab.config.gitlab_shell.hooks_path}/../VERSION" diff --git a/lib/uploaded_file.rb b/lib/uploaded_file.rb index 4b9cb59eab5..53e5ac02e42 100644 --- a/lib/uploaded_file.rb +++ b/lib/uploaded_file.rb @@ -21,7 +21,7 @@ class UploadedFile raise InvalidPathError, "#{path} file does not exist" unless ::File.exist?(path) @content_type = content_type - @original_filename = filename || ::File.basename(path) + @original_filename = sanitize_filename(filename || path) @content_type = content_type @sha256 = sha256 @remote_id = remote_id @@ -55,6 +55,16 @@ class UploadedFile end end + # copy-pasted from CarrierWave::SanitizedFile + def sanitize_filename(name) + name = name.tr("\\", "/") # work-around for IE + name = ::File.basename(name) + name = name.gsub(CarrierWave::SanitizedFile.sanitize_regexp, "_") + name = "_#{name}" if name =~ /\A\.+\z/ + name = "unnamed" if name.empty? + name.mb_chars.to_s + end + def path @tempfile.path end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ab488218288..75b88a2cb2f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,6 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-07-10 16:02-0700\n" +"PO-Revision-Date: 2018-07-10 16:02-0700\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" @@ -129,9 +131,6 @@ msgstr "" msgid "%{unstaged} unstaged and %{staged} staged changes" msgstr "" -msgid "(check out the %{link} for information on how to install it)." -msgstr "" - msgid "+ %{moreCount} more" msgstr "" @@ -205,6 +204,18 @@ msgstr "" msgid "404|Please contact your GitLab administrator if you think this is a mistake." msgstr "" +msgid "<code>\"johnsmith@example.com\": \"@johnsmith\"</code> will add \"By <a href=\"#\">@johnsmith</a>\" to all issues and comments originally created by johnsmith@example.com, and will set <a href=\"#\">@johnsmith</a> as the assignee on all issues originally assigned to johnsmith@example.com." +msgstr "" + +msgid "<code>\"johnsmith@example.com\": \"John Smith\"</code> will add \"By John Smith\" to all issues and comments originally created by johnsmith@example.com." +msgstr "" + +msgid "<code>\"johnsmith@example.com\": \"johnsm...@example.com\"</code> will add \"By johnsm...@example.com\" to all issues and comments originally created by johnsmith@example.com. The email address or username is masked to ensure the user's privacy." +msgstr "" + +msgid "<code>\"johnsmith@example.com\": \"johnsmith@example.com\"</code> will add \"By <a href=\"#\">johnsmith@example.com</a>\" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address." +msgstr "" + msgid "<strong>%{group_name}</strong> group members" msgstr "" @@ -244,6 +255,9 @@ msgstr "" msgid "Access Tokens" msgstr "" +msgid "Access denied! Please verify you can add deploy keys to this repository." +msgstr "" + msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again." msgstr "" @@ -280,6 +294,9 @@ msgstr "" msgid "Add Readme" msgstr "" +msgid "Add new application" +msgstr "" + msgid "Add new directory" msgstr "" @@ -379,9 +396,18 @@ msgstr "" msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import." msgstr "" +msgid "An application called %{link_to_client} is requesting access to your GitLab account." +msgstr "" + +msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator." +msgstr "" + msgid "An error accured whilst committing your changes." msgstr "" +msgid "An error has occurred" +msgstr "" + msgid "An error occured creating the new branch." msgstr "" @@ -475,12 +501,24 @@ msgstr "" msgid "An error occurred. Please try again." msgstr "" +msgid "Anonymous" +msgstr "" + msgid "Any" msgstr "" msgid "Appearance" msgstr "" +msgid "Application" +msgstr "" + +msgid "Application Id" +msgstr "" + +msgid "Application: %{name}" +msgstr "" + msgid "Applications" msgstr "" @@ -562,6 +600,24 @@ msgstr "" msgid "Author" msgstr "" +msgid "Authorization code:" +msgstr "" + +msgid "Authorization was granted by entering your username and password in the application." +msgstr "" + +msgid "Authorize" +msgstr "" + +msgid "Authorize %{link_to_client} to use your account?" +msgstr "" + +msgid "Authorized At" +msgstr "" + +msgid "Authorized applications (%{size})" +msgstr "" + msgid "Authors: %{authors}" msgstr "" @@ -706,6 +762,9 @@ msgstr "" msgid "Below you will find all the groups that are public." msgstr "" +msgid "Bitbucket import" +msgstr "" + msgid "Boards" msgstr "" @@ -921,6 +980,12 @@ msgstr "" msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages." msgstr "" +msgid "Callback URL" +msgstr "" + +msgid "Callback url" +msgstr "" + msgid "Can't find HEAD commit for this branch" msgstr "" @@ -981,6 +1046,12 @@ msgstr "" msgid "Cherry-pick this merge request" msgstr "" +msgid "Choose <strong>Create archive</strong> and wait for archiving to complete." +msgstr "" + +msgid "Choose <strong>Next</strong> at the bottom of the page." +msgstr "" + msgid "Choose File ..." msgstr "" @@ -1092,9 +1163,15 @@ msgstr "" msgid "Click any <strong>project name</strong> in the project list below to navigate to the project milestone." msgstr "" +msgid "Click the <strong>Download</strong> button and wait for downloading to complete." +msgstr "" + msgid "Click the <strong>Promote</strong> button in the top right corner to promote it to a group milestone." msgstr "" +msgid "Click the <strong>Select none</strong> button on the right, since we only need \"Google Code Project Hosting\"." +msgstr "" + msgid "Click the button below to begin the install process by navigating to the Kubernetes page" msgstr "" @@ -1104,6 +1181,9 @@ msgstr "" msgid "Click to expand text" msgstr "" +msgid "Clients" +msgstr "" + msgid "Clone repository" msgstr "" @@ -1167,6 +1247,9 @@ msgstr "" msgid "ClusterIntegration|Create Kubernetes cluster" msgstr "" +msgid "ClusterIntegration|Did you know?" +msgstr "" + msgid "ClusterIntegration|Enter the details for your Kubernetes cluster" msgstr "" @@ -1203,6 +1286,9 @@ msgstr "" msgid "ClusterIntegration|Helm Tiller" msgstr "" +msgid "ClusterIntegration|Hide" +msgstr "" + msgid "ClusterIntegration|Ingress" msgstr "" @@ -1329,9 +1415,6 @@ msgstr "" msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration." msgstr "" -msgid "ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform" -msgstr "" - msgid "ClusterIntegration|Remove Kubernetes cluster integration" msgstr "" @@ -1639,6 +1722,9 @@ msgstr "" msgid "Continue" msgstr "" +msgid "Continue to the next step" +msgstr "" + msgid "Continuous Integration and Deployment" msgstr "" @@ -1690,6 +1776,9 @@ msgstr "" msgid "Copy to clipboard" msgstr "" +msgid "Copy token to clipboard" +msgstr "" + msgid "Create" msgstr "" @@ -1768,6 +1857,9 @@ msgstr "" msgid "Created" msgstr "" +msgid "Created At" +msgstr "" + msgid "Created by me" msgstr "" @@ -1795,6 +1887,12 @@ msgstr "" msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}." msgstr "" +msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import." +msgstr "" + +msgid "Customize how Google Code email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import." +msgstr "" + msgid "Cycle Analytics" msgstr "" @@ -1834,6 +1932,12 @@ msgstr "" msgid "Decline and sign out" msgstr "" +msgid "Default: Directly import the Google Code email address or username" +msgstr "" + +msgid "Default: Map a FogBugz account ID to a full name" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "" @@ -1846,6 +1950,9 @@ msgstr "" msgid "Delete list" msgstr "" +msgid "Deny" +msgstr "" + msgid "Deploy" msgid_plural "Deploys" msgstr[0] "" @@ -1983,6 +2090,9 @@ msgstr "" msgid "Description:" msgstr "" +msgid "Destroy" +msgstr "" + msgid "Details" msgstr "" @@ -2019,6 +2129,9 @@ msgstr "" msgid "Dismiss Cycle Analytics introduction box" msgstr "" +msgid "Do you want to customize how Google Code email addresses and usernames are imported into GitLab?" +msgstr "" + msgid "Domain" msgstr "" @@ -2076,6 +2189,9 @@ msgstr "" msgid "Edit Snippet" msgstr "" +msgid "Edit application" +msgstr "" + msgid "Edit files in the editor and commit changes here" msgstr "" @@ -2355,6 +2471,12 @@ msgstr "" msgid "Find file" msgstr "" +msgid "Find the downloaded ZIP file and decompress it." +msgstr "" + +msgid "Find the newly extracted <code>Takeout/Google Code Project Hosting/GoogleCodeProjectHosting.json</code> file." +msgstr "" + msgid "Finished" msgstr "" @@ -2364,6 +2486,24 @@ msgstr "" msgid "FirstPushedBy|pushed by" msgstr "" +msgid "FogBugz Email" +msgstr "" + +msgid "FogBugz Import" +msgstr "" + +msgid "FogBugz Password" +msgstr "" + +msgid "FogBugz URL" +msgstr "" + +msgid "FogBugz import" +msgstr "" + +msgid "Follow the steps below to export your Google Code project data." +msgstr "" + msgid "For internal projects, any logged in user can view pipelines and access job details (output logs and artifacts)" msgstr "" @@ -2396,6 +2536,18 @@ msgstr "" msgid "From %{provider_title}" msgstr "" +msgid "From Bitbucket" +msgstr "" + +msgid "From FogBugz" +msgstr "" + +msgid "From GitLab.com" +msgstr "" + +msgid "From Google Code" +msgstr "" + msgid "From issue creation until deploy to production" msgstr "" @@ -2417,6 +2569,9 @@ msgstr "" msgid "Generate a default set of labels" msgstr "" +msgid "Git" +msgstr "" + msgid "Git repository URL" msgstr "" @@ -2441,7 +2596,16 @@ msgstr "" msgid "GitLab Group Runners can execute code for all the projects in this group." msgstr "" -msgid "GitLab Runner section" +msgid "GitLab Import" +msgstr "" + +msgid "GitLab User" +msgstr "" + +msgid "GitLab project export" +msgstr "" + +msgid "GitLab.com import" msgstr "" msgid "Gitaly" @@ -2453,18 +2617,33 @@ msgstr "" msgid "Gitaly|Address" msgstr "" +msgid "Gitea Host URL" +msgstr "" + +msgid "Gitea Import" +msgstr "" + msgid "Go Back" msgstr "" msgid "Go back" msgstr "" +msgid "Go to %{link_to_google_takeout}." +msgstr "" + msgid "Go to your fork" msgstr "" msgid "GoToYourFork|Fork" msgstr "" +msgid "Google Code import" +msgstr "" + +msgid "Google Takeout" +msgstr "" + msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service." msgstr "" @@ -2686,31 +2865,64 @@ msgstr "" msgid "Import" msgstr "" +msgid "Import Projects from Gitea" +msgstr "" + +msgid "Import all compatible projects" +msgstr "" + +msgid "Import all projects" +msgstr "" + msgid "Import all repositories" msgstr "" +msgid "Import an exported GitLab project" +msgstr "" + msgid "Import in progress" msgstr "" msgid "Import multiple repositories by uploading a manifest file." msgstr "" +msgid "Import project" +msgstr "" + +msgid "Import projects from Bitbucket" +msgstr "" + +msgid "Import projects from FogBugz" +msgstr "" + +msgid "Import projects from GitLab.com" +msgstr "" + +msgid "Import projects from Google Code" +msgstr "" + msgid "Import repositories from GitHub" msgstr "" msgid "Import repository" msgstr "" +msgid "In the next step, you'll be able to select the projects you want to import." +msgstr "" + msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept." msgstr "" +msgid "Incompatible Project" +msgstr "" + msgid "Inline" msgstr "" -msgid "Install Runner on Kubernetes" +msgid "Install GitLab Runner" msgstr "" -msgid "Install a Runner compatible with GitLab CI" +msgid "Install Runner on Kubernetes" msgstr "" msgid "Instance does not support multiple Kubernetes clusters" @@ -2901,9 +3113,15 @@ msgstr "" msgid "Leave project" msgstr "" +msgid "Leave the \"File type\" and \"Delivery method\" options on their default values." +msgstr "" + msgid "List" msgstr "" +msgid "List Your Gitea Repositories" +msgstr "" + msgid "List available repositories" msgstr "" @@ -2934,12 +3152,21 @@ msgstr "" msgid "Locked to current projects" msgstr "" +msgid "Make sure you're logged into the account that owns the projects you'd like to import." +msgstr "" + msgid "Manage access" msgstr "" msgid "Manage all notifications" msgstr "" +msgid "Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account." +msgstr "" + +msgid "Manage applications that you've authorized to use your account." +msgstr "" + msgid "Manage group labels" msgstr "" @@ -2955,6 +3182,18 @@ msgstr "" msgid "Manifest file import" msgstr "" +msgid "Map a FogBugz account ID to a GitLab user" +msgstr "" + +msgid "Map a Google Code user to a GitLab user" +msgstr "" + +msgid "Map a Google Code user to a full email address" +msgstr "" + +msgid "Map a Google Code user to a full name" +msgstr "" + msgid "Mar" msgstr "" @@ -3141,6 +3380,9 @@ msgstr "" msgid "New" msgstr "" +msgid "New Application" +msgstr "" + msgid "New Group" msgstr "" @@ -3251,6 +3493,9 @@ msgstr "" msgid "No schedules" msgstr "" +msgid "No, directly import the existing email addresses and usernames." +msgstr "" + msgid "None" msgstr "" @@ -3281,6 +3526,9 @@ msgstr "" msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token." msgstr "" +msgid "Notes|Are you sure you want to cancel creating this comment?" +msgstr "" + msgid "Notification events" msgstr "" @@ -3362,6 +3610,12 @@ msgstr "" msgid "OfSearchInADropdown|Filter" msgstr "" +msgid "One or more of your Bitbucket projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git." +msgstr "" + +msgid "One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git." +msgstr "" + msgid "Online IDE integration settings." msgstr "" @@ -3386,6 +3640,12 @@ msgstr "" msgid "Operations" msgstr "" +msgid "Optionally, you can %{link_to_customize} how FogBugz email addresses and usernames are imported into GitLab." +msgstr "" + +msgid "Optionally, you can %{link_to_customize} how Google Code email addresses and usernames are imported into GitLab." +msgstr "" + msgid "Options" msgstr "" @@ -3620,6 +3880,15 @@ msgstr "" msgid "Please accept the Terms of Service before continuing." msgstr "" +msgid "Please convert them to %{link_to_git}, and go through the %{link_to_import_flow} again." +msgstr "" + +msgid "Please convert them to Git on Google Code, and go through the %{link_to_import_flow} again." +msgstr "" + +msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access." +msgstr "" + msgid "Please select at least one filter to see results" msgstr "" @@ -3779,6 +4048,9 @@ msgstr "" msgid "Project export started. A download link will be sent by email." msgstr "" +msgid "Project name" +msgstr "" + msgid "ProjectActivityRSS|Subscribe" msgstr "" @@ -3791,6 +4063,9 @@ msgstr "" msgid "ProjectLifecycle|Stage" msgstr "" +msgid "ProjectPage|Project ID: %{project_id}" +msgstr "" + msgid "Projects" msgstr "" @@ -3839,6 +4114,9 @@ msgstr "" msgid "PrometheusService|Common metrics" msgstr "" +msgid "PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters." +msgstr "" + msgid "PrometheusService|Finding and configuring metrics..." msgstr "" @@ -3854,9 +4132,6 @@ msgstr "" msgid "PrometheusService|Metrics" msgstr "" -msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." -msgstr "" - msgid "PrometheusService|Missing environment variable" msgstr "" @@ -4060,6 +4335,9 @@ msgstr "" msgid "Reviewing (merge request !%{mergeRequestId})" msgstr "" +msgid "Revoke" +msgstr "" + msgid "Runner token" msgstr "" @@ -4084,6 +4362,9 @@ msgstr "" msgid "Save" msgstr "" +msgid "Save application" +msgstr "" + msgid "Save changes" msgstr "" @@ -4105,6 +4386,12 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "" +msgid "Scope" +msgstr "" + +msgid "Scroll down to <strong>Google Code Project Hosting</strong> and enable the switch on the right." +msgstr "" + msgid "Scroll to bottom" msgstr "" @@ -4144,6 +4431,9 @@ msgstr "" msgid "Seconds to wait for a storage access attempt" msgstr "" +msgid "Secret:" +msgstr "" + msgid "Select" msgstr "" @@ -4174,12 +4464,18 @@ msgstr "" msgid "Select project to choose zone" msgstr "" +msgid "Select projects you want to import." +msgstr "" + msgid "Select source branch" msgstr "" msgid "Select target branch" msgstr "" +msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By <a href=\"#\">@johnsmith</a>\"). It will also associate and/or assign these issues and comments with the selected user." +msgstr "" + msgid "Send email" msgstr "" @@ -4688,6 +4984,12 @@ msgstr "" msgid "The time taken by each data entry gathered by that stage." msgstr "" +msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of <code>:</code>. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side." +msgstr "" + +msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below." +msgstr "" + msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6." msgstr "" @@ -4730,6 +5032,12 @@ msgstr "" msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area." msgstr "" +msgid "This application was created by %{link_to_owner}." +msgstr "" + +msgid "This application will be able to:" +msgstr "" + msgid "This diff is collapsed." msgstr "" @@ -4995,6 +5303,12 @@ msgstr "" msgid "To add an SSH key you need to %{generate_link_start}generate one%{link_end} or use an %{existing_link_start}existing key%{link_end}." msgstr "" +msgid "To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import." +msgstr "" + +msgid "To get started, please enter your Gitea Host URL and a %{link_to_personal_token}." +msgstr "" + msgid "To import GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import." msgstr "" @@ -5004,9 +5318,15 @@ msgstr "" msgid "To import an SVN repository, check out %{svn_link}." msgstr "" +msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here." +msgstr "" + msgid "To start serving your jobs you can add Runners to your group" msgstr "" +msgid "To this GitLab instance" +msgstr "" + msgid "To validate your GitLab CI configurations, go to 'CI/CD → Pipelines' inside your project, and click on the 'CI Lint' button." msgstr "" @@ -5108,6 +5428,9 @@ msgstr[1] "" msgid "Update your group name, description, avatar, and other general settings." msgstr "" +msgid "Upload <code>GoogleCodeProjectHosting.json</code> here:" +msgstr "" + msgid "Upload New File" msgstr "" @@ -5126,9 +5449,15 @@ msgstr "" msgid "Usage statistics" msgstr "" +msgid "Use <code>%{native_redirect_uri}</code> for local tests" +msgstr "" + msgid "Use group milestones to manage issues from multiple projects in the same milestone." msgstr "" +msgid "Use one line per URI" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -5138,6 +5467,9 @@ msgstr "" msgid "User and IP Rate Limits" msgstr "" +msgid "User map" +msgstr "" + msgid "Users" msgstr "" @@ -5369,6 +5701,12 @@ msgstr "" msgid "Yes, add it" msgstr "" +msgid "Yes, let me map Google Code users to full names or GitLab users." +msgstr "" + +msgid "You are an admin, which means granting access to <strong>%{client_name}</strong> will allow them to interact with GitLab as an admin as well. Proceed with caution." +msgstr "" + msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?" msgstr "" @@ -5420,6 +5758,12 @@ msgstr "" msgid "You do not have any assigned merge requests" msgstr "" +msgid "You don't have any applications" +msgstr "" + +msgid "You don't have any authorized applications" +msgstr "" + msgid "You have no permissions" msgstr "" @@ -5486,6 +5830,12 @@ msgstr "" msgid "Your Todos" msgstr "" +msgid "Your applications (%{size})" +msgstr "" + +msgid "Your authorized applications" +msgstr "" + msgid "Your changes can be committed to %{branch_name} because a merge request is open." msgstr "" @@ -5516,12 +5866,18 @@ msgstr "" msgid "branch name" msgstr "" +msgid "ciReport|Show complete code vulnerabilities report" +msgstr "" + msgid "command line instructions" msgstr "" msgid "connecting" msgstr "" +msgid "customize" +msgstr "" + msgid "day" msgid_plural "days" msgstr[0] "" @@ -5533,6 +5889,9 @@ msgstr "" msgid "disabled" msgstr "" +msgid "done" +msgstr "" + msgid "enabled" msgstr "" @@ -5545,6 +5904,9 @@ msgstr "" msgid "here" msgstr "" +msgid "import flow" +msgstr "" + msgid "importing" msgstr "" @@ -5756,6 +6118,9 @@ msgstr "" msgid "spendCommand|%{slash_command} will update the sum of the time spent." msgstr "" +msgid "started" +msgstr "" + msgid "this document" msgstr "" diff --git a/package.json b/package.json index 26b87c70e98..256ebc1fb6e 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,11 @@ "webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js" }, "dependencies": { - "@gitlab-org/gitlab-svgs": "^1.25.0", + "@gitlab-org/gitlab-svgs": "^1.26.0", "autosize": "^4.0.0", "axios": "^0.17.1", "babel-core": "^6.26.3", - "babel-loader": "^7.1.4", + "babel-loader": "^7.1.5", "babel-plugin-transform-define": "^1.3.0", "babel-preset-latest": "^6.24.1", "babel-preset-stage-2": "^6.24.1", @@ -36,7 +36,7 @@ "compression-webpack-plugin": "^1.1.11", "core-js": "^2.4.1", "cropper": "^2.3.0", - "css-loader": "^0.28.11", + "css-loader": "^1.0.0", "d3-array": "^1.2.1", "d3-axis": "^1.0.8", "d3-brush": "^1.0.4", @@ -53,6 +53,7 @@ "emoji-unicode-version": "^0.2.1", "exports-loader": "^0.7.0", "file-loader": "^1.1.11", + "formdata-polyfill": "^3.0.11", "fuzzaldrin-plus": "^0.5.0", "glob": "^7.1.2", "imports-loader": "^0.8.0", @@ -90,15 +91,15 @@ "url-loader": "^1.0.1", "visibilityjs": "^1.2.4", "vue": "^2.5.16", - "vue-loader": "^15.2.0", + "vue-loader": "^15.2.4", "vue-resource": "^1.5.0", "vue-router": "^3.0.1", "vue-template-compiler": "^2.5.16", "vue-virtual-scroll-list": "^1.2.5", "vuex": "^3.0.1", - "webpack": "^4.11.1", - "webpack-bundle-analyzer": "^2.11.1", - "webpack-cli": "^3.0.2", + "webpack": "^4.16.0", + "webpack-bundle-analyzer": "^2.13.1", + "webpack-cli": "^3.0.8", "webpack-stats-plugin": "^0.2.1", "worker-loader": "^2.0.0" }, @@ -123,15 +124,16 @@ "ignore": "^3.3.7", "istanbul": "^0.4.5", "jasmine-core": "^2.9.0", + "jasmine-diff": "^0.1.3", "jasmine-jquery": "^2.1.1", - "karma": "^2.0.2", + "karma": "^2.0.4", "karma-chrome-launcher": "^2.2.0", "karma-coverage-istanbul-reporter": "^1.4.2", - "karma-jasmine": "^1.1.1", + "karma-jasmine": "^1.1.2", "karma-mocha-reporter": "^2.2.5", "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "3.0.0", - "nodemon": "^1.17.3", + "karma-webpack": "^4.0.0-beta.0", + "nodemon": "^1.18.2", "prettier": "1.12.1", "webpack-dev-server": "^3.1.4" } @@ -53,6 +53,7 @@ module QA autoload :User, 'qa/factory/resource/user' autoload :ProjectMilestone, 'qa/factory/resource/project_milestone' autoload :Wiki, 'qa/factory/resource/wiki' + autoload :File, 'qa/factory/resource/file' autoload :Fork, 'qa/factory/resource/fork' end @@ -136,6 +137,15 @@ module QA autoload :Show, 'qa/page/group/show' end + module File + autoload :Form, 'qa/page/file/form' + autoload :Show, 'qa/page/file/show' + + module Shared + autoload :CommitMessage, 'qa/page/file/shared/commit_message' + end + end + module Project autoload :New, 'qa/page/project/new' autoload :Show, 'qa/page/project/show' diff --git a/qa/qa/factory/resource/branch.rb b/qa/qa/factory/resource/branch.rb index 7fb0633ec90..bc252bf3148 100644 --- a/qa/qa/factory/resource/branch.rb +++ b/qa/qa/factory/resource/branch.rb @@ -9,18 +9,6 @@ module QA project.name = 'protected-branch-project' end - product :name do - Page::Project::Settings::Repository.act do - expand_protected_branches(&:last_branch_name) - end - end - - product :push_allowance do - Page::Project::Settings::Repository.act do - expand_protected_branches(&:last_push_allowance) - end - end - def initialize @branch_name = 'test/branch' @allow_to_push = true @@ -80,15 +68,6 @@ module QA end page.protect_branch - - # Avoid Selenium::WebDriver::Error::StaleElementReferenceError - # without sleeping. I.e. this completes fast on fast machines. - page.refresh - - # It is possible for the protected branch row to "disappear" at first - page.wait do - page.has_content?(branch_name) - end end end end diff --git a/qa/qa/factory/resource/file.rb b/qa/qa/factory/resource/file.rb new file mode 100644 index 00000000000..2016d10ddae --- /dev/null +++ b/qa/qa/factory/resource/file.rb @@ -0,0 +1,34 @@ +module QA + module Factory + module Resource + class File < Factory::Base + attr_accessor :name, + :content, + :commit_message + + dependency Factory::Resource::Project, as: :project do |project| + project.name = 'project-with-new-file' + end + + def initialize + @name = 'QA Test - File name' + @content = 'QA Test - File content' + @commit_message = 'QA Test - Commit message' + end + + def fabricate! + project.visit! + + Page::Project::Show.act { go_to_new_file! } + + Page::File::Form.perform do |page| + page.add_name(@name) + page.add_content(@content) + page.add_commit_message(@commit_message) + page.commit_changes + end + end + end + end + end +end diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index fc753554fc4..3df6db05970 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -59,7 +59,7 @@ module QA end def add_file(name, contents) - File.write(name, contents) + ::File.write(name, contents) `git add #{name}` end diff --git a/qa/qa/page/component/dropzone.rb b/qa/qa/page/component/dropzone.rb index 15bdc742fda..fd44c57123a 100644 --- a/qa/qa/page/component/dropzone.rb +++ b/qa/qa/page/component/dropzone.rb @@ -15,7 +15,7 @@ module QA # instantiated on one page because there is no distinguishing # attribute per dropzone file field. def attach_file(attachment) - filename = File.basename(attachment) + filename = ::File.basename(attachment) field_style = { visibility: 'visible', height: '', width: '' } page.attach_file(attachment, class: 'dz-hidden-input', make_visible: field_style) diff --git a/qa/qa/page/file/form.rb b/qa/qa/page/file/form.rb new file mode 100644 index 00000000000..f6e502f500b --- /dev/null +++ b/qa/qa/page/file/form.rb @@ -0,0 +1,40 @@ +module QA + module Page + module File + class Form < Page::Base + include Shared::CommitMessage + + view 'app/views/projects/blob/_editor.html.haml' do + element :file_name, "text_field_tag 'file_name'" + element :editor, '#editor' + end + + view 'app/views/projects/_commit_button.html.haml' do + element :commit_changes, "button_tag 'Commit changes'" + end + + def add_name(name) + fill_in 'file_name', with: name + end + + def add_content(content) + text_area.set content + end + + def remove_content + text_area.send_keys([:command, 'a'], :backspace) + end + + def commit_changes + click_on 'Commit changes' + end + + private + + def text_area + find('#editor>textarea', visible: false) + end + end + end + end +end diff --git a/qa/qa/page/file/shared/commit_message.rb b/qa/qa/page/file/shared/commit_message.rb new file mode 100644 index 00000000000..5af1a55e2ef --- /dev/null +++ b/qa/qa/page/file/shared/commit_message.rb @@ -0,0 +1,19 @@ +module QA + module Page + module File + module Shared + module CommitMessage + def self.included(base) + base.view 'app/views/shared/_commit_message_container.html.haml' do + element :commit_message, "text_area_tag 'commit_message'" + end + end + + def add_commit_message(message) + fill_in 'commit_message', with: message + end + end + end + end + end +end diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb new file mode 100644 index 00000000000..99f5924b67f --- /dev/null +++ b/qa/qa/page/file/show.rb @@ -0,0 +1,30 @@ +module QA + module Page + module File + class Show < Page::Base + include Shared::CommitMessage + + view 'app/helpers/blob_helper.rb' do + element :edit_button, "_('Edit')" + element :delete_button, /label:\s+"Delete"/ + end + + view 'app/views/projects/blob/_remove.html.haml' do + element :delete_file_button, "button_tag 'Delete file'" + end + + def click_edit + click_on 'Edit' + end + + def click_delete + click_on 'Delete' + end + + def click_delete_file + click_on 'Delete file' + end + end + end + end +end diff --git a/qa/qa/page/main/oauth.rb b/qa/qa/page/main/oauth.rb index 6f548148363..618f114e058 100644 --- a/qa/qa/page/main/oauth.rb +++ b/qa/qa/page/main/oauth.rb @@ -3,7 +3,7 @@ module QA module Main class OAuth < Page::Base view 'app/views/doorkeeper/authorizations/new.html.haml' do - element :authorization_button, 'submit_tag "Authorize"' + element :authorization_button, 'submit_tag _("Authorize")' end def needs_authorization? diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index e572ae12132..76591a4e3fe 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -16,7 +16,6 @@ module QA end view 'app/views/projects/protected_branches/_update_protected_branch.html.haml' do - element :allowed_to_push element :allowed_to_merge end @@ -24,10 +23,6 @@ module QA element :protected_branches_list end - view 'app/views/projects/protected_branches/shared/_protected_branch.html.haml' do - element :protected_branch_name - end - def select_branch(branch_name) click_element :protected_branch_select @@ -62,18 +57,6 @@ module QA click_on 'Protect' end - def last_branch_name - within_element(:protected_branches_list) do - all('.qa-protected-branch-name').last - end - end - - def last_push_allowance - within_element(:protected_branches_list) do - all('.qa-allowed-to-push').last - end - end - private def click_allow(action, text) diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 88861d5772d..1d3dad4cda0 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -31,10 +31,18 @@ module QA element :tree_holder, '.tree-holder' end + view 'app/presenters/project_presenter.rb' do + element :new_file_button, "label: _('New file')," + end + def project_name find('.qa-project-name').text end + def go_to_new_file! + click_on 'New file' + end + def switch_to_branch(branch_name) find_element(:branches_select).click diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index 6635e1ce039..b2a2da4dbf3 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -9,7 +9,7 @@ module QA end def pathname - @pathname ||= Pathname.new(File.join(__dir__, '../../../', @path)) + @pathname ||= Pathname.new(::File.join(__dir__, '../../../', @path)) .cleanpath.expand_path end @@ -23,7 +23,7 @@ module QA # elements' existence. # @missing ||= @elements.dup.tap do |elements| - File.foreach(pathname.to_s) do |line| + ::File.foreach(pathname.to_s) do |line| elements.reject! { |element| element.matches?(line) } end end diff --git a/qa/qa/runtime/api/request.rb b/qa/qa/runtime/api/request.rb index c33ada0de7a..ff9f0004524 100644 --- a/qa/qa/runtime/api/request.rb +++ b/qa/qa/runtime/api/request.rb @@ -28,7 +28,7 @@ module QA # # Returns the relative path to the requested API resource def request_path(path, version: API_VERSION, **query_string) - full_path = File.join('/api', version, path) + full_path = ::File.join('/api', version, path) if query_string.any? full_path << (path.include?('?') ? '&' : '?') diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 877864fb40c..0c8eca5229e 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -86,7 +86,7 @@ module QA end Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', '')) + ::File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', '')) end Capybara.configure do |config| @@ -94,7 +94,7 @@ module QA config.javascript_driver = :chrome config.default_max_wait_time = 10 # https://github.com/mattheworiordan/capybara-screenshot/issues/164 - config.save_path = File.expand_path('../../tmp', __dir__) + config.save_path = ::File.expand_path('../../tmp', __dir__) end end diff --git a/qa/qa/runtime/key/base.rb b/qa/qa/runtime/key/base.rb index c7e5ebada7b..67a992e2115 100644 --- a/qa/qa/runtime/key/base.rb +++ b/qa/qa/runtime/key/base.rb @@ -25,8 +25,8 @@ module QA end def populate_key_data(path) - @private_key = File.binread(path) - @public_key = File.binread("#{path}.pub") + @private_key = ::File.binread(path) + @public_key = ::File.binread("#{path}.pub") @fingerprint = `ssh-keygen -l -E md5 -f #{path} | cut -d' ' -f2 | cut -d: -f2-`.chomp end diff --git a/qa/qa/runtime/release.rb b/qa/qa/runtime/release.rb index 4f83a773645..b1f7ec482c8 100644 --- a/qa/qa/runtime/release.rb +++ b/qa/qa/runtime/release.rb @@ -13,7 +13,7 @@ module QA end def version - @version ||= File.directory?("#{__dir__}/../ee") ? :EE : :CE + @version ||= ::File.directory?("#{__dir__}/../ee") ? :EE : :CE end def strategy diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb index 567e5fd6cca..46eb2dabb11 100644 --- a/qa/qa/scenario/test/instance.rb +++ b/qa/qa/scenario/test/instance.rb @@ -26,7 +26,7 @@ module QA if rspec_options.any? rspec_options else - File.expand_path('../../specs/features', __dir__) + ::File.expand_path('../../specs/features', __dir__) end end end diff --git a/qa/qa/specs/features/project/file_spec.rb b/qa/qa/specs/features/project/file_spec.rb new file mode 100644 index 00000000000..5659784cd5c --- /dev/null +++ b/qa/qa/specs/features/project/file_spec.rb @@ -0,0 +1,54 @@ +module QA + describe 'File Functionality', :core do + it 'lets a user create, edit and delete a file via WebUI' do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } + + # Create + file_name = 'QA Test - File name' + file_content = 'QA Test - File content' + commit_message_for_create = 'QA Test - Create new file' + + Factory::Resource::File.fabricate! do |file| + file.name = file_name + file.content = file_content + file.commit_message = commit_message_for_create + end + + expect(page).to have_content('The file has been successfully created.') + expect(page).to have_content(file_name) + expect(page).to have_content(file_content) + expect(page).to have_content(commit_message_for_create) + + # Edit + updated_file_content = 'QA Test - Updated file content' + commit_message_for_update = 'QA Test - Update file' + + Page::File::Show.act { click_edit } + + Page::File::Form.act do + remove_content + add_content(updated_file_content) + add_commit_message(commit_message_for_update) + commit_changes + end + + expect(page).to have_content('Your changes have been successfully committed.') + expect(page).to have_content(updated_file_content) + expect(page).to have_content(commit_message_for_update) + + # Delete + commit_message_for_delete = 'QA Test - Delete file' + + Page::File::Show.act do + click_delete + add_commit_message(commit_message_for_delete) + click_delete_file + end + + expect(page).to have_content('The file has been successfully deleted.') + expect(page).to have_content(commit_message_for_delete) + expect(page).to have_no_content(file_name) + end + end +end diff --git a/qa/qa/specs/features/repository/protected_branches_spec.rb b/qa/qa/specs/features/repository/protected_branches_spec.rb index 4e593a69aae..c2de94516d9 100644 --- a/qa/qa/specs/features/repository/protected_branches_spec.rb +++ b/qa/qa/specs/features/repository/protected_branches_spec.rb @@ -21,11 +21,8 @@ module QA end context 'when developers and maintainers are allowed to push to a protected branch' do - let!(:protected_branch) { create_protected_branch(allow_to_push: true) } - it 'user with push rights successfully pushes to the protected branch' do - expect(protected_branch.name).to have_content(branch_name) - expect(protected_branch.push_allowance).to have_content('Developers + Maintainers') + create_protected_branch(allow_to_push: true) push = push_new_file(branch_name) diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb index ee1f08da238..5c65128d10c 100644 --- a/qa/spec/git/repository_spec.rb +++ b/qa/spec/git/repository_spec.rb @@ -29,7 +29,7 @@ describe QA::Git::Repository do def cd_empty_temp_directory tmp_dir = 'tmp/git-repository-spec/' - FileUtils.rm_r(tmp_dir) if File.exist?(tmp_dir) + FileUtils.rm_r(tmp_dir) if ::File.exist?(tmp_dir) FileUtils.mkdir_p tmp_dir FileUtils.cd tmp_dir end diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb index aedbc3863a7..34d2ff11447 100644 --- a/qa/spec/page/view_spec.rb +++ b/qa/spec/page/view_spec.rb @@ -32,7 +32,7 @@ describe QA::Page::View do context 'when pattern is found' do before do - allow(File).to receive(:foreach) + allow(::File).to receive(:foreach) .and_yield('some element').once allow(element).to receive(:matches?) .with('some element').and_return(true) @@ -45,7 +45,7 @@ describe QA::Page::View do context 'when pattern has not been found' do before do - allow(File).to receive(:foreach) + allow(::File).to receive(:foreach) .and_yield('some element').once allow(element).to receive(:matches?) .with('some element').and_return(false) diff --git a/qa/spec/scenario/test/instance_spec.rb b/qa/spec/scenario/test/instance_spec.rb index a74a9538be8..0d0b534911f 100644 --- a/qa/spec/scenario/test/instance_spec.rb +++ b/qa/spec/scenario/test/instance_spec.rb @@ -30,7 +30,7 @@ describe QA::Scenario::Test::Instance do subject.perform("test") expect(runner).to have_received(:options=) - .with(File.expand_path('../../../qa/specs/features', __dir__)) + .with(::File.expand_path('../../../qa/specs/features', __dir__)) end end diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb index c2c6cf95406..8e6613cd688 100644 --- a/qa/spec/spec_helper.rb +++ b/qa/spec/spec_helper.rb @@ -1,6 +1,6 @@ require_relative '../qa' -Dir[File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f } +Dir[::File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f } RSpec.configure do |config| config.expect_with :rspec do |expectations| diff --git a/scripts/lint-rugged b/scripts/lint-rugged index cabd083e9f9..d0c2c544c47 100755 --- a/scripts/lint-rugged +++ b/scripts/lint-rugged @@ -14,7 +14,10 @@ ALLOWED = [ 'lib/tasks/gitlab/cleanup.rake', # The only place where Rugged code is still allowed in production - 'lib/gitlab/git/' + 'lib/gitlab/git/', + + # Needed to avoid using the git binary to validate a branch name + 'lib/gitlab/git_ref_validator.rb' ].freeze rugged_lines = IO.popen(%w[git grep -i -n rugged -- app config lib], &:read).lines diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 74f362fd7fc..f1165c73847 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -89,6 +89,32 @@ describe ApplicationController do end end + describe 'session expiration' do + controller(described_class) do + def index + render text: 'authenticated' + end + end + + context 'authenticated user' do + it 'does not set the expire_after option' do + sign_in(create(:user)) + + get :index + + expect(request.env['rack.session.options'][:expire_after]).to be_nil + end + end + + context 'unauthenticated user' do + it 'sets the expire_after option' do + get :index + + expect(request.env['rack.session.options'][:expire_after]).to eq(Settings.gitlab['unauthenticated_session_expire_delay']) + end + end + end + describe 'rescue from Gitlab::Git::Storage::Inaccessible' do controller(described_class) do def index diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 444415011a9..1692f299552 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -53,6 +53,23 @@ describe Projects::MergeRequestsController do it_behaves_like "loads labels", :show describe 'as html' do + context 'when diff files were cleaned' do + render_views + + it 'renders page when diff size is not persisted and diff_refs does not exist' do + diff = merge_request.merge_request_diff + + diff.clean! + diff.update!(real_size: nil, + start_commit_sha: nil, + base_commit_sha: nil) + + go(format: :html) + + expect(response).to be_success + end + end + it "renders merge request page" do go(format: :html) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 7c00652317b..8e25b61e2f1 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -50,8 +50,6 @@ describe SessionsController do end context 'when using valid password', :clean_gitlab_redis_shared_state do - include UserActivitiesHelpers - let(:user) { create(:user) } let(:user_params) { { login: user.username, password: user.password } } @@ -77,7 +75,7 @@ describe SessionsController do it 'updates the user activity' do expect do post(:create, user: user_params) - end.to change { user_activity(user) } + end.to change { user.reload.last_activity_on }.to(Date.today) end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 9fdc3e616a6..6844ed8aa4a 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -39,6 +39,7 @@ FactoryBot.define do factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do association :project, :repository + position '' end factory :diff_note_on_merge_request, traits: [:on_merge_request], class: DiffNote do diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb index b45f6f30e40..a81b2169b89 100644 --- a/spec/factories/uploads.rb +++ b/spec/factories/uploads.rb @@ -28,6 +28,13 @@ FactoryBot.define do secret SecureRandom.hex end + trait :with_file do + after(:create) do |upload| + FileUtils.mkdir_p(File.dirname(upload.absolute_path)) + FileUtils.touch(upload.absolute_path) + end + end + trait :object_storage do store ObjectStorage::Store::REMOTE end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 9e3221577c7..6c194c9a646 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -315,6 +315,40 @@ describe "Admin::Users" do end end + describe 'show breadcrumbs' do + it do + visit admin_user_path(user) + + check_breadcrumb(user.name) + + visit projects_admin_user_path(user) + + check_breadcrumb(user.name) + + visit keys_admin_user_path(user) + + check_breadcrumb(user.name) + + visit admin_user_impersonation_tokens_path(user) + + check_breadcrumb(user.name) + + visit admin_user_identities_path(user) + + check_breadcrumb(user.name) + + visit new_admin_user_identity_path(user) + + check_breadcrumb("New Identity") + + visit admin_user_identities_path(user) + + find('.table').find(:link, 'Edit').click + + check_breadcrumb("Edit Identity") + end + end + describe 'show user attributes' do it do visit admin_users_path @@ -409,4 +443,8 @@ describe "Admin::Users" do expect(page).not_to have_content('twitter') end end + + def check_breadcrumb(content) + expect(find('.breadcrumbs-sub-title')).to have_content(content) + end end diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb index 02d19db3828..77261f9375c 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -185,11 +185,11 @@ describe 'Merge request > User posts diff notes', :js do end describe 'posting a note' do - xit 'adds as discussion' do + it 'adds as discussion' do expect(page).to have_css('.js-temp-notes-holder', count: 2) should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false) - expect(page).to have_css('.notes_holder .note', count: 1) + expect(page).to have_css('.notes_holder .note.note-discussion', count: 1) expect(page).to have_css('.js-temp-notes-holder', count: 1) expect(page).to have_button('Reply...') end diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index bf4d5396df9..2d268ecab58 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -342,8 +342,9 @@ describe 'Merge request > User resolves diff notes and discussions', :js do end end - it 'shows jump to next discussion button' do - expect(page.all('.discussion-reply-holder', count: 2)).to all(have_selector('.discussion-next-btn')) + it 'shows jump to next discussion button, apart from the last one' do + expect(page).to have_selector('.discussion-reply-holder', count: 2) + expect(page).to have_selector('.discussion-reply-holder .discussion-next-btn', count: 1) end it 'displays next discussion even if hidden' do diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb index c40c720d168..86086a58f18 100644 --- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb +++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Merge request > User sees Check out branch modal', :js do +describe 'Merge request > User sees check out branch modal', :js do let(:project) { create(:project, :public, :repository) } let(:user) { project.creator } let(:merge_request) { create(:merge_request, source_project: project) } @@ -16,7 +16,7 @@ describe 'Merge request > User sees Check out branch modal', :js do expect(page).to have_content('Check out, review, and merge locally') end - it 'closes the check out branch model with Escape keypress' do + it 'closes the check out branch modal with escape keypress' do find('#modal_merge_info').send_keys(:escape) expect(page).not_to have_content('Check out, review, and merge locally') diff --git a/spec/features/merge_request/user_cherry_picks_spec.rb b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb index c6ec3f08cc5..aa499493dbe 100644 --- a/spec/features/merge_request/user_cherry_picks_spec.rb +++ b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb @@ -21,7 +21,7 @@ describe 'Merge request > User cherry-picks', :js do end # Fast-forward merge, or merged before GitLab 8.5. - context 'Without a merge commit' do + context 'without a merge commit' do before do merge_request.merge_commit_sha = nil merge_request.save @@ -34,7 +34,7 @@ describe 'Merge request > User cherry-picks', :js do end end - context 'With a merge commit' do + context 'with a merge commit' do it 'shows a Cherry-pick button' do visit project_merge_request_path(project, merge_request) @@ -49,5 +49,23 @@ describe 'Merge request > User cherry-picks', :js do expect(page).not_to have_link 'Cherry-pick' end end + + context 'and seeing the cherry-pick modal' do + before do + visit project_merge_request_path(project, merge_request) + + click_link('Cherry-pick') + end + + it 'shows the cherry-pick modal' do + expect(page).to have_content('Cherry-pick this merge request') + end + + it 'closes the cherry-pick modal with escape keypress' do + find('#modal-cherry-pick-commit').send_keys(:escape) + + expect(page).not_to have_content('Start a new merge request with these changes') + end + end end end diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index 830565620d6..149eeb4f9ba 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -2,16 +2,22 @@ require "spec_helper" describe "User creates wiki page" do let(:user) { create(:user) } + let(:wiki) { ProjectWiki.new(project, user) } + let(:project) { create(:project) } before do project.add_maintainer(user) - sign_in(user) - visit(project_wikis_path(project)) - click_link "Create your first page" + sign_in(user) end context "when wiki is empty" do + before do + visit(project_wikis_path(project)) + + click_link "Create your first page" + end + context "in a user namespace" do let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } @@ -165,7 +171,9 @@ describe "User creates wiki page" do context "when wiki is not empty", :js do before do - create(:wiki_page, wiki: create(:project, :wiki_repo, namespace: user.namespace).wiki, attrs: { title: "home", content: "Home page" }) + create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'Home page' }) + + visit(project_wikis_path(project)) end context "in a user namespace" do @@ -290,4 +298,34 @@ describe "User creates wiki page" do end end end + + describe 'sidebar feature' do + context 'when there are some existing pages' do + before do + create(:wiki_page, wiki: wiki, attrs: { title: 'home', content: 'home' }) + create(:wiki_page, wiki: wiki, attrs: { title: 'another', content: 'another' }) + end + + it 'renders a default sidebar when there is no customized sidebar' do + visit(project_wikis_path(project)) + + expect(page).to have_content('Another') + expect(page).to have_content('More Pages') + end + + context 'when there is a customized sidebar' do + before do + create(:wiki_page, wiki: wiki, attrs: { title: '_sidebar', content: 'My customized sidebar' }) + end + + it 'renders my customized sidebar instead of the default one' do + visit(project_wikis_path(project)) + + expect(page).to have_content('My customized sidebar') + expect(page).to have_content('More Pages') + expect(page).not_to have_content('Another') + end + end + end + end end diff --git a/spec/features/user_sees_revert_modal_spec.rb b/spec/features/user_sees_revert_modal_spec.rb new file mode 100644 index 00000000000..3b48ea4786d --- /dev/null +++ b/spec/features/user_sees_revert_modal_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +describe 'Merge request > User sees revert modal', :js do + let(:project) { create(:project, :public, :repository) } + let(:user) { project.creator } + let(:merge_request) { create(:merge_request, source_project: project) } + + before do + sign_in(user) + visit(project_merge_request_path(project, merge_request)) + click_button('Merge') + + wait_for_requests + + visit(merge_request_path(merge_request)) + click_link('Revert') + end + + it 'shows the revert modal' do + expect(page).to have_content('Revert this merge request') + end + + it 'closes the revert modal with escape keypress' do + find('#modal-revert-commit').send_keys(:escape) + + expect(page).not_to have_content('Revert this merge request') + end +end diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json index 38ce92a5dc7..3b741d51598 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_widget.json +++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json @@ -29,8 +29,10 @@ "merge_when_pipeline_succeeds": { "type": "boolean" }, "source_branch": { "type": "string" }, "source_project_id": { "type": "integer" }, + "source_project_full_path": { "type": ["string", "null"]}, "target_branch": { "type": "string" }, "target_project_id": { "type": "integer" }, + "target_project_full_path": { "type": ["string", "null"]}, "allow_collaboration": { "type": "boolean"}, "metrics": { "oneOf": [ diff --git a/spec/fixtures/api/schemas/pipeline.json b/spec/fixtures/api/schemas/pipeline.json index 55511d17b5e..b6e30c40f13 100644 --- a/spec/fixtures/api/schemas/pipeline.json +++ b/spec/fixtures/api/schemas/pipeline.json @@ -319,6 +319,10 @@ "id": "/properties/updated_at", "type": "string" }, + "web_url": { + "id": "/properties/web_url", + "type": "string" + }, "user": { "id": "/properties/user", "properties": { diff --git a/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json b/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json index 0d127dc5297..56f86856dd4 100644 --- a/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json +++ b/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json @@ -4,13 +4,15 @@ "id", "sha", "ref", - "status" + "status", + "web_url" ], "properties" : { "id": { "type": "integer" }, "sha": { "type": "string" }, "ref": { "type": "string" }, - "status": { "type": "string" } + "status": { "type": "string" }, + "web_url": { "type": "string" } }, "additionalProperties": false } diff --git a/spec/fixtures/api/schemas/public_api/v4/projects.json b/spec/fixtures/api/schemas/public_api/v4/projects.json index 17ad8d8c48d..af5670ebd33 100644 --- a/spec/fixtures/api/schemas/public_api/v4/projects.json +++ b/spec/fixtures/api/schemas/public_api/v4/projects.json @@ -24,13 +24,24 @@ "avatar_url": { "type": ["string", "null"] }, "star_count": { "type": "integer" }, "forks_count": { "type": "integer" }, - "last_activity_at": { "type": "date" } + "last_activity_at": { "type": "date" }, + "namespace": { + "type": "object", + "properties" : { + "id": { "type": "integer" }, + "name": { "type": "string" }, + "path": { "type": "string" }, + "kind": { "type": "string" }, + "full_path": { "type": "string" }, + "parent_id": { "type": ["integer", "null"] } + } + } }, "required": [ "id", "name", "name_with_namespace", "description", "path", "path_with_namespace", "created_at", "default_branch", "tag_list", "ssh_url_to_repo", "http_url_to_repo", "web_url", "avatar_url", - "star_count", "last_activity_at" + "star_count", "last_activity_at", "namespace" ], "additionalProperties": false } diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index 93d8e672f8c..82f588d1a08 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -55,6 +55,29 @@ describe IconsHelper do expect(sprite_icon(icon_name, size: 72, css_class: 'icon-danger').to_s) .to eq "<svg class=\"s72 icon-danger\"><use xlink:href=\"#{icons_path}##{icon_name}\"></use></svg>" end + + describe 'non existing icon' do + non_existing = 'non_existing_icon_sprite' + + it 'should raise in development mode' do + allow(Rails.env).to receive(:development?).and_return(true) + + expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/) + end + + it 'should raise in test mode' do + allow(Rails.env).to receive(:test?).and_return(true) + + expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/) + end + + it 'should not raise in production mode' do + allow(Rails.env).to receive(:test?).and_return(false) + allow(Rails.env).to receive(:development?).and_return(false) + + expect { sprite_icon(non_existing) }.not_to raise_error + end + end end describe 'file_type_icon_class' do diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index beb6e8ea273..cbd4ff0fb4a 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -290,33 +290,6 @@ describe ProjectsHelper do end end - describe '#sanitizerepo_repo_path' do - let(:project) { create(:project, :repository) } - let(:storage_path) do - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - Gitlab.config.repositories.storages.default.legacy_disk_path - end - end - - before do - allow(Settings.shared).to receive(:[]).with('path').and_return('/base/repo/export/path') - end - - it 'removes the repo path' do - repo = File.join(storage_path, 'namespace/test.git') - import_error = "Could not clone #{repo}\n" - - expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') - end - - it 'removes the temporary repo path used for uploads/exports' do - repo = '/base/repo/export/path/tmp/project_exports/uploads/test.tar.gz' - import_error = "Unable to decompress #{repo}\n" - - expect(sanitize_repo_path(project, import_error)).to eq('Unable to decompress [REPO EXPORT PATH]/uploads/test.tar.gz') - end - end - describe '#last_push_event' do let(:user) { double(:user, fork_of: nil) } let(:project) { double(:project, id: 1) } diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 6c9a7febf14..8bfd520528f 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -55,6 +55,20 @@ describe SearchHelper do expect(search_autocomplete_opts(project.name).size).to eq(1) end + it "includes the required project attrs" do + project = create(:project, namespace: create(:namespace, owner: user)) + result = search_autocomplete_opts(project.name).first + + expect(result.keys).to match_array(%i[category id value label url avatar_url]) + end + + it "includes the required group attrs" do + create(:group).add_owner(user) + result = search_autocomplete_opts("gro").first + + expect(result.keys).to match_array(%i[category id label url avatar_url]) + end + it "does not include the public group" do group = create(:group) expect(search_autocomplete_opts(group.name).size).to eq(0) diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index 5a2e4b34069..a64f8a11ef2 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -92,11 +92,10 @@ describe SubmoduleHelper do context 'in-repository submodule' do let(:group) { create(:group, name: "Master Project", path: "master-project") } let(:project) { create(:project, group: group) } - before do - self.instance_variable_set(:@project, project) - end it 'in-repository' do + allow(repo).to receive(:project).and_return(project) + stub_url('./') expect(submodule_links(submodule_item)).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/tree/hash"]) end @@ -167,32 +166,28 @@ describe SubmoduleHelper do let(:project) { create(:project, group: group) } let(:commit_id) { sample_commit[:id] } - before do - self.instance_variable_set(:@project, project) - end - it 'one level down' do - result = relative_self_links('../test.git', commit_id) + result = relative_self_links('../test.git', commit_id, project) expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"]) end it 'with trailing whitespace' do - result = relative_self_links('../test.git ', commit_id) + result = relative_self_links('../test.git ', commit_id, project) expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"]) end it 'two levels down' do - result = relative_self_links('../../test.git', commit_id) + result = relative_self_links('../../test.git', commit_id, project) expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"]) end it 'one level down with namespace and repo' do - result = relative_self_links('../foobar/test.git', commit_id) + result = relative_self_links('../foobar/test.git', commit_id, project) expect(result).to eq(["/foobar/test", "/foobar/test/tree/#{commit_id}"]) end it 'two levels down with namespace and repo' do - result = relative_self_links('../foobar/baz/test.git', commit_id) + result = relative_self_links('../foobar/baz/test.git', commit_id, project) expect(result).to eq(["/baz/test", "/baz/test/tree/#{commit_id}"]) end @@ -201,7 +196,7 @@ describe SubmoduleHelper do let(:project) { create(:project, namespace: user.namespace) } it 'one level down with personal project' do - result = relative_self_links('../test.git', commit_id) + result = relative_self_links('../test.git', commit_id, project) expect(result).to eq(["/#{user.username}/test", "/#{user.username}/test/tree/#{commit_id}"]) end end diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb index 5077c89d7b4..a3be222b7bd 100644 --- a/spec/helpers/visibility_level_helper_spec.rb +++ b/spec/helpers/visibility_level_helper_spec.rb @@ -6,6 +6,29 @@ describe VisibilityLevelHelper do let(:personal_snippet) { build(:personal_snippet) } let(:project_snippet) { build(:project_snippet) } + describe 'visibility_icon_description' do + context 'used with a Project' do + it 'delegates projects to #project_visibility_icon_description' do + expect(visibility_icon_description(project)) + .to match /project/i + end + + context 'used with a ProjectPresenter' do + it 'delegates projects to #project_visibility_icon_description' do + expect(visibility_icon_description(project.present)) + .to match /project/i + end + end + + context 'used with a Group' do + it 'delegates groups to #group_visibility_icon_description' do + expect(visibility_icon_description(group)) + .to match /group/i + end + end + end + end + describe 'visibility_level_description' do context 'used with a Project' do it 'delegates projects to #project_visibility_level_description' do diff --git a/spec/javascripts/autosave_spec.js b/spec/javascripts/autosave_spec.js index 38ae5b7e00c..dcb1c781591 100644 --- a/spec/javascripts/autosave_spec.js +++ b/spec/javascripts/autosave_spec.js @@ -59,12 +59,10 @@ describe('Autosave', () => { Autosave.prototype.restore.call(autosave); - expect( - field.trigger, - ).toHaveBeenCalled(); + expect(field.trigger).toHaveBeenCalled(); }); - it('triggers native event', (done) => { + it('triggers native event', done => { autosave.field.get(0).addEventListener('change', () => { done(); }); @@ -81,9 +79,7 @@ describe('Autosave', () => { it('does not trigger event', () => { spyOn(field, 'trigger').and.callThrough(); - expect( - field.trigger, - ).not.toHaveBeenCalled(); + expect(field.trigger).not.toHaveBeenCalled(); }); }); }); diff --git a/spec/javascripts/clusters/clusters_bundle_spec.js b/spec/javascripts/clusters/clusters_bundle_spec.js index abe2954d506..839b8a06b48 100644 --- a/spec/javascripts/clusters/clusters_bundle_spec.js +++ b/spec/javascripts/clusters/clusters_bundle_spec.js @@ -45,17 +45,33 @@ describe('Clusters', () => { }); describe('showToken', () => { - it('should update tye field type', () => { + it('should update token field type', () => { cluster.showTokenButton.click(); + expect( cluster.tokenField.getAttribute('type'), ).toEqual('text'); cluster.showTokenButton.click(); + expect( cluster.tokenField.getAttribute('type'), ).toEqual('password'); }); + + it('should update show token button text', () => { + cluster.showTokenButton.click(); + + expect( + cluster.showTokenButton.textContent, + ).toEqual('Hide'); + + cluster.showTokenButton.click(); + + expect( + cluster.showTokenButton.textContent, + ).toEqual('Show'); + }); }); describe('checkForNewInstalls', () => { diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js index 0f3a95da5bf..241ff07026e 100644 --- a/spec/javascripts/diffs/components/diff_file_header_spec.js +++ b/spec/javascripts/diffs/components/diff_file_header_spec.js @@ -24,7 +24,7 @@ describe('diff_file_header', () => { const diffFile = convertObjectPropsToCamelCase(diffDiscussionMock.diff_file, { deep: true }); props = { diffFile, - currentUser: {}, + canCurrentUserFork: false, }; }); diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js index 9b994543e19..7a4616ec8eb 100644 --- a/spec/javascripts/diffs/components/diff_file_spec.js +++ b/spec/javascripts/diffs/components/diff_file_spec.js @@ -11,7 +11,7 @@ describe('DiffFile', () => { beforeEach(() => { vm = createComponentWithStore(Vue.extend(DiffFileComponent), store, { file: getDiffFileMock(), - currentUser: {}, + canCurrentUserFork: false, }).$mount(); }); diff --git a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js index 2d136a63c52..cb85d12daf2 100644 --- a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js +++ b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js @@ -18,10 +18,12 @@ describe('DiffLineGutterContent', () => { }; const setDiscussions = component => { component.$store.dispatch('setInitialNotes', getDiscussionsMockData()); + component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] }); }; const resetDiscussions = component => { component.$store.dispatch('setInitialNotes', []); + component.$store.commit('diffs/SET_DIFF_DATA', {}); }; describe('computed', () => { diff --git a/spec/javascripts/diffs/components/diff_line_note_form_spec.js b/spec/javascripts/diffs/components/diff_line_note_form_spec.js index 81cd4f9769a..6fe5fdaf7f9 100644 --- a/spec/javascripts/diffs/components/diff_line_note_form_spec.js +++ b/spec/javascripts/diffs/components/diff_line_note_form_spec.js @@ -3,6 +3,7 @@ import DiffLineNoteForm from '~/diffs/components/diff_line_note_form.vue'; import store from '~/mr_notes/stores'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import diffFileMockData from '../mock_data/diff_file'; +import { noteableDataMock } from '../../notes/mock_data'; describe('DiffLineNoteForm', () => { let component; @@ -15,16 +16,15 @@ describe('DiffLineNoteForm', () => { diffLines = diffFile.highlightedDiffLines; component = createComponentWithStore(Vue.extend(DiffLineNoteForm), store, { - diffFile, + diffFileHash: diffFile.fileHash, diffLines, line: diffLines[0], noteTargetLine: diffLines[0], }); - Object.defineProperty(component, 'isLoggedIn', { - get() { - return true; - }, + Object.defineProperties(component, { + noteableData: { value: noteableDataMock }, + isLoggedIn: { value: true }, }); component.$mount(); @@ -32,12 +32,37 @@ describe('DiffLineNoteForm', () => { describe('methods', () => { describe('handleCancelCommentForm', () => { - it('should call cancelCommentForm with lineCode', () => { + it('should ask for confirmation when shouldConfirm and isDirty passed as truthy', () => { + spyOn(window, 'confirm').and.returnValue(false); + + component.handleCancelCommentForm(true, true); + expect(window.confirm).toHaveBeenCalled(); + }); + + it('should ask for confirmation when one of the params false', () => { + spyOn(window, 'confirm').and.returnValue(false); + + component.handleCancelCommentForm(true, false); + expect(window.confirm).not.toHaveBeenCalled(); + + component.handleCancelCommentForm(false, true); + expect(window.confirm).not.toHaveBeenCalled(); + }); + + it('should call cancelCommentForm with lineCode', done => { + spyOn(window, 'confirm'); spyOn(component, 'cancelCommentForm'); + spyOn(component, 'resetAutoSave'); component.handleCancelCommentForm(); - expect(component.cancelCommentForm).toHaveBeenCalledWith({ - lineCode: diffLines[0].lineCode, + expect(window.confirm).not.toHaveBeenCalled(); + component.$nextTick(() => { + expect(component.cancelCommentForm).toHaveBeenCalledWith({ + lineCode: diffLines[0].lineCode, + }); + expect(component.resetAutoSave).toHaveBeenCalled(); + + done(); }); }); }); @@ -66,7 +91,7 @@ describe('DiffLineNoteForm', () => { describe('mounted', () => { it('should init autosave', () => { - const key = 'autosave/Note/issue///DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1'; + const key = 'autosave/Note/Issue/98//DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1'; expect(component.autosave).toBeDefined(); expect(component.autosave.key).toEqual(key); diff --git a/spec/javascripts/diffs/components/inline_diff_view_spec.js b/spec/javascripts/diffs/components/inline_diff_view_spec.js index b02328dd359..90dfa5c5a58 100644 --- a/spec/javascripts/diffs/components/inline_diff_view_spec.js +++ b/spec/javascripts/diffs/components/inline_diff_view_spec.js @@ -33,6 +33,7 @@ describe('InlineDiffView', () => { it('should render discussions', done => { const el = component.$el; component.$store.dispatch('setInitialNotes', getDiscussionsMockData()); + component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] }); Vue.nextTick(() => { expect(el.querySelectorAll('.notes_holder').length).toEqual(1); diff --git a/spec/javascripts/diffs/mock_data/diff_discussions.js b/spec/javascripts/diffs/mock_data/diff_discussions.js index 41d0dfd8939..8cd57d2248b 100644 --- a/spec/javascripts/diffs/mock_data/diff_discussions.js +++ b/spec/javascripts/diffs/mock_data/diff_discussions.js @@ -12,6 +12,17 @@ export default { head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', }, }, + original_position: { + formatter: { + old_line: null, + new_line: 2, + old_path: 'CHANGELOG', + new_path: 'CHANGELOG', + base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a', + start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962', + head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', + }, + }, line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', expanded: true, notes: [ diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js index 919b612bb6a..f5628a01a55 100644 --- a/spec/javascripts/diffs/store/getters_spec.js +++ b/spec/javascripts/diffs/store/getters_spec.js @@ -2,6 +2,7 @@ import * as getters from '~/diffs/store/getters'; import state from '~/diffs/store/modules/diff_state'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import discussion from '../mock_data/diff_discussions'; +import diffFile from '../mock_data/diff_file'; describe('Diffs Module Getters', () => { let localState; @@ -184,4 +185,57 @@ describe('Diffs Module Getters', () => { ).toEqual(0); }); }); + + describe('getDiffFileByHash', () => { + it('returns file by hash', () => { + const fileA = { + fileHash: '123', + }; + const fileB = { + fileHash: '456', + }; + localState.diffFiles = [fileA, fileB]; + + expect(getters.getDiffFileByHash(localState)('456')).toEqual(fileB); + }); + + it('returns null if no matching file is found', () => { + localState.diffFiles = []; + expect(getters.getDiffFileByHash(localState)('123')).toBeUndefined(); + }); + }); + + describe('discussionsByLineCode', () => { + let mockState; + + beforeEach(() => { + mockState = { diffFiles: [diffFile] }; + }); + + it('should return a map of diff lines with their line codes', () => { + const mockGetters = { discussions: [discussionMock] }; + + const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters); + expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined(); + expect(Object.keys(map).length).toEqual(1); + }); + + it('should have the diff discussion on the map if the original position matches', () => { + discussionMock.position.formatter.base_sha = 'ff9200'; + const mockGetters = { discussions: [discussionMock] }; + + const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters); + expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined(); + expect(Object.keys(map).length).toEqual(1); + }); + + it('should not add an outdated diff discussion to the returned map', () => { + discussionMock.position.formatter.base_sha = 'ff9200'; + discussionMock.original_position.formatter.base_sha = 'ff9200'; + const mockGetters = { discussions: [discussionMock] }; + + const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters); + expect(Object.keys(map).length).toEqual(0); + }); + }); }); diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js index 32136d9ebff..8e7bd8afca4 100644 --- a/spec/javascripts/diffs/store/utils_spec.js +++ b/spec/javascripts/diffs/store/utils_spec.js @@ -207,4 +207,24 @@ describe('DiffsStoreUtils', () => { expect(utils.trimFirstCharOfLineContent()).toEqual({}); }); }); + + describe('getDiffRefsByLineCode', () => { + it('should return diffRefs for all highlightedDiffLines', () => { + const diffFile = getDiffFileMock(); + const map = utils.getDiffRefsByLineCode([diffFile]); + const { highlightedDiffLines } = diffFile; + const lineCodeCount = highlightedDiffLines.reduce( + (acc, line) => (line.lineCode ? acc + 1 : acc), + 0, + ); + + const { baseSha, headSha, startSha } = diffFile.diffRefs; + const targetLine = map[highlightedDiffLines[4].lineCode]; + + expect(Object.keys(map).length).toEqual(lineCodeCount); + expect(targetLine.baseSha).toEqual(baseSha); + expect(targetLine.headSha).toEqual(headSha); + expect(targetLine.startSha).toEqual(startSha); + }); + }); }); diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js index 7a34126eef7..0b933dda431 100644 --- a/spec/javascripts/environments/environment_item_spec.js +++ b/spec/javascripts/environments/environment_item_spec.js @@ -104,7 +104,7 @@ describe('Environment item', () => { }, ], }, - 'stop_action?': true, + has_stop_action: true, environment_path: 'root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-10T15:55:58.778Z', diff --git a/spec/javascripts/environments/mock_data.js b/spec/javascripts/environments/mock_data.js index 8a1e26935d9..7bb57f938b8 100644 --- a/spec/javascripts/environments/mock_data.js +++ b/spec/javascripts/environments/mock_data.js @@ -7,7 +7,7 @@ export const environmentsList = [ external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -22,7 +22,7 @@ export const environmentsList = [ external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', @@ -41,7 +41,7 @@ export const serverData = [ external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -58,7 +58,7 @@ export const serverData = [ external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', @@ -77,7 +77,7 @@ export const environment = { external_url: null, environment_type: null, last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/7', stop_path: '/root/review-app/environments/7/stop', created_at: '2017-01-31T10:53:46.894Z', @@ -95,7 +95,7 @@ export const folder = { external_url: null, environment_type: 'build', last_deployment: null, - 'stop_action?': false, + has_stop_action: false, environment_path: '/root/review-app/environments/12', stop_path: '/root/review-app/environments/12/stop', created_at: '2017-02-01T19:42:18.400Z', diff --git a/spec/javascripts/helpers/vuex_action_helper.js b/spec/javascripts/helpers/vuex_action_helper.js index 4ca7015184e..dd9174194a1 100644 --- a/spec/javascripts/helpers/vuex_action_helper.js +++ b/spec/javascripts/helpers/vuex_action_helper.js @@ -84,14 +84,12 @@ export default ( done(); }; - return new Promise((resolve, reject) => { - try { - const result = action({ commit, state, dispatch, rootState: state }, payload); - resolve(result); - } catch (e) { - reject(e); - } + const result = action({ commit, state, dispatch, rootState: state }, payload); + + return new Promise(resolve => { + setImmediate(resolve); }) + .then(() => result) .catch(error => { validateResults(); throw error; diff --git a/spec/javascripts/helpers/vuex_action_helper_spec.js b/spec/javascripts/helpers/vuex_action_helper_spec.js index 8d6ad6750c0..09f0bd395c3 100644 --- a/spec/javascripts/helpers/vuex_action_helper_spec.js +++ b/spec/javascripts/helpers/vuex_action_helper_spec.js @@ -138,4 +138,29 @@ describe('VueX test helper (testAction)', () => { }); }); }); + + it('should work with async actions not returning promises', done => { + const data = { FOO: 'BAR' }; + + const promiseAction = ({ commit, dispatch }) => { + dispatch('ACTION'); + + axios + .get(TEST_HOST) + .then(() => { + commit('SUCCESS'); + return data; + }) + .catch(error => { + commit('ERROR'); + throw error; + }); + }; + + mock.onGet(TEST_HOST).replyOnce(200, 42); + + assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] }; + + testAction(promiseAction, null, {}, assertion.mutations, assertion.actions, done); + }); }); diff --git a/spec/javascripts/ide/components/ide_status_bar_spec.js b/spec/javascripts/ide/components/ide_status_bar_spec.js index 9895682f388..0e93c5193a1 100644 --- a/spec/javascripts/ide/components/ide_status_bar_spec.js +++ b/spec/javascripts/ide/components/ide_status_bar_spec.js @@ -70,7 +70,7 @@ describe('ideStatusBar', () => { status: { text: 'success', details_path: 'test', - icon: 'success', + icon: 'status_success', }, }, }); diff --git a/spec/javascripts/ide/components/jobs/detail/description_spec.js b/spec/javascripts/ide/components/jobs/detail/description_spec.js index 9b715a41499..babae00d2f7 100644 --- a/spec/javascripts/ide/components/jobs/detail/description_spec.js +++ b/spec/javascripts/ide/components/jobs/detail/description_spec.js @@ -23,6 +23,6 @@ describe('IDE job description', () => { }); it('renders CI icon', () => { - expect(vm.$el.querySelector('.ci-status-icon .ic-status_passed_borderless')).not.toBe(null); + expect(vm.$el.querySelector('.ci-status-icon .ic-status_success_borderless')).not.toBe(null); }); }); diff --git a/spec/javascripts/ide/components/jobs/item_spec.js b/spec/javascripts/ide/components/jobs/item_spec.js index 79e07f00e7b..2f97d39e98e 100644 --- a/spec/javascripts/ide/components/jobs/item_spec.js +++ b/spec/javascripts/ide/components/jobs/item_spec.js @@ -24,7 +24,7 @@ describe('IDE jobs item', () => { }); it('renders CI icon', () => { - expect(vm.$el.querySelector('.ic-status_passed_borderless')).not.toBe(null); + expect(vm.$el.querySelector('.ic-status_success_borderless')).not.toBe(null); }); it('does not render view logs button if not started', done => { diff --git a/spec/javascripts/ide/components/new_dropdown/modal_spec.js b/spec/javascripts/ide/components/new_dropdown/modal_spec.js index 6dcc5880677..70651535e87 100644 --- a/spec/javascripts/ide/components/new_dropdown/modal_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/modal_spec.js @@ -38,7 +38,7 @@ describe('new file modal component', () => { }); it(`sets form label as ${type}`, () => { - expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe('Name'); + expect(vm.$el.querySelector('.label-bold').textContent.trim()).toBe('Name'); }); describe('createEntryInStore', () => { diff --git a/spec/javascripts/ide/ide_router_spec.js b/spec/javascripts/ide/ide_router_spec.js new file mode 100644 index 00000000000..52ea0882bf4 --- /dev/null +++ b/spec/javascripts/ide/ide_router_spec.js @@ -0,0 +1,44 @@ +import router from '~/ide/ide_router'; +import store from '~/ide/stores'; + +describe('IDE router', () => { + const PROJECT_NAMESPACE = 'my-group/sub-group'; + const PROJECT_NAME = 'my-project'; + + afterEach(() => { + router.push('/'); + }); + + afterAll(() => { + // VueRouter leaves this window.history at the "base" url. We need to clean this up. + window.history.replaceState({}, '', '/'); + }); + + [ + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/master/-/src/blob/`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/master/-/src/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/blob/-/src/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/master/-/src/tree/`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/weird:branch/name-123/-/src/tree/`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/blob/master/-/src/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/blob/master/-/src/edit`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/blob/master/-/src/merge_requests/2`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/blob/blob/-/src/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/edit/blob/-/src/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/merge_requests/2`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/tree/blob`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/edit`, + `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}`, + ].forEach(route => { + it(`finds project path when route is "${route}"`, () => { + spyOn(store, 'dispatch').and.returnValue(new Promise(() => {})); + + router.push(route); + + expect(store.dispatch).toHaveBeenCalledWith('getProjectData', { + namespace: PROJECT_NAMESPACE, + projectId: PROJECT_NAME, + }); + }); + }); +}); diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js index 4bbda4c8e80..7be450a0df7 100644 --- a/spec/javascripts/ide/mock_data.js +++ b/spec/javascripts/ide/mock_data.js @@ -74,7 +74,7 @@ export const jobs = [ name: 'test', path: 'testing', status: { - icon: 'status_passed', + icon: 'status_success', text: 'passed', }, stage: 'test', @@ -86,7 +86,7 @@ export const jobs = [ name: 'test 2', path: 'testing2', status: { - icon: 'status_passed', + icon: 'status_success', text: 'passed', }, stage: 'test', @@ -98,7 +98,7 @@ export const jobs = [ name: 'test 3', path: 'testing3', status: { - icon: 'status_passed', + icon: 'status_success', text: 'passed', }, stage: 'test', @@ -146,7 +146,7 @@ export const fullPipelinesResponse = { }, details: { status: { - icon: 'status_passed', + icon: 'status_success', text: 'passed', }, stages: [...stages], diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js index cef30a007db..e21e2c6d6e3 100644 --- a/spec/javascripts/jobs/header_spec.js +++ b/spec/javascripts/jobs/header_spec.js @@ -20,7 +20,7 @@ describe('Job details header', () => { job: { status: { group: 'failed', - icon: 'ci-status-failed', + icon: 'status_failed', label: 'failed', text: 'failed', details_path: 'path', diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js index dd025255bd1..8fdd9b309b7 100644 --- a/spec/javascripts/jobs/mock_data.js +++ b/spec/javascripts/jobs/mock_data.js @@ -14,7 +14,7 @@ export default { finished_at: threeWeeksAgo.toISOString(), queued: 9.54, status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -72,7 +72,7 @@ export default { }, details: { status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 10808315372..e4c98a3bcb5 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -6561,6 +6561,9 @@ export const environmentData = [ folder_path: '/root/hello-prometheus/environments/folders/production', created_at: '2018-06-29T16:53:38.301Z', updated_at: '2018-06-29T16:57:09.825Z', + last_deployment: { + id: 127, + }, }, }, { @@ -6580,6 +6583,20 @@ export const environmentData = [ folder_path: '/root/hello-prometheus/environments/folders/review', created_at: '2018-07-03T18:39:41.702Z', updated_at: '2018-07-03T18:44:54.010Z', + last_deployment: { + id: 128, + }, + }, + }, + { + name: 'no-deployment', + size: 1, + latest: { + id: 36, + name: 'no-deployment/noop-branch', + state: 'available', + created_at: '2018-07-04T18:39:41.702Z', + updated_at: '2018-07-04T18:44:54.010Z', }, }, ]; diff --git a/spec/javascripts/monitoring/monitoring_store_spec.js b/spec/javascripts/monitoring/monitoring_store_spec.js index 08d54946787..ccdf4eda563 100644 --- a/spec/javascripts/monitoring/monitoring_store_spec.js +++ b/spec/javascripts/monitoring/monitoring_store_spec.js @@ -1,5 +1,5 @@ import MonitoringStore from '~/monitoring/stores/monitoring_store'; -import MonitoringMock, { deploymentData } from './mock_data'; +import MonitoringMock, { deploymentData, environmentData } from './mock_data'; describe('MonitoringStore', function () { this.store = new MonitoringStore(); @@ -21,4 +21,9 @@ describe('MonitoringStore', function () { expect(this.store.deploymentData.length).toEqual(3); expect(typeof this.store.deploymentData[0]).toEqual('object'); }); + + it('only stores environment data that contains deployments', () => { + this.store.storeEnvironmentsData(environmentData); + expect(this.store.environmentsData.length).toEqual(2); + }); }); diff --git a/spec/javascripts/notes/components/discussion_counter_spec.js b/spec/javascripts/notes/components/discussion_counter_spec.js index a3869cc6498..d09bc5037ef 100644 --- a/spec/javascripts/notes/components/discussion_counter_spec.js +++ b/spec/javascripts/notes/components/discussion_counter_spec.js @@ -46,7 +46,7 @@ describe('DiscussionCounter component', () => { discussions, }); setFixtures(` - <div data-discussion-id="${firstDiscussionId}"></div> + <div class="discussion" data-discussion-id="${firstDiscussionId}"></div> `); vm.jumpToFirstUnresolvedDiscussion(); diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js index 7da931fd9cb..2a01bd85520 100644 --- a/spec/javascripts/notes/components/noteable_discussion_spec.js +++ b/spec/javascripts/notes/components/noteable_discussion_spec.js @@ -14,6 +14,7 @@ describe('noteable_discussion component', () => { preloadFixtures(discussionWithTwoUnresolvedNotes); beforeEach(() => { + window.mrTabs = {}; store = createStore(); store.dispatch('setNoteableData', noteableDataMock); store.dispatch('setNotesData', notesDataMock); @@ -46,10 +47,15 @@ describe('noteable_discussion component', () => { it('should toggle reply form', done => { vm.$el.querySelector('.js-vue-discussion-reply').click(); + Vue.nextTick(() => { - expect(vm.$refs.noteForm).not.toBeNull(); expect(vm.isReplying).toEqual(true); - done(); + + // There is a watcher for `isReplying` which will init autosave in the next tick + Vue.nextTick(() => { + expect(vm.$refs.noteForm).not.toBeNull(); + done(); + }); }); }); @@ -101,33 +107,29 @@ describe('noteable_discussion component', () => { describe('methods', () => { describe('jumpToNextDiscussion', () => { - it('expands next unresolved discussion', () => { - spyOn(vm, 'expandDiscussion').and.stub(); - const discussions = [ - discussionMock, - { - ...discussionMock, - id: discussionMock.id + 1, - notes: [{ ...discussionMock.notes[0], resolvable: true, resolved: true }], - }, - { - ...discussionMock, - id: discussionMock.id + 2, - notes: [{ ...discussionMock.notes[0], resolvable: true, resolved: false }], - }, - ]; - const nextDiscussionId = discussionMock.id + 2; - store.replaceState({ - ...store.state, - discussions, - }); - setFixtures(` - <div data-discussion-id="${nextDiscussionId}"></div> - `); + it('expands next unresolved discussion', done => { + const discussion2 = getJSONFixture(discussionWithTwoUnresolvedNotes)[0]; + discussion2.resolved = false; + discussion2.id = 'next'; // prepare this for being identified as next one (to be jumped to) + vm.$store.dispatch('setInitialNotes', [discussionMock, discussion2]); + window.mrTabs.currentAction = 'show'; + + Vue.nextTick() + .then(() => { + spyOn(vm, 'expandDiscussion').and.stub(); + + const nextDiscussionId = discussion2.id; + + setFixtures(` + <div class="discussion" data-discussion-id="${nextDiscussionId}"></div> + `); - vm.jumpToNextDiscussion(); + vm.jumpToNextDiscussion(); - expect(vm.expandDiscussion).toHaveBeenCalledWith({ discussionId: nextDiscussionId }); + expect(vm.expandDiscussion).toHaveBeenCalledWith({ discussionId: nextDiscussionId }); + }) + .then(done) + .catch(done.fail); }); }); }); diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js index be2a8ba67fe..67f6a9629d9 100644 --- a/spec/javascripts/notes/mock_data.js +++ b/spec/javascripts/notes/mock_data.js @@ -1168,3 +1168,87 @@ export const collapsedSystemNotes = [ diff_discussion: false, }, ]; + +export const discussion1 = { + id: 'abc1', + resolvable: true, + resolved: false, + diff_file: { + file_path: 'about.md', + }, + position: { + formatter: { + new_line: 50, + old_line: null, + }, + }, + notes: [ + { + created_at: '2018-07-04T16:25:41.749Z', + }, + ], +}; + +export const resolvedDiscussion1 = { + id: 'abc1', + resolvable: true, + resolved: true, + diff_file: { + file_path: 'about.md', + }, + position: { + formatter: { + new_line: 50, + old_line: null, + }, + }, + notes: [ + { + created_at: '2018-07-04T16:25:41.749Z', + }, + ], +}; + +export const discussion2 = { + id: 'abc2', + resolvable: true, + resolved: false, + diff_file: { + file_path: 'README.md', + }, + position: { + formatter: { + new_line: null, + old_line: 20, + }, + }, + notes: [ + { + created_at: '2018-07-04T12:05:41.749Z', + }, + ], +}; + +export const discussion3 = { + id: 'abc3', + resolvable: true, + resolved: false, + diff_file: { + file_path: 'README.md', + }, + position: { + formatter: { + new_line: 21, + old_line: null, + }, + }, + notes: [ + { + created_at: '2018-07-05T17:25:41.749Z', + }, + ], +}; + +export const unresolvableDiscussion = { + resolvable: false, +}; diff --git a/spec/javascripts/notes/stores/getters_spec.js b/spec/javascripts/notes/stores/getters_spec.js index 41599e00122..7f8ede51508 100644 --- a/spec/javascripts/notes/stores/getters_spec.js +++ b/spec/javascripts/notes/stores/getters_spec.js @@ -5,6 +5,11 @@ import { noteableDataMock, individualNote, collapseNotesMock, + discussion1, + discussion2, + discussion3, + resolvedDiscussion1, + unresolvableDiscussion, } from '../mock_data'; const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json'; @@ -109,4 +114,154 @@ describe('Getters Notes Store', () => { expect(getters.isNotesFetched(state)).toBeFalsy(); }); }); + + describe('allResolvableDiscussions', () => { + it('should return only resolvable discussions in same order', () => { + const localGetters = { + allDiscussions: [ + discussion3, + unresolvableDiscussion, + discussion1, + unresolvableDiscussion, + discussion2, + ], + }; + + expect(getters.allResolvableDiscussions(state, localGetters)).toEqual([ + discussion3, + discussion1, + discussion2, + ]); + }); + + it('should return empty array if there are no resolvable discussions', () => { + const localGetters = { + allDiscussions: [unresolvableDiscussion, unresolvableDiscussion], + }; + + expect(getters.allResolvableDiscussions(state, localGetters)).toEqual([]); + }); + }); + + describe('unresolvedDiscussionsIdsByDiff', () => { + it('should return all discussions IDs in diff order', () => { + const localGetters = { + allResolvableDiscussions: [discussion3, discussion1, discussion2], + }; + + expect(getters.unresolvedDiscussionsIdsByDiff(state, localGetters)).toEqual([ + 'abc1', + 'abc2', + 'abc3', + ]); + }); + + it('should return empty array if all discussions have been resolved', () => { + const localGetters = { + allResolvableDiscussions: [resolvedDiscussion1], + }; + + expect(getters.unresolvedDiscussionsIdsByDiff(state, localGetters)).toEqual([]); + }); + }); + + describe('unresolvedDiscussionsIdsByDate', () => { + it('should return all discussions in date ascending order', () => { + const localGetters = { + allResolvableDiscussions: [discussion3, discussion1, discussion2], + }; + + expect(getters.unresolvedDiscussionsIdsByDate(state, localGetters)).toEqual([ + 'abc2', + 'abc1', + 'abc3', + ]); + }); + + it('should return empty array if all discussions have been resolved', () => { + const localGetters = { + allResolvableDiscussions: [resolvedDiscussion1], + }; + + expect(getters.unresolvedDiscussionsIdsByDate(state, localGetters)).toEqual([]); + }); + }); + + describe('unresolvedDiscussionsIdsOrdered', () => { + const localGetters = { + unresolvedDiscussionsIdsByDate: ['123', '456'], + unresolvedDiscussionsIdsByDiff: ['abc', 'def'], + }; + + it('should return IDs ordered by diff when diffOrder param is true', () => { + expect(getters.unresolvedDiscussionsIdsOrdered(state, localGetters)(true)).toEqual([ + 'abc', + 'def', + ]); + }); + + it('should return IDs ordered by date when diffOrder param is not true', () => { + expect(getters.unresolvedDiscussionsIdsOrdered(state, localGetters)(false)).toEqual([ + '123', + '456', + ]); + expect(getters.unresolvedDiscussionsIdsOrdered(state, localGetters)(undefined)).toEqual([ + '123', + '456', + ]); + }); + }); + + describe('isLastUnresolvedDiscussion', () => { + const localGetters = { + unresolvedDiscussionsIdsOrdered: () => ['123', '456', '789'], + }; + + it('should return true if the discussion id provided is the last', () => { + expect(getters.isLastUnresolvedDiscussion(state, localGetters)('789')).toBe(true); + }); + + it('should return false if the discussion id provided is not the last', () => { + expect(getters.isLastUnresolvedDiscussion(state, localGetters)('123')).toBe(false); + expect(getters.isLastUnresolvedDiscussion(state, localGetters)('456')).toBe(false); + }); + }); + + describe('nextUnresolvedDiscussionId', () => { + const localGetters = { + unresolvedDiscussionsIdsOrdered: () => ['123', '456', '789'], + }; + + it('should return the ID of the discussion after the ID provided', () => { + expect(getters.nextUnresolvedDiscussionId(state, localGetters)('123')).toBe('456'); + expect(getters.nextUnresolvedDiscussionId(state, localGetters)('456')).toBe('789'); + expect(getters.nextUnresolvedDiscussionId(state, localGetters)('789')).toBe(undefined); + }); + }); + + describe('firstUnresolvedDiscussionId', () => { + const localGetters = { + unresolvedDiscussionsIdsByDate: ['123', '456'], + unresolvedDiscussionsIdsByDiff: ['abc', 'def'], + }; + + it('should return the first discussion id by diff when diffOrder param is true', () => { + expect(getters.firstUnresolvedDiscussionId(state, localGetters)(true)).toBe('abc'); + }); + + it('should return the first discussion id by date when diffOrder param is not true', () => { + expect(getters.firstUnresolvedDiscussionId(state, localGetters)(false)).toBe('123'); + expect(getters.firstUnresolvedDiscussionId(state, localGetters)(undefined)).toBe('123'); + }); + + it('should be falsy if all discussions are resolved', () => { + const localGettersFalsy = { + unresolvedDiscussionsIdsByDiff: [], + unresolvedDiscussionsIdsByDate: [], + }; + + expect(getters.firstUnresolvedDiscussionId(state, localGettersFalsy)(true)).toBeFalsy(); + expect(getters.firstUnresolvedDiscussionId(state, localGettersFalsy)(false)).toBeFalsy(); + }); + }); }); diff --git a/spec/javascripts/performance_bar/components/performance_bar_app_spec.js b/spec/javascripts/performance_bar/components/performance_bar_app_spec.js index 9ab9ab1c9f4..7926db44429 100644 --- a/spec/javascripts/performance_bar/components/performance_bar_app_spec.js +++ b/spec/javascripts/performance_bar/components/performance_bar_app_spec.js @@ -1,39 +1,15 @@ import Vue from 'vue'; -import axios from '~/lib/utils/axios_utils'; import performanceBarApp from '~/performance_bar/components/performance_bar_app.vue'; -import PerformanceBarService from '~/performance_bar/services/performance_bar_service'; import PerformanceBarStore from '~/performance_bar/stores/performance_bar_store'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import MockAdapter from 'axios-mock-adapter'; -describe('performance bar', () => { - let mock; +describe('performance bar app', () => { let vm; beforeEach(() => { const store = new PerformanceBarStore(); - mock = new MockAdapter(axios); - - mock.onGet('/-/peek/results').reply( - 200, - { - data: { - gc: { - invokes: 0, - invoke_time: '0.00', - use_size: 0, - total_size: 0, - total_object: 0, - gc_time: '0.00', - }, - host: { hostname: 'web-01' }, - }, - }, - {}, - ); - vm = mountComponent(Vue.extend(performanceBarApp), { store, env: 'development', @@ -45,44 +21,9 @@ describe('performance bar', () => { afterEach(() => { vm.$destroy(); - mock.restore(); }); it('sets the class to match the environment', () => { expect(vm.$el.getAttribute('class')).toContain('development'); }); - - describe('loadRequestDetails', () => { - beforeEach(() => { - spyOn(vm.store, 'addRequest').and.callThrough(); - }); - - it('does nothing if the request cannot be tracked', () => { - spyOn(vm.store, 'canTrackRequest').and.callFake(() => false); - - vm.loadRequestDetails('123', 'https://gitlab.com/'); - - expect(vm.store.addRequest).not.toHaveBeenCalled(); - }); - - it('adds the request immediately', () => { - vm.loadRequestDetails('123', 'https://gitlab.com/'); - - expect(vm.store.addRequest).toHaveBeenCalledWith( - '123', - 'https://gitlab.com/', - ); - }); - - it('makes an HTTP request for the request details', () => { - spyOn(PerformanceBarService, 'fetchRequestDetails').and.callThrough(); - - vm.loadRequestDetails('456', 'https://gitlab.com/'); - - expect(PerformanceBarService.fetchRequestDetails).toHaveBeenCalledWith( - '/-/peek/results', - '456', - ); - }); - }); }); diff --git a/spec/javascripts/performance_bar/index_spec.js b/spec/javascripts/performance_bar/index_spec.js new file mode 100644 index 00000000000..1784bd64adb --- /dev/null +++ b/spec/javascripts/performance_bar/index_spec.js @@ -0,0 +1,83 @@ +import axios from '~/lib/utils/axios_utils'; +import performanceBar from '~/performance_bar'; +import PerformanceBarService from '~/performance_bar/services/performance_bar_service'; + +import MockAdapter from 'axios-mock-adapter'; + +describe('performance bar wrapper', () => { + let mock; + let vm; + + beforeEach(() => { + const peekWrapper = document.createElement('div'); + + peekWrapper.setAttribute('id', 'js-peek'); + peekWrapper.setAttribute('data-env', 'development'); + peekWrapper.setAttribute('data-request-id', '123'); + peekWrapper.setAttribute('data-peek-url', '/-/peek/results'); + peekWrapper.setAttribute('data-profile-url', '?lineprofiler=true'); + + document.body.appendChild(peekWrapper); + + mock = new MockAdapter(axios); + + mock.onGet('/-/peek/results').reply( + 200, + { + data: { + gc: { + invokes: 0, + invoke_time: '0.00', + use_size: 0, + total_size: 0, + total_object: 0, + gc_time: '0.00', + }, + host: { hostname: 'web-01' }, + }, + }, + {}, + ); + + vm = performanceBar({ container: '#js-peek' }); + }); + + afterEach(() => { + vm.$destroy(); + mock.restore(); + }); + + describe('loadRequestDetails', () => { + beforeEach(() => { + spyOn(vm.store, 'addRequest').and.callThrough(); + }); + + it('does nothing if the request cannot be tracked', () => { + spyOn(vm.store, 'canTrackRequest').and.callFake(() => false); + + vm.loadRequestDetails('123', 'https://gitlab.com/'); + + expect(vm.store.addRequest).not.toHaveBeenCalled(); + }); + + it('adds the request immediately', () => { + vm.loadRequestDetails('123', 'https://gitlab.com/'); + + expect(vm.store.addRequest).toHaveBeenCalledWith( + '123', + 'https://gitlab.com/', + ); + }); + + it('makes an HTTP request for the request details', () => { + spyOn(PerformanceBarService, 'fetchRequestDetails').and.callThrough(); + + vm.loadRequestDetails('456', 'https://gitlab.com/'); + + expect(PerformanceBarService.fetchRequestDetails).toHaveBeenCalledWith( + '/-/peek/results', + '456', + ); + }); + }); +}); diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js index 9c55a19ebc7..56476253ad0 100644 --- a/spec/javascripts/pipelines/graph/job_component_spec.js +++ b/spec/javascripts/pipelines/graph/job_component_spec.js @@ -10,7 +10,7 @@ describe('pipeline graph job component', () => { id: 4256, name: 'test', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', tooltip: 'passed', @@ -65,7 +65,7 @@ describe('pipeline graph job component', () => { id: 4257, name: 'test', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -111,7 +111,7 @@ describe('pipeline graph job component', () => { id: 4258, name: 'test', status: { - icon: 'icon_status_success', + icon: 'status_success', }, }, }); @@ -125,7 +125,7 @@ describe('pipeline graph job component', () => { id: 4259, name: 'test', status: { - icon: 'icon_status_success', + icon: 'status_success', label: 'success', tooltip: 'success', }, diff --git a/spec/javascripts/pipelines/graph/job_name_component_spec.js b/spec/javascripts/pipelines/graph/job_name_component_spec.js index 8e2071ba0b3..c861d452dd0 100644 --- a/spec/javascripts/pipelines/graph/job_name_component_spec.js +++ b/spec/javascripts/pipelines/graph/job_name_component_spec.js @@ -10,7 +10,7 @@ describe('job name component', () => { propsData: { name: 'foo', status: { - icon: 'icon_status_success', + icon: 'status_success', }, }, }).$mount(); diff --git a/spec/javascripts/pipelines/graph/mock_data.js b/spec/javascripts/pipelines/graph/mock_data.js index 9e25a4b3fed..b2161d54bce 100644 --- a/spec/javascripts/pipelines/graph/mock_data.js +++ b/spec/javascripts/pipelines/graph/mock_data.js @@ -13,7 +13,7 @@ export default { path: '/root/ci-mock/pipelines/123', details: { status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -33,7 +33,7 @@ export default { name: 'test', size: 1, status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -58,7 +58,7 @@ export default { created_at: '2017-04-13T09:25:18.959Z', updated_at: '2017-04-13T09:25:23.118Z', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -78,7 +78,7 @@ export default { }, ], status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -98,7 +98,7 @@ export default { name: 'deploy to production', size: 1, status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -123,7 +123,7 @@ export default { created_at: '2017-04-19T14:29:46.463Z', updated_at: '2017-04-19T14:30:27.498Z', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -145,7 +145,7 @@ export default { name: 'deploy to staging', size: 1, status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -170,7 +170,7 @@ export default { created_at: '2017-04-18T16:32:08.420Z', updated_at: '2017-04-18T16:32:12.631Z', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', @@ -190,7 +190,7 @@ export default { }, ], status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js index f744f1af5e6..9d1e71fd117 100644 --- a/spec/javascripts/pipelines/graph/stage_column_component_spec.js +++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js @@ -7,7 +7,7 @@ describe('stage column component', () => { id: 4250, name: 'test', status: { - icon: 'icon_status_success', + icon: 'status_success', text: 'passed', label: 'passed', group: 'success', diff --git a/spec/javascripts/pipelines/header_component_spec.js b/spec/javascripts/pipelines/header_component_spec.js index cecc7ceb53d..034d3b4957d 100644 --- a/spec/javascripts/pipelines/header_component_spec.js +++ b/spec/javascripts/pipelines/header_component_spec.js @@ -18,7 +18,7 @@ describe('Pipeline details header', () => { details: { status: { group: 'failed', - icon: 'ci-status-failed', + icon: 'status_failed', label: 'failed', text: 'failed', details_path: 'path', diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js index 16f6db39d6a..3f6789759ae 100644 --- a/spec/javascripts/pipelines/stage_spec.js +++ b/spec/javascripts/pipelines/stage_spec.js @@ -20,7 +20,7 @@ describe('Pipelines stage component', () => { stage: { status: { group: 'success', - icon: 'icon_status_success', + icon: 'status_success', title: 'success', }, dropdown_path: 'path.json', @@ -84,7 +84,7 @@ describe('Pipelines stage component', () => { component.stage = { status: { group: 'running', - icon: 'running', + icon: 'status_running', title: 'running', }, dropdown_path: 'bar.json', diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index a0ca8f8b4c3..bc00fdfd73c 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -6,6 +6,7 @@ import '~/commons'; import Vue from 'vue'; import VueResource from 'vue-resource'; import Translate from '~/vue_shared/translate'; +import jasmineDiff from 'jasmine-diff'; import { getDefaultAdapter } from '~/lib/utils/axios_utils'; import { FIXTURES_PATH, TEST_HOST } from './test_constants'; @@ -35,7 +36,15 @@ Vue.use(Translate); jasmine.getFixtures().fixturesPath = FIXTURES_PATH; jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH; -beforeAll(() => jasmine.addMatchers(customMatchers)); +beforeAll(() => { + jasmine.addMatchers( + jasmineDiff(jasmine, { + colors: true, + inline: true, + }), + ); + jasmine.addMatchers(customMatchers); +}); // globalize common libraries window.$ = $; diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js index 61b7bd2c226..8ac2f26979b 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js @@ -119,6 +119,7 @@ describe('MRWidgetHeader', () => { beforeEach(() => { vm = mountComponent(Component, { mr: { + iid: 1, divergedCommitsCount: 12, sourceBranch: 'mr-widget-refactor', sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>', @@ -130,6 +131,8 @@ describe('MRWidgetHeader', () => { emailPatchesPath: '/mr/email-patches', plainDiffPath: '/mr/plainDiffPath', statusPath: 'abc', + sourceProjectFullPath: 'root/gitlab-ce', + targetProjectFullPath: 'gitlab-org/gitlab-ce', }, }); }); @@ -146,16 +149,40 @@ describe('MRWidgetHeader', () => { const button = vm.$el.querySelector('.js-web-ide'); expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); + expect(button.getAttribute('href')).toEqual( + '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org%2Fgitlab-ce', + ); }); - it('renders web ide button with relative URL', () => { + it('renders web ide button with blank query string if target & source project branch', done => { + vm.mr.targetProjectFullPath = 'root/gitlab-ce'; + + vm.$nextTick(() => { + const button = vm.$el.querySelector('.js-web-ide'); + + expect(button.textContent.trim()).toEqual('Open in Web IDE'); + expect(button.getAttribute('href')).toEqual( + '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=', + ); + + done(); + }); + }); + + it('renders web ide button with relative URL', done => { gon.relative_url_root = '/gitlab'; + vm.mr.iid = 2; - const button = vm.$el.querySelector('.js-web-ide'); + vm.$nextTick(() => { + const button = vm.$el.querySelector('.js-web-ide'); - expect(button.textContent.trim()).toEqual('Open in Web IDE'); - expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); + expect(button.textContent.trim()).toEqual('Open in Web IDE'); + expect(button.getAttribute('href')).toEqual( + '/gitlab/-/ide/project/root/gitlab-ce/merge_requests/2?target_project=gitlab-org%2Fgitlab-ce', + ); + + done(); + }); }); it('renders download dropdown with links', () => { diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js index 9d2a15ff009..7fd1a2350f7 100644 --- a/spec/javascripts/vue_mr_widget/mock_data.js +++ b/spec/javascripts/vue_mr_widget/mock_data.js @@ -29,8 +29,10 @@ export default { source_branch: 'daaaa', source_branch_link: 'daaaa', source_project_id: 19, + source_project_full_path: '/group1/project1', target_branch: 'master', target_project_id: 19, + target_project_full_path: '/group2/project2', metrics: { merged_by: { name: 'Administrator', @@ -74,7 +76,7 @@ export default { path: '/root/acets-app/pipelines/172', details: { status: { - icon: 'icon_status_success', + icon: 'status_success', favicon: 'favicon_status_success', text: 'passed', label: 'passed', @@ -89,7 +91,7 @@ export default { name: 'build', title: 'build: failed', status: { - icon: 'icon_status_failed', + icon: 'status_failed', favicon: 'favicon_status_failed', text: 'failed', label: 'failed', @@ -104,7 +106,7 @@ export default { name: 'review', title: 'review: skipped', status: { - icon: 'icon_status_skipped', + icon: 'status_skipped', favicon: 'favicon_status_skipped', text: 'skipped', label: 'skipped', diff --git a/spec/javascripts/vue_shared/components/ci_icon_spec.js b/spec/javascripts/vue_shared/components/ci_icon_spec.js index 423bc746a22..b59a7d7544f 100644 --- a/spec/javascripts/vue_shared/components/ci_icon_spec.js +++ b/spec/javascripts/vue_shared/components/ci_icon_spec.js @@ -13,7 +13,7 @@ describe('CI Icon component', () => { it('should render a span element with an svg', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_success', + icon: 'status_success', }, }); @@ -24,7 +24,7 @@ describe('CI Icon component', () => { it('should render a success status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_success', + icon: 'status_success', group: 'success', }, }); @@ -35,7 +35,7 @@ describe('CI Icon component', () => { it('should render a failed status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_failed', + icon: 'status_failed', group: 'failed', }, }); @@ -46,7 +46,7 @@ describe('CI Icon component', () => { it('should render success with warnings status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_warning', + icon: 'status_warning', group: 'warning', }, }); @@ -57,7 +57,7 @@ describe('CI Icon component', () => { it('should render pending status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_pending', + icon: 'status_pending', group: 'pending', }, }); @@ -68,7 +68,7 @@ describe('CI Icon component', () => { it('should render running status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_running', + icon: 'status_running', group: 'running', }, }); @@ -79,7 +79,7 @@ describe('CI Icon component', () => { it('should render created status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_created', + icon: 'status_created', group: 'created', }, }); @@ -90,7 +90,7 @@ describe('CI Icon component', () => { it('should render skipped status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_skipped', + icon: 'status_skipped', group: 'skipped', }, }); @@ -101,7 +101,7 @@ describe('CI Icon component', () => { it('should render canceled status', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_canceled', + icon: 'status_canceled', group: 'canceled', }, }); @@ -112,7 +112,7 @@ describe('CI Icon component', () => { it('should render status for manual action', () => { vm = mountComponent(Component, { status: { - icon: 'icon_status_manual', + icon: 'status_manual', group: 'manual', }, }); diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js index 65499a2d730..f17818c17c7 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js @@ -12,7 +12,7 @@ describe('Header CI Component', () => { props = { status: { group: 'failed', - icon: 'ci-status-failed', + icon: 'status_failed', label: 'failed', text: 'failed', details_path: 'path', diff --git a/spec/javascripts/vue_shared/components/icon_spec.js b/spec/javascripts/vue_shared/components/icon_spec.js index cc030e29d61..882420e602e 100644 --- a/spec/javascripts/vue_shared/components/icon_spec.js +++ b/spec/javascripts/vue_shared/components/icon_spec.js @@ -10,7 +10,7 @@ describe('Sprite Icon Component', function () { const IconComponent = Vue.extend(Icon); icon = mountComponent(IconComponent, { - name: 'test', + name: 'commit', size: 32, cssClasses: 'extraclasses', }); @@ -30,7 +30,7 @@ describe('Sprite Icon Component', function () { it('should have <use> as a child element with the correct href', function () { expect(icon.$el.firstChild.tagName).toBe('use'); - expect(icon.$el.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_icons}#test`); + expect(icon.$el.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_icons}#commit`); }); it('should properly compute iconSizeClass', function () { @@ -50,5 +50,13 @@ describe('Sprite Icon Component', function () { expect(containsSizeClass).toBe(true); expect(containsCustomClass).toBe(true); }); + + it('`name` validator should return false for non existing icons', () => { + expect(Icon.props.name.validator('non_existing_icon_sprite')).toBe(false); + }); + + it('`name` validator should return false for existing icons', () => { + expect(Icon.props.name.validator('commit')).toBe(true); + }); }); }); diff --git a/spec/javascripts/vue_shared/components/memory_graph_spec.js b/spec/javascripts/vue_shared/components/memory_graph_spec.js index 73a69df019e..65d8ed39ade 100644 --- a/spec/javascripts/vue_shared/components/memory_graph_spec.js +++ b/spec/javascripts/vue_shared/components/memory_graph_spec.js @@ -113,7 +113,7 @@ describe('MemoryGraph', () => { const circleEl = el.querySelector('circle'); expect(circleEl).toBeDefined(); expect(circleEl.getAttribute('r')).toBe('1.5'); - expect(circleEl.getAttribute('tranform')).toBe('translate(0 -1)'); + expect(circleEl.getAttribute('transform')).toBe('translate(0 -1)'); expect(circleEl.getAttribute('cx')).toBe(`${dotX}`); expect(circleEl.getAttribute('cy')).toBe(`${dotY}`); done(); diff --git a/spec/javascripts/vue_shared/components/notes/system_note_spec.js b/spec/javascripts/vue_shared/components/notes/system_note_spec.js index aa4c9c4c88c..2a6015fe35f 100644 --- a/spec/javascripts/vue_shared/components/notes/system_note_spec.js +++ b/spec/javascripts/vue_shared/components/notes/system_note_spec.js @@ -19,7 +19,7 @@ describe('system note component', () => { path: '/root', }, note_html: '<p dir="auto">closed</p>', - system_note_icon_name: 'icon_status_closed', + system_note_icon_name: 'status_closed', created_at: '2017-08-02T10:51:58.559Z', }, }; diff --git a/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js b/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js new file mode 100644 index 00000000000..8635203c413 --- /dev/null +++ b/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import component from '~/vue_shared/components/reports/modal_open_name.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; + +describe('Modal open name', () => { + const Component = Vue.extend(component); + let vm; + + const store = new Vuex.Store({ + actions: { + openModal: () => {}, + }, + state: {}, + mutations: {}, + }); + + beforeEach(() => { + vm = mountComponentWithStore(Component, { + store, + props: { + issue: { + title: 'Issue', + }, + status: 'failed', + }, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders the issue name', () => { + expect(vm.$el.textContent.trim()).toEqual('Issue'); + }); + + it('calls openModal actions when button is clicked', () => { + spyOn(vm, 'openModal'); + + vm.$el.click(); + + expect(vm.openModal).toHaveBeenCalled(); + }); +}); diff --git a/spec/javascripts/vue_shared/components/reports/report_issues_spec.js b/spec/javascripts/vue_shared/components/reports/report_issues_spec.js new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/spec/javascripts/vue_shared/components/reports/report_issues_spec.js diff --git a/spec/javascripts/vue_shared/components/reports/report_link_spec.js b/spec/javascripts/vue_shared/components/reports/report_link_spec.js new file mode 100644 index 00000000000..a4691f3712f --- /dev/null +++ b/spec/javascripts/vue_shared/components/reports/report_link_spec.js @@ -0,0 +1,71 @@ +import Vue from 'vue'; +import component from '~/vue_shared/components/reports/report_link.vue'; +import mountComponent from '../../../helpers/vue_mount_component_helper'; + +describe('report link', () => { + let vm; + + const Component = Vue.extend(component); + + afterEach(() => { + vm.$destroy(); + }); + + describe('With url', () => { + it('renders link', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: '/Gemfile.lock', + }, + }); + + expect(vm.$el.textContent.trim()).toContain('in'); + expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('/Gemfile.lock'); + expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Gemfile.lock'); + }); + }); + + describe('Without url', () => { + it('does not render link', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + }, + }); + + expect(vm.$el.querySelector('a')).toBeNull(); + expect(vm.$el.textContent.trim()).toContain('in'); + expect(vm.$el.textContent.trim()).toContain('Gemfile.lock'); + }); + }); + + describe('with line', () => { + it('renders line number', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: + 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', + line: 22, + }, + }); + + expect(vm.$el.querySelector('a').textContent.trim()).toContain('Gemfile.lock:22'); + }); + }); + + describe('without line', () => { + it('does not render line number', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: + 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', + }, + }); + + expect(vm.$el.querySelector('a').textContent.trim()).not.toContain(':22'); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/reports/report_section_spec.js b/spec/javascripts/vue_shared/components/reports/report_section_spec.js new file mode 100644 index 00000000000..07401181ffd --- /dev/null +++ b/spec/javascripts/vue_shared/components/reports/report_section_spec.js @@ -0,0 +1,174 @@ +import Vue from 'vue'; +import reportSection from '~/vue_shared/components/reports/report_section.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Report section', () => { + let vm; + const ReportSection = Vue.extend(reportSection); + + const resolvedIssues = [ + { + name: 'Insecure Dependency', + fingerprint: 'ca2e59451e98ae60ba2f54e3857c50e5', + path: 'Gemfile.lock', + line: 12, + urlPath: 'foo/Gemfile.lock', + }, + ]; + + afterEach(() => { + vm.$destroy(); + }); + + describe('computed', () => { + beforeEach(() => { + vm = mountComponent(ReportSection, { + type: 'codequality', + status: 'SUCCESS', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + resolvedIssues, + hasIssues: false, + alwaysOpen: false, + }); + }); + + describe('isCollapsible', () => { + const testMatrix = [ + { hasIssues: false, alwaysOpen: false, isCollapsible: false }, + { hasIssues: false, alwaysOpen: true, isCollapsible: false }, + { hasIssues: true, alwaysOpen: false, isCollapsible: true }, + { hasIssues: true, alwaysOpen: true, isCollapsible: false }, + ]; + + testMatrix.forEach(({ hasIssues, alwaysOpen, isCollapsible }) => { + const issues = hasIssues ? 'has issues' : 'has no issues'; + const open = alwaysOpen ? 'is always open' : 'is not always open'; + + it(`is ${isCollapsible}, if the report ${issues} and ${open}`, done => { + vm.hasIssues = hasIssues; + vm.alwaysOpen = alwaysOpen; + + Vue.nextTick() + .then(() => { + expect(vm.isCollapsible).toBe(isCollapsible); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('isExpanded', () => { + const testMatrix = [ + { isCollapsed: false, alwaysOpen: false, isExpanded: true }, + { isCollapsed: false, alwaysOpen: true, isExpanded: true }, + { isCollapsed: true, alwaysOpen: false, isExpanded: false }, + { isCollapsed: true, alwaysOpen: true, isExpanded: true }, + ]; + + testMatrix.forEach(({ isCollapsed, alwaysOpen, isExpanded }) => { + const issues = isCollapsed ? 'is collapsed' : 'is not collapsed'; + const open = alwaysOpen ? 'is always open' : 'is not always open'; + + it(`is ${isExpanded}, if the report ${issues} and ${open}`, done => { + vm.isCollapsed = isCollapsed; + vm.alwaysOpen = alwaysOpen; + + Vue.nextTick() + .then(() => { + expect(vm.isExpanded).toBe(isExpanded); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + }); + describe('when it is loading', () => { + it('should render loading indicator', () => { + vm = mountComponent(ReportSection, { + type: 'codequality', + status: 'LOADING', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + hasIssues: false, + }); + expect(vm.$el.textContent.trim()).toEqual('Loading codeclimate report'); + }); + }); + + describe('with success status', () => { + beforeEach(() => { + vm = mountComponent(ReportSection, { + type: 'codequality', + status: 'SUCCESS', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + resolvedIssues, + hasIssues: true, + }); + }); + + it('should render provided data', () => { + expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( + 'Code quality improved on 1 point and degraded on 1 point', + ); + + expect(vm.$el.querySelectorAll('.js-mr-code-resolved-issues li').length).toEqual( + resolvedIssues.length, + ); + }); + + describe('toggleCollapsed', () => { + const hiddenCss = { display: 'none' }; + + it('toggles issues', done => { + vm.$el.querySelector('button').click(); + + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Collapse'); + + vm.$el.querySelector('button').click(); + }) + .then(Vue.nextTick) + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Expand'); + }) + .then(done) + .catch(done.fail); + }); + + it('is always expanded, if always-open is set to true', done => { + vm.alwaysOpen = true; + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button')).toBeNull(); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('with failed request', () => { + it('should render error indicator', () => { + vm = mountComponent(ReportSection, { + type: 'codequality', + status: 'ERROR', + loadingText: 'Loading codeclimate report', + errorText: 'Failed to load codeclimate report', + successText: 'Code quality improved on 1 point and degraded on 1 point', + hasIssues: false, + }); + expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report'); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/reports/summary_row_spec.js b/spec/javascripts/vue_shared/components/reports/summary_row_spec.js new file mode 100644 index 00000000000..ac076f05bc0 --- /dev/null +++ b/spec/javascripts/vue_shared/components/reports/summary_row_spec.js @@ -0,0 +1,37 @@ +import Vue from 'vue'; +import component from '~/vue_shared/components/reports/summary_row.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Summary row', () => { + const Component = Vue.extend(component); + let vm; + + const props = { + summary: 'SAST detected 1 new vulnerability and 1 fixed vulnerability', + popoverOptions: { + title: 'Static Application Security Testing (SAST)', + content: '<a>Learn more about SAST</a>', + }, + statusIcon: 'warning', + }; + + beforeEach(() => { + vm = mountComponent(Component, props); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders provided summary', () => { + expect( + vm.$el.querySelector('.report-block-list-issue-description-text').textContent.trim(), + ).toEqual(props.summary); + }); + + it('renders provided icon', () => { + expect(vm.$el.querySelector('.report-block-list-icon span').classList).toContain( + 'js-ci-status-icon-warning', + ); + }); +}); diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb index 211e3aaa94b..0735ebd6dcb 100644 --- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb +++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb @@ -9,6 +9,11 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m let(:merge_request) { merge_requests.create!(iid: 1, target_project_id: project.id, source_project_id: project.id, target_branch: 'feature', source_branch: 'master').becomes(MergeRequest) } let(:merge_request_diff) { MergeRequest.find(merge_request.id).create_merge_request_diff } let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) } + let(:rugged) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged + end + end before do allow_any_instance_of(MergeRequestDiff) @@ -299,11 +304,7 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m let(:commits) { merge_request_diff.commits.map(&:to_hash) } let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) } let(:expected_commits) { commits } - let(:diffs) do - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - first_commit.rugged_diff_from_parent.patches - end - end + let(:diffs) { rugged_diff(first_commit.sha).patches } let(:expected_diffs) { [] } include_examples 'updated MR diff' @@ -313,14 +314,15 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m let(:commits) { merge_request_diff.commits.map(&:to_hash) } let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) } let(:expected_commits) { commits } - let(:diffs) do - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - first_commit.rugged_diff_from_parent.deltas - end - end + let(:diffs) { rugged_diff(first_commit.sha).deltas } let(:expected_diffs) { [] } include_examples 'updated MR diff' end + + def rugged_diff(commit_sha) + rugged_commit = rugged.lookup(commit_sha) + rugged_commit.parents[0].diff(rugged_commit) + end end end diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index 7c04aa27971..4df426c54ae 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -132,6 +132,16 @@ describe Gitlab::Checks::ChangeAccess do expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to protected branches on this project.') end + context 'when project repository is empty' do + let(:project) { create(:project) } + + it 'raises an error if the user is not allowed to push to protected branches' do + expect(user_access).to receive(:can_push_to_branch?).and_return(false) + + expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /Ask a project Owner or Maintainer to create a default branch/) + end + end + context 'branch deletion' do let(:newrev) { '0000000000000000000000000000000000000000' } let(:ref) { 'refs/heads/feature' } diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb index adb3ff4321f..46874662edd 100644 --- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb @@ -75,6 +75,14 @@ describe Gitlab::Ci::Variables::Collection::Item do expect(resource).to eq variable end + it 'supports using a hash with stringified values' do + variable = { 'key' => 'VARIABLE', 'value' => 'my value' } + + resource = described_class.fabricate(variable) + + expect(resource).to eq(key: 'VARIABLE', value: 'my value') + end + it 'supports using an active record resource' do variable = create(:ci_variable, key: 'CI_VAR', value: '123') resource = described_class.fabricate(variable) diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 3a0688b7cbb..1f35d1e4880 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -379,6 +379,20 @@ describe Gitlab::ClosingIssueExtractor do .to match_array([issue, other_issue, third_issue]) end + it 'allows non-comma-separated issue numbers in single line message' do + message = "Closes #{reference} #{reference2} #{reference3}" + + expect(subject.closed_by_message(message)) + .to match_array([issue, other_issue, third_issue]) + end + + it 'allows mixed comma-separated and non-comma-separated issue numbers in single line message' do + message = "Closes #{reference}, #{reference2} and #{reference3}" + + expect(subject.closed_by_message(message)) + .to match_array([issue, other_issue, third_issue]) + end + it 'fetches issues in multi-line message' do message = "Awesome commit (closes #{reference})\nAlso fixes #{reference2}" diff --git a/spec/lib/additional_email_headers_interceptor_spec.rb b/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb index b5c1a360ba9..ae61ece8029 100644 --- a/spec/lib/additional_email_headers_interceptor_spec.rb +++ b/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AdditionalEmailHeadersInterceptor do +describe Gitlab::Email::Hook::AdditionalHeadersInterceptor do let(:mail) do ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', body: 'hello') end diff --git a/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb b/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb new file mode 100644 index 00000000000..4497d4002da --- /dev/null +++ b/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Gitlab::Email::Hook::DeliveryMetricsObserver do + let(:email) do + ActionMailer::Base.mail(to: 'test@example.com', + from: 'info@example.com', + body: 'hello') + end + + context 'when email has been delivered' do + it 'increments both email delivery metrics' do + expect(described_class.delivery_attempts_counter).to receive(:increment) + expect(described_class.delivered_emails_counter).to receive(:increment) + + email.deliver_now + end + end + + context 'when email has not been delivered due to an error' do + before do + allow(email.delivery_method).to receive(:deliver!) + .and_raise(StandardError, 'Some SMTP error') + end + + it 'increments only delivery attempt metric' do + expect(described_class.delivery_attempts_counter) + .to receive(:increment) + expect(described_class.delivered_emails_counter) + .not_to receive(:increment) + + expect { email.deliver_now } + .to raise_error(StandardError, 'Some SMTP error') + end + end +end diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb index 3652d928c43..91aa3bc7c2e 100644 --- a/spec/lib/disable_email_interceptor_spec.rb +++ b/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DisableEmailInterceptor do +describe Gitlab::Email::Hook::DisableEmailInterceptor do before do Mail.register_interceptor(described_class) end diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index ee74c2769eb..0adb684765d 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::Git::Commit, seed_helper: true do } @parents = [repo.head.target] - @gitlab_parents = @parents.map { |c| described_class.decorate(repository, c) } + @gitlab_parents = @parents.map { |c| described_class.find(repository, c.oid) } @tree = @parents.first.tree sha = Rugged::Commit.create( @@ -41,7 +41,7 @@ describe Gitlab::Git::Commit, seed_helper: true do ) @raw_commit = repo.lookup(sha) - @commit = described_class.new(repository, @raw_commit) + @commit = described_class.find(repository, sha) end it { expect(@commit.short_id).to eq(@raw_commit.oid[0..10]) } @@ -488,13 +488,15 @@ describe Gitlab::Git::Commit, seed_helper: true do end end - describe '#init_from_rugged' do - let(:gitlab_commit) { described_class.new(repository, rugged_commit) } - subject { gitlab_commit } + skip 'move this test to gitaly-ruby' do + describe '#init_from_rugged' do + let(:gitlab_commit) { described_class.new(repository, rugged_commit) } + subject { gitlab_commit } - describe '#id' do - subject { super().id } - it { is_expected.to eq(SeedRepo::Commit::ID) } + describe '#id' do + subject { super().id } + it { is_expected.to eq(SeedRepo::Commit::ID) } + end end end diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb index 7c3d2af819b..11ab376ab8f 100644 --- a/spec/lib/gitlab/git/diff_spec.rb +++ b/spec/lib/gitlab/git/diff_spec.rb @@ -269,7 +269,7 @@ EOT before do # TODO use a Gitaly diff object instead rugged_commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e') + repository.rugged.rev_parse('5937ac0a7beb003549fc5fd26fc247adbce4a52e') end @diffs = rugged_commit.parents[0].diff(rugged_commit).patches diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb index 16e6bd35449..e51b875be11 100644 --- a/spec/lib/gitlab/git/index_spec.rb +++ b/spec/lib/gitlab/git/index_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::Git::Index, seed_helper: true do let(:index) { described_class.new(repository) } before do - index.read_tree(repository.lookup('master').tree) + index.read_tree(lookup('master').tree) end around do |example| @@ -30,7 +30,7 @@ describe Gitlab::Git::Index, seed_helper: true do entry = index.get(options[:file_path]) expect(entry).not_to be_nil - expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + expect(lookup(entry[:oid]).content).to eq(options[:content]) end end @@ -54,7 +54,7 @@ describe Gitlab::Git::Index, seed_helper: true do index.create(options) entry = index.get(options[:file_path]) - expect(repository.lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content])) + expect(lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content])) end end @@ -68,7 +68,7 @@ describe Gitlab::Git::Index, seed_helper: true do index.create(options) entry = index.get(options[:file_path]) - expect(repository.lookup(entry[:oid]).content).to eq("Hello,\nWorld") + expect(lookup(entry[:oid]).content).to eq("Hello,\nWorld") end end end @@ -135,7 +135,7 @@ describe Gitlab::Git::Index, seed_helper: true do entry = index.get(options[:file_path]) - expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + expect(lookup(entry[:oid]).content).to eq(options[:content]) end it 'preserves file mode' do @@ -190,7 +190,7 @@ describe Gitlab::Git::Index, seed_helper: true do entry = index.get(options[:file_path]) expect(entry).not_to be_nil - expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + expect(lookup(entry[:oid]).content).to eq(options[:content]) end it 'preserves file mode' do @@ -232,4 +232,8 @@ describe Gitlab::Git::Index, seed_helper: true do end end end + + def lookup(revision) + repository.rugged.rev_parse(revision) + end end diff --git a/spec/lib/gitlab/git/popen_spec.rb b/spec/lib/gitlab/git/popen_spec.rb index b033ede9062..074e66d2a5d 100644 --- a/spec/lib/gitlab/git/popen_spec.rb +++ b/spec/lib/gitlab/git/popen_spec.rb @@ -2,6 +2,9 @@ require 'spec_helper' describe 'Gitlab::Git::Popen' do let(:path) { Rails.root.join('tmp').to_s } + let(:test_string) { 'The quick brown fox jumped over the lazy dog' } + # The pipe buffer is typically 64K. This string is about 440K. + let(:spew_command) { ['bash', '-c', "for i in {1..10000}; do echo '#{test_string}' 1>&2; done"] } let(:klass) do Class.new(Object) do @@ -70,6 +73,15 @@ describe 'Gitlab::Git::Popen' do end end end + + context 'with a process that writes a lot of data to stderr' do + it 'returns zero' do + output, status = klass.new.popen(spew_command, path) + + expect(output).to include(test_string) + expect(status).to eq(0) + end + end end context 'popen_with_timeout' do @@ -85,6 +97,17 @@ describe 'Gitlab::Git::Popen' do it { expect(output).to include('tests') } end + context 'multi-line string' do + let(:test_string) { "this is 1 line\n2nd line\n3rd line\n" } + let(:result) { klass.new.popen_with_timeout(['echo', test_string], timeout, path) } + let(:output) { result.first } + let(:status) { result.last } + + it { expect(status).to be_zero } + # echo adds its own line + it { expect(output).to eq(test_string + "\n") } + end + context 'non-zero status' do let(:result) { klass.new.popen_with_timeout(%w(cat NOTHING), timeout, path) } let(:output) { result.first } @@ -110,6 +133,13 @@ describe 'Gitlab::Git::Popen' do it "handles processes that do not shutdown correctly" do expect { klass.new.popen_with_timeout(['bash', '-c', "trap -- '' SIGTERM; sleep 1000"], timeout, path) }.to raise_error(Timeout::Error) end + + it 'handles process that writes a lot of data to stderr' do + output, status = klass.new.popen_with_timeout(spew_command, timeout, path) + + expect(output).to include(test_string) + expect(status).to eq(0) + end end context 'timeout period' do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 64b08dd9c4b..62396af1ebe 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -321,90 +321,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - context '#submodules' do - around do |example| - # TODO #submodules will be removed, has been migrated to gitaly - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - example.run - end - end - - let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } - - context 'where repo has submodules' do - let(:submodules) { repository.send(:submodules, 'master') } - let(:submodule) { submodules.first } - - it { expect(submodules).to be_kind_of Hash } - it { expect(submodules.empty?).to be_falsey } - - it 'should have valid data' do - expect(submodule).to eq([ - "six", { - "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d", - "name" => "six", - "url" => "git://github.com/randx/six.git" - } - ]) - end - - it 'should handle nested submodules correctly' do - nested = submodules['nested/six'] - expect(nested['name']).to eq('nested/six') - expect(nested['url']).to eq('git://github.com/randx/six.git') - expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196') - end - - it 'should handle deeply nested submodules correctly' do - nested = submodules['deeper/nested/six'] - expect(nested['name']).to eq('deeper/nested/six') - expect(nested['url']).to eq('git://github.com/randx/six.git') - expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196') - end - - it 'should not have an entry for an invalid submodule' do - expect(submodules).not_to have_key('invalid/path') - end - - it 'should not have an entry for an uncommited submodule dir' do - submodules = repository.send(:submodules, 'fix-existing-submodule-dir') - expect(submodules).not_to have_key('submodule-existing-dir') - end - - it 'should handle tags correctly' do - submodules = repository.send(:submodules, 'v1.2.1') - - expect(submodules.first).to eq([ - "six", { - "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d", - "name" => "six", - "url" => "git://github.com/randx/six.git" - } - ]) - end - - it 'should not break on invalid syntax' do - allow(repository).to receive(:blob_content).and_return(<<-GITMODULES.strip_heredoc) - [submodule "six"] - path = six - url = git://github.com/randx/six.git - - [submodule] - foo = bar - GITMODULES - - expect(submodules).to have_key('six') - end - end - - context 'where repo doesn\'t have submodules' do - let(:submodules) { repository.send(:submodules, '6d39438') } - it 'should return an empty hash' do - expect(submodules).to be_empty - end - end - end - describe '#commit_count' do shared_examples 'simple commit counting' do it { expect(repository.commit_count("master")).to eq(25) } @@ -611,25 +527,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe "#remote_update" do - before(:all) do - @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') - @repo.remote_update("expendable", url: TEST_NORMAL_REPO_PATH) - end - - it "should add the remote" do - rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access { @repo.rugged } - - expect(rugged.remotes["expendable"].url).to( - eq(TEST_NORMAL_REPO_PATH) - ) - end - - after(:all) do - ensure_seeds - end - end - describe '#fetch_repository_as_mirror' do let(:new_repository) do Gitlab::Git::Repository.new('default', 'my_project.git', '') @@ -686,58 +583,24 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#remote_tags' do - let(:remote_name) { 'upstream' } - let(:target_commit_id) { SeedRepo::Commit::ID } - let(:tag_name) { 'v0.0.1' } - let(:tag_message) { 'My tag' } - let(:remote_repository) do - Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') - end - - around do |example| - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - example.run - end - end - - subject { repository.remote_tags(remote_name) } - - before do - remote_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { remote_repository.path } - repository.add_remote(remote_name, remote_repository_path) - remote_repository.add_tag(tag_name, user: user, target: target_commit_id) - end - - after do - ensure_seeds - end - - it 'gets the remote tags' do - expect(subject.first).to be_an_instance_of(Gitlab::Git::Tag) - expect(subject.first.name).to eq(tag_name) - expect(subject.first.dereferenced_target.id).to eq(target_commit_id) - end - end - describe "#log" do shared_examples 'repository log' do let(:commit_with_old_name) do - Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id) + Gitlab::Git::Commit.find(repository, @commit_with_old_name_id) end let(:commit_with_new_name) do - Gitlab::Git::Commit.decorate(repository, @commit_with_new_name_id) + Gitlab::Git::Commit.find(repository, @commit_with_new_name_id) end let(:rename_commit) do - Gitlab::Git::Commit.decorate(repository, @rename_commit_id) + Gitlab::Git::Commit.find(repository, @rename_commit_id) end before(:context) do # Add new commits so that there's a renamed file in the commit history repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged - @commit_with_old_name_id = new_commit_edit_old_file(repo) - @rename_commit_id = new_commit_move_file(repo) - @commit_with_new_name_id = new_commit_edit_new_file(repo) + @commit_with_old_name_id = new_commit_edit_old_file(repo).oid + @rename_commit_id = new_commit_move_file(repo).oid + @commit_with_new_name_id = new_commit_edit_new_file(repo).oid end after(:context) do @@ -939,8 +802,8 @@ describe Gitlab::Git::Repository, seed_helper: true do def commit_files(commit) Gitlab::GitalyClient::StorageSettings.allow_disk_access do - commit.rugged_diff_from_parent.deltas.flat_map do |delta| - [delta.old_file[:path], delta.new_file[:path]].uniq.compact + commit.deltas.flat_map do |delta| + [delta.old_path, delta.new_path].uniq.compact end end end @@ -977,10 +840,6 @@ describe Gitlab::Git::Repository, seed_helper: true do context 'when Gitaly find_commits feature is enabled' do it_behaves_like 'repository log' end - - context 'when Gitaly find_commits feature is disabled', :disable_gitaly do - it_behaves_like 'repository log' - end end describe '#count_commits_between' do @@ -1525,31 +1384,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#batch_existence' do - let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] } - - around do |example| - # TODO #batch_existence isn't used anywhere, can we remove it? - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - example.run - end - end - - it 'returns existing refs back' do - result = repository.batch_existence(refs) - - expect(result).to eq([SeedRepo::RubyBlob::ID]) - end - - context 'existing: true' do - it 'inverts meaning and returns non-existing refs' do - result = repository.batch_existence(refs, existing: false) - - expect(result).to eq(%w(deadbeef 909e6157199)) - end - end - end - describe '#local_branches' do before(:all) do @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb deleted file mode 100644 index d9d405e1ccc..00000000000 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Git::RevList do - let(:repository) { create(:project, :repository).repository.raw } - let(:rev_list) { described_class.new(repository, newrev: 'newrev') } - - def args_for_popen(args_list) - [Gitlab.config.git.bin_path, 'rev-list', *args_list] - end - - def stub_popen_rev_list(*additional_args, with_lazy_block: true, output:) - repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.path } - - params = [ - args_for_popen(additional_args), - repo_path, - {}, - hash_including(lazy_block: with_lazy_block ? anything : nil) - ] - - expect(repository).to receive(:popen).with(*params) do |*_, lazy_block:| - output = lazy_block.call(output.lines.lazy.map(&:chomp)) if with_lazy_block - - [output, 0] - end - end - - context "#new_refs" do - it 'calls out to `popen`' do - stub_popen_rev_list('newrev', '--not', '--all', with_lazy_block: false, output: "sha1\nsha2") - - expect(rev_list.new_refs).to eq(%w[sha1 sha2]) - end - end -end diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb index 031d1e87dc1..eaf64e3c9b4 100644 --- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' describe Gitlab::GitalyClient::OperationService do - let(:project) { create(:project) } + set(:project) { create(:project, :repository) } let(:repository) { project.repository.raw } let(:client) { described_class.new(repository) } - let(:user) { create(:user) } + set(:user) { create(:user) } let(:gitaly_user) { Gitlab::Git::User.from_gitlab(user).to_gitaly } describe '#user_create_branch' do @@ -151,18 +151,104 @@ describe Gitlab::GitalyClient::OperationService do end let(:response) { Gitaly::UserFFBranchResponse.new(branch_update: branch_update) } - subject { client.user_ff_branch(user, source_sha, target_branch) } - - it 'sends a user_ff_branch message and returns a BranchUpdate object' do + before do expect_any_instance_of(Gitaly::OperationService::Stub) .to receive(:user_ff_branch).with(request, kind_of(Hash)) .and_return(response) + end + subject { client.user_ff_branch(user, source_sha, target_branch) } + + it 'sends a user_ff_branch message and returns a BranchUpdate object' do expect(subject).to be_a(Gitlab::Git::OperationService::BranchUpdate) expect(subject.newrev).to eq(source_sha) expect(subject.repo_created).to be(false) expect(subject.branch_created).to be(false) end + + context 'when the response has no branch_update' do + let(:response) { Gitaly::UserFFBranchResponse.new } + + it { expect(subject).to be_nil } + end + end + + shared_examples 'cherry pick and revert errors' do + context 'when a pre_receive_error is present' do + let(:response) { response_class.new(pre_receive_error: "something failed") } + + it 'raises a PreReceiveError' do + expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed") + end + end + + context 'when a commit_error is present' do + let(:response) { response_class.new(commit_error: "something failed") } + + it 'raises a CommitError' do + expect { subject }.to raise_error(Gitlab::Git::CommitError, "something failed") + end + end + + context 'when a create_tree_error is present' do + let(:response) { response_class.new(create_tree_error: "something failed") } + + it 'raises a CreateTreeError' do + expect { subject }.to raise_error(Gitlab::Git::Repository::CreateTreeError, "something failed") + end + end + + context 'when branch_update is nil' do + let(:response) { response_class.new } + + it { expect(subject).to be_nil } + end + end + + describe '#user_cherry_pick' do + let(:response_class) { Gitaly::UserCherryPickResponse } + + subject do + client.user_cherry_pick( + user: user, + commit: repository.commit, + branch_name: 'master', + message: 'Cherry-pick message', + start_branch_name: 'master', + start_repository: repository + ) + end + + before do + expect_any_instance_of(Gitaly::OperationService::Stub) + .to receive(:user_cherry_pick).with(kind_of(Gitaly::UserCherryPickRequest), kind_of(Hash)) + .and_return(response) + end + + it_behaves_like 'cherry pick and revert errors' + end + + describe '#user_revert' do + let(:response_class) { Gitaly::UserRevertResponse } + + subject do + client.user_revert( + user: user, + commit: repository.commit, + branch_name: 'master', + message: 'Revert message', + start_branch_name: 'master', + start_repository: repository + ) + end + + before do + expect_any_instance_of(Gitaly::OperationService::Stub) + .to receive(:user_revert).with(kind_of(Gitaly::UserRevertRequest), kind_of(Hash)) + .and_return(response) + end + + it_behaves_like 'cherry pick and revert errors' end describe '#user_squash' do @@ -203,7 +289,7 @@ describe Gitlab::GitalyClient::OperationService do Gitaly::UserSquashResponse.new(git_error: "something failed") end - it "throws a PreReceive exception" do + it "raises a GitError exception" do expect_any_instance_of(Gitaly::OperationService::Stub) .to receive(:user_squash).with(request, kind_of(Hash)) .and_return(response) @@ -212,5 +298,41 @@ describe Gitlab::GitalyClient::OperationService do Gitlab::Git::Repository::GitError, "something failed") end end + + describe '#user_commit_files' do + subject do + client.user_commit_files( + gitaly_user, 'my-branch', 'Commit files message', [], 'janedoe@example.com', 'Jane Doe', + 'master', repository) + end + + before do + expect_any_instance_of(Gitaly::OperationService::Stub) + .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash)) + .and_return(response) + end + + context 'when a pre_receive_error is present' do + let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "something failed") } + + it 'raises a PreReceiveError' do + expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed") + end + end + + context 'when an index_error is present' do + let(:response) { Gitaly::UserCommitFilesResponse.new(index_error: "something failed") } + + it 'raises a PreReceiveError' do + expect { subject }.to raise_error(Gitlab::Git::Index::IndexError, "something failed") + end + end + + context 'when branch_update is nil' do + let(:response) { Gitaly::UserCommitFilesResponse.new } + + it { expect(subject).to be_nil } + end + end end end diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 257e4c50f2d..400d426c949 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -18,6 +18,44 @@ describe Gitlab::GitalyClient::RefService do end end + describe '#remote_branches' do + let(:remote_name) { 'my_remote' } + subject { client.remote_branches(remote_name) } + + it 'sends a find_all_remote_branches message' do + expect_any_instance_of(Gitaly::RefService::Stub) + .to receive(:find_all_remote_branches) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return([]) + + subject + end + + it 'concantes and returns the response branches as Gitlab::Git::Branch objects' do + target_commits = create_list(:gitaly_commit, 4) + response_branches = target_commits.each_with_index.map do |gitaly_commit, i| + Gitaly::Branch.new(name: "#{remote_name}/#{i}", target_commit: gitaly_commit) + end + response = [ + Gitaly::FindAllRemoteBranchesResponse.new(branches: response_branches[0, 2]), + Gitaly::FindAllRemoteBranchesResponse.new(branches: response_branches[2, 2]) + ] + + expect_any_instance_of(Gitaly::RefService::Stub) + .to receive(:find_all_remote_branches).and_return(response) + + expect(subject.length).to be(response_branches.length) + + response_branches.each_with_index do |gitaly_branch, i| + branch = subject[i] + commit = Gitlab::Git::Commit.new(repository, gitaly_branch.target_commit) + + expect(branch.name).to eq(i.to_s) # It removes the `remote/` prefix + expect(branch.dereferenced_target).to eq(commit) + end + end + end + describe '#branch_names' do it 'sends a find_all_branch_names message' do expect_any_instance_of(Gitaly::RefService::Stub) diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb index 50e8d7183ce..22ad88e28cb 100644 --- a/spec/lib/gitlab/gitlab_import/client_spec.rb +++ b/spec/lib/gitlab/gitlab_import/client_spec.rb @@ -15,4 +15,88 @@ describe Gitlab::GitlabImport::Client do expect(key).to be_kind_of(Symbol) end end + + it 'uses membership and simple flags' do + stub_request('/api/v4/projects?membership=true&page=1&per_page=100&simple=true') + + expect_any_instance_of(OAuth2::Response).to receive(:parsed).and_return([]) + + expect(client.projects.to_a).to eq [] + end + + shared_examples 'pagination params' do + before do + allow_any_instance_of(OAuth2::Response).to receive(:parsed).and_return([]) + end + + it 'allows page_limit param' do + allow_any_instance_of(OAuth2::Response).to receive(:parsed).and_return(element_list) + + expect(client).to receive(:lazy_page_iterator).with(hash_including(page_limit: 2)).and_call_original + + client.send(method, *args, page_limit: 2, per_page: 1).to_a + end + + it 'allows per_page param' do + expect(client).to receive(:lazy_page_iterator).with(hash_including(per_page: 2)).and_call_original + + client.send(method, *args, per_page: 2).to_a + end + + it 'allows starting_page param' do + expect(client).to receive(:lazy_page_iterator).with(hash_including(starting_page: 3)).and_call_original + + client.send(method, *args, starting_page: 3).to_a + end + end + + describe '#projects' do + subject(:method) { :projects } + let(:args) { [] } + let(:element_list) { build_list(:project, 2) } + + before do + stub_request('/api/v4/projects?membership=true&page=1&per_page=1&simple=true') + stub_request('/api/v4/projects?membership=true&page=2&per_page=1&simple=true') + stub_request('/api/v4/projects?membership=true&page=1&per_page=2&simple=true') + stub_request('/api/v4/projects?membership=true&page=3&per_page=100&simple=true') + end + + it_behaves_like 'pagination params' + end + + describe '#issues' do + subject(:method) { :issues } + let(:args) { [1] } + let(:element_list) { build_list(:issue, 2) } + + before do + stub_request('/api/v4/projects/1/issues?page=1&per_page=1') + stub_request('/api/v4/projects/1/issues?page=2&per_page=1') + stub_request('/api/v4/projects/1/issues?page=1&per_page=2') + stub_request('/api/v4/projects/1/issues?page=3&per_page=100') + end + + it_behaves_like 'pagination params' + end + + describe '#issue_comments' do + subject(:method) { :issue_comments } + let(:args) { [1, 1] } + let(:element_list) { build_list(:note_on_issue, 2) } + + before do + stub_request('/api/v4/projects/1/issues/1/notes?page=1&per_page=1') + stub_request('/api/v4/projects/1/issues/1/notes?page=2&per_page=1') + stub_request('/api/v4/projects/1/issues/1/notes?page=1&per_page=2') + stub_request('/api/v4/projects/1/issues/1/notes?page=3&per_page=100') + end + + it_behaves_like 'pagination params' + end + + def stub_request(path) + WebMock.stub_request(:get, "https://gitlab.com#{path}") + .to_return(status: 200) + end end diff --git a/spec/lib/gitlab/hook_data/base_builder_spec.rb b/spec/lib/gitlab/hook_data/base_builder_spec.rb new file mode 100644 index 00000000000..a921dd766c3 --- /dev/null +++ b/spec/lib/gitlab/hook_data/base_builder_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe Gitlab::HookData::BaseBuilder do + describe '#absolute_image_urls' do + let(:subclass) do + Class.new(described_class) do + public :absolute_image_urls + end + end + + subject { subclass.new(nil) } + + using RSpec::Parameterized::TableSyntax + + where do + { + 'relative image URL' => { + input: '![an image](foo.png)', + output: "![an image](#{Gitlab.config.gitlab.url}/foo.png)" + }, + 'HTTP URL' => { + input: '![an image](http://example.com/foo.png)', + output: '![an image](http://example.com/foo.png)' + }, + 'HTTPS URL' => { + input: '![an image](https://example.com/foo.png)', + output: '![an image](https://example.com/foo.png)' + }, + 'protocol-relative URL' => { + input: '![an image](//example.com/foo.png)', + output: '![an image](//example.com/foo.png)' + }, + 'URL reference by title' => { + input: "![foo]\n\n[foo]: foo.png", + output: "![foo]\n\n[foo]: foo.png" + }, + 'URL reference by label' => { + input: "![][foo]\n\n[foo]: foo.png", + output: "![][foo]\n\n[foo]: foo.png" + }, + 'in Markdown inline code block' => { + input: '`![an image](foo.png)`', + output: "`![an image](#{Gitlab.config.gitlab.url}/foo.png)`" + }, + 'in HTML tag on the same line' => { + input: '<p>![an image](foo.png)</p>', + output: "<p>![an image](#{Gitlab.config.gitlab.url}/foo.png)</p>" + }, + 'in Markdown multi-line code block' => { + input: "```\n![an image](foo.png)\n```", + output: "```\n![an image](foo.png)\n```" + }, + 'in HTML tag on different lines' => { + input: "<p>\n![an image](foo.png)\n</p>", + output: "<p>\n![an image](foo.png)\n</p>" + } + } + end + + with_them do + it { expect(subject.absolute_image_urls(input)).to eq(output) } + end + end +end diff --git a/spec/lib/gitlab/hook_data/issue_builder_spec.rb b/spec/lib/gitlab/hook_data/issue_builder_spec.rb index 506b2c0be20..60093474f8a 100644 --- a/spec/lib/gitlab/hook_data/issue_builder_spec.rb +++ b/spec/lib/gitlab/hook_data/issue_builder_spec.rb @@ -40,5 +40,14 @@ describe Gitlab::HookData::IssueBuilder do expect(data).to include(:human_total_time_spent) expect(data).to include(:assignee_ids) end + + context 'when the issue has an image in the description' do + let(:issue_with_description) { create(:issue, description: 'test![Issue_Image](/uploads/abc/Issue_Image.png)') } + let(:builder) { described_class.new(issue_with_description) } + + it 'sets the image to use an absolute URL' do + expect(data[:description]).to eq("test![Issue_Image](#{Settings.gitlab.url}/uploads/abc/Issue_Image.png)") + end + end end end diff --git a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb index b61614e4790..dd586af6118 100644 --- a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb +++ b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb @@ -56,5 +56,14 @@ describe Gitlab::HookData::MergeRequestBuilder do expect(data).to include(:human_time_estimate) expect(data).to include(:human_total_time_spent) end + + context 'when the MR has an image in the description' do + let(:mr_with_description) { create(:merge_request, description: 'test![Issue_Image](/uploads/abc/Issue_Image.png)') } + let(:builder) { described_class.new(mr_with_description) } + + it 'sets the image to use an absolute URL' do + expect(data[:description]).to eq("test![Issue_Image](#{Settings.gitlab.url}/uploads/abc/Issue_Image.png)") + end + end end end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 084ce3066d6..db5aab0cd76 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -211,6 +211,7 @@ project: - slack_service - microsoft_teams_service - mattermost_service +- hangouts_chat_service - buildkite_service - bamboo_service - teamcity_service diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 2223f163177..90e6d653d34 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -9,6 +9,7 @@ describe Gitlab::ImportExport::AvatarSaver do before do FileUtils.mkdir_p("#{shared.export_path}/avatar/") allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) + stub_feature_flags(import_export_object_storage: false) end after do diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb index 58b9fb06cc5..265937f899e 100644 --- a/spec/lib/gitlab/import_export/file_importer_spec.rb +++ b/spec/lib/gitlab/import_export/file_importer_spec.rb @@ -7,6 +7,7 @@ describe Gitlab::ImportExport::FileImporter do let(:symlink_file) { "#{shared.export_path}/invalid.json" } let(:hidden_symlink_file) { "#{shared.export_path}/.hidden" } let(:subfolder_symlink_file) { "#{shared.export_path}/subfolder/invalid.json" } + let(:evil_symlink_file) { "#{shared.export_path}/.\nevil" } before do stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0) @@ -34,6 +35,10 @@ describe Gitlab::ImportExport::FileImporter do expect(File.exist?(hidden_symlink_file)).to be false end + it 'removes evil symlinks in root folder' do + expect(File.exist?(evil_symlink_file)).to be false + end + it 'removes symlinks in subfolders' do expect(File.exist?(subfolder_symlink_file)).to be false end @@ -75,5 +80,7 @@ describe Gitlab::ImportExport::FileImporter do FileUtils.touch(valid_file) FileUtils.ln_s(valid_file, symlink_file) FileUtils.ln_s(valid_file, subfolder_symlink_file) + FileUtils.ln_s(valid_file, hidden_symlink_file) + FileUtils.ln_s(valid_file, evil_symlink_file) end end diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb new file mode 100644 index 00000000000..9c3870a0af8 --- /dev/null +++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::ImportExport::UploadsManager do + let(:shared) { project.import_export_shared } + let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } + let(:project) { create(:project) } + let(:exported_file_path) { "#{shared.export_path}/uploads/#{upload.secret}/#{File.basename(upload.path)}" } + + subject(:manager) { described_class.new(project: project, shared: shared) } + + before do + allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) + FileUtils.mkdir_p(shared.export_path) + end + + after do + FileUtils.rm_rf(shared.export_path) + end + + describe '#save' do + context 'when the project has uploads locally stored' do + let(:upload) { create(:upload, :issuable_upload, :with_file, model: project) } + + before do + project.uploads << upload + end + + it 'does not cause errors' do + manager.save + + expect(shared.errors).to be_empty + end + + it 'copies the file in the correct location when there is an upload' do + manager.save + + expect(File).to exist(exported_file_path) + end + end + + context 'using object storage' do + let!(:upload) { create(:upload, :issuable_upload, :object_storage, model: project) } + + before do + stub_feature_flags(import_export_object_storage: true) + stub_uploads_object_storage(FileUploader) + end + + it 'saves the file' do + fake_uri = double + + expect(fake_uri).to receive(:open).and_return(StringIO.new('File content')) + expect(URI).to receive(:parse).and_return(fake_uri) + + manager.save + + expect(File.read(exported_file_path)).to eq('File content') + end + end + + describe '#restore' do + context 'using object storage' do + before do + stub_feature_flags(import_export_object_storage: true) + stub_uploads_object_storage(FileUploader) + + FileUtils.mkdir_p(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038')) + FileUtils.touch(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038', "dummy.txt")) + end + + it 'restores the file' do + manager.restore + + expect(project.uploads.size).to eq(1) + expect(project.uploads.first.build_uploader.filename).to eq('dummy.txt') + end + end + end + end +end diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb index 095687fa89d..c716edd9397 100644 --- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb @@ -7,6 +7,7 @@ describe Gitlab::ImportExport::UploadsSaver do let(:shared) { project.import_export_shared } before do + stub_feature_flags(import_export_object_storage: false) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) end @@ -30,7 +31,7 @@ describe Gitlab::ImportExport::UploadsSaver do it 'copies the uploads to the export path' do saver.save - uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) } + uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) } expect(uploads).to include('banana_sample.gif') end @@ -52,7 +53,7 @@ describe Gitlab::ImportExport::UploadsSaver do it 'copies the uploads to the export path' do saver.save - uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) } + uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) } expect(uploads).to include('banana_sample.gif') end diff --git a/spec/lib/gitlab/json_logger_spec.rb b/spec/lib/gitlab/json_logger_spec.rb new file mode 100644 index 00000000000..0a62785f880 --- /dev/null +++ b/spec/lib/gitlab/json_logger_spec.rb @@ -0,0 +1,29 @@ +# coding: utf-8 +require 'spec_helper' + +describe Gitlab::JsonLogger do + subject { described_class.new('/dev/null') } + + let(:now) { Time.now } + + describe '#format_message' do + it 'formats strings' do + output = subject.format_message('INFO', now, 'test', 'Hello world') + data = JSON.parse(output) + + expect(data['severity']).to eq('INFO') + expect(data['time']).to eq(now.utc.iso8601(3)) + expect(data['message']).to eq('Hello world') + end + + it 'formats hashes' do + output = subject.format_message('INFO', now, 'test', { hello: 1 }) + data = JSON.parse(output) + + expect(data['severity']).to eq('INFO') + expect(data['time']).to eq(now.utc.iso8601(3)) + expect(data['hello']).to eq(1) + expect(data['message']).to be_nil + end + end +end diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb index 1dbead16d5b..c1b84e9f077 100644 --- a/spec/lib/gitlab/popen_spec.rb +++ b/spec/lib/gitlab/popen_spec.rb @@ -55,6 +55,19 @@ describe Gitlab::Popen do end end + context 'with a process that writes a lot of data to stderr' do + let(:test_string) { 'The quick brown fox jumped over the lazy dog' } + # The pipe buffer is typically 64K. This string is about 440K. + let(:spew_command) { ['bash', '-c', "for i in {1..10000}; do echo '#{test_string}' 1>&2; done"] } + + it 'returns zero' do + output, status = @klass.new.popen(spew_command, path) + + expect(output).to include(test_string) + expect(status).to eq(0) + end + end + context 'without a directory argument' do before do @output, @status = @klass.new.popen(%w(ls)) diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 767a3092c73..4a0dc3686ec 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -64,6 +64,49 @@ describe Gitlab::ProjectSearchResults do end end + shared_examples 'blob search repository ref' do |entity_type| + let(:query) { 'files' } + let(:file_finder) { double } + let(:project_branch) { 'project_branch' } + + subject(:results) { described_class.new(user, project, query, repository_ref).objects(blob_type) } + + before do + allow(entity).to receive(:default_branch).and_return(project_branch) + allow(file_finder).to receive(:find).and_return([]) + end + + context 'when repository_ref exists' do + let(:repository_ref) { 'ref_branch' } + + it 'uses it' do + expect(Gitlab::FileFinder).to receive(:new).with(project, repository_ref).and_return(file_finder) + + results + end + end + + context 'when repository_ref is not present' do + let(:repository_ref) { nil } + + it "uses #{entity_type} repository default reference" do + expect(Gitlab::FileFinder).to receive(:new).with(project, project_branch).and_return(file_finder) + + results + end + end + + context 'when repository_ref is blank' do + let(:repository_ref) { '' } + + it "uses #{entity_type} repository default reference" do + expect(Gitlab::FileFinder).to receive(:new).with(project, project_branch).and_return(file_finder) + + results + end + end + end + describe 'blob search' do let(:project) { create(:project, :public, :repository) } @@ -75,6 +118,11 @@ describe Gitlab::ProjectSearchResults do let(:expected_file_by_content) { 'CHANGELOG' } end + it_behaves_like 'blob search repository ref', 'project' do + let(:blob_type) { 'blobs' } + let(:entity) { project } + end + describe 'parsing results' do let(:results) { project.repository.search_files_by_content('feature', 'master') } let(:search_result) { results.first } @@ -212,6 +260,11 @@ describe Gitlab::ProjectSearchResults do let(:expected_file_by_name) { 'Files/Title.md' } let(:expected_file_by_content) { 'CHANGELOG.md' } end + + it_behaves_like 'blob search repository ref', 'wiki' do + let(:blob_type) { 'wiki_blobs' } + let(:entity) { project.wiki } + end end it 'does not list issues on private projects' do diff --git a/spec/lib/gitlab/serializer/ci/variables_spec.rb b/spec/lib/gitlab/serializer/ci/variables_spec.rb index c4b7fda5dbb..1d1fd5b0763 100644 --- a/spec/lib/gitlab/serializer/ci/variables_spec.rb +++ b/spec/lib/gitlab/serializer/ci/variables_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'fast_spec_helper' describe Gitlab::Serializer::Ci::Variables do subject do @@ -6,11 +6,11 @@ describe Gitlab::Serializer::Ci::Variables do end let(:object) do - [{ key: :key, value: 'value', public: true }, + [{ 'key' => :key, 'value' => 'value', 'public' => true }, { key: 'wee', value: 1, public: false }] end - it 'converts keys into strings' do + it 'converts keys into strings and symbolizes hash' do is_expected.to eq([ { key: 'key', value: 'value', public: true }, { key: 'wee', value: 1, public: false } diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index 758a9bc5a2b..b41a81a8167 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -145,6 +145,10 @@ describe Gitlab::UrlSanitizer do 'http://foo:@example.com' | 'http://foo@example.com' 'http://:bar@example.com' | :same 'http://foo:bar@example.com' | :same + 'http://foo:g p@example.com' | 'http://foo:g%20p@example.com' + 'http://foo:s/h@example.com' | 'http://foo:s%2Fh@example.com' + 'http://t u:a#b@example.com' | 'http://t%20u:a%23b@example.com' + 'http://t+u:a#b@example.com' | 'http://t%2Bu:a%23b@example.com' end with_them do @@ -160,7 +164,7 @@ describe Gitlab::UrlSanitizer do url_sanitizer = described_class.new("https://foo:b?r@github.com/me/project.git") expect(url_sanitizer.sanitized_url).to eq("https://github.com/me/project.git") - expect(url_sanitizer.full_url).to eq("https://foo:b?r@github.com/me/project.git") + expect(url_sanitizer.full_url).to eq("https://foo:b%3Fr@github.com/me/project.git") end end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 20def4fefe2..a19b3c0ba66 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -133,7 +133,7 @@ describe Gitlab::UsageData do expect(subject[:signup_enabled]).to eq(Gitlab::CurrentSettings.allow_signup?) expect(subject[:ldap_enabled]).to eq(Gitlab.config.ldap.enabled) expect(subject[:gravatar_enabled]).to eq(Gitlab::CurrentSettings.gravatar_enabled?) - expect(subject[:omniauth_enabled]).to eq(Gitlab.config.omniauth.enabled) + expect(subject[:omniauth_enabled]).to eq(Gitlab::Auth.omniauth_enabled?) expect(subject[:reply_by_email_enabled]).to eq(Gitlab::IncomingEmail.enabled?) expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled) expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) diff --git a/spec/lib/gitlab/user_activities_spec.rb b/spec/lib/gitlab/user_activities_spec.rb deleted file mode 100644 index 6bce2ee13cf..00000000000 --- a/spec/lib/gitlab/user_activities_spec.rb +++ /dev/null @@ -1,127 +0,0 @@ -require 'spec_helper' - -describe Gitlab::UserActivities, :clean_gitlab_redis_shared_state do - let(:now) { Time.now } - - describe '.record' do - context 'with no time given' do - it 'uses Time.now and records an activity in SharedState' do - Timecop.freeze do - now # eager-load now - described_class.record(42) - end - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]]) - end - end - end - - context 'with a time given' do - it 'uses the given time and records an activity in SharedState' do - described_class.record(42, now) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]]) - end - end - end - end - - describe '.delete' do - context 'with a single key' do - context 'and key exists' do - it 'removes the pair from SharedState' do - described_class.record(42, now) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]]) - end - - subject.delete(42) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []]) - end - end - end - - context 'and key does not exist' do - it 'removes the pair from SharedState' do - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []]) - end - - subject.delete(42) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []]) - end - end - end - end - - context 'with multiple keys' do - context 'and all keys exist' do - it 'removes the pair from SharedState' do - described_class.record(41, now) - described_class.record(42, now) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['41', now.to_i.to_s], ['42', now.to_i.to_s]]]) - end - - subject.delete(41, 42) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []]) - end - end - end - - context 'and some keys does not exist' do - it 'removes the existing pair from SharedState' do - described_class.record(42, now) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]]) - end - - subject.delete(41, 42) - - Gitlab::Redis::SharedState.with do |redis| - expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []]) - end - end - end - end - end - - describe 'Enumerable' do - before do - described_class.record(40, now) - described_class.record(41, now) - described_class.record(42, now) - end - - it 'allows to read the activities sequentially' do - expected = { '40' => now.to_i.to_s, '41' => now.to_i.to_s, '42' => now.to_i.to_s } - - actual = described_class.new.each_with_object({}) do |(key, time), actual| - actual[key] = time - end - - expect(actual).to eq(expected) - end - - context 'with many records' do - before do - 1_000.times { |i| described_class.record(i, now) } - end - - it 'is possible to loop through all the records' do - expect(described_class.new.count).to eq(1_000) - end - end - end -end diff --git a/spec/lib/uploaded_file_spec.rb b/spec/lib/uploaded_file_spec.rb index cc99e7e8911..a2f5c2e7121 100644 --- a/spec/lib/uploaded_file_spec.rb +++ b/spec/lib/uploaded_file_spec.rb @@ -1,24 +1,28 @@ require 'spec_helper' describe UploadedFile do - describe ".from_params" do - let(:temp_dir) { Dir.tmpdir } - let(:temp_file) { Tempfile.new("test", temp_dir) } - let(:upload_path) { nil } + let(:temp_dir) { Dir.tmpdir } + let(:temp_file) { Tempfile.new("test", temp_dir) } - subject do - described_class.from_params(params, :file, upload_path) - end + before do + FileUtils.touch(temp_file) + end - before do - FileUtils.touch(temp_file) - end + after do + FileUtils.rm_f(temp_file) + end + + describe ".from_params" do + let(:upload_path) { nil } after do - FileUtils.rm_f(temp_file) FileUtils.rm_r(upload_path) if upload_path end + subject do + described_class.from_params(params, :file, upload_path) + end + context 'when valid file is specified' do context 'only local path is specified' do let(:params) do @@ -37,7 +41,7 @@ describe UploadedFile do context 'all parameters are specified' do let(:params) do { 'file.path' => temp_file.path, - 'file.name' => 'my_file.txt', + 'file.name' => 'dir/my file&.txt', 'file.type' => 'my/type', 'file.sha256' => 'sha256', 'file.remote_id' => 'remote_id' } @@ -48,7 +52,7 @@ describe UploadedFile do end it "generates filename from path" do - expect(subject.original_filename).to eq('my_file.txt') + expect(subject.original_filename).to eq('my_file_.txt') expect(subject.content_type).to eq('my/type') expect(subject.sha256).to eq('sha256') expect(subject.remote_id).to eq('remote_id') @@ -113,4 +117,11 @@ describe UploadedFile do end end end + + describe '#sanitize_filename' do + it { expect(described_class.new(temp_file.path).sanitize_filename('spaced name')).to eq('spaced_name') } + it { expect(described_class.new(temp_file.path).sanitize_filename('#$%^&')).to eq('_____') } + it { expect(described_class.new(temp_file.path).sanitize_filename('..')).to eq('_..') } + it { expect(described_class.new(temp_file.path).sanitize_filename('')).to eq('unnamed') } + end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 581132b6672..ff1a5aa2536 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -1366,7 +1366,8 @@ describe Notify do it 'only sends the text template' do stub_application_setting(html_emails_enabled: false) - EmailTemplateInterceptor.delivering_email(multipart_mail) + Gitlab::Email::Hook::EmailTemplateInterceptor + .delivering_email(multipart_mail) expect(multipart_mail).to have_part_with('text/plain') expect(multipart_mail).not_to have_part_with('text/html') @@ -1377,7 +1378,8 @@ describe Notify do it 'sends a multipart message' do stub_application_setting(html_emails_enabled: true) - EmailTemplateInterceptor.delivering_email(multipart_mail) + Gitlab::Email::Hook::EmailTemplateInterceptor + .delivering_email(multipart_mail) expect(multipart_mail).to have_part_with('text/plain') expect(multipart_mail).to have_part_with('text/html') diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb index ac34efa4f9d..6219a67c900 100644 --- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb +++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb @@ -4,12 +4,10 @@ require 'spec_helper' require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_worker_jobs.rb') describe MigrateProcessCommitWorkerJobs do - let(:project) { create(:project, :legacy_storage, :repository) } # rubocop:disable RSpec/FactoriesInMigrationSpecs - let(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs + set(:project) { create(:project, :legacy_storage, :repository) } # rubocop:disable RSpec/FactoriesInMigrationSpecs + set(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs let(:commit) do - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - project.commit.raw.rugged_commit - end + Gitlab::Git::Commit.last(project.repository.raw) end describe 'Project' do @@ -28,32 +26,13 @@ describe MigrateProcessCommitWorkerJobs do end end - describe '#repository_storage_path' do - it 'returns the storage path for the repository' do - migration_project = described_class::Project - .find_including_path(project.id) - - expect(File.directory?(migration_project.repository_storage_path)) - .to eq(true) - end - end - - describe '#repository_path' do - it 'returns the path to the repository' do - migration_project = described_class::Project - .find_including_path(project.id) - - expect(File.directory?(migration_project.repository_path)).to eq(true) - end - end - describe '#repository' do - it 'returns a Rugged::Repository' do + it 'returns a mock implemention of ::Repository' do migration_project = described_class::Project .find_including_path(project.id) - expect(migration_project.repository) - .to be_an_instance_of(Rugged::Repository) + expect(migration_project.repository).to respond_to(:storage) + expect(migration_project.repository).to respond_to(:gitaly_repository) end end end @@ -71,7 +50,7 @@ describe MigrateProcessCommitWorkerJobs do before do Sidekiq.redis do |redis| - job = JSON.dump(args: [project.id, user.id, commit.oid]) + job = JSON.dump(args: [project.id, user.id, commit.id]) redis.lpush('queue:process_commit', job) end end @@ -87,9 +66,10 @@ describe MigrateProcessCommitWorkerJobs do end it 'skips jobs using commits that no longer exist' do - allow_any_instance_of(Rugged::Repository).to receive(:lookup) - .with(commit.oid) - .and_raise(Rugged::OdbError) + allow_any_instance_of(Gitlab::GitalyClient::CommitService) + .to receive(:find_commit) + .with(commit.id) + .and_return(nil) migration.up @@ -103,11 +83,7 @@ describe MigrateProcessCommitWorkerJobs do end it 'encodes data to UTF-8' do - allow_any_instance_of(Rugged::Repository).to receive(:lookup) - .with(commit.oid) - .and_return(commit) - - allow(commit).to receive(:message) + allow(commit).to receive(:body) .and_return('김치'.force_encoding('BINARY')) migration.up @@ -139,7 +115,7 @@ describe MigrateProcessCommitWorkerJobs do end it 'includes the commit ID' do - expect(commit_hash['id']).to eq(commit.oid) + expect(commit_hash['id']).to eq(commit.id) end it 'includes the commit message' do @@ -151,27 +127,27 @@ describe MigrateProcessCommitWorkerJobs do end it 'includes the author date' do - expect(commit_hash['authored_date']).to eq(commit.author[:time].to_s) + expect(commit_hash['authored_date']).to eq(commit.authored_date.to_s) end it 'includes the author name' do - expect(commit_hash['author_name']).to eq(commit.author[:name]) + expect(commit_hash['author_name']).to eq(commit.author_name) end it 'includes the author Email' do - expect(commit_hash['author_email']).to eq(commit.author[:email]) + expect(commit_hash['author_email']).to eq(commit.author_email) end it 'includes the commit date' do - expect(commit_hash['committed_date']).to eq(commit.committer[:time].to_s) + expect(commit_hash['committed_date']).to eq(commit.committed_date.to_s) end it 'includes the committer name' do - expect(commit_hash['committer_name']).to eq(commit.committer[:name]) + expect(commit_hash['committer_name']).to eq(commit.committer_name) end it 'includes the committer Email' do - expect(commit_hash['committer_email']).to eq(commit.committer[:email]) + expect(commit_hash['committer_email']).to eq(commit.committer_email) end end end @@ -185,7 +161,7 @@ describe MigrateProcessCommitWorkerJobs do before do Sidekiq.redis do |redis| - job = JSON.dump(args: [project.id, user.id, commit.oid]) + job = JSON.dump(args: [project.id, user.id, commit.id]) redis.lpush('queue:process_commit', job) migration.up @@ -214,7 +190,7 @@ describe MigrateProcessCommitWorkerJobs do end it 'includes the commit SHA' do - expect(job['args'][2]).to eq(commit.oid) + expect(job['args'][2]).to eq(commit.id) end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 3c96fe76829..67199eb6d26 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1613,6 +1613,7 @@ describe Ci::Build do { key: 'CI_JOB_NAME', value: 'test', public: true }, { key: 'CI_JOB_STAGE', value: 'test', public: true }, { key: 'CI_COMMIT_SHA', value: build.sha, public: true }, + { key: 'CI_COMMIT_BEFORE_SHA', value: build.before_sha, public: true }, { key: 'CI_COMMIT_REF_NAME', value: build.ref, public: true }, { key: 'CI_COMMIT_REF_SLUG', value: build.ref_slug, public: true }, { key: 'CI_BUILD_REF', value: build.sha, public: true }, @@ -2268,6 +2269,34 @@ describe Ci::Build do end end + describe '#yaml_variables' do + before do + build.update_attribute(:yaml_variables, variables) + end + + context 'when serialized valu is a symbolized hash' do + let(:variables) do + [{ key: :VARIABLE, value: 'my value 1' }] + end + + it 'keeps symbolizes keys and stringifies variables names' do + expect(build.yaml_variables) + .to eq [{ key: 'VARIABLE', value: 'my value 1' }] + end + end + + context 'when serialized value is a hash with string keys' do + let(:variables) do + [{ 'key' => :VARIABLE, 'value' => 'my value 2' }] + end + + it 'symblizes variables hash' do + expect(build.yaml_variables) + .to eq [{ key: 'VARIABLE', value: 'my value 2' }] + end + end + end + describe 'state transition: any => [:pending]' do let(:build) { create(:ci_build, :created) } diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb index f8d51a95833..cd84a684fec 100644 --- a/spec/models/deploy_token_spec.rb +++ b/spec/models/deploy_token_spec.rb @@ -62,11 +62,18 @@ describe DeployToken do end end - context "when it hasn't been revoked" do + context "when it hasn't been revoked and is not expired" do it 'should return true' do expect(deploy_token.active?).to be_truthy end end + + context "when it hasn't been revoked and is expired" do + it 'should return true' do + deploy_token.update_attribute(:expires_at, Date.today - 5.days) + expect(deploy_token.active?).to be_falsy + end + end end describe '#username' do diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index e01906f4b6c..b335e0fbeb3 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -157,22 +157,4 @@ describe Deployment do end end end - - describe '#stop_action?' do - subject { deployment.stop_action? } - - context 'when no other actions' do - let(:deployment) { build(:deployment) } - - it { is_expected.to be_falsey } - end - - context 'when matching action is defined' do - let(:build) { create(:ci_build) } - let(:deployment) { FactoryBot.build(:deployment, deployable: build, on_stop: 'close_app') } - let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') } - - it { is_expected.to be_truthy } - end - end end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 4bded9efe91..c65e0b81451 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -170,8 +170,8 @@ describe Environment do end end - describe '#stop_action?' do - subject { environment.stop_action? } + describe '#stop_action_available?' do + subject { environment.stop_action_available? } context 'when no other actions' do it { is_expected.to be_falsey } @@ -179,8 +179,17 @@ describe Environment do context 'when matching action is defined' do let(:build) { create(:ci_build) } - let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') } + + let!(:deployment) do + create(:deployment, environment: environment, + deployable: build, + on_stop: 'close_app') + end + + let!(:close_action) do + create(:ci_build, :manual, pipeline: build.pipeline, + name: 'close_app') + end context 'when environment is available' do before do diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index ccc3ff861c5..0aee78ac12d 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -82,6 +82,14 @@ describe MergeRequestDiff do diff.diffs end + + it 'returns persisted diffs if diff refs does not exist' do + expect(diff).to receive(:load_diffs) + + diff.update!(start_commit_sha: nil, base_commit_sha: nil) + + diff.diffs + end end end diff --git a/spec/models/project_services/hangouts_chat_service_spec.rb b/spec/models/project_services/hangouts_chat_service_spec.rb new file mode 100644 index 00000000000..cfa55188a64 --- /dev/null +++ b/spec/models/project_services/hangouts_chat_service_spec.rb @@ -0,0 +1,246 @@ +require 'spec_helper' + +describe HangoutsChatService do + describe 'Associations' do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before do + subject.active = true + end + + it { is_expected.to validate_presence_of(:webhook) } + it_behaves_like 'issue tracker service URL attribute', :webhook + end + + context 'when service is inactive' do + before do + subject.active = false + end + + it { is_expected.not_to validate_presence_of(:webhook) } + end + end + + describe '#execute' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:webhook_url) { 'https://example.gitlab.com/' } + + before do + allow(subject).to receive_messages( + project: project, + project_id: project.id, + service_hook: true, + webhook: webhook_url + ) + + WebMock.stub_request(:post, webhook_url) + end + + shared_examples 'Hangouts Chat service' do + it 'calls Hangouts Chat API' do + subject.execute(sample_data) + + expect(WebMock) + .to have_requested(:post, webhook_url) + .with { |req| req.body =~ /\A{"text":.+}\Z/ } + .once + end + end + + context 'with push events' do + let(:sample_data) do + Gitlab::DataBuilder::Push.build_sample(project, user) + end + + it_behaves_like 'Hangouts Chat service' + + it 'specifies the webhook when it is configured' do + expect(HangoutsChat::Sender).to receive(:new).with(webhook_url).and_return(double(:hangouts_chat_service).as_null_object) + + subject.execute(sample_data) + end + + context 'with not default branch' do + let(:sample_data) do + Gitlab::DataBuilder::Push.build(project, user, nil, nil, 'not-the-default-branch') + end + + context 'when notify_only_default_branch enabled' do + before do + subject.notify_only_default_branch = true + end + + it 'does not call the Hangouts Chat API' do + result = subject.execute(sample_data) + + expect(result).to be_falsy + end + end + + context 'when notify_only_default_branch disabled' do + before do + subject.notify_only_default_branch = false + end + + it_behaves_like 'Hangouts Chat service' + end + end + end + + context 'with issue events' do + let(:opts) { { title: 'Awesome issue', description: 'please fix' } } + let(:sample_data) do + service = Issues::CreateService.new(project, user, opts) + issue = service.execute + service.hook_data(issue, 'open') + end + + it_behaves_like 'Hangouts Chat service' + end + + context 'with merge events' do + let(:opts) do + { + title: 'Awesome merge_request', + description: 'please fix', + source_branch: 'feature', + target_branch: 'master' + } + end + + let(:sample_data) do + service = MergeRequests::CreateService.new(project, user, opts) + merge_request = service.execute + service.hook_data(merge_request, 'open') + end + + before do + project.add_developer(user) + end + + it_behaves_like 'Hangouts Chat service' + end + + context 'with wiki page events' do + let(:opts) do + { + title: 'Awesome wiki_page', + content: 'Some text describing some thing or another', + format: 'md', + message: 'user created page: Awesome wiki_page' + } + end + let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) } + let(:sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') } + + it_behaves_like 'Hangouts Chat service' + end + + context 'with note events' do + let(:sample_data) { Gitlab::DataBuilder::Note.build(note, user) } + + context 'with commit comment' do + let(:note) do + create(:note_on_commit, author: user, + project: project, + commit_id: project.repository.commit.id, + note: 'a comment on a commit') + end + + it_behaves_like 'Hangouts Chat service' + end + + context 'with merge request comment' do + let(:note) do + create(:note_on_merge_request, project: project, + note: 'merge request note') + end + + it_behaves_like 'Hangouts Chat service' + end + + context 'with issue comment' do + let(:note) do + create(:note_on_issue, project: project, note: 'issue note') + end + + it_behaves_like 'Hangouts Chat service' + end + + context 'with snippet comment' do + let(:note) do + create(:note_on_project_snippet, project: project, + note: 'snippet note') + end + + it_behaves_like 'Hangouts Chat service' + end + end + + context 'with pipeline events' do + let(:pipeline) do + create(:ci_pipeline, + project: project, status: status, + sha: project.commit.sha, ref: project.default_branch) + end + let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) } + + context 'with failed pipeline' do + let(:status) { 'failed' } + + it_behaves_like 'Hangouts Chat service' + end + + context 'with succeeded pipeline' do + let(:status) { 'success' } + + context 'with default notify_only_broken_pipelines' do + it 'does not call Hangouts Chat API' do + result = subject.execute(sample_data) + + expect(result).to be_falsy + end + end + + context 'when notify_only_broken_pipelines is false' do + before do + subject.notify_only_broken_pipelines = false + end + + it_behaves_like 'Hangouts Chat service' + end + end + + context 'with not default branch' do + let(:pipeline) do + create(:ci_pipeline, project: project, status: 'failed', ref: 'not-the-default-branch') + end + + context 'when notify_only_default_branch enabled' do + before do + subject.notify_only_default_branch = true + end + + it 'does not call the Hangouts Chat API' do + result = subject.execute(sample_data) + + expect(result).to be_falsy + end + end + + context 'when notify_only_default_branch disabled' do + before do + subject.notify_only_default_branch = false + end + + it_behaves_like 'Hangouts Chat service' + end + end + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index c01c7bc47b5..b0ec725bf70 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -26,6 +26,7 @@ describe Project do it { is_expected.to have_one(:slack_service) } it { is_expected.to have_one(:microsoft_teams_service) } it { is_expected.to have_one(:mattermost_service) } + it { is_expected.to have_one(:hangouts_chat_service) } it { is_expected.to have_one(:packagist_service) } it { is_expected.to have_one(:pushover_service) } it { is_expected.to have_one(:asana_service) } @@ -149,23 +150,25 @@ describe Project do it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) } it { is_expected.to validate_length_of(:name).is_at_most(255) } - it { is_expected.to validate_presence_of(:path) } it { is_expected.to validate_length_of(:path).is_at_most(255) } - it { is_expected.to validate_length_of(:description).is_at_most(2000) } - it { is_expected.to validate_length_of(:ci_config_path).is_at_most(255) } it { is_expected.to allow_value('').for(:ci_config_path) } it { is_expected.not_to allow_value('test/../foo').for(:ci_config_path) } it { is_expected.not_to allow_value('/test/foo').for(:ci_config_path) } - it { is_expected.to validate_presence_of(:creator) } - it { is_expected.to validate_presence_of(:namespace) } - it { is_expected.to validate_presence_of(:repository_storage) } + it 'validates build timeout constraints' do + is_expected.to validate_numericality_of(:build_timeout) + .only_integer + .is_greater_than_or_equal_to(10.minutes) + .is_less_than(1.month) + .with_message('needs to be beetween 10 minutes and 1 month') + end + it 'does not allow new projects beyond user limits' do project2 = build(:project) allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index a544940800a..528f5b610d7 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -189,6 +189,22 @@ describe ProjectWiki do end end + describe '#find_sidebar' do + before do + create_page(described_class::SIDEBAR, 'This is an awesome Sidebar') + end + + after do + subject.pages.each { |page| destroy_page(page.page) } + end + + it 'finds the page defined as _sidebar' do + page = subject.find_page('_sidebar') + + expect(page.content).to eq('This is an awesome Sidebar') + end + end + describe '#find_file' do shared_examples 'finding a wiki file' do let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 02d31098cfd..5d64602ca56 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -296,24 +296,40 @@ describe Repository do end describe '#new_commits' do - let(:new_refs) do - double(:git_rev_list, new_refs: %w[ - c1acaa58bbcbc3eafe538cb8274ba387047b69f8 - 5937ac0a7beb003549fc5fd26fc247adbce4a52e - ]) - end + shared_examples 'finding unreferenced commits' do + set(:project) { create(:project, :repository) } + let(:repository) { project.repository } - it 'delegates to Gitlab::Git::RevList' do - expect(Gitlab::Git::RevList).to receive(:new).with( - repository.raw, - newrev: 'aaaabbbbccccddddeeeeffffgggghhhhiiiijjjj').and_return(new_refs) + subject { repository.new_commits(rev) } - commits = repository.new_commits('aaaabbbbccccddddeeeeffffgggghhhhiiiijjjj') + context 'when there are no new commits' do + let(:rev) { repository.commit.id } - expect(commits).to eq([ - repository.commit('c1acaa58bbcbc3eafe538cb8274ba387047b69f8'), - repository.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e') - ]) + it 'returns an empty array' do + expect(subject).to eq([]) + end + end + + context 'when new commits are found' do + let(:branch) { 'orphaned-branch' } + let!(:rev) { repository.commit(branch).id } + + it 'returns the commits' do + repository.delete_branch(branch) + + expect(subject).not_to be_empty + expect(subject).to all( be_a(::Commit) ) + expect(subject.size).to eq(1) + end + end + end + + context 'when Gitaly handles the request' do + it_behaves_like 'finding unreferenced commits' + end + + context 'when Gitaly is disabled', :disable_gitaly do + it_behaves_like 'finding unreferenced commits' end end @@ -2209,20 +2225,6 @@ describe Repository do end end - describe '#remote_branches' do - it 'returns the remote branches' do - masterrev = repository.find_branch('master').dereferenced_target - create_remote_branch('joe', 'remote_branch', masterrev) - repository.add_branch(user, 'local_branch', masterrev.id) - - # TODO: move this test to gitaly https://gitlab.com/gitlab-org/gitaly/issues/1243 - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - expect(repository.remote_branches('joe').any? { |branch| branch.name == 'local_branch' }).to eq(false) - expect(repository.remote_branches('joe').any? { |branch| branch.name == 'remote_branch' }).to eq(true) - end - end - end - describe '#commit_count' do context 'with a non-existing repository' do it 'returns 0' do diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 1c765ceac2f..63850939be1 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -554,6 +554,16 @@ describe WikiPage do end end + describe '#hook_attrs' do + it 'adds absolute urls for images in the content' do + create_page("test page", "test![WikiPage_Image](/uploads/abc/WikiPage_Image.png)") + page = wiki.wiki.page(title: "test page") + wiki_page = described_class.new(wiki, page, true) + + expect(wiki_page.hook_attrs['content']).to eq("test![WikiPage_Image](#{Settings.gitlab.url}/uploads/abc/WikiPage_Image.png)") + end + end + private def remove_temp_repo(path) diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 113703fac38..246947e58a8 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -514,6 +514,38 @@ describe API::Commits do expect(response).to have_gitlab_http_status(400) end end + + context 'when committing into a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + def push_params(branch_name) + { + branch: branch_name, + commit_message: 'Hello world', + actions: [ + { + action: 'create', + file_path: 'foo/bar/baz.txt', + content: 'puts 8' + } + ] + } + end + + it 'allows pushing to the source branch of the merge request' do + post api(url, user), push_params('feature') + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies pushing to another branch' do + post api(url, user), push_params('other-branch') + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'GET /projects/:id/repository/commits/:sha/refs' do @@ -1065,11 +1097,29 @@ describe API::Commits do it 'returns 400 if you are not allowed to push to the target branch' do post api(route, current_user), branch: 'feature' - expect(response).to have_gitlab_http_status(400) - expect(json_response['message']).to eq('You are not allowed to push into this branch') + expect(response).to have_gitlab_http_status(:forbidden) + expect(json_response['message']).to match(/You are not allowed to push into this branch/) end end end + + context 'when cherry picking to a fork as a maintainer' do + include_context 'merge request allowing collaboration' + + let(:project_id) { forked_project.id } + + it 'allows access from a maintainer that to the source branch' do + post api(route, user), branch: 'feature' + + expect(response).to have_gitlab_http_status(:created) + end + + it 'denies cherry picking to another branch' do + post api(route, user), branch: 'master' + + expect(response).to have_gitlab_http_status(:forbidden) + end + end end describe 'POST /projects/:id/repository/commits/:sha/comments' do diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index bf93555b0f0..f3db0c122a0 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -20,7 +20,7 @@ describe API::Environments do path path_with_namespace star_count forks_count created_at last_activity_at - avatar_url + avatar_url namespace ) get api("/projects/#{project.id}/environments", user) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index a56b913198c..a2cfa706f58 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -279,7 +279,7 @@ describe API::Internal do expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq('/') expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end @@ -291,7 +291,7 @@ describe API::Internal do expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq('/') expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") - expect(user).to have_an_activity_record + expect(user.reload.last_activity_on).to eql(Date.today) end end @@ -309,7 +309,7 @@ describe API::Internal do expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) - expect(user).to have_an_activity_record + expect(user.reload.last_activity_on).to eql(Date.today) end end @@ -328,7 +328,7 @@ describe API::Internal do expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end end @@ -345,7 +345,7 @@ describe API::Internal do expect(response).to have_gitlab_http_status(200) expect(json_response["status"]).to be_falsey - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end @@ -355,7 +355,7 @@ describe API::Internal do expect(response).to have_gitlab_http_status(200) expect(json_response["status"]).to be_falsey - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end end @@ -373,7 +373,7 @@ describe API::Internal do expect(response).to have_gitlab_http_status(200) expect(json_response["status"]).to be_falsey - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end @@ -383,7 +383,7 @@ describe API::Internal do expect(response).to have_gitlab_http_status(200) expect(json_response["status"]).to be_falsey - expect(user).not_to have_an_activity_record + expect(user.reload.last_activity_on).to be_nil end end end diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 7d1a5c12805..8412d0383f7 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -220,6 +220,7 @@ describe API::Jobs do expect(Time.parse(json_response['finished_at'])).to be_like_time(job.finished_at) expect(Time.parse(json_response['artifacts_expire_at'])).to be_like_time(job.artifacts_expire_at) expect(json_response['duration']).to eq(job.duration) + expect(json_response['web_url']).to be_present end it 'returns pipeline data' do diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index e2ca27f5d41..342a97b6a69 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -24,7 +24,8 @@ describe API::Pipelines do expect(json_response).to be_an Array expect(json_response.first['sha']).to match /\A\h{40}\z/ expect(json_response.first['id']).to eq pipeline.id - expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status]) + expect(json_response.first['web_url']).to be_present + expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status web_url]) end context 'when parameter is passed' do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8389cb7cf9c..5ac008c7e40 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -225,7 +225,7 @@ describe API::Projects do path path_with_namespace star_count forks_count created_at last_activity_at - avatar_url + avatar_url namespace ) get api('/projects?simple=true', user) @@ -237,6 +237,39 @@ describe API::Projects do end end + context 'and using archived' do + let!(:archived_project) { create(:project, creator_id: user.id, namespace: user.namespace, archived: true) } + + it 'returns archived projects' do + get api('/projects?archived=true', user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: true).size) + expect(json_response.map { |project| project['id'] }).to include(archived_project.id) + end + + it 'returns non-archived projects' do + get api('/projects?archived=false', user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: false).size) + expect(json_response.map { |project| project['id'] }).not_to include(archived_project.id) + end + + it 'returns every project' do + get api('/projects', user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.map { |project| project['id'] }).to contain_exactly(*Project.public_or_visible_to_user(user).pluck(:id)) + end + end + context 'and using search' do it_behaves_like 'projects response' do let(:filter) { { search: project.name } } diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index b030d9862c6..0f3e7157e14 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -5,7 +5,6 @@ describe 'Git HTTP requests' do include TermsHelper include GitHttpHelpers include WorkhorseHelpers - include UserActivitiesHelpers shared_examples 'pulls require Basic HTTP Authentication' do context "when no credentials are provided" do @@ -440,10 +439,10 @@ describe 'Git HTTP requests' do end it 'updates the user last activity', :clean_gitlab_redis_shared_state do - expect(user_activity(user)).to be_nil + expect(user.last_activity_on).to be_nil download(path, env) do |response| - expect(user_activity(user)).to be_present + expect(user.reload.last_activity_on).to eql(Date.today) end end end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index de39abdb746..c2378646f89 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -575,6 +575,40 @@ describe 'Git LFS API and storage' do end end + context 'when using Deploy Tokens' do + let(:project) { create(:project, :repository) } + let(:authorization) { authorize_deploy_token } + let(:update_user_permissions) { nil } + let(:role) { nil } + let(:update_lfs_permissions) do + project.lfs_objects << lfs_object + end + + context 'when Deploy Token is valid' do + let(:deploy_token) { create(:deploy_token, projects: [project]) } + + it_behaves_like 'an authorized requests' + end + + context 'when Deploy Token is not valid' do + let(:deploy_token) { create(:deploy_token, projects: [project], read_repository: false) } + + it 'responds with access denied' do + expect(response).to have_gitlab_http_status(401) + end + end + + context 'when Deploy Token is not related to the project' do + let(:another_project) { create(:project, :repository) } + let(:deploy_token) { create(:deploy_token, projects: [another_project]) } + + it 'responds with access forbidden' do + # We render 404, to prevent data leakage about existence of the project + expect(response).to have_gitlab_http_status(404) + end + end + end + context 'when build is authorized as' do let(:authorization) { authorize_ci_project } @@ -1381,6 +1415,10 @@ describe 'Git LFS API and storage' do ActionController::HttpAuthentication::Basic.encode_credentials(user.username, Gitlab::LfsToken.new(user).token) end + def authorize_deploy_token + ActionController::HttpAuthentication::Basic.encode_credentials(deploy_token.username, deploy_token.token) + end + def post_lfs_json(url, body = nil, headers = nil) post(url, body.try(:to_json), (headers || {}).merge('Content-Type' => LfsRequest::CONTENT_TYPE)) end diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index d2072198d83..0ba2539a717 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -11,6 +11,21 @@ describe MergeRequestWidgetEntity do described_class.new(resource, request: request).as_json end + describe 'source_project_full_path' do + it 'includes the full path of the source project' do + expect(subject[:source_project_full_path]).to be_present + end + + context 'when the source project is missing' do + it 'returns `nil` for the source project' do + resource.allow_broken = true + resource.update!(source_project: nil) + + expect(subject[:source_project_full_path]).to be_nil + end + end + end + describe 'pipeline' do let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) } diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 13395a7cac3..68e310b0506 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe EventCreateService do - include UserActivitiesHelpers - let(:service) { described_class.new } describe 'Issues' do @@ -146,7 +144,7 @@ describe EventCreateService do it 'updates user last activity' do expect { service.push(project, user, push_data) } - .to change { user_activity(user) } + .to change { user.last_activity_on }.to(Date.today) end it 'caches the last push event for the user' do diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb index 17eabad73be..f20849e6924 100644 --- a/spec/services/users/activity_service_spec.rb +++ b/spec/services/users/activity_service_spec.rb @@ -1,60 +1,61 @@ require 'spec_helper' describe Users::ActivityService do - include UserActivitiesHelpers + include ExclusiveLeaseHelpers - let(:user) { create(:user) } + let(:user) { create(:user, last_activity_on: last_activity_on) } - subject(:service) { described_class.new(user, 'type') } + subject { described_class.new(user, 'type') } describe '#execute', :clean_gitlab_redis_shared_state do context 'when last activity is nil' do - before do - service.execute - end + let(:last_activity_on) { nil } - it 'sets the last activity timestamp for the user' do - expect(last_hour_user_ids).to eq([user.id]) + it 'updates last_activity_on for the user' do + expect { subject.execute } + .to change(user, :last_activity_on).from(last_activity_on).to(Date.today) end + end - it 'updates the same user' do - service.execute + context 'when last activity is in the past' do + let(:last_activity_on) { Date.today - 1.week } - expect(last_hour_user_ids).to eq([user.id]) - end - - it 'updates the timestamp of an existing user' do - Timecop.freeze(Date.tomorrow) do - expect { service.execute }.to change { user_activity(user) }.to(Time.now.to_i.to_s) - end + it 'updates last_activity_on for the user' do + expect { subject.execute } + .to change(user, :last_activity_on) + .from(last_activity_on) + .to(Date.today) end + end - describe 'other user' do - it 'updates other user' do - other_user = create(:user) - described_class.new(other_user, 'type').execute + context 'when last activity is today' do + let(:last_activity_on) { Date.today } - expect(last_hour_user_ids).to match_array([user.id, other_user.id]) - end + it 'does not update last_activity_on' do + expect { subject.execute }.not_to change(user, :last_activity_on) end end context 'when in GitLab read-only instance' do + let(:last_activity_on) { nil } + before do allow(Gitlab::Database).to receive(:read_only?).and_return(true) end - it 'does not update last_activity_at' do - service.execute - - expect(last_hour_user_ids).to eq([]) + it 'does not update last_activity_on' do + expect { subject.execute }.not_to change(user, :last_activity_on) end end - end - def last_hour_user_ids - Gitlab::UserActivities.new - .select { |k, v| v >= 1.hour.ago.to_i.to_s } - .map { |k, _| k.to_i } + context 'when a lease could not be obtained' do + let(:last_activity_on) { nil } + + it 'does not update last_activity_on' do + stub_exclusive_lease_taken("acitvity_service:#{user.id}", timeout: 1.minute.to_i) + + expect { subject.execute }.not_to change(user, :last_activity_on) + end + end end end diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index 32d9807f06a..c228bd2393b 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -125,7 +125,8 @@ module CycleAnalyticsHelpers _, opts = args commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - raw_repository.commit(branch_update.newrev).rugged_commit + rugged = raw_repository.rugged + rugged.rev_parse(branch_update.newrev) end branch_update.newrev = commit.amend( diff --git a/spec/support/helpers/user_activities_helpers.rb b/spec/support/helpers/user_activities_helpers.rb deleted file mode 100644 index 44feb104644..00000000000 --- a/spec/support/helpers/user_activities_helpers.rb +++ /dev/null @@ -1,7 +0,0 @@ -module UserActivitiesHelpers - def user_activity(user) - Gitlab::UserActivities.new - .find { |k, _| k == user.id.to_s }&. - second - end -end diff --git a/spec/support/matchers/user_activity_matchers.rb b/spec/support/matchers/user_activity_matchers.rb deleted file mode 100644 index ce3b683b6d2..00000000000 --- a/spec/support/matchers/user_activity_matchers.rb +++ /dev/null @@ -1,5 +0,0 @@ -RSpec::Matchers.define :have_an_activity_record do |expected| - match do |user| - expect(Gitlab::UserActivities.new.find { |k, _| k == user.id.to_s }).to be_present - end -end diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb new file mode 100644 index 00000000000..05424d08b9d --- /dev/null +++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb @@ -0,0 +1,15 @@ +shared_context 'merge request allowing collaboration' do + include ProjectForksHelper + + let(:canonical) { create(:project, :public, :repository) } + let(:forked_project) { fork_project(canonical, nil, repository: true) } + + before do + canonical.add_maintainer(user) + create(:merge_request, + target_project: canonical, + source_project: forked_project, + source_branch: 'feature', + allow_collaboration: true) + end +end diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index 7ba28b4fc1f..7e24efda5dd 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -124,6 +124,15 @@ describe FileUploader do end end + describe '.extract_dynamic_path' do + it 'works with hashed storage' do + path = 'export/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a/test/uploads/72a497a02fe3ee09edae2ed06d390038/dummy.txt' + + expect(described_class.extract_dynamic_path(path)[:identifier]).to eq('dummy.txt') + expect(described_class.extract_dynamic_path(path)[:secret]).to eq('72a497a02fe3ee09edae2ed06d390038') + end + end + describe '#secret' do it 'generates a secret if none is provided' do expect(described_class).to receive(:generate_secret).and_return('secret') @@ -157,4 +166,50 @@ describe FileUploader do uploader.upload = upload end end + + describe '#cache!' do + subject do + uploader.store!(uploaded_file) + end + + context 'when remote file is used' do + let(:temp_file) { Tempfile.new("test") } + + let!(:fog_connection) do + stub_uploads_object_storage(described_class) + end + + let(:uploaded_file) do + UploadedFile.new(temp_file.path, filename: "my file.txt", remote_id: "test/123123") + end + + let!(:fog_file) do + fog_connection.directories.get('uploads').files.create( + key: 'tmp/uploads/test/123123', + body: 'content' + ) + end + + before do + FileUtils.touch(temp_file) + end + + after do + FileUtils.rm_f(temp_file) + end + + it 'file is stored remotely in permament location with sanitized name' do + subject + + expect(uploader).to be_exists + expect(uploader).not_to be_cached + expect(uploader).not_to be_file_storage + expect(uploader.path).not_to be_nil + expect(uploader.path).not_to include('tmp/upload') + expect(uploader.path).not_to include('tmp/cache') + expect(uploader.url).to include('/my_file.txt') + expect(uploader.object_store).to eq(described_class::Store::REMOTE) + end + end + end end diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb index 15fce65979b..b56940a9613 100644 --- a/spec/views/projects/_home_panel.html.haml_spec.rb +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -1,55 +1,48 @@ require 'spec_helper' describe 'projects/_home_panel' do - let(:group) { create(:group) } - let(:project) { create(:project, :public, namespace: group) } + context 'notifications' do + let(:project) { create(:project) } - let(:notification_settings) do - user&.notification_settings_for(project) - end + before do + assign(:project, project) - before do - assign(:project, project) - assign(:notification_setting, notification_settings) + allow(view).to receive(:current_user).and_return(user) + allow(view).to receive(:can?).with(user, :read_project, project).and_return(false) + end - allow(view).to receive(:current_user).and_return(user) - allow(view).to receive(:can?).and_return(false) - end + context 'when user is signed in' do + let(:user) { create(:user) } - context 'when user is signed in' do - let(:user) { create(:user) } + before do + notification_settings = user.notification_settings_for(project) + assign(:notification_setting, notification_settings) + end - it 'makes it possible to set notification level' do - render + it 'makes it possible to set notification level' do + render - expect(view).to render_template('shared/notifications/_button') - expect(rendered).to have_selector('.notification-dropdown') + expect(view).to render_template('shared/notifications/_button') + expect(rendered).to have_selector('.notification-dropdown') + end end - end - - context 'when user is signed out' do - let(:user) { nil } - it 'is not possible to set notification level' do - render + context 'when user is signed out' do + let(:user) { nil } - expect(rendered).not_to have_selector('.notification_dropdown') - end - end - - context 'when project' do - let!(:user) { create(:user) } - let(:badges) { project.badges } + before do + assign(:notification_setting, nil) + end - context 'has no badges' do - it 'should not render any badge' do + it 'is not possible to set notification level' do render - expect(rendered).to have_selector('.project-badges') - expect(rendered).not_to have_selector('.project-badges > a') + expect(rendered).not_to have_selector('.notification_dropdown') end end + end + context 'badges' do shared_examples 'show badges' do it 'should render the all badges' do render @@ -62,7 +55,31 @@ describe 'projects/_home_panel' do end end + let(:user) { create(:user) } + let(:badges) { project.badges } + + before do + assign(:project, project) + + allow(view).to receive(:current_user).and_return(user) + allow(view).to receive(:can?).with(user, :read_project, project).and_return(false) + end + + context 'has no badges' do + let(:project) { create(:project) } + + it 'should not render any badge' do + render + + expect(rendered).to have_selector('.project-badges') + expect(rendered).not_to have_selector('.project-badges > a') + end + end + context 'only has group badges' do + let(:group) { create(:group) } + let(:project) { create(:project, namespace: group) } + before do create(:group_badge, group: project.group) end @@ -71,6 +88,8 @@ describe 'projects/_home_panel' do end context 'only has project badges' do + let(:project) { create(:project) } + before do create(:project_badge, project: project) end @@ -79,6 +98,9 @@ describe 'projects/_home_panel' do end context 'has both group and project badges' do + let(:group) { create(:group) } + let(:project) { create(:project, namespace: group) } + before do create(:project_badge, project: project) create(:group_badge, group: project.group) @@ -87,4 +109,35 @@ describe 'projects/_home_panel' do it_behaves_like 'show badges' end end + + context 'project id' do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + assign(:project, project) + + allow(view).to receive(:current_user).and_return(user) + end + + context 'user can read project' do + it 'is shown' do + allow(view).to receive(:can?).with(user, :read_project, project).and_return(true) + + render + + expect(rendered).to have_content("Project ID: #{project.id}") + end + end + + context 'user cannot read project' do + it 'is not shown' do + allow(view).to receive(:can?).with(user, :read_project, project).and_return(false) + + render + + expect(rendered).not_to have_content("Project ID: #{project.id}") + end + end + end end diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb index 318aad4bc1e..f17c5ac6aac 100644 --- a/spec/workers/emails_on_push_worker_spec.rb +++ b/spec/workers/emails_on_push_worker_spec.rb @@ -100,10 +100,6 @@ describe EmailsOnPushWorker, :mailer do end context "when there are multiple recipients" do - let(:recipients) do - 1.upto(5).map { |i| user.email.sub('@', "+#{i}@") }.join("\n") - end - before do # This is a hack because we modify the mail object before sending, for efficency, # but the TestMailer adapter just appends the objects to an array. To clone a mail @@ -114,16 +110,57 @@ describe EmailsOnPushWorker, :mailer do end end - it "sends the mail to each of the recipients" do - perform - expect(ActionMailer::Base.deliveries.count).to eq(5) - expect(ActionMailer::Base.deliveries.map(&:to).flatten).to contain_exactly(*recipients.split) + context "when the recipient addresses are a list of email addresses" do + let(:recipients) do + 1.upto(5).map { |i| user.email.sub('@', "+#{i}@") }.join("\n") + end + + it "sends the mail to each of the recipients" do + perform + + expect(ActionMailer::Base.deliveries.count).to eq(5) + expect(email_recipients).to contain_exactly(*recipients.split) + end + + it "only generates the mail once" do + expect(Notify).to receive(:repository_push_email).once.and_call_original + expect(Premailer::Rails::CustomizedPremailer).to receive(:new).once.and_call_original + + perform + end end - it "only generates the mail once" do - expect(Notify).to receive(:repository_push_email).once.and_call_original - expect(Premailer::Rails::CustomizedPremailer).to receive(:new).once.and_call_original - perform + context "when the recipient addresses contains angle brackets and are separated by spaces" do + let(:recipients) { "John Doe <johndoe@example.com> Jane Doe <janedoe@example.com>" } + + it "accepts emails separated by whitespace" do + perform + + expect(ActionMailer::Base.deliveries.count).to eq(2) + expect(email_recipients).to contain_exactly("johndoe@example.com", "janedoe@example.com") + end + end + + context "when the recipient addresses contain a mix of emails with and without angle brackets" do + let(:recipients) { "johndoe@example.com Jane Doe <janedoe@example.com>" } + + it "accepts both kind of emails" do + perform + + expect(ActionMailer::Base.deliveries.count).to eq(2) + expect(email_recipients).to contain_exactly("johndoe@example.com", "janedoe@example.com") + end + end + + context "when the recipient addresses contains angle brackets and are separated by newlines" do + let(:recipients) { "John Doe <johndoe@example.com>\nJane Doe <janedoe@example.com>" } + + it "accepts emails separated by newlines" do + perform + + expect(ActionMailer::Base.deliveries.count).to eq(2) + expect(email_recipients).to contain_exactly("johndoe@example.com", "janedoe@example.com") + end end end end diff --git a/spec/workers/schedule_update_user_activity_worker_spec.rb b/spec/workers/schedule_update_user_activity_worker_spec.rb deleted file mode 100644 index 32c59381b01..00000000000 --- a/spec/workers/schedule_update_user_activity_worker_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'spec_helper' - -describe ScheduleUpdateUserActivityWorker, :clean_gitlab_redis_shared_state do - let(:now) { Time.now } - - before do - Gitlab::UserActivities.record('1', now) - Gitlab::UserActivities.record('2', now) - end - - it 'schedules UpdateUserActivityWorker once' do - expect(UpdateUserActivityWorker).to receive(:perform_async).with({ '1' => now.to_i.to_s, '2' => now.to_i.to_s }) - - subject.perform - end - - context 'when specifying a batch size' do - it 'schedules UpdateUserActivityWorker twice' do - expect(UpdateUserActivityWorker).to receive(:perform_async).with({ '1' => now.to_i.to_s }) - expect(UpdateUserActivityWorker).to receive(:perform_async).with({ '2' => now.to_i.to_s }) - - subject.perform(1) - end - end -end diff --git a/spec/workers/update_user_activity_worker_spec.rb b/spec/workers/update_user_activity_worker_spec.rb deleted file mode 100644 index 268ca1d81f2..00000000000 --- a/spec/workers/update_user_activity_worker_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -describe UpdateUserActivityWorker, :clean_gitlab_redis_shared_state do - let(:user_active_2_days_ago) { create(:user, current_sign_in_at: 10.months.ago) } - let(:user_active_yesterday_1) { create(:user) } - let(:user_active_yesterday_2) { create(:user) } - let(:user_active_today) { create(:user) } - let(:data) do - { - user_active_2_days_ago.id.to_s => 2.days.ago.at_midday.to_i.to_s, - user_active_yesterday_1.id.to_s => 1.day.ago.at_midday.to_i.to_s, - user_active_yesterday_2.id.to_s => 1.day.ago.at_midday.to_i.to_s, - user_active_today.id.to_s => Time.now.to_i.to_s - } - end - - it 'updates users.last_activity_on' do - subject.perform(data) - - aggregate_failures do - expect(user_active_2_days_ago.reload.last_activity_on).to eq(2.days.ago.to_date) - expect(user_active_yesterday_1.reload.last_activity_on).to eq(1.day.ago.to_date) - expect(user_active_yesterday_2.reload.last_activity_on).to eq(1.day.ago.to_date) - expect(user_active_today.reload.reload.last_activity_on).to eq(Date.today) - end - end - - it 'deletes the pairs from SharedState' do - data.each { |id, time| Gitlab::UserActivities.record(id, time) } - - subject.perform(data) - - expect(Gitlab::UserActivities.new.to_a).to be_empty - end -end diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index ee0df7711e7..b698248bc38 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -677,6 +677,7 @@ rollout 100%: auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app} auto_chart_name=$(basename $auto_chart) auto_chart_name=${auto_chart_name%.tgz} + auto_chart_name=${auto_chart_name%.tar.gz} else auto_chart="chart" auto_chart_name="chart" diff --git a/vendor/jupyter/values.yaml b/vendor/jupyter/values.yaml index 90817de0f1b..4ea5b44c59c 100644 --- a/vendor/jupyter/values.yaml +++ b/vendor/jupyter/values.yaml @@ -4,6 +4,7 @@ rbac: hub: extraEnv: JUPYTER_ENABLE_LAB: 1 + SINGLEUSER_IMAGE: 'registry.gitlab.com/gitlab-org/jupyterhub-user-image:latest' extraConfig: | c.KubeSpawner.cmd = ['jupyter-labhub'] diff --git a/yarn.lock b/yarn.lock index d844ae4f8e9..85fdb150d34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -78,9 +78,9 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@gitlab-org/gitlab-svgs@^1.25.0": - version "1.25.0" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.25.0.tgz#1a82b1be43e1a46e6b0767ef46f26f5fd6bbd101" +"@gitlab-org/gitlab-svgs@^1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.26.0.tgz#d89c633e866d031a9e4787b05eacc7144c3a7791" "@sindresorhus/is@^0.7.0": version "0.7.0" @@ -104,139 +104,140 @@ source-map "^0.5.6" vue-template-es2015-compiler "^1.6.0" -"@webassemblyjs/ast@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.10.tgz#7f1e81149ca4e103c9e7cc321ea0dcb83a392512" +"@webassemblyjs/ast@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25" dependencies: - "@webassemblyjs/helper-module-context" "1.5.10" - "@webassemblyjs/helper-wasm-bytecode" "1.5.10" - "@webassemblyjs/wast-parser" "1.5.10" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" debug "^3.1.0" mamacro "^0.0.3" -"@webassemblyjs/floating-point-hex-parser@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.10.tgz#ae48705fd58927df62023f114520b8215330ff86" +"@webassemblyjs/floating-point-hex-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298" -"@webassemblyjs/helper-api-error@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.10.tgz#0baf9453ce2fd8db58f0fdb4fb2852557c71d5a7" +"@webassemblyjs/helper-api-error@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59" -"@webassemblyjs/helper-buffer@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.10.tgz#abee4284161e9cd6ba7619785ca277bfcb8052ce" +"@webassemblyjs/helper-buffer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e" dependencies: debug "^3.1.0" -"@webassemblyjs/helper-code-frame@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.10.tgz#4e23c05431665f16322104580af7c06253d4b4e0" +"@webassemblyjs/helper-code-frame@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58" dependencies: - "@webassemblyjs/wast-printer" "1.5.10" + "@webassemblyjs/wast-printer" "1.5.13" -"@webassemblyjs/helper-fsm@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.10.tgz#490bab613ea255a9272b764826d3cc9d15170676" +"@webassemblyjs/helper-fsm@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924" -"@webassemblyjs/helper-module-context@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.10.tgz#6fca93585228bf33e6da076d0a1373db1fdd6580" +"@webassemblyjs/helper-module-context@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5" dependencies: + debug "^3.1.0" mamacro "^0.0.3" -"@webassemblyjs/helper-wasm-bytecode@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.10.tgz#90f6da93c7a186bfb2f587de442982ff533c4b44" +"@webassemblyjs/helper-wasm-bytecode@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747" -"@webassemblyjs/helper-wasm-section@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.10.tgz#d64292a19f7f357c49719461065efdf7ec975d66" +"@webassemblyjs/helper-wasm-section@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-buffer" "1.5.10" - "@webassemblyjs/helper-wasm-bytecode" "1.5.10" - "@webassemblyjs/wasm-gen" "1.5.10" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" debug "^3.1.0" -"@webassemblyjs/ieee754@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.10.tgz#257cad440dd6c8a339402d31e035ba2e38e9c245" +"@webassemblyjs/ieee754@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364" dependencies: ieee754 "^1.1.11" -"@webassemblyjs/leb128@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.10.tgz#a8e4fe5f4b16daadb241fcc44d9735e9f27b05a3" +"@webassemblyjs/leb128@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee" dependencies: - leb "^0.3.0" + long "4.0.0" -"@webassemblyjs/utf8@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.10.tgz#0b3b6bc86b7619c5dc7b2789db6665aa35689983" +"@webassemblyjs/utf8@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469" -"@webassemblyjs/wasm-edit@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.10.tgz#0fe80f19e57f669eab1caa8c1faf9690b259d5b9" +"@webassemblyjs/wasm-edit@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-buffer" "1.5.10" - "@webassemblyjs/helper-wasm-bytecode" "1.5.10" - "@webassemblyjs/helper-wasm-section" "1.5.10" - "@webassemblyjs/wasm-gen" "1.5.10" - "@webassemblyjs/wasm-opt" "1.5.10" - "@webassemblyjs/wasm-parser" "1.5.10" - "@webassemblyjs/wast-printer" "1.5.10" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/helper-wasm-section" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + "@webassemblyjs/wast-printer" "1.5.13" debug "^3.1.0" -"@webassemblyjs/wasm-gen@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.10.tgz#8b29ddd3651259408ae5d5c816a011fb3f3f3584" +"@webassemblyjs/wasm-gen@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-wasm-bytecode" "1.5.10" - "@webassemblyjs/ieee754" "1.5.10" - "@webassemblyjs/leb128" "1.5.10" - "@webassemblyjs/utf8" "1.5.10" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" -"@webassemblyjs/wasm-opt@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.10.tgz#569e45ab1b2bf0a7706cdf6d1b51d1188e9e4c7b" +"@webassemblyjs/wasm-opt@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-buffer" "1.5.10" - "@webassemblyjs/wasm-gen" "1.5.10" - "@webassemblyjs/wasm-parser" "1.5.10" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-buffer" "1.5.13" + "@webassemblyjs/wasm-gen" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" debug "^3.1.0" -"@webassemblyjs/wasm-parser@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.10.tgz#3e1017e49f833f46b840db7cf9d194d4f00037ff" - dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-api-error" "1.5.10" - "@webassemblyjs/helper-wasm-bytecode" "1.5.10" - "@webassemblyjs/ieee754" "1.5.10" - "@webassemblyjs/leb128" "1.5.10" - "@webassemblyjs/wasm-parser" "1.5.10" - -"@webassemblyjs/wast-parser@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.10.tgz#1a3235926483c985a00ee8ebca856ffda9544934" - dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/floating-point-hex-parser" "1.5.10" - "@webassemblyjs/helper-api-error" "1.5.10" - "@webassemblyjs/helper-code-frame" "1.5.10" - "@webassemblyjs/helper-fsm" "1.5.10" +"@webassemblyjs/wasm-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-wasm-bytecode" "1.5.13" + "@webassemblyjs/ieee754" "1.5.13" + "@webassemblyjs/leb128" "1.5.13" + "@webassemblyjs/utf8" "1.5.13" + +"@webassemblyjs/wast-parser@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea" + dependencies: + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/floating-point-hex-parser" "1.5.13" + "@webassemblyjs/helper-api-error" "1.5.13" + "@webassemblyjs/helper-code-frame" "1.5.13" + "@webassemblyjs/helper-fsm" "1.5.13" long "^3.2.0" mamacro "^0.0.3" -"@webassemblyjs/wast-printer@1.5.10": - version "1.5.10" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.10.tgz#adb38831ba45efd0a5c7971b666e179b64f68bba" +"@webassemblyjs/wast-printer@1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/wast-parser" "1.5.10" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/wast-parser" "1.5.13" long "^3.2.0" abbrev@1: @@ -274,6 +275,10 @@ acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0: version "5.6.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.2.tgz#b1da1d7be2ac1b4a327fb9eab851702c5045b4e7" +acorn@^5.6.2: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + addressparser@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" @@ -282,12 +287,11 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +agent-base@4, agent-base@^4.1.0, agent-base@^4.2.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" dependencies: - extend "~3.0.0" - semver "~5.0.1" + es6-promisify "^5.0.0" ajv-keywords@^2.1.0: version "2.1.1" @@ -322,10 +326,6 @@ align-text@^0.1.1, align-text@^0.1.3: longest "^1.0.1" repeat-string "^1.5.2" -alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -372,13 +372,6 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -409,17 +402,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" @@ -532,11 +519,11 @@ async@^2.0.0, async@^2.1.4: dependencies: lodash "^4.14.0" -async@~2.1.2: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" +async@~2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: - lodash "^4.14.0" + lodash "^4.17.10" asynckit@^0.4.0: version "0.4.0" @@ -546,17 +533,6 @@ atob@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" -autoprefixer@^6.3.1: - version "6.7.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" - dependencies: - browserslist "^1.7.6" - caniuse-db "^1.0.30000634" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^5.2.16" - postcss-value-parser "^3.2.3" - autosize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.0.tgz#7a0599b1ba84d73bd7589b0d9da3870152c69237" @@ -766,9 +742,9 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-loader@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015" +babel-loader@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68" dependencies: find-cache-dir "^1.0.0" loader-utils "^1.0.2" @@ -1202,10 +1178,6 @@ backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" -balanced-match@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1374,14 +1346,6 @@ braces@^0.1.2: dependencies: expand-range "^0.1.0" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - braces@^2.3.0, braces@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" @@ -1455,13 +1419,6 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: - version "1.7.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" - dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" - buffer-from@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" @@ -1600,19 +1557,6 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -caniuse-api@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" - dependencies: - browserslist "^1.3.6" - caniuse-db "^1.0.30000529" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000649" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000649.tgz#1ee1754a6df235450c8b7cd15e0ebf507221a86a" - capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" @@ -1654,6 +1598,10 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +chardet@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" + "charenc@>= 0.0.1": version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -1666,24 +1614,27 @@ check-types@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.3.0.tgz#468f571a4435c24248f5fd0cb0e8d87c3c341e7d" -chokidar@^1.4.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" +chokidar@^2.0.0, chokidar@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" dependencies: - anymatch "^1.3.0" + anymatch "^2.0.0" async-each "^1.0.0" - glob-parent "^2.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" inherits "^2.0.1" is-binary-path "^1.0.0" - is-glob "^2.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" path-is-absolute "^1.0.0" readdirp "^2.0.0" + upath "^1.0.0" optionalDependencies: fsevents "^1.0.0" -chokidar@^2.0.0, chokidar@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" +chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" dependencies: anymatch "^2.0.0" async-each "^1.0.0" @@ -1692,20 +1643,23 @@ chokidar@^2.0.0, chokidar@^2.0.2: inherits "^2.0.1" is-binary-path "^1.0.0" is-glob "^4.0.0" + lodash.debounce "^4.0.8" normalize-path "^2.1.1" path-is-absolute "^1.0.0" readdirp "^2.0.0" - upath "^1.0.0" + upath "^1.0.5" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.2.2" chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -chrome-trace-event@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.2.tgz#90f36885d5345a50621332f0717b595883d5d982" +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + dependencies: + tslib "^1.9.0" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -1718,15 +1672,9 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" -circular-json@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.1.tgz#b8942a09e535863dc21b04417a91971e1d9cd91f" - -clap@^1.0.9: - version "1.1.3" - resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.3.tgz#b3bd36e93dd4cbfb395a3c26896352445265c05b" - dependencies: - chalk "^1.1.3" +circular-json@^0.5.4: + version "0.5.5" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.5.tgz#64182ef359042d37cd8e767fc9de878b1e9447d3" class-utils@^0.3.5: version "0.3.6" @@ -1785,24 +1733,10 @@ clone-response@1.0.2: dependencies: mimic-response "^1.0.0" -clone@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" -co@~3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/co/-/co-3.0.6.tgz#1445f226c5eb956138e68c9ac30167ea7d2e6bda" - -coa@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" - dependencies: - q "^1.1.2" - code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1814,39 +1748,17 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.3.0, color-convert@^1.9.0: +color-convert@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" -color-name@^1.0.0, color-name@^1.1.1: +color-name@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d" -color-string@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" - dependencies: - color-name "^1.0.0" - -color@^0.11.0: - version "0.11.4" - resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" - dependencies: - clone "^1.0.2" - color-convert "^1.3.0" - color-string "^0.3.0" - -colormin@^1.0.5: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" - dependencies: - color "^0.11.0" - css-color-names "0.0.4" - has "^1.0.1" - -colors@^1.1.0, colors@~1.1.2: +colors@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -2115,22 +2027,16 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" -css-color-names@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - -css-loader@^0.28.11: - version "0.28.11" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.11.tgz#c3f9864a700be2711bb5a2462b2389b1a392dab7" +css-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.0.tgz#9f46aaa5ca41dbe31860e3b62b8e23c42916bf56" dependencies: babel-code-frame "^6.26.0" css-selector-tokenizer "^0.7.0" - cssnano "^3.10.0" icss-utils "^2.1.0" loader-utils "^1.0.2" lodash.camelcase "^4.3.0" - object-assign "^4.1.1" - postcss "^5.0.6" + postcss "^6.0.23" postcss-modules-extract-imports "^1.2.0" postcss-modules-local-by-default "^1.2.0" postcss-modules-scope "^1.1.0" @@ -2150,50 +2056,6 @@ cssesc@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" -cssnano@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" - dependencies: - autoprefixer "^6.3.1" - decamelize "^1.1.2" - defined "^1.0.0" - has "^1.0.1" - object-assign "^4.0.1" - postcss "^5.0.14" - postcss-calc "^5.2.0" - postcss-colormin "^2.1.8" - postcss-convert-values "^2.3.4" - postcss-discard-comments "^2.0.4" - postcss-discard-duplicates "^2.0.1" - postcss-discard-empty "^2.0.1" - postcss-discard-overridden "^0.1.1" - postcss-discard-unused "^2.2.1" - postcss-filter-plugins "^2.0.0" - postcss-merge-idents "^2.1.5" - postcss-merge-longhand "^2.0.1" - postcss-merge-rules "^2.0.3" - postcss-minify-font-values "^1.0.2" - postcss-minify-gradients "^1.0.1" - postcss-minify-params "^1.0.4" - postcss-minify-selectors "^2.0.4" - postcss-normalize-charset "^1.1.0" - postcss-normalize-url "^3.0.7" - postcss-ordered-values "^2.1.0" - postcss-reduce-idents "^2.2.2" - postcss-reduce-initial "^1.0.0" - postcss-reduce-transforms "^1.0.3" - postcss-svgo "^2.1.1" - postcss-unique-selectors "^2.0.2" - postcss-value-parser "^3.2.3" - postcss-zindex "^2.0.1" - -csso@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" - dependencies: - clap "^1.0.9" - source-map "^0.5.3" - currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -2368,18 +2230,12 @@ debug@2.6.8: dependencies: ms "2.0.0" -debug@^3.0.1, debug@^3.1.0, debug@~3.1.0: +debug@3.1.0, debug@^3.0.1, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -debug@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2442,11 +2298,7 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -degenerator@~1.0.2: +degenerator@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-1.0.4.tgz#fcf490a37ece266464d9cc431ab98c5819ced095" dependencies: @@ -2493,6 +2345,10 @@ depd@1.1.1, depd@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" @@ -2522,7 +2378,7 @@ di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" -diff@^3.4.0: +diff@^3.2.0, diff@^3.4.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -2654,10 +2510,6 @@ ejs@^2.5.7: version "2.5.9" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" -electron-to-chromium@^1.2.7: - version "1.3.3" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.3.tgz#651eb63fe89f39db70ffc8dbd5d9b66958bc6a0e" - elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -2735,6 +2587,14 @@ enhanced-resolve@^4.0.0: memory-fs "^0.4.0" tapable "^1.0.0" +enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + enhanced-resolve@~0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" @@ -2787,10 +2647,20 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + es6-promise@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2964,7 +2834,7 @@ espree@^3.5.2: acorn "^5.5.0" acorn-jsx "^3.0.0" -esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: +esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -3061,12 +2931,6 @@ expand-braces@^0.1.1: array-unique "^0.2.1" braces "^0.1.2" -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -3086,12 +2950,6 @@ expand-range@^0.1.0: is-number "^0.1.1" repeat-string "^0.2.2" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - exports-loader@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-0.7.0.tgz#84881c784dea6036b8e1cd1dac3da9b6409e21a5" @@ -3151,7 +3009,7 @@ extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^2.0.4, external-editor@^2.1.0: +external-editor@^2.0.4: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -3159,11 +3017,13 @@ external-editor@^2.0.4, external-editor@^2.1.0: iconv-lite "^0.4.17" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" +external-editor@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6" dependencies: - is-extglob "^1.0.0" + chardet "^0.5.0" + iconv-lite "^0.4.22" + tmp "^0.0.33" extglob@^2.0.4: version "2.0.4" @@ -3238,10 +3098,6 @@ file-uri-to-path@1: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - fileset@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" @@ -3253,16 +3109,6 @@ filesize@^3.5.11: version "3.6.0" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa" -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -3318,10 +3164,6 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flatten@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" - flush-write-stream@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417" @@ -3341,16 +3183,10 @@ follow-redirects@^1.2.5: dependencies: debug "^3.1.0" -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -3367,15 +3203,7 @@ form-data@~2.0.0: combined-stream "^1.0.5" mime-types "^2.1.11" -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -form-data@~2.3.1: +form-data@~2.3.0, form-data@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" dependencies: @@ -3383,6 +3211,10 @@ form-data@~2.3.1: combined-stream "1.0.6" mime-types "^2.1.12" +formdata-polyfill@^3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.11.tgz#c82b4b4bea3356c0a6752219e54ce1edb2a7fb5b" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -3433,7 +3265,7 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0: +fsevents@^1.0.0, fsevents@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: @@ -3494,9 +3326,9 @@ get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" -get-uri@2: - version "2.0.1" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.1.tgz#dbdcacacd8c608a38316869368117697a1631c59" +get-uri@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.2.tgz#5c795e71326f6ca1286f2fc82575cd2bab2af578" dependencies: data-uri-to-buffer "1" debug "2" @@ -3515,19 +3347,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -3850,10 +3669,6 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-comment-regex@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" - html-entities@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" @@ -3886,13 +3701,21 @@ http-errors@1.6.2, http-errors@~1.6.1, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" -http-proxy-agent@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz#cc1ce38e453bf984a0f7702d2dd59c73d081284a" +http-errors@1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: - agent-base "2" - debug "2" - extend "3" + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + dependencies: + agent-base "4" + debug "3.1.0" http-proxy-middleware@~0.18.0: version "0.18.0" @@ -3941,13 +3764,12 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -https-proxy-agent@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" dependencies: - agent-base "2" - debug "2" - extend "3" + agent-base "^4.1.0" + debug "^3.1.0" iconv-lite@0.4.15: version "0.4.15" @@ -3957,7 +3779,7 @@ iconv-lite@0.4.19, iconv-lite@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.4: +iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -4035,9 +3857,9 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inflection@~1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" +inflection@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflection@~1.3.0: version "1.3.8" @@ -4081,20 +3903,20 @@ inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" -inquirer@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" +inquirer@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.0.0.tgz#e8c20303ddc15bbfc2c12a6213710ccd9e1413d8" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.1.0" + external-editor "^3.0.0" figures "^2.0.0" lodash "^4.3.0" mute-stream "0.0.7" run-async "^2.2.0" - rxjs "^5.5.2" + rxjs "^6.1.0" string-width "^2.1.0" strip-ansi "^4.0.0" through "^2.3.6" @@ -4126,10 +3948,6 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ip@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.0.1.tgz#c7e356cdea225ae71b36d70f2e71a92ba4e42590" - ip@^1.1.0, ip@^1.1.2, ip@^1.1.4, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -4138,10 +3956,6 @@ ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4210,16 +4024,6 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -4230,10 +4034,6 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -4254,12 +4054,6 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -4301,12 +4095,6 @@ is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4357,14 +4145,6 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -4397,12 +4177,6 @@ is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-svg@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" - dependencies: - html-comment-regex "^1.1.0" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" @@ -4554,6 +4328,12 @@ jasmine-core@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.9.0.tgz#bfbb56defcd30789adec5a3fbba8504233289c72" +jasmine-diff@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/jasmine-diff/-/jasmine-diff-0.1.3.tgz#93ccc2dcc41028c5ddd4606558074839f2deeaa8" + dependencies: + diff "^3.2.0" + jasmine-jquery@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/jasmine-jquery/-/jasmine-jquery-2.1.1.tgz#d4095e646944a26763235769ab018d9f30f0d47b" @@ -4576,10 +4356,6 @@ jquery.waitforimages@^2.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" -js-base64@^2.1.9: - version "2.1.9" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" - js-cookie@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.1.3.tgz#48071625217ac9ecfab8c343a13d42ec09ff0526" @@ -4595,13 +4371,6 @@ js-yaml@3.x, js-yaml@^3.7.0, js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" - dependencies: - argparse "^1.0.7" - esprima "^2.6.0" - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -4691,9 +4460,9 @@ karma-coverage-istanbul-reporter@^1.4.2: istanbul-api "^1.1.14" minimatch "^3.0.4" -karma-jasmine@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.1.tgz#6fe840e75a11600c9d91e84b33c458e1c46a3529" +karma-jasmine@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.2.tgz#394f2b25ffb4a644b9ada6f22d443e2fd08886c3" karma-mocha-reporter@^2.2.5: version "2.2.5" @@ -4709,24 +4478,24 @@ karma-sourcemap-loader@^0.3.7: dependencies: graceful-fs "^4.1.2" -karma-webpack@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-3.0.0.tgz#bf009c5b73c667c11c015717e9e520f581317c44" +karma-webpack@^4.0.0-beta.0: + version "4.0.0-beta.0" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-4.0.0-beta.0.tgz#2b386df6c364f588f896ffbdae57c2e51513d1ba" dependencies: async "^2.0.0" babel-runtime "^6.0.0" loader-utils "^1.0.0" lodash "^4.0.0" source-map "^0.5.6" - webpack-dev-middleware "^2.0.6" + webpack-dev-middleware "^3.0.1" -karma@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/karma/-/karma-2.0.2.tgz#4d2db9402850a66551fa784b0164fb0824ed8c4b" +karma@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/karma/-/karma-2.0.4.tgz#b399785f57e9bab1d3c4384db33fef4dec8ae349" dependencies: bluebird "^3.3.0" body-parser "^1.16.1" - chokidar "^1.4.1" + chokidar "^2.0.3" colors "^1.1.0" combine-lists "^1.0.0" connect "^3.6.0" @@ -4739,7 +4508,7 @@ karma@^2.0.2: http-proxy "^1.13.0" isbinaryfile "^3.0.0" lodash "^4.17.4" - log4js "^2.3.9" + log4js "^2.5.3" mime "^1.3.4" minimatch "^3.0.2" optimist "^0.6.1" @@ -4810,10 +4579,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -leb@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/leb/-/leb-0.3.0.tgz#32bee9fad168328d6aea8522d833f4180eed1da3" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -4889,6 +4654,10 @@ lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" @@ -4897,10 +4666,6 @@ lodash.kebabcase@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" @@ -4909,10 +4674,6 @@ lodash.snakecase@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - lodash.upperfirst@4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" @@ -4921,7 +4682,7 @@ lodash@4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@^4.0.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0: +lodash@^4.0.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -4931,21 +4692,21 @@ log-symbols@^2.1.0: dependencies: chalk "^2.0.1" -log4js@^2.3.9: - version "2.5.3" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-2.5.3.tgz#38bb7bde5e9c1c181bd75e8bc128c5cd0409caf1" +log4js@^2.5.3: + version "2.11.0" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-2.11.0.tgz#bf3902eff65c6923d9ce9cfbd2db54160e34005a" dependencies: - circular-json "^0.5.1" + circular-json "^0.5.4" date-format "^1.2.0" debug "^3.1.0" - semver "^5.3.0" - streamroller "^0.7.0" + semver "^5.5.0" + streamroller "0.7.0" optionalDependencies: amqplib "^0.5.2" axios "^0.15.3" hipchat-notifier "^1.1.0" loggly "^1.1.0" - mailgun-js "^0.7.0" + mailgun-js "^0.18.0" nodemailer "^2.5.0" redis "^2.7.1" slack-node "~0.2.0" @@ -4966,6 +4727,10 @@ loglevelnext@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.3.tgz#0f69277e73bbbf2cd61b94d82313216bf87ac66e" +long@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + long@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" @@ -5002,14 +4767,6 @@ lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@~2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.5.tgz#e56d6354148ede8d7707b58d143220fd08df0fd5" - -macaddress@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" - mailcomposer@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-4.0.1.tgz#0e1c44b2a07cf740ee17dc149ba009f19cadfeb4" @@ -5017,18 +4774,18 @@ mailcomposer@4.0.1: buildmail "4.0.1" libmime "3.0.0" -mailgun-js@^0.7.0: - version "0.7.15" - resolved "https://registry.yarnpkg.com/mailgun-js/-/mailgun-js-0.7.15.tgz#ee366a20dac64c3c15c03d6c1b3e0ed795252abb" +mailgun-js@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/mailgun-js/-/mailgun-js-0.18.1.tgz#ee39aa18d7bb598a5ce9ede84afb681defc8a6b0" dependencies: - async "~2.1.2" - debug "~2.2.0" - form-data "~2.1.1" - inflection "~1.10.0" + async "~2.6.0" + debug "~3.1.0" + form-data "~2.3.0" + inflection "~1.12.0" is-stream "^1.1.0" path-proxy "~1.0.0" - proxy-agent "~2.0.0" - q "~1.4.0" + promisify-call "^2.0.2" + proxy-agent "~3.0.0" tsscmp "~1.0.0" make-dir@^1.0.0: @@ -5067,10 +4824,6 @@ match-at@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/match-at/-/match-at-0.1.1.tgz#25d040d291777704d5e6556bbb79230ec2de0540" -math-expression-evaluator@^1.2.14: - version "1.2.16" - resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9" - md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -5128,24 +4881,6 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -5262,7 +4997,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -5295,10 +5030,6 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -5359,7 +5090,7 @@ neo-async@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" -netmask@~1.0.4: +netmask@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" @@ -5467,9 +5198,9 @@ nodemailer@^2.5.0: nodemailer-smtp-transport "2.7.2" socks "1.1.9" -nodemon@^1.17.3: - version "1.17.3" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.17.3.tgz#3b0bbc2ee05ccb43b1aef15ba05c63c7bc9b8530" +nodemon@^1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.2.tgz#36b89c790da70c4f270e2cc0718723131bc04abb" dependencies: chokidar "^2.0.2" debug "^3.1.0" @@ -5510,16 +5241,12 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - normalize-url@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" @@ -5528,15 +5255,6 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -normalize-url@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" - dependencies: - object-assign "^4.0.1" - prepend-http "^1.0.0" - query-string "^4.1.0" - sort-keys "^1.0.0" - npm-bundled@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" @@ -5567,10 +5285,6 @@ null-check@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -5579,7 +5293,7 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5605,13 +5319,6 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -5743,29 +5450,28 @@ p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" -pac-proxy-agent@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz#34a385dfdf61d2f0ecace08858c745d3e791fd4d" +pac-proxy-agent@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz#90d9f6730ab0f4d2607dcdcd4d3d641aa26c3896" dependencies: - agent-base "2" - debug "2" - extend "3" - get-uri "2" - http-proxy-agent "1" - https-proxy-agent "1" - pac-resolver "~2.0.0" - raw-body "2" - socks-proxy-agent "2" - -pac-resolver@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-2.0.0.tgz#99b88d2f193fbdeefc1c9a529c1f3260ab5277cd" + agent-base "^4.2.0" + debug "^3.1.0" + get-uri "^2.0.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + pac-resolver "^3.0.0" + raw-body "^2.2.0" + socks-proxy-agent "^3.0.0" + +pac-resolver@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-3.0.0.tgz#6aea30787db0a891704deb7800a722a7615a6f26" dependencies: - co "~3.0.6" - degenerator "~1.0.2" - ip "1.0.1" - netmask "~1.0.4" - thunkify "~2.1.1" + co "^4.6.0" + degenerator "^1.0.4" + ip "^1.1.5" + netmask "^1.0.6" + thunkify "^2.1.2" package-json@^4.0.0: version "4.0.1" @@ -5798,15 +5504,6 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -5967,128 +5664,6 @@ posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" -postcss-calc@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" - dependencies: - postcss "^5.0.2" - postcss-message-helpers "^2.0.0" - reduce-css-calc "^1.2.6" - -postcss-colormin@^2.1.8: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" - dependencies: - colormin "^1.0.5" - postcss "^5.0.13" - postcss-value-parser "^3.2.3" - -postcss-convert-values@^2.3.4: - version "2.6.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" - dependencies: - postcss "^5.0.11" - postcss-value-parser "^3.1.2" - -postcss-discard-comments@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" - dependencies: - postcss "^5.0.14" - -postcss-discard-duplicates@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" - dependencies: - postcss "^5.0.4" - -postcss-discard-empty@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" - dependencies: - postcss "^5.0.14" - -postcss-discard-overridden@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" - dependencies: - postcss "^5.0.16" - -postcss-discard-unused@^2.2.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" - dependencies: - postcss "^5.0.14" - uniqs "^2.0.0" - -postcss-filter-plugins@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" - dependencies: - postcss "^5.0.4" - uniqid "^4.0.0" - -postcss-merge-idents@^2.1.5: - version "2.1.7" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" - dependencies: - has "^1.0.1" - postcss "^5.0.10" - postcss-value-parser "^3.1.1" - -postcss-merge-longhand@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" - dependencies: - postcss "^5.0.4" - -postcss-merge-rules@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" - dependencies: - browserslist "^1.5.2" - caniuse-api "^1.5.2" - postcss "^5.0.4" - postcss-selector-parser "^2.2.2" - vendors "^1.0.0" - -postcss-message-helpers@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" - -postcss-minify-font-values@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" - dependencies: - object-assign "^4.0.1" - postcss "^5.0.4" - postcss-value-parser "^3.0.2" - -postcss-minify-gradients@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" - dependencies: - postcss "^5.0.12" - postcss-value-parser "^3.3.0" - -postcss-minify-params@^1.0.4: - version "1.2.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" - dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.2" - postcss-value-parser "^3.0.2" - uniqs "^2.0.0" - -postcss-minify-selectors@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" - dependencies: - alphanum-sort "^1.0.2" - has "^1.0.1" - postcss "^5.0.14" - postcss-selector-parser "^2.0.0" - postcss-modules-extract-imports@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" @@ -6116,57 +5691,6 @@ postcss-modules-values@^1.3.0: icss-replace-symbols "^1.1.0" postcss "^6.0.1" -postcss-normalize-charset@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" - dependencies: - postcss "^5.0.5" - -postcss-normalize-url@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^1.4.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - -postcss-ordered-values@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.1" - -postcss-reduce-idents@^2.2.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.2" - -postcss-reduce-initial@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" - dependencies: - postcss "^5.0.4" - -postcss-reduce-transforms@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" - dependencies: - has "^1.0.1" - postcss "^5.0.8" - postcss-value-parser "^3.0.1" - -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" - dependencies: - flatten "^1.0.2" - indexes-of "^1.0.1" - uniq "^1.0.1" - postcss-selector-parser@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" @@ -6175,44 +5699,10 @@ postcss-selector-parser@^3.1.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-svgo@^2.1.1: - version "2.1.6" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" - dependencies: - is-svg "^2.0.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - svgo "^0.7.0" - -postcss-unique-selectors@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" - dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: +postcss-value-parser@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" -postcss-zindex@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" - dependencies: - has "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16: - version "5.2.16" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.16.tgz#732b3100000f9ff8379a48a53839ed097376ad57" - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.2.3" - postcss@^6.0.1, postcss@^6.0.14, postcss@^6.0.20: version "6.0.22" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3" @@ -6221,11 +5711,19 @@ postcss@^6.0.1, postcss@^6.0.14, postcss@^6.0.20: source-map "^0.6.1" supports-color "^5.4.0" +postcss@^6.0.23: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" -prepend-http@^1.0.0, prepend-http@^1.0.1: +prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -6233,10 +5731,6 @@ prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - prettier@1.12.1, prettier@^1.11.1: version "1.12.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" @@ -6271,6 +5765,12 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" +promisify-call@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/promisify-call/-/promisify-call-2.0.4.tgz#d48c2d45652ccccd52801ddecbd533a6d4bd5fba" + dependencies: + with-callback "^1.0.2" + proxy-addr@~2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" @@ -6278,18 +5778,22 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.6.0" -proxy-agent@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-2.0.0.tgz#57eb5347aa805d74ec681cb25649dba39c933499" +proxy-agent@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-3.0.1.tgz#4fb7b61b1476d0fe8e3a3384d90e2460bbded3f9" dependencies: - agent-base "2" - debug "2" - extend "3" - http-proxy-agent "1" - https-proxy-agent "1" - lru-cache "~2.6.5" - pac-proxy-agent "1" - socks-proxy-agent "2" + agent-base "^4.2.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + pac-proxy-agent "^2.0.1" + proxy-from-env "^1.0.0" + socks-proxy-agent "^4.0.1" + +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" prr@~0.0.0: version "0.0.0" @@ -6348,14 +5852,6 @@ punycode@1.4.1, punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -q@^1.1.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" - -q@~1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" - qjobs@^1.1.4: version "1.2.0" resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" @@ -6368,13 +5864,6 @@ qs@~6.2.0: version "6.2.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" -query-string@^4.1.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.2.tgz#ec0fd765f58a50031a3968c2431386f8947a5cdd" - dependencies: - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -6399,13 +5888,6 @@ querystringify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" @@ -6433,7 +5915,7 @@ raven-js@^3.22.1: version "3.22.1" resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.22.1.tgz#1117f00dfefaa427ef6e1a7d50bbb1fb998a24da" -raw-body@2, raw-body@2.3.2: +raw-body@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" dependencies: @@ -6442,6 +5924,15 @@ raw-body@2, raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" +raw-body@^2.2.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + raw-loader@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" @@ -6561,20 +6052,6 @@ redis@^2.7.1: redis-commands "^1.2.0" redis-parser "^2.6.0" -reduce-css-calc@^1.2.6: - version "1.3.0" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" - dependencies: - balanced-match "^0.4.2" - math-expression-evaluator "^1.2.14" - reduce-function-call "^1.0.1" - -reduce-function-call@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" - dependencies: - balanced-match "^0.4.2" - regenerate@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" @@ -6591,12 +6068,6 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" private "^0.1.6" -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -6832,11 +6303,11 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -rxjs@^5.5.2: - version "5.5.10" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045" +rxjs@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.1.tgz#246cebec189a6cbc143a3ef9f62d6f4c91813ca1" dependencies: - symbol-observable "1.0.1" + tslib "^1.9.0" safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" @@ -6872,10 +6343,6 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -sax@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" - schema-utils@^0.4.0, schema-utils@^0.4.2, schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" @@ -6911,10 +6378,6 @@ semver-diff@^2.0.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -7050,6 +6513,10 @@ smart-buffer@^1.0.13, smart-buffer@^1.0.4: version "1.1.15" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + smtp-connection@2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.12.0.tgz#d76ef9127cb23c2259edb1e8349c2e8d5e2d74c1" @@ -7155,13 +6622,19 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" -socks-proxy-agent@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz#86ebb07193258637870e13b7bd99f26c663df3d3" +socks-proxy-agent@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz#2eae7cf8e2a82d34565761539a7f9718c5617659" dependencies: - agent-base "2" - extend "3" - socks "~1.1.5" + agent-base "^4.1.0" + socks "^1.1.10" + +socks-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" socks@1.1.9: version "1.1.9" @@ -7170,18 +6643,19 @@ socks@1.1.9: ip "^1.1.2" smart-buffer "^1.0.4" -socks@~1.1.5: +socks@^1.1.10: version "1.1.10" resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" dependencies: ip "^1.1.4" smart-buffer "^1.0.13" -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" +socks@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" dependencies: - is-plain-obj "^1.0.0" + ip "^1.1.5" + smart-buffer "^4.0.1" sort-keys@^2.0.0: version "2.0.0" @@ -7340,6 +6814,10 @@ static-extend@^0.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -7382,7 +6860,7 @@ stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" -streamroller@^0.7.0: +streamroller@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" dependencies: @@ -7477,7 +6955,7 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3: +supports-color@^3.1.0, supports-color@^3.1.2: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: @@ -7493,22 +6971,6 @@ svg4everybody@2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/svg4everybody/-/svg4everybody-2.1.9.tgz#5bd9f6defc133859a044646d4743fabc28db7e2d" -svgo@^0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" - dependencies: - coa "~1.0.1" - colors "~1.1.2" - csso "~2.3.1" - js-yaml "~3.7.0" - mkdirp "~0.5.1" - sax "~1.2.1" - whet.extend "~0.9.9" - -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - table@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" @@ -7583,7 +7045,7 @@ through@2, through@^2.3.6, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" -thunkify@~2.1.1: +thunkify@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" @@ -7691,6 +7153,10 @@ tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + tsscmp@~1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" @@ -7794,16 +7260,6 @@ uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" -uniqid@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" - dependencies: - macaddress "^0.2.8" - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - unique-filename@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" @@ -7841,6 +7297,10 @@ upath@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.5.tgz#02cab9ecebe95bbec6d5fc2566325725ab6d1a73" +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + update-notifier@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.3.0.tgz#4e8827a6bb915140ab093559d7014e3ebb837451" @@ -7859,10 +7319,6 @@ urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" -url-join@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - url-join@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" @@ -7968,10 +7424,6 @@ vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" -vendors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -8009,9 +7461,9 @@ vue-hot-reload-api@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926" -vue-loader@^15.2.0: - version "15.2.0" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.2.0.tgz#5a8138e490a1040942d2f10ae68fa72b5a923364" +vue-loader@^15.2.4: + version "15.2.4" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.2.4.tgz#a7b923123d3cf87230a8ff54a1c16d31a6c5dbb4" dependencies: "@vue/component-compiler-utils" "^1.2.1" hash-sum "^1.0.2" @@ -8073,9 +7525,9 @@ wbuf@^1.1.0, wbuf@^1.7.2: dependencies: minimalistic-assert "^1.0.0" -webpack-bundle-analyzer@^2.11.1: - version "2.11.1" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.1.tgz#b9fbfb6a32c0a8c1c3237223e90890796b950ab9" +webpack-bundle-analyzer@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz#07d2176c6e86c3cdce4c23e56fae2a7b6b4ad526" dependencies: acorn "^5.3.0" bfj-node4 "^5.2.0" @@ -8090,23 +7542,23 @@ webpack-bundle-analyzer@^2.11.1: opener "^1.4.3" ws "^4.0.0" -webpack-cli@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.0.2.tgz#e48c5662aff8ed5aac3db5f82f51d7f32e50459e" +webpack-cli@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.0.8.tgz#90eddcf04a4bfc31aa8c0edc4c76785bc4f1ccd9" dependencies: chalk "^2.4.1" cross-spawn "^6.0.5" enhanced-resolve "^4.0.0" global-modules-path "^2.1.0" import-local "^1.0.0" - inquirer "^5.2.0" + inquirer "^6.0.0" interpret "^1.1.0" loader-utils "^1.1.0" supports-color "^5.4.0" v8-compile-cache "^2.0.0" yargs "^11.1.0" -webpack-dev-middleware@3.1.3: +webpack-dev-middleware@3.1.3, webpack-dev-middleware@^3.0.1: version "3.1.3" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.1.3.tgz#8b32aa43da9ae79368c1bf1183f2b6cf5e1f39ed" dependencies: @@ -8118,18 +7570,6 @@ webpack-dev-middleware@3.1.3: url-join "^4.0.0" webpack-log "^1.0.1" -webpack-dev-middleware@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-2.0.6.tgz#a51692801e8310844ef3e3790e1eacfe52326fd4" - dependencies: - loud-rejection "^1.6.0" - memory-fs "~0.4.1" - mime "^2.1.0" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - url-join "^2.0.2" - webpack-log "^1.0.1" - webpack-dev-server@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.4.tgz#9a08d13c4addd1e3b6d8ace116e86715094ad5b4" @@ -8183,21 +7623,21 @@ webpack-stats-plugin@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/webpack-stats-plugin/-/webpack-stats-plugin-0.2.1.tgz#1f5bac13fc25d62cbb5fd0ff646757dc802b8595" -webpack@^4.11.1: - version "4.11.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.11.1.tgz#1aa0b936f7ae93a52cf38d2ad0d0f46dcf3c2723" +webpack@^4.16.0: + version "4.16.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.0.tgz#660dae90890e55b8ed17c6f9d17bebb01dab5b4c" dependencies: - "@webassemblyjs/ast" "1.5.10" - "@webassemblyjs/helper-module-context" "1.5.10" - "@webassemblyjs/wasm-edit" "1.5.10" - "@webassemblyjs/wasm-opt" "1.5.10" - "@webassemblyjs/wasm-parser" "1.5.10" - acorn "^5.0.0" + "@webassemblyjs/ast" "1.5.13" + "@webassemblyjs/helper-module-context" "1.5.13" + "@webassemblyjs/wasm-edit" "1.5.13" + "@webassemblyjs/wasm-opt" "1.5.13" + "@webassemblyjs/wasm-parser" "1.5.13" + acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" ajv-keywords "^3.1.0" - chrome-trace-event "^0.1.1" - enhanced-resolve "^4.0.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" eslint-scope "^3.7.1" json-parse-better-errors "^1.0.2" loader-runner "^2.3.0" @@ -8227,10 +7667,6 @@ when@^3.7.7: version "3.7.8" resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" -whet.extend@~0.9.9: - version "0.9.9" - resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -8257,6 +7693,10 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" +with-callback@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/with-callback/-/with-callback-1.0.2.tgz#a09629b9a920028d721404fb435bdcff5c91bc21" + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" |