diff options
462 files changed, 3127 insertions, 2665 deletions
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml index df1fec61c25..8bcf8d4cb48 100644 --- a/.gitlab/ci/reports.gitlab-ci.yml +++ b/.gitlab/ci/reports.gitlab-ci.yml @@ -1,5 +1,5 @@ include: - - local: /lib/gitlab/ci/templates/Code-Quality.gitlab-ci.yml + - template: Code-Quality.gitlab-ci.yml code_quality: extends: .dedicated-no-docs-no-db-pull-cache-job diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml index dee72930a28..9cfb50eeefc 100644 --- a/.gitlab/ci/review.gitlab-ci.yml +++ b/.gitlab/ci/review.gitlab-ci.yml @@ -32,7 +32,6 @@ environment: &review-environment name: review/${CI_COMMIT_REF_NAME} url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN} - before_script: [] .review-docker: &review-docker <<: *review-base @@ -48,6 +47,7 @@ DOCKER_HOST: tcp://docker:2375 LATEST_QA_IMAGE: "gitlab/${CI_PROJECT_NAME}-qa:nightly" QA_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab/${CI_PROJECT_NAME}-qa:${CI_COMMIT_REF_SLUG}" + before_script: [] build-qa-image: <<: *review-docker @@ -85,6 +85,7 @@ schedule:review-build-cng: .review-deploy-base: &review-deploy-base <<: *review-base + retry: 2 allow_failure: true variables: HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}" diff --git a/.rubocop.yml b/.rubocop.yml index aa49f41ebf4..e5fe527e611 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -75,6 +75,7 @@ Naming/FileName: - 'qa/spec/**/*' - 'qa/qa/specs/**/*' - 'qa/bin/*' + - 'ee/bin/*' - 'config/**/*' - 'ee/config/**/*' - 'lib/generators/**/*' diff --git a/CHANGELOG.md b/CHANGELOG.md index 41506746c98..bd4c0e479cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,264 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 11.10.1 (2019-04-23) + +### Fixed (2 changes) + +- Upgrade Gitaly to 1.34.0. !27494 +- Fix filtering of labels from system note link. !27507 + +### Changed (1 change) + +- Disable just-in-time Kubernetes resource creation for project level clusters. !27352 + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + +### Other (1 change) + +- Bump required Ruby version check to 2.5.3. !27495 + + +## 11.10.0 (2019-04-22) + +### Security (9 changes) + +- Update Rails to 5.0.7.2. !27022 +- Disallow guest users from accessing Releases. +- Return cached languages if they've been detected before. +- Added rake task for removing EXIF data from existing uploads. +- Disallow updating namespace when updating a project. +- Fix XSS in resolve conflicts form. +- Hide "related branches" when user does not have permission. +- Fix PDF.js vulnerability. +- Use UntrustedRegexp for matching refs policy. + +### Fixed (81 changes, 21 of them are from the community) + +- Update `border-radius` of form controls and remove extra space above page titles. !24497 +- Disallow reopening of a locked merge request. !24882 (Jan Beckmann) +- Align EmailValidator to validate_email gem implementation. !24971 (Horatiu Eugen Vlad) +- add a uniq constraints on issues and mrs labels. !25435 (Antoine Huret) +- Display draft when toggling replies. !25563 +- Fix markdown table header and table content borders. !25666 +- Fix authorized application count. !25715 (moyuru) +- Added "Add List" checkbox to create label dropdown to make creation of list optional. !25716 (Tucker Chapman) +- Makes emoji picker full width on mobile. !25883 (Jacopo Beschi @jacopo-beschi) +- Don't cutoff letters in MR and Issue links. !25910 (gfyoung) +- Fix unwanted character replacement on project members page caused by usage of sanitize function. !25946 (Elias Werberich) +- Fix UI for closed MR when source project is removed. !25967 (Takuya Noguchi) +- Keep inline as much as possible in system notes on issuable. !25968 (Takuya Noguchi) +- Fixes long review app subdomains. !25990 (walkafwalka) +- Fix counting of groups in admin dashboard. !26009 +- Disable inaccessible navigation links upon archiving a project. !26020 (Elias Werberich) +- Fixed - Create project label window is cut off at the bottom. !26049 +- Fix error shown when loading links to specific comments. !26092 +- Fix group transfer selection possibilities. !26123 (Peter Marko) +- Fix UI layout on Commits on mobile. !26133 (Takuya Noguchi) +- Fix continuous bitbucket import loading spinner. !26175 +- Resolves Branch name is lost if I change commit mode in Web IDE. !26180 +- Fix removing remote mirror failure which leaves unnecessary refs behind. !26213 +- Fix Error 500 when user commits Wiki page with no commit message. !26247 +- Handle missing keys in sentry api response. !26264 +- Implemented whitespace-trimming for file names in Web IDE. !26270 +- Fix misalignment of group overview page buttons. !26292 +- Reject HEAD requests to info/refs endpoint. !26334 +- Prevent namespace dropdown in new project form from exceeding container. !26343 +- Fix hover animation consistency in top navbar items. !26345 +- Exclude system notes from commits in merge request discussions. !26396 +- Resolve Code in other column of side-by-side diff is highlighted when selecting code on one side. !26423 +- Prevent fade out transition on loading-button component. !26428 +- Fix merge commits being used as default squash commit messages. !26445 +- Expand resolved discussion when linking to a comment in the discussion. !26483 +- Show statistics also when repository is disabled. !26509 (Peter Marko) +- Fix multiple series queries on metrics dashboard. !26514 +- Releases will now be automatically deleted when deleting corresponding tag. !26530 +- Make stylistic improvements to diff nav header. !26557 +- Clear pipeline status cache after destruction of pipeline. !26575 +- Update fugit which fixes a potential infinite loop. !26579 +- Fixes job link in artifacts page breadcrumb. !26592 +- Fix quick actions add label name middle word overlaps. !26602 (Jacopo Beschi @jacopo-beschi) +- Fix Auto DevOps missing domain error handling. !26627 +- Fix jupyter rendering bug that ended in an infinite loop. !26656 (ROSPARS Benoit) +- Use a fixed git abbrev parameter when we fetch a git revision. !26707 +- Enabled text selection highlighting in diffs in Web IDE. !26721 (Isaac Smith) +- Remove `path` and `branch` labels from metrics. !26744 +- Resolve "Hide Kubernetes cluster warning if project has cluster related". !26749 +- Fix long label overflow on metrics dashboard. !26775 +- Group transfer now properly redirects to edit on failure. !26837 +- Only execute system hooks once when pushing tags. !26888 +- Fix UI anchor links after docs refactor. !26890 +- Fix MWPS does not work for merge request pipelines. !26906 +- Create pipelines for merge requests only when source branch is updated. !26921 +- Fix notfication emails having wrong encoding. !26931 +- Allow task lists that follow a blockquote to work correctly. !26937 +- Fix image diff swipe view on commit and compare pages. !26968 (ftab) +- Fix IDE detection of MR from fork with same branch name. !26986 +- Fix single string values for the 'include' keyword validation of gitlab-ci.yml. !26998 (Paul Bonaud (@paulrbr)) +- Do not display Ingress IP help text when there isn’t an Ingress IP assigned. !27057 +- Fix real-time updates for projects that contain a reserved word. !27060 +- Remove duplicates from issue related merge requests. !27067 +- Add to white-space nowrap to all buttons. !27069 +- Handle possible HTTP exception for Sentry client. !27080 +- Guard against nil dereferenced_target. !27192 +- Update GitLab Workhorse to v8.5.1. !27217 +- Fix long file header names bug in diffs. !27233 +- Always return the deployment in the UpdateDeploymentService#execute method. !27322 +- Fix remove_source_branch merge request API handling. !27392 +- Fixed bug with hashes in urls in WebIDE. !54376 (Kieran Andrews) +- Fix bug where MR popover doesn't go away on mouse leave. +- Only consider active milestones when using the special Started milestone filter. +- Scroll to diff file content when clicking on file header name and it is not a link to other page. +- Remove non-functional add issue button on welcome list. +- Fixed expand full file button showing on images. +- Fixed Web IDE web workers not working with relative URLs. +- Fixed Web IDE not loading merge request files. +- Fixed duplicated diff too large error message. +- Fixed sticky headers in merge request creation diffs. +- Fix bug when reopening milestone from index page. + +### Deprecated (1 change) + +- Allow to use untrusted Regexp via feature flag. !26905 + +### Changed (35 changes, 4 of them are from the community) + +- Create MR pipelines with `refs/merge-requests/:iid/head`. !25504 +- Create Kubernetes resources for projects when their deployment jobs run. !25586 +- Remove unnecessary folder prefix from environment name. !25600 +- Update deploy boards to additionally select on "app.gitlab.com" annotations. !25623 +- Allow failed custom hook script errors to safely appear in GitLab UI by filtering error messages by the prefix GL-HOOK-ERR:. !25625 +- Add link on two-factor authorization settings page to leave group that enforces two-factor authorization. !25731 +- Reduce height of instance system header and footer. !25752 +- Unify behaviour of 'Copy commit SHA to clipboard' to use full commit SHA. !25829 (Max Winterstein) +- Show loading spinner while Ingress/Knative IP is being assigned. !25912 +- Hashed Storage: Prevent a migration and rollback running at the same time. !25976 +- Make time counters show 'just now' for everything under one minute. !25992 (Sergiu Marton) +- Allow filtering labels list by one or two characters. !26012 +- Implements the creation strategy for multi-line suggestions. !26057 +- Automate base domain help text on Clusters page. !26124 +- Set user.name limit to 128 characters. !26146 +- Update gitlab-markup to 1.7.0 which requies python3. !26246 +- Update system message banner font size to 12px. !26293 +- Extend timezone dropdown. !26311 +- Upgrade to Gitaly v1.29.0. !26406 +- Automatically set Prometheus step interval. !26441 +- Knative version bump 0.2.2 -> 0.3.0. !26459 (Chris Baumbauer) +- Display cluster form validation error messages inline. !26502 +- Split Auto-DevOps.gitlab-ci.yml into reusable templates. !26520 +- Update spinners in group list component. !26572 +- Allow removing last owner from subgroup if parent group has owners. !26718 +- Check mergeability in MergeToRefService. !26757 +- Show download diff links for closed MRs. !26772 +- Fix Container Scanning in Kubernetes Runners. !26793 +- Move "Authorize project access with external service" to Core. !26823 +- Localize notifications dropdown. !26844 +- Order labels alphabetically in issue boards. !26927 +- Upgrade to Gitaly v1.32.0. !26989 +- Upgrade to Gitaly v1.33.0. !27065 +- collapse file tree by default if the merge request changes only one file. (Riccardo Padovani <riccardo@rpadovani.com>) +- Removes the undescriptive CI Charts header. + +### Performance (17 changes) + +- Drop legacy artifacts usage as there are no leftovers. !24294 +- Cache Repository#root_ref within a request. !25903 +- Allow ref name caching CommitService#find_commit. !26248 +- Avoid loading pipeline status in project search. !26342 +- Fix some N+1s in loading routes and counting members for groups in @-autocomplete. !26491 +- GitHub import: Run housekeeping after initial import. !26600 +- Add initial complexity limits to GraphQL queries. !26629 +- Cache FindCommit results in pipelines view. !26776 +- Fix and expand Gitaly FindCommit caching. !27018 +- Enable FindCommit caching for project and commits pages. !27048 +- Expand FindCommit caching to blob and refs. !27084 +- Enable Gitaly FindCommit caching for TreeController. !27100 +- Improve performance of PR import. !27121 +- Process at most 4 pipelines during push. !27205 +- Disable method instrumentation for diffs. !27235 +- Speed up filtering issues in a project when searching. +- Speed up generation of avatar URLs when using object storage. + +### Added (35 changes, 6 of them are from the community) + +- Add users search results to global search. !21197 (Alexis Reigel) +- Add target branch filter to merge requests search bar. !24380 (Hiroyuki Sato) +- Add Knative metrics to Prometheus. !24663 (Chris Baumbauer <cab@cabnetworks.net>) +- Support multi-line suggestions. !25211 +- Allow to sort wiki pages by date and title. !25365 +- Allow external diffs to be used conditionally. !25432 +- Add usage counts for error tracking feature. !25472 +- Enable/disable Auto DevOps at the Group level. !25533 +- Update pipeline list view to accommodate post-merge pipeline information. !25690 +- GraphQL Types can be made to always authorize access to resources of that Type. !25724 +- Update clair-local-scan to 2.0.6. !25743 (Takuya Noguchi) +- Update pipeline block on merge request page to accommodate post-merge pipeline information. !25745 +- Support multiple queries per chart on metrics dash. !25758 +- Update pipeline detail view to accommodate post-merge pipelines. !25775 +- Update job detail sidebar to accommodate post-merge pipeline information. !25777 +- Add merge request pipeline flag to pipeline entity. !25846 +- Expose group id on home panel. !25897 (Peter Marko) +- Move allow developers to create projects in groups to Core. !25975 +- Add two new warning messages to the MR widget about merge request pipelines. !25983 +- Support installing Group runner on group-level cluster. !26260 +- Improve the Knative installation on Clusters. !26339 +- Show error when namespace/svc account missing. !26362 +- Add select by title to milestones API. !26573 +- Implemented support for creation of new files from URL in Web IDE. !26622 +- Add control for masking variable values in runner logs. !26751 +- Allow merge requests to be created via git push options. !26752 +- Create a shortcut for a new MR in the Web IDE. !26792 +- Allow reactive caching to be used in services. !26839 +- Add a Prometheus API per environment. !26841 +- Allow merge requests to be set to merge when pipeline succeeds via git push options. !26842 +- Use gitlabktl to build and deploy GitLab Serverless Functions. !26926 +- Make touch events work on image diff swipe view and onion skin. !26971 (ftab) +- Add extended merge request tooltip. +- Added prometheus monitoring to GraphQL. +- Adding highest role property to admin's user details page. + +### Other (29 changes, 6 of them are from the community) + +- Update rack-oauth2 1.2.1 -> 1.9.3. !17868 +- Merge the gitlab-shell "gitlab-keys" functionality into GitLab CE. !25598 +- Refactor all_pipelines in Merge request. !25676 +- Show error backtrace when logging errors to kubernetes.log. !25726 +- Apply recaptcha API change in 4.0. !25921 (Praveen Arimbrathodiyil) +- Remove fake repository_path response. !25942 (Fabio Papa) +- Use curl silent/show-error options on Auto DevOps. !25954 (Takuya Noguchi) +- Explicitly set master_auth setting to enable basic auth and client certificate for new GKE clusters. !26018 +- Project: Improve empty repository state UI. !26024 +- Externalize strings from `/app/views/projects/pipelines`. !26035 (George Tsiolis) +- Prepare multi-line suggestions for rendering in Markdown. !26107 +- Improve mobile UI on User Profile page. !26240 (Takuya Noguchi) +- Update GitLab Runner Helm Chart to 0.3.0/11.9.0. !26467 +- Improve project merge request settings. !26495 +- Bump kubectl to 1.11.9 and Helm to 2.13.1 in Auto-DevOps.gitlab-ci.yml. !26534 +- Upgrade bootstrap_form Gem. !26568 +- Add API access check to Graphql. !26570 +- Change project avatar remove button to a link. !26589 +- Log Gitaly RPC duration to api_json.log and production_json.log. !26652 +- Add cluster domain to Project Cluster API. !26735 +- Move project tags to separate line. !26797 +- Changed button label at /pipelines/new. !26893 (antfobe,leonardofl) +- Update GitLab Shell to v9.0.0. !27002 +- Migrate clusters tests to jest. !27013 +- Rewrite related MRs widget with Vue. !27027 +- Restore HipChat project service. !27172 +- Externalize admin deploy keys strings. +- Removes EE differences for environments_table.vue. +- Removes EE differences for environment_item.vue. + + +## 11.9.9 (2019-04-23) + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + + ## 11.9.8 (2019-04-11) ### Deprecated (1 change) @@ -353,6 +611,28 @@ entry. - Removes EE differences for jobs/getters.js. +## 11.8.8 (2019-04-23) + +### Fixed (5 changes) + +- Bring back Rugged implementation of find_commit. !25477 +- Fix bug in BitBucket imports with SHA shorter than 40 chars. !26050 +- Fix health checks not working behind load balancers. !26055 +- Fix error creating a merge request when diff includes a null byte. !26190 +- Avoid excessive recursive calls with Rugged TreeEntries. !26813 + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + +### Other (4 changes) + +- Bring back Rugged implementation of GetTreeEntries. !25674 +- Bring back Rugged implementation of CommitIsAncestor. !25702 +- Bring back Rugged implementation of TreeEntry. !25706 +- Bring back Rugged implementation of commit_tree_entry. !25896 + + ## 11.8.3 (2019-03-19) ### Security (1 change) @@ -622,6 +902,25 @@ entry. - Creates mixin to reduce code duplication between CE and EE in graph component. +## 11.7.12 (2019-04-23) + +### Fixed (2 changes) + +- Bring back Rugged implementation of find_commit. !25477 +- Avoid excessive recursive calls with Rugged TreeEntries. !26813 + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + +### Other (4 changes) + +- Bring back Rugged implementation of GetTreeEntries. !25674 +- Bring back Rugged implementation of CommitIsAncestor. !25702 +- Bring back Rugged implementation of TreeEntry. !25706 +- Bring back Rugged implementation of commit_tree_entry. !25896 + + ## 11.7.11 (2019-04-09) - No changes. @@ -897,6 +1196,30 @@ entry. - Update url placeholder for the sentry configuration page. !24338 +## 11.6.11 (2019-04-23) + +### Security (2 changes) + +- Fixed ability to see private groups by users not belonging to given group. +- Fix XSS in resolve conflicts form. + +### Fixed (2 changes) + +- Bring back Rugged implementation of find_commit. !25477 +- Avoid excessive recursive calls with Rugged TreeEntries. !26813 + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + +### Other (4 changes) + +- Bring back Rugged implementation of GetTreeEntries. !25674 +- Bring back Rugged implementation of CommitIsAncestor. !25702 +- Bring back Rugged implementation of TreeEntry. !25706 +- Bring back Rugged implementation of commit_tree_entry. !25896 + + ## 11.6.10 (2019-02-28) ### Security (21 changes) @@ -1268,6 +1591,25 @@ entry. - Enable Rubocop on lib/gitlab. (gfyoung) +## 11.5.11 (2019-04-23) + +### Fixed (2 changes) + +- Bring back Rugged implementation of find_commit. !25477 +- Avoid excessive recursive calls with Rugged TreeEntries. !26813 + +### Performance (1 change) + +- Bring back Rugged implementation of ListCommitsByOid. !27441 + +### Other (4 changes) + +- Bring back Rugged implementation of GetTreeEntries. !25674 +- Bring back Rugged implementation of CommitIsAncestor. !25702 +- Bring back Rugged implementation of TreeEntry. !25706 +- Bring back Rugged implementation of commit_tree_entry. !25896 + + ## 11.5.8 (2019-01-28) ### Security (21 changes) diff --git a/Dangerfile b/Dangerfile index 3e8cb456003..9e3a08949b0 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1,3 +1,4 @@ +# frozen_string_literal: true danger.import_plugin('danger/plugins/helper.rb') unless helper.release_automation? @@ -16,4 +17,5 @@ unless helper.release_automation? danger.import_dangerfile(path: 'danger/roulette') danger.import_dangerfile(path: 'danger/single_codebase') danger.import_dangerfile(path: 'danger/gitlab_ui_wg') + danger.import_dangerfile(path: 'danger/ce_ee_vue_templates') end diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index acd405b1d62..df5119ec64e 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -8.6.0 +8.7.0 @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '5.0.7.2' +gem 'rails', '5.1.7' # Improves copy-on-write performance for MRI gem 'nakayoshi_fork', '~> 0.0.4' @@ -18,7 +18,7 @@ gem 'mysql2', '~> 0.4.10', group: :mysql gem 'pg', '~> 1.1', group: :postgres gem 'rugged', '~> 0.28' -gem 'grape-path-helpers', '~> 1.0' +gem 'grape-path-helpers', '~> 1.1' gem 'faraday', '~> 0.12' @@ -129,7 +129,7 @@ gem 'asciidoctor-plantuml', '0.0.8' gem 'rouge', '~> 3.1' gem 'truncato', '~> 0.7.11' gem 'bootstrap_form', '~> 4.2.0' -gem 'nokogiri', '~> 1.10.1' +gem 'nokogiri', '~> 1.10.3' gem 'escape_utils', '~> 1.1' # Calendar rendering @@ -158,7 +158,7 @@ gem 'state_machines-activerecord', '~> 0.5.1' gem 'acts-as-taggable-on', '~> 6.0' # Background jobs -gem 'sidekiq', '~> 5.2.1' +gem 'sidekiq', '~> 5.2.7' gem 'sidekiq-cron', '~> 1.0' gem 'redis-namespace', '~> 1.6.0' gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch' @@ -418,9 +418,9 @@ end # Gitaly GRPC client gem 'gitaly-proto', '~> 1.19.0', require: 'gitaly' -gem 'grpc', '~> 1.15.0' +gem 'grpc', '~> 1.19.0' -gem 'google-protobuf', '~> 3.6' +gem 'google-protobuf', '~> 3.7.1' gem 'toml-rb', '~> 1.0.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index ba4418cd8b3..da8f8db9528 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,41 +4,41 @@ GEM RedCloth (4.3.2) abstract_type (0.0.7) ace-rails-ap (4.1.2) - actioncable (5.0.7.2) - actionpack (= 5.0.7.2) - nio4r (>= 1.2, < 3.0) + actioncable (5.1.7) + actionpack (= 5.1.7) + nio4r (~> 2.0) websocket-driver (~> 0.6.1) - actionmailer (5.0.7.2) - actionpack (= 5.0.7.2) - actionview (= 5.0.7.2) - activejob (= 5.0.7.2) + actionmailer (5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.7.2) - actionview (= 5.0.7.2) - activesupport (= 5.0.7.2) + actionpack (5.1.7) + actionview (= 5.1.7) + activesupport (= 5.1.7) rack (~> 2.0) - rack-test (~> 0.6.3) + rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.7.2) - activesupport (= 5.0.7.2) + actionview (5.1.7) + activesupport (= 5.1.7) builder (~> 3.1) - erubis (~> 2.7.0) + erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.7.2) - activesupport (= 5.0.7.2) + activejob (5.1.7) + activesupport (= 5.1.7) globalid (>= 0.3.6) - activemodel (5.0.7.2) - activesupport (= 5.0.7.2) - activerecord (5.0.7.2) - activemodel (= 5.0.7.2) - activesupport (= 5.0.7.2) - arel (~> 7.0) + activemodel (5.1.7) + activesupport (= 5.1.7) + activerecord (5.1.7) + activemodel (= 5.1.7) + activesupport (= 5.1.7) + arel (~> 8.0) activerecord_sane_schema_dumper (1.0) rails (>= 5, < 6) - activesupport (5.0.7.2) + activesupport (5.1.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -52,7 +52,7 @@ GEM public_suffix (>= 2.0.2, < 4.0) aes_key_wrap (1.0.1) akismet (2.0.0) - arel (7.1.4) + arel (8.0.0) asana (0.8.1) faraday (~> 0.9) faraday_middleware (~> 0.9) @@ -185,8 +185,7 @@ GEM mail (~> 2.7) encryptor (3.0.0) equalizer (0.0.11) - erubi (1.7.1) - erubis (2.7.0) + erubi (1.8.0) escape_utils (1.2.1) et-orbi (1.1.7) tzinfo @@ -257,8 +256,8 @@ GEM fog-xml (0.1.3) fog-core nokogiri (>= 1.5.11, < 2.0.0) - font-awesome-rails (4.7.0.1) - railties (>= 3.2, < 5.1) + font-awesome-rails (4.7.0.4) + railties (>= 3.2, < 6.0) foreman (0.84.0) thor (~> 0.19.1) formatador (0.2.5) @@ -317,8 +316,8 @@ GEM mime-types (~> 3.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - google-protobuf (3.6.1) - googleapis-common-protos-types (1.0.3) + google-protobuf (3.7.1) + googleapis-common-protos-types (1.0.4) google-protobuf (~> 3.0) googleauth (0.6.6) faraday (~> 0.12) @@ -339,8 +338,8 @@ GEM grape-entity (0.7.1) activesupport (>= 4.0) multi_json (>= 1.3.2) - grape-path-helpers (1.0.6) - activesupport (>= 4, < 5.1) + grape-path-helpers (1.1.0) + activesupport grape (~> 1.0) rake (~> 12) grape_logging (1.7.0) @@ -349,7 +348,7 @@ GEM railties sprockets-rails graphql (1.8.1) - grpc (1.15.0) + grpc (1.19.0) google-protobuf (~> 3.1) googleapis-common-protos-types (~> 1.0.0) haml (5.0.4) @@ -494,7 +493,7 @@ GEM net-ssh (5.0.1) netrc (0.11.0) nio4r (2.3.1) - nokogiri (1.10.2) + nokogiri (1.10.3) mini_portile2 (~> 2.4.0) nokogumbo (1.5.0) nokogiri @@ -658,19 +657,19 @@ GEM rack rack-proxy (0.6.0) rack - rack-test (0.6.3) - rack (>= 1.0) - rails (5.0.7.2) - actioncable (= 5.0.7.2) - actionmailer (= 5.0.7.2) - actionpack (= 5.0.7.2) - actionview (= 5.0.7.2) - activejob (= 5.0.7.2) - activemodel (= 5.0.7.2) - activerecord (= 5.0.7.2) - activesupport (= 5.0.7.2) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.1.7) + actioncable (= 5.1.7) + actionmailer (= 5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + activemodel (= 5.1.7) + activerecord (= 5.1.7) + activesupport (= 5.1.7) bundler (>= 1.3.0) - railties (= 5.0.7.2) + railties (= 5.1.7) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.2) actionpack (~> 5.x, >= 5.0.1) @@ -684,9 +683,9 @@ GEM rails-i18n (5.1.1) i18n (>= 0.7, < 2) railties (>= 5.0, < 6) - railties (5.0.7.2) - actionpack (= 5.0.7.2) - activesupport (= 5.0.7.2) + railties (5.1.7) + actionpack (= 5.1.7) + activesupport (= 5.1.7) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -846,7 +845,7 @@ GEM rack shoulda-matchers (3.1.2) activesupport (>= 4.0.0) - sidekiq (5.2.5) + sidekiq (5.2.7) connection_pool (~> 2.2, >= 2.2.2) rack (>= 1.5.0) rack-protection (>= 1.5.0) @@ -1063,15 +1062,15 @@ DEPENDENCIES gitlab_omniauth-ldap (~> 2.1.1) gon (~> 6.2) google-api-client (~> 0.23) - google-protobuf (~> 3.6) + google-protobuf (~> 3.7.1) gpgme (~> 2.0.18) grape (~> 1.1.0) grape-entity (~> 0.7.1) - grape-path-helpers (~> 1.0) + grape-path-helpers (~> 1.1) grape_logging (~> 1.7) graphiql-rails (~> 1.4.10) graphql (~> 1.8.0) - grpc (~> 1.15.0) + grpc (~> 1.19.0) haml_lint (~> 0.28.0) hamlit (~> 2.8.8) hangouts-chat (~> 0.0.5) @@ -1104,7 +1103,7 @@ DEPENDENCIES nakayoshi_fork (~> 0.0.4) net-ldap net-ssh (~> 5.0) - nokogiri (~> 1.10.1) + nokogiri (~> 1.10.3) oauth2 (~> 1.4) octokit (~> 4.9) omniauth (~> 1.8) @@ -1142,7 +1141,7 @@ DEPENDENCIES rack-cors (~> 1.0.0) rack-oauth2 (~> 1.9.3) rack-proxy (~> 0.6.0) - rails (= 5.0.7.2) + rails (= 5.1.7) rails-controller-testing rails-i18n (~> 5.1) rainbow (~> 3.0) @@ -1183,7 +1182,7 @@ DEPENDENCIES settingslogic (~> 2.0.9) sham_rack (~> 1.3.6) shoulda-matchers (~> 3.1.2) - sidekiq (~> 5.2.1) + sidekiq (~> 5.2.7) sidekiq-cron (~> 1.0) simple_po_parser (~> 1.1.2) simplecov (~> 0.14.0) @@ -1 +1 @@ -11.10.0-pre +11.11.0-pre diff --git a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js index 55c68139ded..b7200150925 100644 --- a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js +++ b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import { parseBoolean } from '~/lib/utils/common_utils'; -import GfmAutoComplete from '~/gfm_auto_complete'; +import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; export default function initGFMInput() { $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => { diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index 6cf77705847..7e5d0e0f888 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -90,6 +90,7 @@ class List { this.id = data.id; this.type = data.list_type; this.position = data.position; + this.label = data.label; return this.getIssues(); }); diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index f5e2e46237f..5a6d44ef838 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import autosize from 'autosize'; -import GfmAutoComplete, * as GFMConfig from './gfm_auto_complete'; +import GfmAutoComplete, { defaultAutocompleteConfig } from 'ee_else_ce/gfm_auto_complete'; import dropzoneInput from './dropzone_input'; import { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_markdown'; @@ -8,7 +8,7 @@ export default class GLForm { constructor(form, enableGFM = {}) { this.form = form; this.textarea = this.form.find('textarea.js-gfm-input'); - this.enableGFM = Object.assign({}, GFMConfig.defaultAutocompleteConfig, enableGFM); + this.enableGFM = Object.assign({}, defaultAutocompleteConfig, enableGFM); // Disable autocomplete for keywords which do not have dataSources available const dataSources = (gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources) || {}; Object.keys(this.enableGFM).forEach(item => { diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue index ec759043efc..188518dd419 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue @@ -57,6 +57,8 @@ export default { type: 'blob', content: result, base64: !isText, + binary: !isText, + rawPath: !isText ? target.result : '', }); }, readFile(file) { diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 94a9e87369c..e15b2a6f76b 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -1,5 +1,6 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; +import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils'; import flash from '~/flash'; import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; @@ -35,7 +36,7 @@ export default { ]), ...mapGetters('fileTemplates', ['showFileTemplatesBar']), shouldHideEditor() { - return this.file && this.file.binary && !this.file.content; + return this.file && this.file.binary; }, showContentViewer() { return ( @@ -56,6 +57,10 @@ export default { active: this.file.viewMode === 'preview', }; }, + fileType() { + const info = viewerInformationForPath(this.file.path); + return (info && info.id) || ''; + }, }, watch: { file(newVal, oldVal) { @@ -258,6 +263,7 @@ export default { :path="file.rawPath || file.path" :file-size="file.size" :project-path="file.projectId" + :type="fileType" /> <diff-viewer v-if="showDiffViewer" diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index 7c560c89695..e30670e119f 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -72,4 +72,11 @@ export const modalTypes = { tree: 'tree', }; +export const commitActionTypes = { + move: 'move', + delete: 'delete', + create: 'create', + update: 'update', +}; + export const packageJsonPath = 'package.json'; diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js index df100f753d7..b8abaa41f23 100644 --- a/app/assets/javascripts/ide/lib/files.js +++ b/app/assets/javascripts/ide/lib/files.js @@ -22,6 +22,8 @@ export const decorateFiles = ({ tempFile = false, content = '', base64 = false, + binary = false, + rawPath = '', }) => { const treeList = []; const entries = {}; @@ -90,6 +92,8 @@ export const decorateFiles = ({ changed: tempFile, content, base64, + binary, + rawPath, previewMode: viewerInformationForPath(name), parentPath, }); diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 7b660bda081..fd678e6e10c 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -53,7 +53,7 @@ export const setResizingStatus = ({ commit }, resizing) => { export const createTempEntry = ( { state, commit, dispatch }, - { name, type, content = '', base64 = false }, + { name, type, content = '', base64 = false, binary = false, rawPath = '' }, ) => new Promise(resolve => { const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name; @@ -79,8 +79,10 @@ export const createTempEntry = ( branchId: state.currentBranchId, type, tempFile: true, - base64, content, + base64, + binary, + rawPath, }); const { file, parentPath } = data; diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js index b7090e09daf..59ead8a3dcf 100644 --- a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js +++ b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js @@ -23,22 +23,27 @@ export const receiveTemplateTypesError = ({ commit, dispatch }) => { export const receiveTemplateTypesSuccess = ({ commit }, templates) => commit(types.RECEIVE_TEMPLATE_TYPES_SUCCESS, templates); -export const fetchTemplateTypes = ({ dispatch, state, rootState }, page = 1) => { +export const fetchTemplateTypes = ({ dispatch, state, rootState }) => { if (!Object.keys(state.selectedTemplateType).length) return Promise.reject(); dispatch('requestTemplateTypes'); - return Api.projectTemplates(rootState.currentProjectId, state.selectedTemplateType.key, { page }) - .then(({ data, headers }) => { - const nextPage = parseInt(normalizeHeaders(headers)['X-NEXT-PAGE'], 10); + const fetchPages = (page = 1, prev = []) => + Api.projectTemplates(rootState.currentProjectId, state.selectedTemplateType.key, { + page, + per_page: 100, + }) + .then(({ data, headers }) => { + const nextPage = parseInt(normalizeHeaders(headers)['X-NEXT-PAGE'], 10); + const nextData = prev.concat(data); - dispatch('receiveTemplateTypesSuccess', data); + dispatch('receiveTemplateTypesSuccess', nextData); - if (nextPage) { - dispatch('fetchTemplateTypes', nextPage); - } - }) - .catch(() => dispatch('receiveTemplateTypesError')); + return nextPage ? fetchPages(nextPage, nextData) : nextData; + }) + .catch(() => dispatch('receiveTemplateTypesError')); + + return fetchPages(); }; export const setSelectedTemplateType = ({ commit, dispatch, rootGetters }, type) => { diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js index 25a65b047f1..7fc1c9134a7 100644 --- a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js @@ -3,13 +3,14 @@ import * as types from './mutation_types'; export default { [types.REQUEST_TEMPLATE_TYPES](state) { state.isLoading = true; + state.templates = []; }, [types.RECEIVE_TEMPLATE_TYPES_ERROR](state) { state.isLoading = false; }, [types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, templates) { state.isLoading = false; - state.templates = state.templates.concat(templates); + state.templates = templates; }, [types.SET_SELECTED_TEMPLATE_TYPE](state, type) { state.selectedTemplateType = type; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 9b9f4b21f1c..344b189decf 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -213,7 +213,7 @@ export default { ? `${slashedParentPath}${oldEntry.name}` : `${slashedParentPath}${name}`; - state.entries[newPath] = { + Vue.set(state.entries, newPath, { ...oldEntry, id: newPath, key: `${newPath}-${oldEntry.type}-${oldEntry.id}`, @@ -225,7 +225,7 @@ export default { tree: [], parentPath, raw: '', - }; + }); oldEntry.moved = true; oldEntry.movedPath = newPath; diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index 3ab8f3f11be..bcc9ca60d9b 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -1,3 +1,5 @@ +import { commitActionTypes } from '../constants'; + export const dataStructure = () => ({ id: '', // Key will contain a mixture of ID and path @@ -69,6 +71,8 @@ export const decorateData = entity => { changed = false, parentTreeUrl = '', base64 = false, + binary = false, + rawPath = '', previewMode, file_lock, html, @@ -92,6 +96,8 @@ export const decorateData = entity => { renderError, content, base64, + binary, + rawPath, previewMode, file_lock, html, @@ -110,14 +116,14 @@ export const setPageTitle = title => { export const commitActionForFile = file => { if (file.prevPath) { - return 'move'; + return commitActionTypes.move; } else if (file.deleted) { - return 'delete'; + return commitActionTypes.delete; } else if (file.tempFile) { - return 'create'; + return commitActionTypes.create; } - return 'update'; + return commitActionTypes.update; }; export const getCommitFiles = stagedFiles => diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 9336b71cfd7..7576d36f27d 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -1,8 +1,8 @@ import $ from 'jquery'; import Pikaday from 'pikaday'; +import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import Autosave from './autosave'; import UsersSelect from './users_select'; -import GfmAutoComplete from './gfm_auto_complete'; import ZenMode from './zen_mode'; import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select'; import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js index f134a54dd53..4d304c5fe69 100644 --- a/app/assets/javascripts/label_manager.js +++ b/app/assets/javascripts/label_manager.js @@ -14,13 +14,16 @@ export default class LabelManager { this.errorMessage = 'Unable to update label prioritization at this time'; this.emptyState = document.querySelector('#js-priority-labels-empty-state'); this.$badgeItemTemplate = $('#js-badge-item-template'); - this.sortable = Sortable.create(this.prioritizedLabels.get(0), { - filter: '.empty-message', - forceFallback: true, - fallbackClass: 'is-dragging', - dataIdAttr: 'data-id', - onUpdate: this.onPrioritySortUpdate.bind(this), - }); + + if ('sortable' in this.prioritizedLabels.data()) { + Sortable.create(this.prioritizedLabels.get(0), { + filter: '.empty-message', + forceFallback: true, + fallbackClass: 'is-dragging', + dataIdAttr: 'data-id', + onUpdate: this.onPrioritySortUpdate.bind(this), + }); + } this.bindEvents(); } diff --git a/app/assets/javascripts/mr_popover/index.js b/app/assets/javascripts/mr_popover/index.js index 9a97e98f9db..18c0e201300 100644 --- a/app/assets/javascripts/mr_popover/index.js +++ b/app/assets/javascripts/mr_popover/index.js @@ -22,13 +22,10 @@ const handleUserPopoverMouseOut = ({ target }) => { * Adds a MergeRequestPopover component to the body, hands over as much data as the target element has in data attributes. * loads based on data-project-path and data-iid more data about an MR from the API and sets it on the popover */ -const handleMRPopoverMount = apolloProvider => ({ target }) => { +const handleMRPopoverMount = ({ apolloProvider, projectPath, mrTitle, iid }) => ({ target }) => { // Add listener to actually remove it again target.addEventListener('mouseleave', handleUserPopoverMouseOut); - const { projectPath, mrTitle, iid } = target.dataset; - const mergeRequest = {}; - renderFn = setTimeout(() => { const MRPopoverComponent = Vue.extend(MRPopover); renderedPopover = new MRPopoverComponent({ @@ -36,7 +33,6 @@ const handleMRPopoverMount = apolloProvider => ({ target }) => { target, projectPath, mergeRequestIID: iid, - mergeRequest, mergeRequestTitle: mrTitle, }, apolloProvider, @@ -57,8 +53,13 @@ export default elements => { const listenerAddedAttr = 'data-mr-listener-added'; mrLinks.forEach(el => { - if (!el.getAttribute(listenerAddedAttr)) { - el.addEventListener('mouseenter', handleMRPopoverMount(apolloProvider)); + const { projectPath, mrTitle, iid } = el.dataset; + + if (!el.getAttribute(listenerAddedAttr) && projectPath && mrTitle && iid) { + el.addEventListener( + 'mouseenter', + handleMRPopoverMount({ apolloProvider, projectPath, mrTitle, iid }), + ); el.setAttribute(listenerAddedAttr, true); } }); diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 89563711bcd..1e47bef7b61 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -454,8 +454,13 @@ Please check your network connection and try again.`; </component> </template> </ul> + <draft-note + v-if="showDraft(discussion.reply_id)" + :key="`draft_${discussion.id}`" + :draft="draftForDiscussion(discussion.reply_id)" + /> <div - v-if="isExpanded || !hasReplies" + v-else-if="isExpanded || !hasReplies" :class="{ 'is-replying': isReplying }" class="discussion-reply-holder" > diff --git a/app/assets/javascripts/pages/profiles/show/index.js b/app/assets/javascripts/pages/profiles/show/index.js index 0dd0d5336fc..e726ab0e220 100644 --- a/app/assets/javascripts/pages/profiles/show/index.js +++ b/app/assets/javascripts/pages/profiles/show/index.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import createFlash from '~/flash'; -import GfmAutoComplete from '~/gfm_auto_complete'; +import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import emojiRegex from 'emoji-regex'; import EmojiMenu from './emoji_menu'; diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue index 7f86741ed29..c0659a0173a 100644 --- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue +++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue @@ -2,7 +2,7 @@ import $ from 'jquery'; import createFlash from '~/flash'; import Icon from '~/vue_shared/components/icon.vue'; -import GfmAutoComplete from '~/gfm_auto_complete'; +import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import { __, s__ } from '~/locale'; import Api from '~/api'; import { GlModal, GlTooltipDirective } from '@gitlab/ui'; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index bb76eb1030d..851939d5d4e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -3,6 +3,7 @@ import successSvg from 'icons/_icon_status_success.svg'; import warningSvg from 'icons/_icon_status_warning.svg'; import simplePoll from '~/lib/utils/simple_poll'; import { __ } from '~/locale'; +import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge'; import MergeRequest from '../../../merge_request'; import Flash from '../../../flash'; import statusIcon from '../mr_widget_status_icon.vue'; @@ -21,6 +22,7 @@ export default { CommitEdit, CommitMessageDropdown, }, + mixins: [readyToMergeMixin], props: { mr: { type: Object, required: true }, service: { type: Object, required: true }, @@ -94,15 +96,6 @@ export default { shouldShowMergeOptionsDropdown() { return this.mr.isPipelineActive && !this.mr.onlyAllowMergeIfPipelineSucceeds; }, - isMergeButtonDisabled() { - const { commitMessage } = this; - return Boolean( - !commitMessage.length || - !this.shouldShowMergeControls || - this.isMakingRequest || - this.mr.preventMerge, - ); - }, isRemoveSourceBranchButtonDisabled() { return this.isMergeButtonDisabled; }, diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js new file mode 100644 index 00000000000..b2e64506472 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js @@ -0,0 +1,13 @@ +export default { + computed: { + isMergeButtonDisabled() { + const { commitMessage } = this; + return Boolean( + !commitMessage.length || + !this.shouldShowMergeControls || + this.isMakingRequest || + this.mr.preventMerge, + ); + }, + }, +}; diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue index 4155e1bab9c..1e6f4c376c1 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue @@ -1,5 +1,4 @@ <script> -import { viewerInformationForPath } from './lib/viewer_utils'; import MarkdownViewer from './viewers/markdown_viewer.vue'; import ImageViewer from './viewers/image_viewer.vue'; import DownloadViewer from './viewers/download_viewer.vue'; @@ -24,15 +23,18 @@ export default { required: false, default: '', }, + type: { + type: String, + required: false, + default: '', + }, }, computed: { viewer() { if (!this.path) return null; + if (!this.type) return DownloadViewer; - const previewInfo = viewerInformationForPath(this.path); - if (!previewInfo) return DownloadViewer; - - switch (previewInfo.id) { + switch (this.type) { case 'markdown': return MarkdownViewer; case 'image': diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue index ad3b3b81ac5..8d77b156aa4 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue @@ -58,12 +58,11 @@ export default { const moveX = e.pageX || e.touches[0].pageX; let leftValue = moveX - this.$refs.swipeFrame.getBoundingClientRect().left; - const spaceLeft = 20; const { clientWidth } = this.$refs.swipeFrame; if (leftValue <= 0) { leftValue = 0; - } else if (leftValue > clientWidth - spaceLeft) { - leftValue = clientWidth - spaceLeft; + } else if (leftValue > clientWidth) { + leftValue = clientWidth; } this.swipeWrapWidth = (leftValue / clientWidth) * 100; @@ -80,7 +79,7 @@ export default { document.body.removeEventListener('touchmove', this.dragMove); }, prepareSwipe() { - if (this.swipeOldImgInfo && this.swipeNewImgInfo) { + if (this.swipeOldImgInfo && this.swipeNewImgInfo && this.swipeOldImgInfo.renderedWidth > 0) { // Add 2 for border width this.swipeMaxWidth = Math.max(this.swipeOldImgInfo.renderedWidth, this.swipeNewImgInfo.renderedWidth) + 2; @@ -101,6 +100,8 @@ export default { }, resize: _.throttle(function throttledResize() { this.swipeBarPos = 0; + this.swipeWrapWidth = 0; + this.prepareSwipe(); }, 400), }, }; @@ -111,6 +112,8 @@ export default { <div ref="swipeFrame" :style="{ + width: swipeMaxPixelWidth, + height: swipeMaxPixelHeight, 'user-select': dragging ? 'none' : null, }" class="swipe-frame" diff --git a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue index bf96ce0bafb..ffde55bf083 100644 --- a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue +++ b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue @@ -45,10 +45,10 @@ export default { 'issuable-info-container': !canReorder, 'card-body': canReorder, }" - class="item-body" + class="item-body d-flex align-items-center p-2 p-lg-3 p-xl-2 pl-xl-3" > - <div class="item-contents"> - <div class="item-title d-flex align-items-center"> + <div class="item-contents d-flex align-items-center flex-wrap flex-grow-1 flex-xl-nowrap"> + <div class="item-title d-flex align-items-center mb-1 mb-xl-0"> <icon v-if="hasState" v-tooltip @@ -65,13 +65,15 @@ export default { name="eye-slash" :size="16" :title="__('Confidential')" - class="confidential-icon append-right-4" + class="confidential-icon append-right-4 align-self-baseline align-self-md-auto mt-xl-0" :aria-label="__('Confidential')" /> <a :href="computedPath" class="sortable-link">{{ title }}</a> </div> - <div class="item-meta"> - <div class="d-flex align-items-center item-path-id"> + <div class="item-meta d-flex flex-wrap mt-xl-0 justify-content-xl-end flex-xl-nowrap"> + <div + class="d-flex align-items-center item-path-id order-md-0 mt-md-0 mt-1 ml-xl-2 mr-xl-auto" + > <icon v-if="hasState" v-tooltip @@ -88,7 +90,9 @@ export default { }}</span> {{ pathIdSeparator }}{{ itemId }} </div> - <div class="item-meta-child d-flex align-items-center"> + <div + class="item-meta-child d-flex align-items-center order-0 flex-wrap mr-md-1 ml-md-auto ml-xl-2 flex-xl-nowrap" + > <span v-if="hasPipeline" class="mr-ci-status pr-2"> <a :href="pipelineStatus.details_path"> <ci-icon v-gl-tooltip :status="pipelineStatus" :title="pipelineStatusTooltip" /> @@ -105,7 +109,7 @@ export default { <issue-assignees v-if="assignees.length" :assignees="assignees" - class="item-assignees d-inline-flex" + class="item-assignees d-inline-flex align-items-center align-self-end ml-auto ml-md-0 mb-md-0 order-2 flex-xl-grow-0 mt-xl-0 mr-xl-1" /> </div> </div> @@ -115,7 +119,7 @@ export default { v-tooltip :disabled="removeDisabled" type="button" - class="btn btn-default btn-svg btn-item-remove js-issue-item-remove-button qa-remove-issue-button" + class="btn btn-default btn-svg btn-item-remove js-issue-item-remove-button qa-remove-issue-button mr-xl-0 align-self-xl-center" title="Remove" aria-label="Remove" @click="onRemoveRequest" diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss index 0fdb11d311a..7f9cf1266b1 100644 --- a/app/assets/stylesheets/components/related_items_list.scss +++ b/app/assets/stylesheets/components/related_items_list.scss @@ -16,10 +16,7 @@ $item-weight-max-width: 48px; } .item-body { - display: flex; position: relative; - align-items: center; - padding: $gl-padding-8; line-height: $gl-line-height; .issue-token-state-icon-open { @@ -49,14 +46,11 @@ $item-weight-max-width: 48px; } .confidential-icon { - align-self: baseline; color: $orange-600; - margin-right: $gl-padding-4; } .item-title { flex-basis: 100%; - margin-bottom: $gl-padding-8; font-size: $gl-font-size-small; &.mr-title { @@ -80,24 +74,12 @@ $item-weight-max-width: 48px; } } -.item-contents { - display: flex; - align-items: center; - flex-wrap: wrap; - flex-grow: 1; -} - .item-meta { - display: flex; - flex-wrap: wrap; flex-basis: 100%; font-size: $gl-font-size-small; color: $gl-text-color-secondary; .item-meta-child { - order: 0; - display: flex; - flex-wrap: wrap; flex-basis: 100%; } @@ -117,16 +99,10 @@ $item-weight-max-width: 48px; } .item-weight { - margin-right: 0; max-width: $item-weight-max-width; } .item-assignees { - order: 2; - align-self: flex-end; - align-items: center; - margin-left: auto; - .user-avatar-link { margin-right: -$gl-padding-4; @@ -162,7 +138,6 @@ $item-weight-max-width: 48px; } .item-path-id { - margin-top: $gl-padding-4; font-size: $gl-font-size-xs; white-space: nowrap; @@ -176,8 +151,10 @@ $item-weight-max-width: 48px; display: block; } - &:not(.mr-item-path) { - order: 1; + @include media-breakpoint-down(sm) { + &:not(.mr-item-path) { + order: 1; + } } } @@ -219,15 +196,14 @@ $item-weight-max-width: 48px; .item-body { .item-contents { min-width: 0; + } - .item-title { - flex-basis: unset; - // 95% because we compensate - // for remove button which is - // positioned absolutely - width: 95%; - margin-bottom: $gl-padding-4; - } + .item-title { + flex-basis: unset; + // 95% because we compensate + // for remove button which is + // positioned absolutely + width: 95%; } .btn-item-remove { @@ -236,34 +212,19 @@ $item-weight-max-width: 48px; } .item-meta { - .item-path-id { - order: 0; - margin-top: 0; - } - .item-meta-child { flex-basis: unset; - margin-left: auto; - margin-right: $gl-padding-4; ~ .item-assignees { margin-left: $gl-padding-4; } } - - .item-assignees { - margin-bottom: 0; - margin-left: 0; - order: 2; - } } } /* Medium devices (desktops, 992px and up) */ @include media-breakpoint-up(lg) { .item-body { - padding: $gl-padding; - .item-title { font-size: $gl-font-size; } @@ -277,12 +238,7 @@ $item-weight-max-width: 48px; /* Large devices (large desktops, 1200px and up) */ @include media-breakpoint-up(xl) { .item-body { - padding: $gl-padding-8; - padding-left: $gl-padding; - .item-title { - display: flex; - margin-bottom: 0; min-width: 0; width: auto; flex-basis: unset; @@ -293,43 +249,18 @@ $item-weight-max-width: 48px; display: block; margin-right: $gl-padding-8; } - - .confidential-icon { - align-self: auto; - margin-top: 0; - } } } .item-contents { - flex-wrap: nowrap; overflow: hidden; } .item-meta { - margin-top: 0; - justify-content: flex-end; flex: 1; - flex-wrap: nowrap; - - .item-meta-child { - margin-left: $gl-padding-8; - flex-wrap: nowrap; - } - } - - .item-path-id { - order: 0; - margin-top: 0; - margin-left: $gl-padding-8; - margin-right: auto; } .item-assignees { - flex-grow: 0; - margin-top: 0; - margin-right: $gl-padding-4; - .avatar { height: $gl-padding-24; width: $gl-padding-24; @@ -345,10 +276,8 @@ $item-weight-max-width: 48px; .btn-item-remove { position: relative; - align-self: center; top: initial; right: 0; - margin-right: 0; padding: $btn-sm-side-margin; &:hover { @@ -357,10 +286,6 @@ $item-weight-max-width: 48px; } .sortable-link { - display: block; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; line-height: 1.3; } } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 5ea96392afa..b2b3720fdde 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -431,9 +431,9 @@ table.code { &.diff-line-num { user-select: none; margin: 0; - border: 0; padding: 0 10px 0 5px; - border-right: 1px solid; + border-right-width: 1px; + border-right-style: solid; text-align: right; width: 50px; position: relative; diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index e3d0d0b0fa2..60a840aac1b 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -75,7 +75,7 @@ padding: 0; margin-bottom: 0; - > li:not(.empty-message):not(.is-not-draggable) { + > li:not(.empty-message):not(.no-border) { background-color: $white-light; margin-bottom: 5px; display: flex; @@ -92,7 +92,7 @@ opacity: 0.3; } - .prioritized-labels & { + .prioritized-labels:not(.is-not-draggable) & { box-shadow: 0 1px 2px $issue-boards-card-shadow; cursor: move; cursor: grab; @@ -353,7 +353,7 @@ @media (max-width: map-get($grid-breakpoints, md)-1) { .manage-labels-list { - > li:not(.empty-message):not(.is-not-draggable) { + > li:not(.empty-message):not(.no-border) { flex-wrap: wrap; } diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index d5c4712bd78..4926062f9ca 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -8,13 +8,6 @@ module AuthenticatesWithTwoFactor extend ActiveSupport::Concern - included do - # This action comes from DeviseController, but because we call `sign_in` - # manually, not skipping this action would cause a "You are already signed - # in." error message to be shown upon successful login. - skip_before_action :require_no_authentication, only: [:create], raise: false - end - # Store the user's ID in the session for later retrieval and render the # two factor code prompt # diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb index c0c0160a827..cfff154c3dd 100644 --- a/app/controllers/concerns/milestone_actions.rb +++ b/app/controllers/concerns/milestone_actions.rb @@ -31,7 +31,7 @@ module MilestoneActions format.html { redirect_to milestone_redirect_path } format.json do render json: tabs_json("shared/milestones/_labels_tab", { - labels: @milestone.labels # rubocop:disable Gitlab/ModuleWithInstanceVariables + labels: @milestone.labels.map { |label| label.present(issuable_subject: @milestone.parent) } # rubocop:disable Gitlab/ModuleWithInstanceVariables }) end end diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index e14abbf7c78..fc708400657 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -100,14 +100,14 @@ class Projects::BranchesController < Projects::ApplicationController respond_to do |format| format.html do - flash_type = result[:status] == :error ? :alert : :notice - flash[flash_type] = result[:message] + flash_type = result.error? ? :alert : :notice + flash[flash_type] = result.message redirect_to project_branches_path(@project), status: :see_other end - format.js { head result[:return_code] } - format.json { render json: { message: result[:message] }, status: result[:return_code] } + format.js { head result.http_status } + format.json { render json: { message: result.message }, status: result.http_status } end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 3d16a368f23..2ef5c207d67 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -10,11 +10,11 @@ class Projects::IssuesController < Projects::ApplicationController include SpammableActions include RecordUserLastActivity - def self.issue_except_actions + def issue_except_actions %i[index calendar new create bulk_update import_csv] end - def self.set_issuables_index_only_actions + def set_issuables_index_only_actions %i[index calendar] end @@ -25,9 +25,9 @@ class Projects::IssuesController < Projects::ApplicationController before_action :whitelist_query_limiting, only: [:create, :create_merge_request, :move, :bulk_update] before_action :check_issues_available! - before_action :issue, except: issue_except_actions + before_action :issue, unless: ->(c) { c.issue_except_actions.include?(c.action_name.to_sym) } - before_action :set_issuables_index, only: set_issuables_index_only_actions + before_action :set_issuables_index, if: ->(c) { c.set_issuables_index_only_actions.include?(c.action_name.to_sym) } # Allow write(create) issue before_action :authorize_create_issue!, only: [:new, :create] diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index d1c5cef76fa..c4dff95a4b9 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -19,7 +19,7 @@ module Projects redirect_to project_settings_ci_cd_path(@project) else - render 'show' + redirect_to project_settings_ci_cd_path(@project), alert: result[:message] end end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 6943795e8ac..6fea61cf45d 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -8,6 +8,8 @@ class SessionsController < Devise::SessionsController include Recaptcha::Verify skip_before_action :check_two_factor_requirement, only: [:destroy] + # replaced with :require_no_authentication_without_flash + skip_before_action :require_no_authentication, only: [:new, :create] prepend_before_action :check_initial_setup, only: [:new] prepend_before_action :authenticate_with_two_factor, @@ -15,6 +17,8 @@ class SessionsController < Devise::SessionsController prepend_before_action :check_captcha, only: [:create] prepend_before_action :store_redirect_uri, only: [:new] prepend_before_action :ldap_servers, only: [:new, :create] + prepend_before_action :require_no_authentication_without_flash, only: [:new, :create] + before_action :auto_sign_in_with_provider, only: [:new] before_action :load_recaptcha @@ -54,6 +58,14 @@ class SessionsController < Devise::SessionsController private + def require_no_authentication_without_flash + require_no_authentication + + if flash[:alert] == I18n.t('devise.failure.already_authenticated') + flash[:alert] = nil + end + end + def captcha_enabled? request.headers[CAPTCHA_HEADER] && Gitlab::Recaptcha.enabled? end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 88ec77426d5..f1dd040515f 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -53,6 +53,7 @@ class IssuableFinder assignee_username author_id author_username + label_name milestone_title my_reaction_emoji search diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index a07c3f90a91..76300e791e6 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -13,9 +13,7 @@ module LabelsHelper # Link to a Label # - # label - Label object to link to - # subject - Project/Group object which will be used as the context for the - # label's link. If omitted, defaults to the label's own group/project. + # label - LabelPresenter object to link to # type - The type of item the link will point to (:issue or # :merge_request). If omitted, defaults to :issue. # block - An optional block that will be passed to `link_to`, forming the @@ -40,8 +38,8 @@ module LabelsHelper # link_to_label(label) { "My Custom Label Text" } # # Returns a String - def link_to_label(label, subject: nil, type: :issue, tooltip: true, css_class: nil, &block) - link = label_filter_path(subject || label.subject, label, type: type) + def link_to_label(label, type: :issue, tooltip: true, css_class: nil, &block) + link = label.filter_path(type: type) if block_given? link_to link, class: css_class, &block @@ -50,34 +48,6 @@ module LabelsHelper end end - def label_filter_path(subject, label, type: :issue) - case subject - when Group - send("#{type.to_s.pluralize}_group_path", # rubocop:disable GitlabSecurity/PublicSend - subject, - label_name: [label.name]) - when Project - send("namespace_project_#{type.to_s.pluralize}_path", # rubocop:disable GitlabSecurity/PublicSend - subject.namespace, - subject, - label_name: [label.name]) - end - end - - def edit_label_path(label) - case label - when GroupLabel then edit_group_label_path(label.group, label) - when ProjectLabel then edit_project_label_path(label.project, label) - end - end - - def destroy_label_path(label) - case label - when GroupLabel then group_label_path(label.group, label) - when ProjectLabel then project_label_path(label.project, label) - end - end - def render_label(label, tooltip: true, link: nil, css: nil) # if scoped label is used then EE wraps label tag with scoped label # doc link @@ -168,10 +138,6 @@ module LabelsHelper end end - def can_subscribe_to_label_in_different_levels?(label) - defined?(@project) && label.is_a?(GroupLabel) - end - def label_subscription_status(label, project) return 'group-level' if label.subscribed?(current_user) return 'project-level' if label.subscribed?(current_user, project) @@ -241,8 +207,8 @@ module LabelsHelper "#{action} at #{level} level" end - def labels_sorted_by_title(labels) - labels.sort_by(&:title) + def presented_labels_sorted_by_title(labels, subject) + labels.sort_by(&:title).map { |label| label.present(issuable_subject: subject) } end def label_dropdown_data(project, opts = {}) @@ -276,6 +242,10 @@ module LabelsHelper klass.new(hash.slice(:color, :description, :title, :group_id, :project_id)) end + def issuable_types + ['issues', 'merge requests'] + end + # Required for Banzai::Filter::LabelReferenceFilter module_function :render_colored_label, :text_color_for_bg, :escape_once, :label_tooltip_title end diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb index be4fc2531ae..ad77f99fe44 100644 --- a/app/helpers/markup_helper.rb +++ b/app/helpers/markup_helper.rb @@ -83,7 +83,8 @@ module MarkupHelper text = sanitize( text, tags: tags, - attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-src', 'data-name', 'data-unicode-version'] + attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + + %w(style data-src data-name data-unicode-version data-iid data-project-path data-mr-title) ) # since <img> tags are stripped, this can leave empty <a> tags hanging around diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 5318ab4ddef..a7ce7667916 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -93,4 +93,11 @@ module NotificationsHelper s_(event.to_s.humanize) end end + + def notification_setting_icon(notification_setting) + sprite_icon( + notification_setting.disabled? ? "notifications-off" : "notifications", + css_class: "icon notifications-icon js-notifications-icon" + ) + end end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 5cf9bb4979a..e5236051118 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -15,6 +15,7 @@ module Ci include Gitlab::Utils::StrongMemoize include Deployable include HasRef + include UpdateProjectStatistics BuildArchivedError = Class.new(StandardError) @@ -157,8 +158,7 @@ module Ci run_after_commit { BuildHooksWorker.perform_async(build.id) } end - after_save :update_project_statistics_after_save, if: :artifacts_size_changed? - after_destroy :update_project_statistics_after_destroy, unless: :project_destroyed? + update_project_statistics stat: :build_artifacts_size, attribute: :artifacts_size class << self # This is needed for url_for to work, @@ -847,21 +847,5 @@ module Ci pipeline.config_processor.build_attributes(name) end - - def update_project_statistics_after_save - update_project_statistics(read_attribute(:artifacts_size).to_i - artifacts_size_was.to_i) - end - - def update_project_statistics_after_destroy - update_project_statistics(-artifacts_size) - end - - def update_project_statistics(difference) - ProjectStatistics.increment_statistic(project_id, :build_artifacts_size, difference) - end - - def project_destroyed? - project.pending_delete? - end end end diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index 9695d49d18b..f9cf398556d 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -4,6 +4,7 @@ module Ci class JobArtifact < ApplicationRecord include AfterCommitQueue include ObjectStorage::BackgroundMove + include UpdateProjectStatistics extend Gitlab::Ci::Model NotSupportedAdapterError = Class.new(StandardError) @@ -52,10 +53,10 @@ module Ci validates :file_format, presence: true, unless: :trace?, on: :create validate :valid_file_format?, unless: :trace?, on: :create before_save :set_size, if: :file_changed? - after_save :update_project_statistics_after_save, if: :size_changed? - after_destroy :update_project_statistics_after_destroy, unless: :project_destroyed? - after_save :update_file_store, if: :file_changed? + update_project_statistics stat: :build_artifacts_size + + after_save :update_file_store, if: :saved_change_to_file? scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) } @@ -176,18 +177,6 @@ module Ci self.size = file.size end - def update_project_statistics_after_save - update_project_statistics(size.to_i - size_was.to_i) - end - - def update_project_statistics_after_destroy - update_project_statistics(-self.size.to_i) - end - - def update_project_statistics(difference) - ProjectStatistics.increment_statistic(project_id, :build_artifacts_size, difference) - end - def project_destroyed? # Use job.project to avoid extra DB query for project job.project.pending_delete? diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index b8edaf82c3d..bbd21eb0e78 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -642,6 +642,7 @@ module Ci variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s) variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s) variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s) + variables.append(key: 'CI_COMMIT_REF_PROTECTED', value: (!!protected_ref?).to_s) if merge_request_event? && merge_request variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', value: source_sha.to_s) diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 8cb81bfcbe4..06ab0855e40 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ApplicationRecord - VERSION = '0.3.0'.freeze + VERSION = '0.4.0'.freeze self.table_name = 'clusters_applications_runners' diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 2ae141190a8..a806367a49b 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -230,7 +230,7 @@ module Clusters end def update_kubernetes_namespace - return unless namespace_changed? + return unless saved_change_to_namespace? run_after_commit do ClusterConfigureWorker.perform_async(cluster_id) diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 28ea51d6769..f90cd1ea690 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -15,7 +15,7 @@ module CacheMarkdownField # Increment this number every time the renderer changes its output CACHE_COMMONMARK_VERSION_START = 10 - CACHE_COMMONMARK_VERSION = 15 + CACHE_COMMONMARK_VERSION = 16 # changes to these attributes cause the cache to be invalidates INVALIDATED_BY = %w[author project].freeze diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 3232c51bfbd..775aaa44e5b 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -128,10 +128,6 @@ module Issuable assignees.count > 1 end - def milestone_available? - project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group) - end - private def milestone_is_valid @@ -277,6 +273,10 @@ module Issuable end end + def milestone_available? + project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group) + end + def assignee_or_author?(user) author_id == user.id || assignees.exists?(user.id) end diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index 498996f4f80..1cbe27ad03a 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -13,8 +13,8 @@ module Storage raise Gitlab::UpdatePathError.new("Namespace #{name} (#{id}) cannot be moved because at least one project (e.g. #{proj_with_tags.name} (#{proj_with_tags.id})) has tags in container registry") end - parent_was = if parent_changed? && parent_id_was.present? - Namespace.find(parent_id_was) # raise NotFound early if needed + parent_was = if parent_changed? && parent_id_before_last_save.present? + Namespace.find(parent_id_before_last_save) # raise NotFound early if needed end move_repositories @@ -104,11 +104,5 @@ module Storage end end end - - def remove_legacy_exports! - legacy_export_path = File.join(Gitlab::ImportExport.storage_path, full_path_was) - - FileUtils.rm_rf(legacy_export_path) - end end end diff --git a/app/models/concerns/update_project_statistics.rb b/app/models/concerns/update_project_statistics.rb new file mode 100644 index 00000000000..67e1f0ec930 --- /dev/null +++ b/app/models/concerns/update_project_statistics.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# This module is providing helpers for updating `ProjectStatistics` with `after_save` and `before_destroy` hooks. +# +# It deals with `ProjectStatistics.increment_statistic` making sure not to update statistics on a cascade delete from the +# project, and keeping track of value deltas on each save. It updates the DB only when a change is needed. +# +# How to use +# - Invoke `update_project_statistics stat: :a_project_statistics_column, attribute: :an_attr_to_track` in a model class body. +# +# Expectation +# - `attribute` must be an ActiveRecord attribute +# - The model must implement `project` and `project_id`. i.e. direct Project relationship or delegation +module UpdateProjectStatistics + extend ActiveSupport::Concern + + class_methods do + attr_reader :statistic_name, :statistic_attribute + + # Configure the model to update +stat+ on ProjectStatistics when +attribute+ changes + # + # +stat+:: a column of ProjectStatistics to update + # +attribute+:: an attribute of the current model, default to +:size+ + def update_project_statistics(stat:, attribute: :size) + @statistic_name = stat + @statistic_attribute = attribute + + after_save(:update_project_statistics_after_save, if: :update_project_statistics_attribute_changed?) + after_destroy(:update_project_statistics_after_destroy, unless: :project_destroyed?) + end + private :update_project_statistics + end + + included do + private + + def project_destroyed? + project.pending_delete? + end + + def update_project_statistics_attribute_changed? + saved_change_to_attribute?(self.class.statistic_attribute) + end + + def update_project_statistics_after_save + attr = self.class.statistic_attribute + delta = read_attribute(attr).to_i - attribute_before_last_save(attr).to_i + + update_project_statistics(delta) + end + + def update_project_statistics_after_destroy + update_project_statistics(-read_attribute(self.class.statistic_attribute).to_i) + end + + def update_project_statistics(delta) + ProjectStatistics.increment_statistic(project_id, self.class.statistic_name, delta) + end + end +end diff --git a/app/models/global_label.rb b/app/models/global_label.rb index 572cb12b26a..7c020dd3b3d 100644 --- a/app/models/global_label.rb +++ b/app/models/global_label.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class GlobalLabel + include Presentable + attr_accessor :title, :labels alias_attribute :name, :title @@ -23,4 +25,8 @@ class GlobalLabel @labels = labels @first_label = labels.find { |lbl| lbl.description.present? } || labels.first end + + def present(attributes) + super(attributes.merge(presenter_class: ::LabelPresenter)) + end end diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index fd17745b035..59f5a7703e2 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -8,7 +8,9 @@ class GlobalMilestone attr_reader :milestone alias_attribute :name, :title - delegate :title, :state, :due_date, :start_date, :participants, :project, :group, :expires_at, :closed?, :iid, :group_milestone?, :safe_title, :milestoneish_id, to: :milestone + delegate :title, :state, :due_date, :start_date, :participants, :project, + :group, :expires_at, :closed?, :iid, :group_milestone?, :safe_title, + :milestoneish_id, :parent, to: :milestone def to_hash { diff --git a/app/models/group.rb b/app/models/group.rb index 8bc9b75f0a9..53331a19776 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -61,7 +61,7 @@ class Group < Namespace after_create :post_create_hook after_destroy :post_destroy_hook after_save :update_two_factor_requirement - after_update :path_changed_hook, if: :path_changed? + after_update :path_changed_hook, if: :saved_change_to_path? class << self def sort_by_attribute(method) @@ -411,7 +411,7 @@ class Group < Namespace private def update_two_factor_requirement - return unless require_two_factor_authentication_changed? || two_factor_grace_period_changed? + return unless saved_change_to_require_two_factor_authentication? || saved_change_to_two_factor_grace_period? users.find_each(&:update_two_factor_requirement) end diff --git a/app/models/internal_id.rb b/app/models/internal_id.rb index 401b94d36e5..237401899db 100644 --- a/app/models/internal_id.rb +++ b/app/models/internal_id.rb @@ -87,12 +87,16 @@ class InternalId < ApplicationRecord end def available? - @available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION # rubocop:disable Gitlab/PredicateMemoization + return true unless Rails.env.test? + + Gitlab::SafeRequestStore.fetch(:internal_ids_available_flag) do + ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION + end end # Flushes cached information about schema def reset_column_information - @available_flag = nil + Gitlab::SafeRequestStore[:internal_ids_available_flag] = nil super end end diff --git a/app/models/label.rb b/app/models/label.rb index c7fff0d393e..e9085e8bd25 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -8,6 +8,7 @@ class Label < ApplicationRecord include OptionallySearch include Sortable include FromUnion + include Presentable cache_markdown_field :description, pipeline: :single_line @@ -233,6 +234,10 @@ class Label < ApplicationRecord attributes end + def present(attributes) + super(attributes.merge(presenter_class: ::LabelPresenter)) + end + private def issues_count(user, params = {}) diff --git a/app/models/lfs_object.rb b/app/models/lfs_object.rb index e1aac691a64..5245dbc8d15 100644 --- a/app/models/lfs_object.rb +++ b/app/models/lfs_object.rb @@ -13,7 +13,7 @@ class LfsObject < ApplicationRecord mount_uploader :file, LfsObjectUploader - after_save :update_file_store, if: :file_changed? + after_save :update_file_store, if: :saved_change_to_file? def update_file_store # The file.object_store is set during `uploader.store!` diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 510f856087d..b266c61f002 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -55,7 +55,7 @@ class GroupMember < Member end def post_update_hook - if access_level_changed? + if saved_change_to_access_level? run_after_commit { notification_service.update_group_member(self) } end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 5372c6084f4..c64e2669b6a 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -111,7 +111,7 @@ class ProjectMember < Member end def post_update_hook - if access_level_changed? + if saved_change_to_access_level? run_after_commit { notification_service.update_project_member(self) } end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 251a7ff41f5..a5b62659b24 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -698,7 +698,7 @@ class MergeRequest < ApplicationRecord end def reload_diff_if_branch_changed - if (source_branch_changed? || target_branch_changed?) && + if (saved_change_to_source_branch? || saved_change_to_target_branch?) && (source_branch_head && target_branch_head) reload_diff end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index dea34e812ca..7228aab2c2e 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -50,13 +50,16 @@ class Namespace < ApplicationRecord validate :nesting_level_allowed + validates_associated :runners + delegate :name, to: :owner, allow_nil: true, prefix: true + delegate :avatar_url, to: :owner, allow_nil: true after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') } before_create :sync_share_with_group_lock_with_parent before_update :sync_share_with_group_lock_with_parent, if: :parent_changed? - after_update :force_share_with_group_lock_on_descendants, if: -> { share_with_group_lock_changed? && share_with_group_lock? } + after_update :force_share_with_group_lock_on_descendants, if: -> { saved_change_to_share_with_group_lock? && share_with_group_lock? } # Legacy Storage specific hooks @@ -149,6 +152,10 @@ class Namespace < ApplicationRecord type == 'Group' ? 'group' : 'user' end + def user? + kind == 'user' + end + def find_fork_of(project) return unless project.fork_network @@ -287,7 +294,7 @@ class Namespace < ApplicationRecord private def path_or_parent_changed? - path_changed? || parent_changed? + saved_change_to_path? || saved_change_to_parent_id? end def refresh_access_of_projects_invited_groups diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb index 82901ceec01..d73b2889f30 100644 --- a/app/models/pages_domain.rb +++ b/app/models/pages_domain.rb @@ -147,20 +147,20 @@ class PagesDomain < ApplicationRecord # rubocop: enable CodeReuse/ServiceClass def pages_config_changed? - project_id_changed? || - domain_changed? || - certificate_changed? || - key_changed? || + saved_change_to_project_id? || + saved_change_to_domain? || + saved_change_to_certificate? || + saved_change_to_key? || became_enabled? || became_disabled? end def became_enabled? - enabled_until.present? && !enabled_until_was.present? + enabled_until.present? && !enabled_until_before_last_save.present? end def became_disabled? - !enabled_until.present? && enabled_until_was.present? + !enabled_until.present? && enabled_until_before_last_save.present? end def validate_matching_key diff --git a/app/models/pool_repository.rb b/app/models/pool_repository.rb index 7934118761e..50eed7344bd 100644 --- a/app/models/pool_repository.rb +++ b/app/models/pool_repository.rb @@ -7,7 +7,7 @@ class PoolRepository < ApplicationRecord include Shardable include AfterCommitQueue - has_one :source_project, class_name: 'Project' + belongs_to :source_project, class_name: 'Project' validates :source_project, presence: true has_many :member_projects, class_name: 'Project' @@ -99,7 +99,8 @@ class PoolRepository < ApplicationRecord end def inspect - "#<#{self.class.name} id:#{id} state:#{state} disk_path:#{disk_path} source_project: #{source_project.full_path}>" + source = source_project ? source_project.full_path : 'nil' + "#<#{self.class.name} id:#{id} state:#{state} disk_path:#{disk_path} source_project: #{source}>" end private diff --git a/app/models/project.rb b/app/models/project.rb index 2fb6f5cb6a7..626ff9e1389 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -90,7 +90,7 @@ class Project < ApplicationRecord before_save :ensure_runners_token - after_save :update_project_statistics, if: :namespace_id_changed? + after_save :update_project_statistics, if: :saved_change_to_namespace_id? after_save :create_import_state, if: ->(project) { project.import? && project.import_state.nil? } @@ -116,7 +116,7 @@ class Project < ApplicationRecord after_initialize :use_hashed_storage after_create :check_repository_absence! after_create :ensure_storage_path_exists - after_save :ensure_storage_path_exists, if: :namespace_id_changed? + after_save :ensure_storage_path_exists, if: :saved_change_to_namespace_id? acts_as_ordered_taggable @@ -1430,7 +1430,7 @@ class Project < ApplicationRecord # update visibility_level of forks def update_forks_visibility_level - return unless visibility_level < visibility_level_was + return unless visibility_level < visibility_level_before_last_save forks.each do |forked_project| if forked_project.visibility_level > visibility_level @@ -2131,13 +2131,11 @@ class Project < ApplicationRecord end def create_new_pool_repository - pool = begin - create_pool_repository!(shard: Shard.by_name(repository_storage), source_project: self) - rescue ActiveRecord::RecordNotUnique - pool_repository(true) - end + pool = PoolRepository.safe_find_or_create_by!(shard: Shard.by_name(repository_storage), source_project: self) + update!(pool_repository: pool) pool.schedule unless pool.scheduled? + pool end diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb index b2fd5394a03..535f772b6a1 100644 --- a/app/models/remote_mirror.rb +++ b/app/models/remote_mirror.rb @@ -248,7 +248,7 @@ class RemoteMirror < ApplicationRecord # Before adding a new remote we have to delete the data from # the previous remote name - prev_remote_name = remote_name_was || fallback_remote_name + prev_remote_name = remote_name_before_last_save || fallback_remote_name run_after_commit do project.repository.async_remove_remote(prev_remote_name) end diff --git a/app/models/route.rb b/app/models/route.rb index 7e3db54d4fe..91ea2966013 100644 --- a/app/models/route.rb +++ b/app/models/route.rb @@ -14,26 +14,26 @@ class Route < ApplicationRecord before_validation :delete_conflicting_orphaned_routes after_create :delete_conflicting_redirects - after_update :delete_conflicting_redirects, if: :path_changed? + after_update :delete_conflicting_redirects, if: :saved_change_to_path? after_update :create_redirect_for_old_path after_update :rename_descendants scope :inside_path, -> (path) { where('routes.path LIKE ?', "#{sanitize_sql_like(path)}/%") } def rename_descendants - return unless path_changed? || name_changed? + return unless saved_change_to_path? || saved_change_to_name? - descendant_routes = self.class.inside_path(path_was) + descendant_routes = self.class.inside_path(path_before_last_save) descendant_routes.each do |route| attributes = {} - if path_changed? && route.path.present? - attributes[:path] = route.path.sub(path_was, path) + if saved_change_to_path? && route.path.present? + attributes[:path] = route.path.sub(path_before_last_save, path) end - if name_changed? && name_was.present? && route.name.present? - attributes[:name] = route.name.sub(name_was, name) + if saved_change_to_name? && name_before_last_save.present? && route.name.present? + attributes[:name] = route.name.sub(name_before_last_save, name) end if attributes.present? @@ -65,7 +65,7 @@ class Route < ApplicationRecord private def create_redirect_for_old_path - create_redirect(path_was) if path_changed? + create_redirect(path_before_last_save) if saved_change_to_path? end def delete_conflicting_orphaned_routes diff --git a/app/models/user.rb b/app/models/user.rb index 551eb58a4de..43039f3760e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -194,7 +194,7 @@ class User < ApplicationRecord before_validation :ensure_namespace_correct before_save :ensure_namespace_correct # in case validation is skipped after_validation :set_username_errors - after_update :username_changed_hook, if: :username_changed? + after_update :username_changed_hook, if: :saved_change_to_username? after_destroy :post_destroy_hook after_destroy :remove_key_cache after_commit(on: :update) do diff --git a/app/presenters/label_presenter.rb b/app/presenters/label_presenter.rb new file mode 100644 index 00000000000..5227ef353c3 --- /dev/null +++ b/app/presenters/label_presenter.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class LabelPresenter < Gitlab::View::Presenter::Delegated + presents :label + + def edit_path + case label + when GroupLabel then edit_group_label_path(label.group, label) + when ProjectLabel then edit_project_label_path(label.project, label) + end + end + + def destroy_path + case label + when GroupLabel then group_label_path(label.group, label) + when ProjectLabel then project_label_path(label.project, label) + end + end + + def filter_path(type: :issue) + case context_subject + when Group + send("#{type.to_s.pluralize}_group_path", # rubocop:disable GitlabSecurity/PublicSend + context_subject, + label_name: [label.name]) + when Project + send("namespace_project_#{type.to_s.pluralize}_path", # rubocop:disable GitlabSecurity/PublicSend + context_subject.namespace, + context_subject, + label_name: [label.name]) + end + end + + def can_subscribe_to_label_in_different_levels? + issuable_subject.is_a?(Project) && label.is_a?(GroupLabel) + end + + private + + def context_subject + issuable_subject || label.try(:subject) + end +end diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb index 161eebcfb3f..9afbaf035c7 100644 --- a/app/presenters/project_presenter.rb +++ b/app/presenters/project_presenter.rb @@ -37,7 +37,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout), kubernetes_cluster_anchor_data, gitlab_ci_anchor_data - ].compact.reject(&:is_link) + ].compact.reject(&:is_link).sort_by.with_index { |item, idx| [item.class_modifier ? 0 : 1, idx] } end def empty_repo_statistics_anchors @@ -259,7 +259,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout if auto_devops_enabled? AnchorData.new(false, - statistic_icon('doc-text') + _('Auto DevOps enabled'), + statistic_icon('settings') + _('Auto DevOps enabled'), project_settings_ci_cd_path(project, anchor: 'autodevops-settings'), 'default') else diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 3adf8a0c1a1..3f0aedfbfb2 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,7 +3,7 @@ require 'securerandom' # Compare 2 refs for one repo or between repositories -# and return Gitlab::Git::Compare object that responds to commits and diffs +# and return Compare object that responds to commits and diffs class CompareService attr_reader :start_project, :start_ref_name @@ -15,7 +15,7 @@ class CompareService def execute(target_project, target_ref, base_sha: nil, straight: false) raw_compare = target_project.repository.compare_source_branch(target_ref, start_project.repository, start_ref_name, straight: straight) - return unless raw_compare + return unless raw_compare && raw_compare.base && raw_compare.head Compare.new(raw_compare, target_project, diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb index 4c3ac19f754..fd41ce54486 100644 --- a/app/services/delete_branch_service.rb +++ b/app/services/delete_branch_service.rb @@ -6,27 +6,25 @@ class DeleteBranchService < BaseService branch = repository.find_branch(branch_name) unless current_user.can?(:push_code, project) - return error('You dont have push access to repo', 405) + return ServiceResponse.error( + message: 'You dont have push access to repo', + http_status: 405) end unless branch - return error('No such branch', 404) + return ServiceResponse.error( + message: 'No such branch', + http_status: 404) end if repository.rm_branch(current_user, branch_name) - success('Branch was deleted') + ServiceResponse.success(message: 'Branch was deleted') else - error('Failed to remove branch') + ServiceResponse.error( + message: 'Failed to remove branch', + http_status: 400) end rescue Gitlab::Git::PreReceiveError => ex - error(ex.message) - end - - def error(message, return_code = 400) - super(message).merge(return_code: return_code) - end - - def success(message) - super().merge(message: message) + ServiceResponse.error(message: ex.message, http_status: 400) end end diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb index 633a263af7b..a2f36d2bd1b 100644 --- a/app/services/projects/propagate_service_template.rb +++ b/app/services/projects/propagate_service_template.rb @@ -80,7 +80,7 @@ module Projects value = value.is_a?(Hash) ? value.to_json : value service_hash[ActiveRecord::Base.connection.quote_column_name(key)] = - ActiveRecord::Base.sanitize(value) + ActiveRecord::Base.connection.quote(value) end end end diff --git a/app/services/service_response.rb b/app/services/service_response.rb new file mode 100644 index 00000000000..1de30e68d87 --- /dev/null +++ b/app/services/service_response.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class ServiceResponse + def self.success(message: nil) + new(status: :success, message: message) + end + + def self.error(message:, http_status: nil) + new(status: :error, message: message, http_status: http_status) + end + + attr_reader :status, :message, :http_status + + def initialize(status:, message: nil, http_status: nil) + self.status = status + self.message = message + self.http_status = http_status + end + + def success? + status == :success + end + + def error? + status == :error + end + + private + + attr_writer :status, :message, :http_status +end diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml index dbb7224f5f9..6d934654c5d 100644 --- a/app/views/admin/labels/_label.html.haml +++ b/app/views/admin/labels/_label.html.haml @@ -1,5 +1,5 @@ %li.label-list-item{ id: dom_id(label) } - = render "shared/label_row", label: label + = render "shared/label_row", label: label.present(issuable_subject: nil) .label-actions-list = link_to edit_admin_label_path(label), class: 'btn btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do = sprite_icon('pencil') diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml index 5cf3193bc62..a8358704b03 100644 --- a/app/views/groups/labels/index.html.haml +++ b/app/views/groups/labels/index.html.haml @@ -1,7 +1,6 @@ - @no_container = true -- page_title "Labels" +- page_title 'Labels' - can_admin_label = can?(current_user, :admin_label, @group) -- issuables = ['issues', 'merge requests'] - search = params[:search] - subscribed = params[:subscribed] - labels_or_filters = @labels.exists? || search.present? || subscribed.present? @@ -14,11 +13,11 @@ .labels-container.prepend-top-5 - if @labels.any? .text-muted - = _('Labels can be applied to %{features}. Group labels are available for any project within the group.') % { features: issuables.to_sentence } + = _('Labels can be applied to %{features}. Group labels are available for any project within the group.') % { features: issuable_types.to_sentence } .other-labels %h5= _('Labels') %ul.content-list.manage-labels-list.js-other-labels - = render partial: 'shared/label', subject: @group, collection: @labels, as: :label, locals: { use_label_priority: false } + = render partial: 'shared/label', collection: @labels, as: :label, locals: { use_label_priority: false, subject: @group } = paginate @labels, theme: 'gitlab' - elsif search.present? .nothing-here-block diff --git a/app/views/import/gitea/new.html.haml b/app/views/import/gitea/new.html.haml index a88b04eccbb..c4670869c93 100644 --- a/app/views/import/gitea/new.html.haml +++ b/app/views/import/gitea/new.html.haml @@ -2,18 +2,18 @@ - header_title _("Projects"), root_path %h3.page-title - = custom_icon('go_logo') + = custom_icon('gitea_logo') = _('Import Projects from Gitea') %p - - link_to_personal_token = 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://docs.gitea.io/en-us/api-usage/#authentication-via-the-api') = _('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' .col-sm-4 - = text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control' + = text_field_tag :gitea_host_url, nil, placeholder: 'https://gitea.com', class: 'form-control' .form-group.row = label_tag :personal_access_token, _('Personal Access Token'), class: 'col-form-label col-sm-2' .col-sm-4 diff --git a/app/views/import/gitea/status.html.haml b/app/views/import/gitea/status.html.haml index 88244fde16b..ef0693e73c3 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 %h3.page-title - = custom_icon('go_logo') + = custom_icon('gitea_logo') = _('Import Projects from Gitea') = render 'import/githubish_status', provider: 'gitea' diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml index 2b425f18389..9c854369c93 100644 --- a/app/views/projects/_import_project_pane.html.haml +++ b/app/views/projects/_import_project_pane.html.haml @@ -50,7 +50,7 @@ - if gitea_import_enabled? %div = link_to new_import_gitea_path, class: 'btn import_gitea', data: { track_label: "#{track_label}", track_event: "click_button", track_property: "gitea" } do - = custom_icon('go_logo') + = custom_icon('gitea_logo') Gitea - if git_import_enabled? diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml index e8a89b8c6fc..b37dba8b35d 100644 --- a/app/views/projects/forks/error.html.haml +++ b/app/views/projects/forks/error.html.haml @@ -1,24 +1,20 @@ -- page_title "Fork project" +- page_title _("Fork project") - if @forked_project && !@forked_project.saved? .alert.alert-danger.alert-block %h4 = sprite_icon('fork', size: 16) - Fork Error! + = _("Fork Error!") %p - You tried to fork - = link_to_project @project - but it failed for the following reason: - + = _("You tried to fork %{link_to_the_project} but it failed for the following reason:").html_safe % { link_to_the_project: link_to_project(@project) } - if @forked_project && @forked_project.errors.any? %p – - error = @forked_project.errors.full_messages.first - if error.include?("already been taken") - Name has already been taken + = _("Name has already been taken") - else = error %p - = link_to new_project_fork_path(@project), title: "Fork", class: "btn" do - Try to fork again + = link_to _("Try to fork again"), new_project_fork_path(@project), title: _("Fork"), class: "btn" diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml index c63c34c4ebb..0397a7034c7 100644 --- a/app/views/projects/forks/index.html.haml +++ b/app/views/projects/forks/index.html.haml @@ -5,12 +5,12 @@ .nav-controls = form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| - = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short', + = search_field_tag :filter_projects, nil, placeholder: _('Search forks'), class: 'projects-list-filter project-filter-form-field form-control input-short', spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } .dropdown %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' } - %span.light sort: + %span.light= _("sort:") - if @sort.present? = sort_options_hash[@sort] - else @@ -30,13 +30,12 @@ - if current_user && can?(current_user, :fork_project, @project) - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 - = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-success' do + = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn btn-success' do = sprite_icon('fork', size: 12) - %span Fork + %span= _('Fork') - else - = link_to new_project_fork_path(@project), title: "Fork project", class: 'btn btn-success' do + = link_to new_project_fork_path(@project), title: _("Fork project"), class: 'btn btn-success' do = sprite_icon('fork', size: 12) - %span Fork - + %span= _('Fork') = render 'projects', projects: @forks diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index a603b1024eb..bf03353a565 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -1,13 +1,11 @@ -- page_title "Fork project" +- page_title _("Fork project") .row.prepend-top-default .col-lg-3 %h4.prepend-top-0 - Fork project + = _("Fork project") %p - A fork is a copy of a project. - %br - Forking a repository allows you to make changes without affecting the original project. + = _("A fork is a copy of a project.<br />Forking a repository allows you to make changes without affecting the original project.").html_safe .col-lg-9 - if @namespaces.present? .fork-thumbnail-container.js-fork-content @@ -17,13 +15,13 @@ = render 'fork_button', namespace: namespace - else %strong - No available namespaces to fork the project. + = _("No available namespaces to fork the project.") %p.prepend-top-default - You must have permission to create a project in a namespace before forking. + = _("You must have permission to create a project in a namespace before forking.") .save-project-loader.hide.js-fork-content %h2.text-center = icon('spinner spin') - Forking repository + = _("Forking repository") %p.text-center - Please wait a moment, this page will automatically refresh when ready. + = _("Please wait a moment, this page will automatically refresh when ready.") diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml index 377b2a6d8d9..945d1b00b08 100644 --- a/app/views/projects/issues/_issue.html.haml +++ b/app/views/projects/issues/_issue.html.haml @@ -36,8 +36,8 @@ = issue.due_date.to_s(:medium) - if issue.labels.any? - - labels_sorted_by_title(issue.labels).each do |label| - = link_to_label(label, subject: issue.project, css_class: 'label-link') + - presented_labels_sorted_by_title(issue.labels, issue.project).each do |label| + = link_to_label(label, css_class: 'label-link') .issuable-meta %ul.controls diff --git a/app/views/projects/issues/new.html.haml b/app/views/projects/issues/new.html.haml index 9a081a42b6f..c6ff0d50ef4 100644 --- a/app/views/projects/issues/new.html.haml +++ b/app/views/projects/issues/new.html.haml @@ -1,9 +1,9 @@ -- add_to_breadcrumbs "Issues", project_issues_path(@project) -- breadcrumb_title "New" -- page_title "New Issue" +- add_to_breadcrumbs _("Issues"), project_issues_path(@project) +- breadcrumb_title _("New") +- page_title _("New Issue") %h3.page-title - New Issue + _("New Issue") %hr = render "form" diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 4bf1d8702af..0bf664d5b66 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,7 +1,7 @@ - @content_class = "limit-container-width" unless fluid_layout -- add_to_breadcrumbs "Issues", project_issues_path(@project) +- add_to_breadcrumbs _("Issues"), project_issues_path(@project) - breadcrumb_title @issue.to_reference -- page_title "#{@issue.title} (#{@issue.to_reference})", "Issues" +- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues") - page_description @issue.description - page_card_attributes @issue.card_attributes @@ -77,6 +77,8 @@ = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago') + = render_if_exists 'projects/issues/related_issues' + #js-related-merge-requests{ data: { endpoint: expose_url(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: @issue.iid)), project_namespace: @project.namespace.path, project_path: @project.path } } - if can?(current_user, :download_code, @project) diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index bb7c297ba1f..511d7a82d1b 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -11,31 +11,30 @@ = render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label .labels-container.prepend-top-10 - - if can_admin_label - - if search.blank? - %p.text-muted - = _('Labels can be applied to issues and merge requests.') - %br - = _('Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.') - -# Only show it in the first page - - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1') - .prioritized-labels{ class: ('hide' if hide) } - %h5.prepend-top-10= _('Prioritized Labels') - .content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_project_labels_path(@project) } - #js-priority-labels-empty-state.priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty? && search.blank?}" } - = render 'shared/empty_states/priority_labels' - - if @prioritized_labels.present? - = render partial: 'shared/label', subject: @project, collection: @prioritized_labels, as: :label, locals: { force_priority: true } - - elsif search.present? - .nothing-here-block - = _('No prioritised labels with such name or description') + - if can_admin_label && search.blank? + %p.text-muted + = _('Labels can be applied to issues and merge requests.') + %br + = _('Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.') + + -# Only show it in the first page + - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1') + .prioritized-labels{ class: [('hide' if hide), ('is-not-draggable' unless can_admin_label)] } + %h5.prepend-top-10= _('Prioritized Labels') + .content-list.manage-labels-list.js-prioritized-labels{ data: { url: set_priorities_project_labels_path(@project), sortable: can_admin_label } } + #js-priority-labels-empty-state.priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty? && search.blank?}" } + = render 'shared/empty_states/priority_labels' + - if @prioritized_labels.present? + = render partial: 'shared/label', collection: @prioritized_labels, as: :label, locals: { force_priority: true, subject: @project } + - elsif search.present? + .nothing-here-block + = _('No prioritised labels with such name or description') - if @labels.present? .other-labels - - if can_admin_label - %h5{ class: ('hide' if hide) }= _('Other Labels') + %h5{ class: ('hide' if hide) }= _('Other Labels') .content-list.manage-labels-list.js-other-labels - = render partial: 'shared/label', subject: @project, collection: @labels, as: :label + = render partial: 'shared/label', collection: @labels, as: :label, locals: { subject: @project } = paginate @labels, theme: 'gitlab' - elsif search.present? .other-labels diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 47c8e3d73f5..67e5e4ca62d 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -34,8 +34,8 @@ = merge_request.target_branch - if merge_request.labels.any? - - labels_sorted_by_title(merge_request.labels).each do |label| - = link_to_label(label, subject: merge_request.project, type: :merge_request, css_class: 'label-link') + - presented_labels_sorted_by_title(merge_request.labels, merge_request.project).each do |label| + = link_to_label(label, type: :merge_request, css_class: 'label-link') .issuable-meta %ul.controls diff --git a/app/views/shared/_delete_label_modal.html.haml b/app/views/shared/_delete_label_modal.html.haml index dbd3bbb43af..6bd8cadd7d9 100644 --- a/app/views/shared/_delete_label_modal.html.haml +++ b/app/views/shared/_delete_label_modal.html.haml @@ -9,13 +9,13 @@ .modal-body %p %strong= label.name - %span will be permanently deleted from #{label.is_a?(ProjectLabel)? label.project.name : label.group.name}. This cannot be undone. + %span will be permanently deleted from #{label.subject.name}. This cannot be undone. .modal-footer %a{ href: '#', data: { dismiss: 'modal' }, class: 'btn btn-default' } Cancel = link_to 'Delete label', - destroy_label_path(label), + label.destroy_path, title: 'Delete', method: :delete, class: 'btn btn-remove' diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml index 21ea188d7b3..2b4a24a001f 100644 --- a/app/views/shared/_label.html.haml +++ b/app/views/shared/_label.html.haml @@ -1,13 +1,13 @@ +- label = label.present(issuable_subject: local_assigns[:subject]) - label_css_id = dom_id(label) - status = label_subscription_status(label, @project).inquiry if current_user -- subject = local_assigns[:subject] - use_label_priority = local_assigns.fetch(:use_label_priority, false) - force_priority = local_assigns.fetch(:force_priority, use_label_priority ? label.priority.present? : false) - toggle_subscription_path = toggle_subscription_label_path(label, @project) if current_user - tooltip_title = label_status_tooltip(label, status) if status %li.label-list-item{ id: label_css_id, data: { id: label.id } } - = render "shared/label_row", label: label, subject: subject, force_priority: force_priority + = render "shared/label_row", label: label, force_priority: force_priority %ul.label-actions-list - if @project %li.inline @@ -21,7 +21,7 @@ = sprite_icon('star') - if can?(current_user, :admin_label, label) %li.inline - = link_to edit_label_path(label), class: 'btn btn-transparent label-action edit has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do + = link_to label.edit_path, class: 'btn btn-transparent label-action edit has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do = sprite_icon('pencil') - if can?(current_user, :admin_label, label) %li.inline @@ -48,7 +48,7 @@ %button.text-danger.remove-row{ type: 'button' }= _('Delete') - if current_user %li.inline.label-subscription - - if can_subscribe_to_label_in_different_levels?(label) + - if label.can_subscribe_to_label_in_different_levels? %button.js-unsubscribe-button.label-subscribe-button.btn.btn-default{ class: ('hidden' if status.unsubscribed?), data: { url: toggle_subscription_path, toggle: 'tooltip' }, title: tooltip_title } %span= _('Unsubscribe') .dropdown.dropdown-group-label{ class: ('hidden' unless status.unsubscribed?) } diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml index 9d1648fbf70..a1aab2e6a08 100644 --- a/app/views/shared/_label_row.html.haml +++ b/app/views/shared/_label_row.html.haml @@ -1,4 +1,3 @@ -- subject = local_assigns[:subject] - force_priority = local_assigns.fetch(:force_priority, false) - subject_or_group_defined = defined?(@project) || defined?(@group) - show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues, project: @project) @@ -14,11 +13,11 @@ %ul.label-links - if show_label_issues_link %li.label-link-item.inline - = link_to_label(label, subject: subject) { 'Issues' } + = link_to_label(label) { 'Issues' } - if show_label_merge_requests_link · %li.label-link-item.inline - = link_to_label(label, subject: subject, type: :merge_request) { _('Merge requests') } + = link_to_label(label, type: :merge_request) { _('Merge requests') } - if force_priority · %li.label-link-item.priority-badge.js-priority-badge.inline.prepend-left-10 diff --git a/app/views/shared/_sidebar_toggle_button.html.haml b/app/views/shared/_sidebar_toggle_button.html.haml index 2530db986e0..aa428f9fe73 100644 --- a/app/views/shared/_sidebar_toggle_button.html.haml +++ b/app/views/shared/_sidebar_toggle_button.html.haml @@ -1,8 +1,8 @@ %a.toggle-sidebar-button.js-toggle-sidebar{ role: "button", type: "button", title: "Toggle sidebar" } = sprite_icon('angle-double-left', css_class: 'icon-angle-double-left') = sprite_icon('angle-double-right', css_class: 'icon-angle-double-right') - %span.collapse-text Collapse sidebar + %span.collapse-text _("Collapse sidebar") = button_tag class: 'close-nav-button', type: 'button' do = sprite_icon('close', size: 16) - %span.collapse-text Close sidebar + %span.collapse-text _("Close sidebar") diff --git a/app/views/shared/icons/_gitea_logo.svg.erb b/app/views/shared/icons/_gitea_logo.svg.erb new file mode 100644 index 00000000000..c8ddbc5535e --- /dev/null +++ b/app/views/shared/icons/_gitea_logo.svg.erb @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!-- Created with Inkscape (http://www.inkscape.org/) --><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="<%= size %>" height="<%= size %>" viewBox="0 0 135.46667 135.46667" version="1.1" id="svg8" sodipodi:docname="logo.svg" inkscape:version="0.92.1 r15371" inkscape:export-filename="" inkscape:export-xdpi="48.000004" inkscape:export-ydpi="48.000004" style="zoom: 1;"><defs id="defs2"></defs><sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:zoom="0.70710678" inkscape:cx="418.13805" inkscape:cy="177.57445" inkscape:document-units="mm" inkscape:current-layer="layer2" showgrid="false" units="px" width="256px" showguides="false" inkscape:window-width="1920" inkscape:window-height="1137" inkscape:window-x="1912" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:pagecheckerboard="false" inkscape:measure-start="283.373,243.952" inkscape:measure-end="290.267,236.527"><sodipodi:guide position="0,0" orientation="0,512" id="guide3699" inkscape:locked="false"></sodipodi:guide><sodipodi:guide position="135.46667,0" orientation="-512,0" id="guide3701" inkscape:locked="false"></sodipodi:guide><sodipodi:guide position="135.46667,135.46667" orientation="0,-512" id="guide3703" inkscape:locked="false"></sodipodi:guide><sodipodi:guide position="0,135.46667" orientation="512,0" id="guide3705" inkscape:locked="false"></sodipodi:guide></sodipodi:namedview><metadata id="metadata5"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"></dc:type><dc:title></dc:title></cc:Work></rdf:RDF></metadata><g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,-161.53334)" style="display:inline"><path d="M27.709937,195.15095 c-9.546573,-0.0272 -22.3392732,6.79805 -21.6317552,23.90397 c1.105534,26.72889 25.4565952,29.20839 35.1916502,29.42301 c1.068023,5.01357 12.521798,22.30563 21.001818,23.21667 h37.15277 c22.27763,-1.66785 38.9607,-75.75671 26.59321,-76.03825 c-46.781583,2.47691 -49.995146,2.13838 -88.599758,0 c-2.495053,-0.0266 -5.972321,-0.49474 -9.707935,-0.5054 z m2.491319,9.45886 c1.351378,13.69267 3.555849,21.70359 8.018216,33.94345 c-11.382872,-1.50473 -21.069822,-5.22443 -22.851515,-19.10984 c-0.950962,-7.4112 2.390428,-15.16769 14.833299,-14.83361 z " id="path3722" sodipodi:nodetypes="sscccccsccsc" inkscape:connector-curvature="0" style="fill:#000;fill-opacity:1;stroke:#000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"></path></g><g inkscape:groupmode="layer" id="layer2" inkscape:label="Layer 2" style="display:inline"><rect style="display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.24757317;stroke-opacity:1" id="rect4599" width="34.762054" height="34.762054" x="87.508659" y="18.291576" transform="rotate(25.914715)" ry="5.4825778"></rect><path style="display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26644793px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 79.804947,57.359056 3.241146,1.609954 V 35.255731 h -3.262698 z" id="path4525" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"></path></g><g inkscape:groupmode="layer" id="layer3" inkscape:label="Layer 3" style="display:inline"><g style="display:inline" id="g4539"><circle style="fill:#000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1" id="path4606" cy="90.077766" r="3.4745038" cx="49.064713" transform="rotate(-19.796137)"></circle><circle style="fill:#000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1" id="path4606-3" cy="102.1049" r="3.4745038" cx="36.810425" transform="rotate(-19.796137)"></circle><circle style="fill:#000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1" id="path4606-1" cy="111.43928" r="3.4745038" cx="46.484283" transform="rotate(-19.796137)"></circle><rect height="27.261492" style="fill:#000;fill-opacity:1;stroke:none;stroke-width:0.27444693;stroke-opacity:1" x="97.333458" y="18.061695" id="rect4629-8" width="2.6726954" transform="rotate(26.024158)"></rect><path d="M76.558096,68.116343 c12.97589,6.395378 13.012989,4.101862 4.890858,20.907244 " id="path4514" sodipodi:nodetypes="cc" inkscape:connector-curvature="0" style="fill:none;stroke:#000;stroke-width:2.68000007;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"></path></g></g></svg>
\ No newline at end of file diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index d4be7289a49..2c185549b24 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -106,7 +106,7 @@ .value.issuable-show-labels.dont-hide.hide-collapsed.qa-labels-block{ class: ("has-labels" if selected_labels.any?) } - if selected_labels.any? - selected_labels.each do |label_hash| - = render_label(label_from_hash(label_hash), link: sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label_hash[:title])) + = render_label(label_from_hash(label_hash).present(issuable_subject: nil), link: sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label_hash[:title])) - else %span.no-value = _('None') diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml index 5863f52aa78..ae3ab2adfd0 100644 --- a/app/views/shared/milestones/_issuable.html.haml +++ b/app/views/shared/milestones/_issuable.html.haml @@ -21,7 +21,7 @@ %span.issuable-number= issuable.to_reference - labels.each do |label| - = render_label(label, link: polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' })) + = render_label(label.present(issuable_subject: project), link: polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' })) %span.assignee-icon - assignees.each do |assignee| diff --git a/app/views/shared/milestones/_labels_tab.html.haml b/app/views/shared/milestones/_labels_tab.html.haml index 6b0640bd8cb..ecab037e378 100644 --- a/app/views/shared/milestones/_labels_tab.html.haml +++ b/app/views/shared/milestones/_labels_tab.html.haml @@ -2,7 +2,7 @@ - labels.each do |label| - options = { milestone_title: @milestone.title, label_name: label.title } - %li.is-not-draggable + %li.no-border %span.label-row %span.label-name = render_label(label, tooltip: false, link: milestones_label_path(options)) diff --git a/app/views/shared/notifications/_new_button.html.haml b/app/views/shared/notifications/_new_button.html.haml index 6d26dbebbc8..af8ab992f0e 100644 --- a/app/views/shared/notifications/_new_button.html.haml +++ b/app/views/shared/notifications/_new_button.html.haml @@ -10,14 +10,14 @@ %div{ class: ("btn-group" if notification_setting.custom?) } - if notification_setting.custom? %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }, class: "#{btn_class}", "aria-label" => _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }, data: { container: "body", placement: 'top', toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } } - = sprite_icon("notifications", css_class: "icon notifications-icon js-notifications-icon") + = notification_setting_icon(notification_setting) %span.js-notification-loading.fa.hidden %button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" }, class: "#{btn_class}" } = sprite_icon("arrow-down", css_class: "icon mr-0") .sr-only Toggle dropdown - else %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting - #{notification_title(notification_setting.level)}", class: "#{btn_class}", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", placement: 'top', toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } } - = sprite_icon("notifications", css_class: "icon notifications-icon js-notifications-icon") + = notification_setting_icon(notification_setting) %span.js-notification-loading.fa.hidden = sprite_icon("arrow-down", css_class: "icon") diff --git a/changelogs/unreleased/10029-env-item.yml b/changelogs/unreleased/10029-env-item.yml deleted file mode 100644 index f4e742d3e17..00000000000 --- a/changelogs/unreleased/10029-env-item.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes EE differences for environment_item.vue -merge_request: -author: -type: other diff --git a/changelogs/unreleased/10081-env-table.yml b/changelogs/unreleased/10081-env-table.yml deleted file mode 100644 index b27a1be8cca..00000000000 --- a/changelogs/unreleased/10081-env-table.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes EE differences for environments_table.vue -merge_request: -author: -type: other diff --git a/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml b/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml deleted file mode 100644 index 2360295b022..00000000000 --- a/changelogs/unreleased/10735-geo-gitlab-revision-can-return-not-consistent-results.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use a fixed git abbrev parameter when we fetch a git revision -merge_request: 26707 -author: -type: fixed diff --git a/changelogs/unreleased/11124-update-deployment-service-fails-if-project-is-nil.yml b/changelogs/unreleased/11124-update-deployment-service-fails-if-project-is-nil.yml deleted file mode 100644 index 355743f4cb0..00000000000 --- a/changelogs/unreleased/11124-update-deployment-service-fails-if-project-is-nil.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Always return the deployment in the UpdateDeploymentService#execute method -merge_request: 27322 -author: -type: fixed diff --git a/changelogs/unreleased/13784-validate-variables-for-masking.yml b/changelogs/unreleased/13784-validate-variables-for-masking.yml deleted file mode 100644 index e8e97fac3d2..00000000000 --- a/changelogs/unreleased/13784-validate-variables-for-masking.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add control for masking variable values in runner logs -merge_request: 26751 -author: -type: added diff --git a/changelogs/unreleased/24936-remove-type-from-review-app-name.yml b/changelogs/unreleased/24936-remove-type-from-review-app-name.yml deleted file mode 100644 index 639333264f6..00000000000 --- a/changelogs/unreleased/24936-remove-type-from-review-app-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove unnecessary folder prefix from environment name -merge_request: 25600 -author: -type: changed diff --git a/changelogs/unreleased/24971-align-emailvalidator-to-validate_email-gem-implementation.yml b/changelogs/unreleased/24971-align-emailvalidator-to-validate_email-gem-implementation.yml deleted file mode 100644 index 04dbc3a1d5a..00000000000 --- a/changelogs/unreleased/24971-align-emailvalidator-to-validate_email-gem-implementation.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Align EmailValidator to validate_email gem implementation -merge_request: 24971 -author: Horatiu Eugen Vlad -type: fixed diff --git a/changelogs/unreleased/25942-remove-fake-repository-path-response.yml b/changelogs/unreleased/25942-remove-fake-repository-path-response.yml deleted file mode 100644 index e1da28ab03c..00000000000 --- a/changelogs/unreleased/25942-remove-fake-repository-path-response.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove fake repository_path response -merge_request: 25942 -author: Fabio Papa -type: other diff --git a/changelogs/unreleased/27424-tklk-gitea-logo.yml b/changelogs/unreleased/27424-tklk-gitea-logo.yml new file mode 100644 index 00000000000..0d41bb39aad --- /dev/null +++ b/changelogs/unreleased/27424-tklk-gitea-logo.yml @@ -0,0 +1,5 @@ +--- +title: "Use official Gitea logo in importer" +merge_request: 27424 +author: Matti Ranta (@techknowlogick) +type: added
\ No newline at end of file diff --git a/changelogs/unreleased/29249-show-download-diff-even-when-merge-request-is-closed.yml b/changelogs/unreleased/29249-show-download-diff-even-when-merge-request-is-closed.yml deleted file mode 100644 index 5942860a20f..00000000000 --- a/changelogs/unreleased/29249-show-download-diff-even-when-merge-request-is-closed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show download diff links for closed MRs -merge_request: 26772 -author: -type: changed diff --git a/changelogs/unreleased/38564-cant-leave-subgroup.yml b/changelogs/unreleased/38564-cant-leave-subgroup.yml deleted file mode 100644 index a6397062343..00000000000 --- a/changelogs/unreleased/38564-cant-leave-subgroup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow removing last owner from subgroup if parent group has owners -merge_request: 26718 -author: -type: changed diff --git a/changelogs/unreleased/43263-git-push-option-to-create-mr.yml b/changelogs/unreleased/43263-git-push-option-to-create-mr.yml deleted file mode 100644 index d50c33da162..00000000000 --- a/changelogs/unreleased/43263-git-push-option-to-create-mr.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow merge requests to be created via git push options -merge_request: 26752 -author: -type: added diff --git a/changelogs/unreleased/43297-authorized-application-count.yml b/changelogs/unreleased/43297-authorized-application-count.yml deleted file mode 100644 index d22e155fb14..00000000000 --- a/changelogs/unreleased/43297-authorized-application-count.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix authorized application count -merge_request: 25715 -author: moyuru -type: fixed diff --git a/changelogs/unreleased/46787-create-project-label-window-is-cut-off-at-the-bottom.yml b/changelogs/unreleased/46787-create-project-label-window-is-cut-off-at-the-bottom.yml deleted file mode 100644 index dca1d57d14e..00000000000 --- a/changelogs/unreleased/46787-create-project-label-window-is-cut-off-at-the-bottom.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed - Create project label window is cut off at the bottom -merge_request: 26049 -author: -type: fixed diff --git a/changelogs/unreleased/47234-composable-auto-devops.yml b/changelogs/unreleased/47234-composable-auto-devops.yml deleted file mode 100644 index 9403c5ae6d3..00000000000 --- a/changelogs/unreleased/47234-composable-auto-devops.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Split Auto-DevOps.gitlab-ci.yml into reusable templates -merge_request: 26520 -author: -type: changed diff --git a/changelogs/unreleased/47584-label-text-color.yml b/changelogs/unreleased/47584-label-text-color.yml new file mode 100644 index 00000000000..7d5eaa62793 --- /dev/null +++ b/changelogs/unreleased/47584-label-text-color.yml @@ -0,0 +1,5 @@ +--- +title: Resolve issue where list labels did not have the correct text color on creation +merge_request: 26794 +author: Tucker Chapman +type: fixed diff --git a/changelogs/unreleased/47771-highlighting-in-diff.yml b/changelogs/unreleased/47771-highlighting-in-diff.yml deleted file mode 100644 index a8e8cbf0174..00000000000 --- a/changelogs/unreleased/47771-highlighting-in-diff.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enabled text selection highlighting in diffs in Web IDE -merge_request: 26721 -author: Isaac Smith -type: fixed diff --git a/changelogs/unreleased/48090-filter-sensitive-metric-labels.yml b/changelogs/unreleased/48090-filter-sensitive-metric-labels.yml deleted file mode 100644 index e588fa79619..00000000000 --- a/changelogs/unreleased/48090-filter-sensitive-metric-labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove `path` and `branch` labels from metrics -merge_request: 26744 -author: -type: fixed diff --git a/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml b/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml deleted file mode 100644 index e06a4d5ee75..00000000000 --- a/changelogs/unreleased/48132-display-output-from-pre-receive-scripts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Allow failed custom hook script errors to safely appear in GitLab UI by filtering error messages by the prefix GL-HOOK-ERR:" -merge_request: 25625 -author: -type: changed diff --git a/changelogs/unreleased/48297-fix-code-selection.yml b/changelogs/unreleased/48297-fix-code-selection.yml deleted file mode 100644 index 14841b00969..00000000000 --- a/changelogs/unreleased/48297-fix-code-selection.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Resolve Code in other column of side-by-side diff is highlighted when selecting - code on one side -merge_request: 26423 -author: -type: fixed diff --git a/changelogs/unreleased/49856-upgrade-bootstrap-form-gem.yml b/changelogs/unreleased/49856-upgrade-bootstrap-form-gem.yml deleted file mode 100644 index 1dc8d5b4179..00000000000 --- a/changelogs/unreleased/49856-upgrade-bootstrap-form-gem.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade bootstrap_form Gem -merge_request: 26568 -author: -type: other diff --git a/changelogs/unreleased/49863-ingress-ip-loading-state.yml b/changelogs/unreleased/49863-ingress-ip-loading-state.yml deleted file mode 100644 index 51bb27d3153..00000000000 --- a/changelogs/unreleased/49863-ingress-ip-loading-state.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show loading spinner while Ingress/Knative IP is being assigned -merge_request: 25912 -author: -type: changed diff --git a/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml b/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml deleted file mode 100644 index 68d38cd56c5..00000000000 --- a/changelogs/unreleased/49910-reopening-a-closed-milestone-from-the-closed-milestones-page-fails2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix bug when reopening milestone from index page -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml b/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml deleted file mode 100644 index 86f08dd1798..00000000000 --- a/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Support installing Group runner on group-level cluster -merge_request: 26260 -author: -type: added diff --git a/changelogs/unreleased/52258-labels-with-long-names-overflow-on-metrics-dashboard.yml b/changelogs/unreleased/52258-labels-with-long-names-overflow-on-metrics-dashboard.yml deleted file mode 100644 index 5dd25d0ffc1..00000000000 --- a/changelogs/unreleased/52258-labels-with-long-names-overflow-on-metrics-dashboard.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix long label overflow on metrics dashboard -merge_request: 26775 -author: -type: fixed diff --git a/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml b/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml deleted file mode 100644 index ab09272eaf4..00000000000 --- a/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update spinners in group list component -merge_request: 26572 -author: -type: changed diff --git a/changelogs/unreleased/52447-auto-devops-at-group-level.yml b/changelogs/unreleased/52447-auto-devops-at-group-level.yml deleted file mode 100644 index 0a21c6a2b7b..00000000000 --- a/changelogs/unreleased/52447-auto-devops-at-group-level.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable/disable Auto DevOps at the Group level -merge_request: 25533 -author: -type: added diff --git a/changelogs/unreleased/52560-fix-duplicate-tag-system-hooks.yml b/changelogs/unreleased/52560-fix-duplicate-tag-system-hooks.yml deleted file mode 100644 index b8d58d6bd30..00000000000 --- a/changelogs/unreleased/52560-fix-duplicate-tag-system-hooks.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Only execute system hooks once when pushing tags -merge_request: 26888 -author: -type: fixed diff --git a/changelogs/unreleased/53139-hide-tree-single-file.yml b/changelogs/unreleased/53139-hide-tree-single-file.yml deleted file mode 100644 index 17fe957e42e..00000000000 --- a/changelogs/unreleased/53139-hide-tree-single-file.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: collapse file tree by default if the merge request changes only one file -merge_request: -author: Riccardo Padovani <riccardo@rpadovani.com> -type: changed diff --git a/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml b/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml deleted file mode 100644 index 6fefd05049c..00000000000 --- a/changelogs/unreleased/53198-git-push-option-merge-when-pipeline-succeeds.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Allow merge requests to be set to merge when pipeline succeeds via git push - options -merge_request: 26842 -author: -type: added diff --git a/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml b/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml deleted file mode 100644 index f9cd8716b92..00000000000 --- a/changelogs/unreleased/53210-add-uniq-constraints-on-issues-and-mrs-labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: add a uniq constraints on issues and mrs labels -merge_request: 25435 -author: Antoine Huret -type: fixed diff --git a/changelogs/unreleased/53459-quick-action-adds-multiple-labels-to-issue-if-middle-words-overlap-with-existing-label.yml b/changelogs/unreleased/53459-quick-action-adds-multiple-labels-to-issue-if-middle-words-overlap-with-existing-label.yml deleted file mode 100644 index 30d8c0e95d7..00000000000 --- a/changelogs/unreleased/53459-quick-action-adds-multiple-labels-to-issue-if-middle-words-overlap-with-existing-label.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix quick actions add label name middle word overlaps -merge_request: 26602 -author: Jacopo Beschi @jacopo-beschi -type: fixed diff --git a/changelogs/unreleased/54417-graphql-type-authorization.yml b/changelogs/unreleased/54417-graphql-type-authorization.yml deleted file mode 100644 index 528b58a858a..00000000000 --- a/changelogs/unreleased/54417-graphql-type-authorization.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: GraphQL Types can be made to always authorize access to resources of that Type -merge_request: 25724 -author: -type: added diff --git a/changelogs/unreleased/54506-show-error-when-namespace-svc-missing.yml b/changelogs/unreleased/54506-show-error-when-namespace-svc-missing.yml deleted file mode 100644 index 3e3784d5413..00000000000 --- a/changelogs/unreleased/54506-show-error-when-namespace-svc-missing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show error when namespace/svc account missing -merge_request: 26362 -author: -type: added diff --git a/changelogs/unreleased/54656-500-error-on-save-of-general-pipeline-settings-timeout.yml b/changelogs/unreleased/54656-500-error-on-save-of-general-pipeline-settings-timeout.yml new file mode 100644 index 00000000000..8b4f4894048 --- /dev/null +++ b/changelogs/unreleased/54656-500-error-on-save-of-general-pipeline-settings-timeout.yml @@ -0,0 +1,5 @@ +--- +title: Fix 500 in general pipeline settings when passing an invalid build timeout. +merge_request: 27416 +author: +type: fixed diff --git a/changelogs/unreleased/54670-external-diffs-when-outdated.yml b/changelogs/unreleased/54670-external-diffs-when-outdated.yml deleted file mode 100644 index 2a0b9e75cb4..00000000000 --- a/changelogs/unreleased/54670-external-diffs-when-outdated.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Allow external diffs to be used conditionally' -merge_request: 25432 -author: -type: added diff --git a/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml b/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml deleted file mode 100644 index 7fd0bcd1c00..00000000000 --- a/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add extended merge request tooltip -merge_request: !25221 -author: -type: added diff --git a/changelogs/unreleased/55268-exclude-system-notes-from-commits-in-mr.yml b/changelogs/unreleased/55268-exclude-system-notes-from-commits-in-mr.yml deleted file mode 100644 index 7af4739136b..00000000000 --- a/changelogs/unreleased/55268-exclude-system-notes-from-commits-in-mr.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Exclude system notes from commits in merge request discussions -merge_request: 26396 -author: -type: fixed diff --git a/changelogs/unreleased/55964-fix-email-encoding.yml b/changelogs/unreleased/55964-fix-email-encoding.yml deleted file mode 100644 index 2195a853702..00000000000 --- a/changelogs/unreleased/55964-fix-email-encoding.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix notfication emails having wrong encoding -merge_request: 26931 -author: -type: fixed diff --git a/changelogs/unreleased/55980-remove-add-issue-on-blank-list.yml b/changelogs/unreleased/55980-remove-add-issue-on-blank-list.yml deleted file mode 100644 index 4c16b635297..00000000000 --- a/changelogs/unreleased/55980-remove-add-issue-on-blank-list.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove non-functional add issue button on welcome list -merge_request: !26742 -author: -type: fixed diff --git a/changelogs/unreleased/56015-remove-remote-timeout.yml b/changelogs/unreleased/56015-remove-remote-timeout.yml deleted file mode 100644 index 9b40ada5291..00000000000 --- a/changelogs/unreleased/56015-remove-remote-timeout.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix removing remote mirror failure which leaves unnecessary refs behind -merge_request: 26213 -author: -type: fixed diff --git a/changelogs/unreleased/56089-merge-gitlab-keys.yml b/changelogs/unreleased/56089-merge-gitlab-keys.yml deleted file mode 100644 index 5e2cafd3254..00000000000 --- a/changelogs/unreleased/56089-merge-gitlab-keys.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Merge the gitlab-shell "gitlab-keys" functionality into GitLab CE -merge_request: 25598 -author: -type: other diff --git a/changelogs/unreleased/56762-fix-commit-swipe-view-26968.yml b/changelogs/unreleased/56762-fix-commit-swipe-view-26968.yml deleted file mode 100644 index 18bd51711d9..00000000000 --- a/changelogs/unreleased/56762-fix-commit-swipe-view-26968.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Fix image diff swipe view on commit and compare pages" -merge_request: 26968 -author: ftab -type: fixed
\ No newline at end of file diff --git a/changelogs/unreleased/56833-project-improve-empty-repository-state-ui-fe.yml b/changelogs/unreleased/56833-project-improve-empty-repository-state-ui-fe.yml deleted file mode 100644 index 19cf3d69db1..00000000000 --- a/changelogs/unreleased/56833-project-improve-empty-repository-state-ui-fe.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Project: Improve empty repository state UI' -merge_request: 26024 -author: -type: other diff --git a/changelogs/unreleased/56864-reopen-locked-mr.yml b/changelogs/unreleased/56864-reopen-locked-mr.yml deleted file mode 100644 index d1d71531ac8..00000000000 --- a/changelogs/unreleased/56864-reopen-locked-mr.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disallow reopening of a locked merge request -merge_request: 24882 -author: Jan Beckmann -type: fixed diff --git a/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml b/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml deleted file mode 100644 index b9fb27c3218..00000000000 --- a/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve the Knative installation on Clusters -merge_request: 26339 -author: -type: added diff --git a/changelogs/unreleased/57115-just-in-time-k8s-resource-creation.yml b/changelogs/unreleased/57115-just-in-time-k8s-resource-creation.yml deleted file mode 100644 index 2141c75ec72..00000000000 --- a/changelogs/unreleased/57115-just-in-time-k8s-resource-creation.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create Kubernetes resources for projects when their deployment jobs run. -merge_request: 25586 -author: -type: changed diff --git a/changelogs/unreleased/57131-external_auth_to_core.yml b/changelogs/unreleased/57131-external_auth_to_core.yml deleted file mode 100644 index aacd3916c82..00000000000 --- a/changelogs/unreleased/57131-external_auth_to_core.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move "Authorize project access with external service" to Core -merge_request: 26823 -author: -type: changed diff --git a/changelogs/unreleased/57247-show-prioritized-labels-to-guests.yml b/changelogs/unreleased/57247-show-prioritized-labels-to-guests.yml new file mode 100644 index 00000000000..5210ff0ccef --- /dev/null +++ b/changelogs/unreleased/57247-show-prioritized-labels-to-guests.yml @@ -0,0 +1,5 @@ +--- +title: Show prioritized labels to guests +merge_request: 27307 +author: +type: fixed diff --git a/changelogs/unreleased/57293-fix-image-rename.yml b/changelogs/unreleased/57293-fix-image-rename.yml new file mode 100644 index 00000000000..50dddbdf114 --- /dev/null +++ b/changelogs/unreleased/57293-fix-image-rename.yml @@ -0,0 +1,5 @@ +--- +title: Resolve Renaming an image via Web IDE corrupts it +merge_request: 27486 +author: +type: fixed diff --git a/changelogs/unreleased/57319-hide-kubernetes-cluster-warning-if-project-has-cluster-related.yml b/changelogs/unreleased/57319-hide-kubernetes-cluster-warning-if-project-has-cluster-related.yml deleted file mode 100644 index a6953a68a76..00000000000 --- a/changelogs/unreleased/57319-hide-kubernetes-cluster-warning-if-project-has-cluster-related.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve "Hide Kubernetes cluster warning if project has cluster related" -merge_request: 26749 -author: -type: fixed diff --git a/changelogs/unreleased/57357-automate-base-domain-help-text.yml b/changelogs/unreleased/57357-automate-base-domain-help-text.yml deleted file mode 100644 index fa1831b66ea..00000000000 --- a/changelogs/unreleased/57357-automate-base-domain-help-text.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Automate base domain help text on Clusters page -merge_request: 26124 -author: -type: changed diff --git a/changelogs/unreleased/57364-improve-diff-nav-header.yml b/changelogs/unreleased/57364-improve-diff-nav-header.yml deleted file mode 100644 index 95d119b949c..00000000000 --- a/changelogs/unreleased/57364-improve-diff-nav-header.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make stylistic improvements to diff nav header -merge_request: 26557 -author: -type: fixed diff --git a/changelogs/unreleased/57409-loading-button-transition.yml b/changelogs/unreleased/57409-loading-button-transition.yml deleted file mode 100644 index 3cf169d79de..00000000000 --- a/changelogs/unreleased/57409-loading-button-transition.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent fade out transition on loading-button component. -merge_request: 26428 -author: -type: fixed diff --git a/changelogs/unreleased/57482-shortcut-to-create-merge-request-from-web-ide.yml b/changelogs/unreleased/57482-shortcut-to-create-merge-request-from-web-ide.yml deleted file mode 100644 index c188d59fe94..00000000000 --- a/changelogs/unreleased/57482-shortcut-to-create-merge-request-from-web-ide.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create a shortcut for a new MR in the Web IDE -merge_request: 26792 -author: -type: added diff --git a/changelogs/unreleased/57493-add-limit-to-user-name.yml b/changelogs/unreleased/57493-add-limit-to-user-name.yml deleted file mode 100644 index e6c78572d23..00000000000 --- a/changelogs/unreleased/57493-add-limit-to-user-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Set user.name limit to 128 characters -merge_request: 26146 -author: -type: changed diff --git a/changelogs/unreleased/57540-filename-trailing-space.yml b/changelogs/unreleased/57540-filename-trailing-space.yml deleted file mode 100644 index db85fb350db..00000000000 --- a/changelogs/unreleased/57540-filename-trailing-space.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Implemented whitespace-trimming for file names in Web IDE -merge_request: 26270 -author: -type: fixed diff --git a/changelogs/unreleased/57602-create-cluster-validations.yml b/changelogs/unreleased/57602-create-cluster-validations.yml deleted file mode 100644 index 35349c1e9f4..00000000000 --- a/changelogs/unreleased/57602-create-cluster-validations.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Display cluster form validation error messages inline -merge_request: 26502 -author: -type: changed diff --git a/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml b/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml deleted file mode 100644 index d92fd2a762e..00000000000 --- a/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Makes emoji picker full width on mobile. -merge_request: 25883 -author: Jacopo Beschi @jacopo-beschi -type: fixed diff --git a/changelogs/unreleased/57655-fix-markdown-tables-border.yml b/changelogs/unreleased/57655-fix-markdown-tables-border.yml deleted file mode 100644 index 6a8ba8c4353..00000000000 --- a/changelogs/unreleased/57655-fix-markdown-tables-border.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix markdown table header and table content borders -merge_request: 25666 -author: -type: fixed diff --git a/changelogs/unreleased/57668-create-file-from-url.yml b/changelogs/unreleased/57668-create-file-from-url.yml deleted file mode 100644 index b6033fa24ca..00000000000 --- a/changelogs/unreleased/57668-create-file-from-url.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Implemented support for creation of new files from URL in Web IDE -merge_request: 26622 -author: -type: added diff --git a/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml b/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml deleted file mode 100644 index c6161870096..00000000000 --- a/changelogs/unreleased/57669-fix-bug-clicking-file-header-refreshes-page.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Scroll to diff file content when clicking on file header name and it is not - a link to other page -merge_request: !26422 -author: -type: fixed diff --git a/changelogs/unreleased/57894-buttons-on-group-page-are-misaligned.yml b/changelogs/unreleased/57894-buttons-on-group-page-are-misaligned.yml deleted file mode 100644 index ca0f529df6c..00000000000 --- a/changelogs/unreleased/57894-buttons-on-group-page-are-misaligned.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix misalignment of group overview page buttons -merge_request: 26292 -author: -type: fixed diff --git a/changelogs/unreleased/57984-store-branch-name.yml b/changelogs/unreleased/57984-store-branch-name.yml deleted file mode 100644 index 26dfdb7a5d6..00000000000 --- a/changelogs/unreleased/57984-store-branch-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolves Branch name is lost if I change commit mode in Web IDE -merge_request: 26180 -author: -type: fixed diff --git a/changelogs/unreleased/58208-explicitly-set-masterauth.yml b/changelogs/unreleased/58208-explicitly-set-masterauth.yml deleted file mode 100644 index e3512d11113..00000000000 --- a/changelogs/unreleased/58208-explicitly-set-masterauth.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Explicitly set master_auth setting to enable basic auth and client certificate - for new GKE clusters -merge_request: 26018 -author: -type: other diff --git a/changelogs/unreleased/58252-web-ide-dropdown-duplicates.yml b/changelogs/unreleased/58252-web-ide-dropdown-duplicates.yml new file mode 100644 index 00000000000..48b03994586 --- /dev/null +++ b/changelogs/unreleased/58252-web-ide-dropdown-duplicates.yml @@ -0,0 +1,5 @@ +--- +title: Resolve Web IDE template dropdown showing duplicates +merge_request: 27237 +author: +type: fixed diff --git a/changelogs/unreleased/58375-api-controller.yml b/changelogs/unreleased/58375-api-controller.yml deleted file mode 100644 index 60f21b37ae7..00000000000 --- a/changelogs/unreleased/58375-api-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add a Prometheus API per environment -merge_request: 26841 -author: -type: added diff --git a/changelogs/unreleased/58375-reactive-caching-changes.yml b/changelogs/unreleased/58375-reactive-caching-changes.yml deleted file mode 100644 index cf73736b8ef..00000000000 --- a/changelogs/unreleased/58375-reactive-caching-changes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow reactive caching to be used in services -merge_request: 26839 -author: -type: added diff --git a/changelogs/unreleased/58405-basic-limiting-complexity-of-graphql-queries.yml b/changelogs/unreleased/58405-basic-limiting-complexity-of-graphql-queries.yml deleted file mode 100644 index 058a120b500..00000000000 --- a/changelogs/unreleased/58405-basic-limiting-complexity-of-graphql-queries.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add initial complexity limits to GraphQL queries -merge_request: 26629 -author: -type: performance diff --git a/changelogs/unreleased/58410-change-pixel-size-of-instance-header-footer-message-to-16px.yml b/changelogs/unreleased/58410-change-pixel-size-of-instance-header-footer-message-to-16px.yml deleted file mode 100644 index 3e494847e75..00000000000 --- a/changelogs/unreleased/58410-change-pixel-size-of-instance-header-footer-message-to-16px.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reduce height of instance system header and footer -merge_request: 25752 -author: -type: changed diff --git a/changelogs/unreleased/58482-update-airminc-clair-local-scan-to-2-0-6.yml b/changelogs/unreleased/58482-update-airminc-clair-local-scan-to-2-0-6.yml deleted file mode 100644 index be9c38aba1e..00000000000 --- a/changelogs/unreleased/58482-update-airminc-clair-local-scan-to-2-0-6.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update clair-local-scan to 2.0.6 -merge_request: 25743 -author: Takuya Noguchi -type: added diff --git a/changelogs/unreleased/58717-checkbox-cannot-be-checked-if-a-blockquote-is-above.yml b/changelogs/unreleased/58717-checkbox-cannot-be-checked-if-a-blockquote-is-above.yml deleted file mode 100644 index 9f5881966c7..00000000000 --- a/changelogs/unreleased/58717-checkbox-cannot-be-checked-if-a-blockquote-is-above.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow task lists that follow a blockquote to work correctly -merge_request: 26937 -author: -type: fixed diff --git a/changelogs/unreleased/58739-hashed-storage-prevent-a-migration-and-rollback-running-at-the-same-time.yml b/changelogs/unreleased/58739-hashed-storage-prevent-a-migration-and-rollback-running-at-the-same-time.yml deleted file mode 100644 index 765a991bb6a..00000000000 --- a/changelogs/unreleased/58739-hashed-storage-prevent-a-migration-and-rollback-running-at-the-same-time.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Hashed Storage: Prevent a migration and rollback running at the same time' -merge_request: 25976 -author: -type: changed diff --git a/changelogs/unreleased/58751-fix-project-name-members-page.yml b/changelogs/unreleased/58751-fix-project-name-members-page.yml deleted file mode 100644 index a295afc5c48..00000000000 --- a/changelogs/unreleased/58751-fix-project-name-members-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Fix unwanted character replacement on project members page caused by usage of sanitize function" -merge_request: 25946 -author: Elias Werberich -type: fixed diff --git a/changelogs/unreleased/58781-silent-progress-in-auto-devops.yml b/changelogs/unreleased/58781-silent-progress-in-auto-devops.yml deleted file mode 100644 index e45db8eafc3..00000000000 --- a/changelogs/unreleased/58781-silent-progress-in-auto-devops.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use curl silent/show-error options on Auto DevOps -merge_request: 25954 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/58789-some-system-notes-on-issuable-are-folded-on-mobile.yml b/changelogs/unreleased/58789-some-system-notes-on-issuable-are-folded-on-mobile.yml deleted file mode 100644 index ebfb7aeaa1f..00000000000 --- a/changelogs/unreleased/58789-some-system-notes-on-issuable-are-folded-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Keep inline as much as possible in system notes on issuable -merge_request: 25968 -author: Takuya Noguchi -type: fixed diff --git a/changelogs/unreleased/58793-fix-nav-links-archived-project.yml b/changelogs/unreleased/58793-fix-nav-links-archived-project.yml deleted file mode 100644 index a8250804c34..00000000000 --- a/changelogs/unreleased/58793-fix-nav-links-archived-project.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Disable inaccessible navigation links upon archiving a project" -merge_request: 26020 -author: Elias Werberich -type: fixed diff --git a/changelogs/unreleased/58797-broken-ui-on-a-closed-merge-request-from-a-deleted-source-project.yml b/changelogs/unreleased/58797-broken-ui-on-a-closed-merge-request-from-a-deleted-source-project.yml deleted file mode 100644 index e30f48ed1a8..00000000000 --- a/changelogs/unreleased/58797-broken-ui-on-a-closed-merge-request-from-a-deleted-source-project.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix UI for closed MR when source project is removed -merge_request: 25967 -author: Takuya Noguchi -type: fixed diff --git a/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml b/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml deleted file mode 100644 index 4377ebfdbdf..00000000000 --- a/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix merge commits being used as default squash commit messages -merge_request: 26445 -author: -type: fixed diff --git a/changelogs/unreleased/58835-button-run-pipeline.yml b/changelogs/unreleased/58835-button-run-pipeline.yml deleted file mode 100644 index 39407a60780..00000000000 --- a/changelogs/unreleased/58835-button-run-pipeline.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Changed button label at /pipelines/new -merge_request: 26893 -author: antfobe,leonardofl -type: other diff --git a/changelogs/unreleased/58839-automatically-set-prometheus-step-interval.yml b/changelogs/unreleased/58839-automatically-set-prometheus-step-interval.yml deleted file mode 100644 index 2c6edf45ae2..00000000000 --- a/changelogs/unreleased/58839-automatically-set-prometheus-step-interval.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Automatically set Prometheus step interval -merge_request: 26441 -author: -type: changed diff --git a/changelogs/unreleased/58850-fix-misplaced-swipe-view-26969.yml b/changelogs/unreleased/58850-fix-misplaced-swipe-view-26969.yml new file mode 100644 index 00000000000..fa3e81df4e0 --- /dev/null +++ b/changelogs/unreleased/58850-fix-misplaced-swipe-view-26969.yml @@ -0,0 +1,5 @@ +--- +title: "Fix misaligned image diff swipe view" +merge_request: 26969 +author: ftab +type: fixed diff --git a/changelogs/unreleased/58883-fix-fetching-comments.yml b/changelogs/unreleased/58883-fix-fetching-comments.yml deleted file mode 100644 index 14c0f1687f2..00000000000 --- a/changelogs/unreleased/58883-fix-fetching-comments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix error shown when loading links to specific comments -merge_request: 26092 -author: -type: fixed diff --git a/changelogs/unreleased/58889-spinners-are-active-prematurely-in-bitbucket-cloud-import.yml b/changelogs/unreleased/58889-spinners-are-active-prematurely-in-bitbucket-cloud-import.yml deleted file mode 100644 index ec357d9a832..00000000000 --- a/changelogs/unreleased/58889-spinners-are-active-prematurely-in-bitbucket-cloud-import.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix continuous bitbucket import loading spinner -merge_request: 26175 -author: -type: fixed diff --git a/changelogs/unreleased/58933-broken-ui-on-commits-on-mobile.yml b/changelogs/unreleased/58933-broken-ui-on-commits-on-mobile.yml deleted file mode 100644 index ca9f9dd21c9..00000000000 --- a/changelogs/unreleased/58933-broken-ui-on-commits-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix UI layout on Commits on mobile -merge_request: 26133 -author: Takuya Noguchi -type: fixed diff --git a/changelogs/unreleased/58971-sentry-api-keyerror.yml b/changelogs/unreleased/58971-sentry-api-keyerror.yml deleted file mode 100644 index 0f195c4b4f7..00000000000 --- a/changelogs/unreleased/58971-sentry-api-keyerror.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Handle missing keys in sentry api response -merge_request: 26264 -author: -type: fixed diff --git a/changelogs/unreleased/58981-migrate-clusters-tests-to-jest.yml b/changelogs/unreleased/58981-migrate-clusters-tests-to-jest.yml deleted file mode 100644 index 3df13dbb960..00000000000 --- a/changelogs/unreleased/58981-migrate-clusters-tests-to-jest.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Migrate clusters tests to jest -merge_request: 27013 -author: -type: other diff --git a/changelogs/unreleased/59057-buttons-on-top-from-a-user-profile-page-on-mobile.yml b/changelogs/unreleased/59057-buttons-on-top-from-a-user-profile-page-on-mobile.yml deleted file mode 100644 index febbbce2139..00000000000 --- a/changelogs/unreleased/59057-buttons-on-top-from-a-user-profile-page-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve mobile UI on User Profile page -merge_request: 26240 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/59062-update-gitlab-markup-python-3.yml b/changelogs/unreleased/59062-update-gitlab-markup-python-3.yml deleted file mode 100644 index 265a7e36841..00000000000 --- a/changelogs/unreleased/59062-update-gitlab-markup-python-3.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update gitlab-markup to 1.7.0 which requies python3 -merge_request: 26246 -author: -type: changed diff --git a/changelogs/unreleased/59079-fix-jupyter-render-loop.yml b/changelogs/unreleased/59079-fix-jupyter-render-loop.yml deleted file mode 100644 index 29264b33dfa..00000000000 --- a/changelogs/unreleased/59079-fix-jupyter-render-loop.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix jupyter rendering bug that ended in an infinite loop -merge_request: 26656 -author: ROSPARS Benoit -type: fixed diff --git a/changelogs/unreleased/59117-inconsistent-hover-behavior-on-navbar-items.yml b/changelogs/unreleased/59117-inconsistent-hover-behavior-on-navbar-items.yml deleted file mode 100644 index eb9dcef4a89..00000000000 --- a/changelogs/unreleased/59117-inconsistent-hover-behavior-on-navbar-items.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix hover animation consistency in top navbar items -merge_request: 26345 -author: -type: fixed diff --git a/changelogs/unreleased/59131-set-the-size-of-instance-system-message-text-12px.yml b/changelogs/unreleased/59131-set-the-size-of-instance-system-message-text-12px.yml deleted file mode 100644 index 688190f4458..00000000000 --- a/changelogs/unreleased/59131-set-the-size-of-instance-system-message-text-12px.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update system message banner font size to 12px -merge_request: 26293 -author: -type: changed diff --git a/changelogs/unreleased/59189-long-names-in-project-path-namespace-dropdown-breaks-past-container.yml b/changelogs/unreleased/59189-long-names-in-project-path-namespace-dropdown-breaks-past-container.yml deleted file mode 100644 index bed7fcf2651..00000000000 --- a/changelogs/unreleased/59189-long-names-in-project-path-namespace-dropdown-breaks-past-container.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent namespace dropdown in new project form from exceeding container -merge_request: 26343 -author: -type: fixed diff --git a/changelogs/unreleased/59273-update-fugit.yml b/changelogs/unreleased/59273-update-fugit.yml deleted file mode 100644 index 3a1c64d87ef..00000000000 --- a/changelogs/unreleased/59273-update-fugit.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update fugit which fixes a potential infinite loop -merge_request: 26579 -author: -type: fixed diff --git a/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml b/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml deleted file mode 100644 index 440b24a548c..00000000000 --- a/changelogs/unreleased/59296-add-filter-by-title-milestones-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add select by title to milestones API -merge_request: 26573 -author: -type: added diff --git a/changelogs/unreleased/59324-queries-which-return-multiple-series-are-not-working-correctly.yml b/changelogs/unreleased/59324-queries-which-return-multiple-series-are-not-working-correctly.yml deleted file mode 100644 index 9ab8d2b8596..00000000000 --- a/changelogs/unreleased/59324-queries-which-return-multiple-series-are-not-working-correctly.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix multiple series queries on metrics dashboard -merge_request: 26514 -author: -type: fixed diff --git a/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml b/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml deleted file mode 100644 index ab9ad53835c..00000000000 --- a/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expand resolved discussion when linking to a comment in the discussion -merge_request: 26483 -author: -type: fixed diff --git a/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml b/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml deleted file mode 100644 index cb5cbba4e92..00000000000 --- a/changelogs/unreleased/59441-add-base-domain-to-cluster-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add cluster domain to Project Cluster API -merge_request: 26735 -author: -type: other diff --git a/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml b/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml deleted file mode 100644 index da65c3bc870..00000000000 --- a/changelogs/unreleased/59502-fix-breadcrumb-artifacts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes job link in artifacts page breadcrumb -merge_request: 26592 -author: -type: fixed diff --git a/changelogs/unreleased/59514-uploading-images-base64.yml b/changelogs/unreleased/59514-uploading-images-base64.yml new file mode 100644 index 00000000000..905b00db06a --- /dev/null +++ b/changelogs/unreleased/59514-uploading-images-base64.yml @@ -0,0 +1,5 @@ +--- +title: Show proper preview for uploaded images in Web IDE +merge_request: 27471 +author: +type: fixed diff --git a/changelogs/unreleased/59546-fix-error-handling-for-missing-domain.yml b/changelogs/unreleased/59546-fix-error-handling-for-missing-domain.yml deleted file mode 100644 index 8f0ce5d57c5..00000000000 --- a/changelogs/unreleased/59546-fix-error-handling-for-missing-domain.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Auto DevOps missing domain error handling -merge_request: 26627 -author: -type: fixed diff --git a/changelogs/unreleased/59621-order-labels-alphabetically-in-issue-boards.yml b/changelogs/unreleased/59621-order-labels-alphabetically-in-issue-boards.yml deleted file mode 100644 index 8b82d757303..00000000000 --- a/changelogs/unreleased/59621-order-labels-alphabetically-in-issue-boards.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Order labels alphabetically in issue boards -merge_request: 26927 -author: -type: changed diff --git a/changelogs/unreleased/60006-add-touch-events-to-image-diff-26971.yml b/changelogs/unreleased/60006-add-touch-events-to-image-diff-26971.yml deleted file mode 100644 index bfea3ac52af..00000000000 --- a/changelogs/unreleased/60006-add-touch-events-to-image-diff-26971.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Make touch events work on image diff swipe view and onion skin" -merge_request: 26971 -author: ftab -type: added diff --git a/changelogs/unreleased/60068-avoid-null-domain-help-text.yml b/changelogs/unreleased/60068-avoid-null-domain-help-text.yml deleted file mode 100644 index 5305b8584a8..00000000000 --- a/changelogs/unreleased/60068-avoid-null-domain-help-text.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Do not display Ingress IP help text when there isn’t an Ingress IP assigned -merge_request: 27057 -author: -type: fixed diff --git a/changelogs/unreleased/60116-fix-button-wrapping.yml b/changelogs/unreleased/60116-fix-button-wrapping.yml deleted file mode 100644 index d6df920b51d..00000000000 --- a/changelogs/unreleased/60116-fix-button-wrapping.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add to white-space nowrap to all buttons -merge_request: 27069 -author: -type: fixed diff --git a/changelogs/unreleased/60149-nameerror-uninitialized-constant-sentry-client-sentryerror.yml b/changelogs/unreleased/60149-nameerror-uninitialized-constant-sentry-client-sentryerror.yml deleted file mode 100644 index 8c3a47cf62c..00000000000 --- a/changelogs/unreleased/60149-nameerror-uninitialized-constant-sentry-client-sentryerror.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Handle possible HTTP exception for Sentry client -merge_request: 27080 -author: -type: fixed diff --git a/changelogs/unreleased/60241-merge-request-popover-doesn-t-go-away-on-mouse-leave.yml b/changelogs/unreleased/60241-merge-request-popover-doesn-t-go-away-on-mouse-leave.yml deleted file mode 100644 index ce942777dca..00000000000 --- a/changelogs/unreleased/60241-merge-request-popover-doesn-t-go-away-on-mouse-leave.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix bug where MR popover doesn't go away on mouse leave -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/60304-long-file-names-in-mr-diffs-cause-horizontal-scrolling.yml b/changelogs/unreleased/60304-long-file-names-in-mr-diffs-cause-horizontal-scrolling.yml deleted file mode 100644 index ec5e9e4703b..00000000000 --- a/changelogs/unreleased/60304-long-file-names-in-mr-diffs-cause-horizontal-scrolling.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix long file header names bug in diffs -merge_request: 27233 -author: -type: fixed diff --git a/changelogs/unreleased/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml b/changelogs/unreleased/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml deleted file mode 100644 index df6e6ea4be3..00000000000 --- a/changelogs/unreleased/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disable just-in-time Kubernetes resource creation for project level clusters -merge_request: 27352 -author: -type: changed diff --git a/changelogs/unreleased/60540-merge-request-popover-is-not-working-on-the-to-do-page.yml b/changelogs/unreleased/60540-merge-request-popover-is-not-working-on-the-to-do-page.yml new file mode 100644 index 00000000000..7b5fae016bb --- /dev/null +++ b/changelogs/unreleased/60540-merge-request-popover-is-not-working-on-the-to-do-page.yml @@ -0,0 +1,5 @@ +--- +title: Fix MR popover on ToDos page +merge_request: 27382 +author: +type: fixed diff --git a/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml b/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml deleted file mode 100644 index 8fb9f1057fe..00000000000 --- a/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Unify behaviour of 'Copy commit SHA to clipboard' to use full commit SHA. -merge_request: 25829 -author: Max Winterstein -type: changed diff --git a/changelogs/unreleased/_acet-related-mrs-widget-rewrite.yml b/changelogs/unreleased/_acet-related-mrs-widget-rewrite.yml deleted file mode 100644 index b773eb2720c..00000000000 --- a/changelogs/unreleased/_acet-related-mrs-widget-rewrite.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rewrite related MRs widget with Vue -merge_request: 27027 -author: -type: other diff --git a/changelogs/unreleased/add-ci-variable-protected-ref.yml b/changelogs/unreleased/add-ci-variable-protected-ref.yml new file mode 100644 index 00000000000..150ddcc21ad --- /dev/null +++ b/changelogs/unreleased/add-ci-variable-protected-ref.yml @@ -0,0 +1,5 @@ +--- +title: Add CI_COMMIT_REF_PROTECTED CI variable +merge_request: 26716 +author: Jason van den Hurk +type: added diff --git a/changelogs/unreleased/add-runner-access-level-registration.yml b/changelogs/unreleased/add-runner-access-level-registration.yml new file mode 100644 index 00000000000..7ae95025abb --- /dev/null +++ b/changelogs/unreleased/add-runner-access-level-registration.yml @@ -0,0 +1,5 @@ +--- +title: Add option to set access_level of runners upon registration +merge_request: 27490 +author: Zelin L +type: added diff --git a/changelogs/unreleased/add_backtrace_to_kubernetes_log.yml b/changelogs/unreleased/add_backtrace_to_kubernetes_log.yml deleted file mode 100644 index 26b8ac4b1ef..00000000000 --- a/changelogs/unreleased/add_backtrace_to_kubernetes_log.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show error backtrace when logging errors to kubernetes.log -merge_request: 25726 -author: -type: other diff --git a/changelogs/unreleased/allow-filtering-labels-by-a-single-character.yml b/changelogs/unreleased/allow-filtering-labels-by-a-single-character.yml deleted file mode 100644 index 31165bbadb7..00000000000 --- a/changelogs/unreleased/allow-filtering-labels-by-a-single-character.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow filtering labels list by one or two characters -merge_request: 26012 -author: -type: changed diff --git a/changelogs/unreleased/allow-ref-name-caching-projects-controller.yml b/changelogs/unreleased/allow-ref-name-caching-projects-controller.yml deleted file mode 100644 index 61236b9b82b..00000000000 --- a/changelogs/unreleased/allow-ref-name-caching-projects-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable FindCommit caching for project and commits pages -merge_request: 27048 -author: -type: performance diff --git a/changelogs/unreleased/avoid_es_loading_project_ci_status.yml b/changelogs/unreleased/avoid_es_loading_project_ci_status.yml deleted file mode 100644 index 514909c730d..00000000000 --- a/changelogs/unreleased/avoid_es_loading_project_ci_status.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid loading pipeline status in project search -merge_request: 26342 -author: -type: performance diff --git a/changelogs/unreleased/ce-56153-error-tracking-counts.yml b/changelogs/unreleased/ce-56153-error-tracking-counts.yml deleted file mode 100644 index fc3d8c01d7f..00000000000 --- a/changelogs/unreleased/ce-56153-error-tracking-counts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add usage counts for error tracking feature -merge_request: 25472 -author: -type: added diff --git a/changelogs/unreleased/ce-proj-settings-ok-avatar-only.yml b/changelogs/unreleased/ce-proj-settings-ok-avatar-only.yml deleted file mode 100644 index 10475824a75..00000000000 --- a/changelogs/unreleased/ce-proj-settings-ok-avatar-only.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change project avatar remove button to a link -merge_request: 26589 -author: -type: other diff --git a/changelogs/unreleased/ce-proj-settings-ok-mr-settings-only.yml b/changelogs/unreleased/ce-proj-settings-ok-mr-settings-only.yml deleted file mode 100644 index 4bbbc706e62..00000000000 --- a/changelogs/unreleased/ce-proj-settings-ok-mr-settings-only.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve project merge request settings -merge_request: 26495 -author: -type: other diff --git a/changelogs/unreleased/ce-remove-already-signed-in.yml b/changelogs/unreleased/ce-remove-already-signed-in.yml new file mode 100644 index 00000000000..70bed136ced --- /dev/null +++ b/changelogs/unreleased/ce-remove-already-signed-in.yml @@ -0,0 +1,5 @@ +--- +title: Remove "You are already signed in" banner +merge_request: 27377 +author: +type: other diff --git a/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml b/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml deleted file mode 100644 index 9f615bbb54a..00000000000 --- a/changelogs/unreleased/check-mergeability-in-merge-to-ref-service.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Check mergeability in MergeToRefService -merge_request: 26757 -author: -type: changed diff --git a/changelogs/unreleased/create-label-and-list-checkbox.yml b/changelogs/unreleased/create-label-and-list-checkbox.yml deleted file mode 100644 index 330372df1be..00000000000 --- a/changelogs/unreleased/create-label-and-list-checkbox.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Added "Add List" checkbox to create label dropdown to make creation of list optional' -merge_request: 25716 -author: Tucker Chapman -type: fixed diff --git a/changelogs/unreleased/delete-release-when-delete-tag.yml b/changelogs/unreleased/delete-release-when-delete-tag.yml deleted file mode 100644 index 58acd449bf1..00000000000 --- a/changelogs/unreleased/delete-release-when-delete-tag.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Releases will now be automatically deleted when deleting corresponding tag -merge_request: 26530 -author: -type: fixed diff --git a/changelogs/unreleased/deploy-keys-ext.yml b/changelogs/unreleased/deploy-keys-ext.yml deleted file mode 100644 index e1d2fe08425..00000000000 --- a/changelogs/unreleased/deploy-keys-ext.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Externalize admin deploy keys strings -merge_request: -author: -type: other diff --git a/changelogs/unreleased/disallow-guests-to-access-releases.yml b/changelogs/unreleased/disallow-guests-to-access-releases.yml deleted file mode 100644 index f2d518108d2..00000000000 --- a/changelogs/unreleased/disallow-guests-to-access-releases.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disallow guest users from accessing Releases -merge_request: -author: -type: security diff --git a/changelogs/unreleased/do-not-force-2fa.yml b/changelogs/unreleased/do-not-force-2fa.yml deleted file mode 100644 index f9be40e8f37..00000000000 --- a/changelogs/unreleased/do-not-force-2fa.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Add link on two-factor authorization settings page to leave group that enforces - two-factor authorization -merge_request: 25731 -author: -type: changed diff --git a/changelogs/unreleased/drop-usage-of-leagcy-artifacts.yml b/changelogs/unreleased/drop-usage-of-leagcy-artifacts.yml deleted file mode 100644 index d99187d8d41..00000000000 --- a/changelogs/unreleased/drop-usage-of-leagcy-artifacts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Drop legacy artifacts usage as there are no leftovers -merge_request: 24294 -author: -type: performance diff --git a/changelogs/unreleased/duplicate-related-mrs.yml b/changelogs/unreleased/duplicate-related-mrs.yml deleted file mode 100644 index 0f5f6ede9f8..00000000000 --- a/changelogs/unreleased/duplicate-related-mrs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove duplicates from issue related merge requests -merge_request: 27067 -author: -type: fixed diff --git a/changelogs/unreleased/ekigbo-extend-timezone-dropdown.yml b/changelogs/unreleased/ekigbo-extend-timezone-dropdown.yml deleted file mode 100644 index 42bc320a542..00000000000 --- a/changelogs/unreleased/ekigbo-extend-timezone-dropdown.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Extend timezone dropdown -merge_request: 26311 -author: -type: changed diff --git a/changelogs/unreleased/expose-group-id-on-home-panel.yml b/changelogs/unreleased/expose-group-id-on-home-panel.yml deleted file mode 100644 index 1efe15a6e1a..00000000000 --- a/changelogs/unreleased/expose-group-id-on-home-panel.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expose group id on home panel -merge_request: 25897 -author: Peter Marko -type: added diff --git a/changelogs/unreleased/extend-cte-optimisations-to-projects.yml b/changelogs/unreleased/extend-cte-optimisations-to-projects.yml deleted file mode 100644 index e5407127b2f..00000000000 --- a/changelogs/unreleased/extend-cte-optimisations-to-projects.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Speed up filtering issues in a project when searching -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/feature-gb-serverless-switch-to-gitlabktl.yml b/changelogs/unreleased/feature-gb-serverless-switch-to-gitlabktl.yml deleted file mode 100644 index 81cf5cb810d..00000000000 --- a/changelogs/unreleased/feature-gb-serverless-switch-to-gitlabktl.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use gitlabktl to build and deploy GitLab Serverless Functions -merge_request: 26926 -author: -type: added diff --git a/changelogs/unreleased/feature-users-search-results.yml b/changelogs/unreleased/feature-users-search-results.yml deleted file mode 100644 index 151d08bce12..00000000000 --- a/changelogs/unreleased/feature-users-search-results.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add users search results to global search -merge_request: 21197 -author: Alexis Reigel -type: added diff --git a/changelogs/unreleased/feature-webide_escaping.yml b/changelogs/unreleased/feature-webide_escaping.yml deleted file mode 100644 index 88fa1bd948e..00000000000 --- a/changelogs/unreleased/feature-webide_escaping.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed bug with hashes in urls in WebIDE -merge_request: 54376 -author: Kieran Andrews -type: fixed diff --git a/changelogs/unreleased/filter-merge-requests-by-target-branch.yml b/changelogs/unreleased/filter-merge-requests-by-target-branch.yml deleted file mode 100644 index d0aba631c96..00000000000 --- a/changelogs/unreleased/filter-merge-requests-by-target-branch.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add target branch filter to merge requests search bar -merge_request: 24380 -author: Hiroyuki Sato -type: added diff --git a/changelogs/unreleased/fix-UI-links-to-route-map-info.yml b/changelogs/unreleased/fix-UI-links-to-route-map-info.yml deleted file mode 100644 index bb506507080..00000000000 --- a/changelogs/unreleased/fix-UI-links-to-route-map-info.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix UI anchor links after docs refactor -merge_request: 26890 -author: -type: fixed diff --git a/changelogs/unreleased/fix-container-scanning-on-k8s.yml b/changelogs/unreleased/fix-container-scanning-on-k8s.yml deleted file mode 100644 index f4500370a0b..00000000000 --- a/changelogs/unreleased/fix-container-scanning-on-k8s.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Container Scanning in Kubernetes Runners -merge_request: 26793 -author: -type: changed diff --git a/changelogs/unreleased/fix-expand-full-file-on-image.yml b/changelogs/unreleased/fix-expand-full-file-on-image.yml deleted file mode 100644 index a88d30cfa38..00000000000 --- a/changelogs/unreleased/fix-expand-full-file-on-image.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed expand full file button showing on images -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-hidden-statistics.yml b/changelogs/unreleased/fix-hidden-statistics.yml deleted file mode 100644 index 4d99bd00136..00000000000 --- a/changelogs/unreleased/fix-hidden-statistics.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show statistics also when repository is disabled -merge_request: 26509 -author: Peter Marko -type: fixed diff --git a/changelogs/unreleased/fix-ide-web-worker-relative-url.yml b/changelogs/unreleased/fix-ide-web-worker-relative-url.yml deleted file mode 100644 index 2accad68c4e..00000000000 --- a/changelogs/unreleased/fix-ide-web-worker-relative-url.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed Web IDE web workers not working with relative URLs -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-include-ci-yaml.yml b/changelogs/unreleased/fix-include-ci-yaml.yml deleted file mode 100644 index 042413b89aa..00000000000 --- a/changelogs/unreleased/fix-include-ci-yaml.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix single string values for the 'include' keyword validation of gitlab-ci.yml. -merge_request: 26998 -author: Paul Bonaud (@paulrbr) -type: fixed diff --git a/changelogs/unreleased/fix-issues-time-counter.yml b/changelogs/unreleased/fix-issues-time-counter.yml deleted file mode 100644 index 76f17063db5..00000000000 --- a/changelogs/unreleased/fix-issues-time-counter.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make time counters show 'just now' for everything under one minute -merge_request: 25992 -author: Sergiu Marton -type: changed diff --git a/changelogs/unreleased/fix-merge-request-relations-with-pipeline-on-mwps.yml b/changelogs/unreleased/fix-merge-request-relations-with-pipeline-on-mwps.yml deleted file mode 100644 index 9ccc79109d8..00000000000 --- a/changelogs/unreleased/fix-merge-request-relations-with-pipeline-on-mwps.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix MWPS does not work for merge request pipelines -merge_request: 26906 -author: -type: fixed diff --git a/changelogs/unreleased/fix-new-merge-request-diff-headers-sticky-position.yml b/changelogs/unreleased/fix-new-merge-request-diff-headers-sticky-position.yml deleted file mode 100644 index dadbd5c940f..00000000000 --- a/changelogs/unreleased/fix-new-merge-request-diff-headers-sticky-position.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed sticky headers in merge request creation diffs -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-pipeline-entity.yml b/changelogs/unreleased/fix-pipeline-entity.yml deleted file mode 100644 index b429139402c..00000000000 --- a/changelogs/unreleased/fix-pipeline-entity.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add merge request pipeline flag to pipeline entity -merge_request: 25846 -author: -type: added diff --git a/changelogs/unreleased/fix-review-app-env-url.yml b/changelogs/unreleased/fix-review-app-env-url.yml deleted file mode 100644 index 963cd0c2992..00000000000 --- a/changelogs/unreleased/fix-review-app-env-url.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes long review app subdomains -merge_request: 25990 -author: walkafwalka -type: fixed diff --git a/changelogs/unreleased/fix-routes-n-plus-one-in-user-autocomplete.yml b/changelogs/unreleased/fix-routes-n-plus-one-in-user-autocomplete.yml deleted file mode 100644 index ae097e859d9..00000000000 --- a/changelogs/unreleased/fix-routes-n-plus-one-in-user-autocomplete.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix some N+1s in loading routes and counting members for groups in @-autocomplete -merge_request: 26491 -author: -type: performance diff --git a/changelogs/unreleased/fix-transfer-group-possibilities.yml b/changelogs/unreleased/fix-transfer-group-possibilities.yml deleted file mode 100644 index ebefb47b3da..00000000000 --- a/changelogs/unreleased/fix-transfer-group-possibilities.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix group transfer selection possibilities -merge_request: 26123 -author: Peter Marko -type: fixed diff --git a/changelogs/unreleased/fixed-duplicated-large-text-on-diffs.yml b/changelogs/unreleased/fixed-duplicated-large-text-on-diffs.yml deleted file mode 100644 index 770186a64b0..00000000000 --- a/changelogs/unreleased/fixed-duplicated-large-text-on-diffs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed duplicated diff too large error message -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fixed-web-ide-merge-request-review.yml b/changelogs/unreleased/fixed-web-ide-merge-request-review.yml deleted file mode 100644 index 2799f5ee38a..00000000000 --- a/changelogs/unreleased/fixed-web-ide-merge-request-review.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed Web IDE not loading merge request files -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fj-60827-fix-web-strategy-error.yml b/changelogs/unreleased/fj-60827-fix-web-strategy-error.yml new file mode 100644 index 00000000000..ad707ca0225 --- /dev/null +++ b/changelogs/unreleased/fj-60827-fix-web-strategy-error.yml @@ -0,0 +1,5 @@ +--- +title: Fix bug when project export to remote url fails +merge_request: 27614 +author: +type: fixed diff --git a/changelogs/unreleased/gitaly-version-v1.29.0.yml b/changelogs/unreleased/gitaly-version-v1.29.0.yml deleted file mode 100644 index b6ce14c33a2..00000000000 --- a/changelogs/unreleased/gitaly-version-v1.29.0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade to Gitaly v1.29.0 -merge_request: 26406 -author: -type: changed diff --git a/changelogs/unreleased/gitaly-version-v1.32.0.yml b/changelogs/unreleased/gitaly-version-v1.32.0.yml deleted file mode 100644 index 8413f31278e..00000000000 --- a/changelogs/unreleased/gitaly-version-v1.32.0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade to Gitaly v1.32.0 -merge_request: 26989 -author: -type: changed diff --git a/changelogs/unreleased/gitaly-version-v1.33.0.yml b/changelogs/unreleased/gitaly-version-v1.33.0.yml deleted file mode 100644 index d21e521a0bb..00000000000 --- a/changelogs/unreleased/gitaly-version-v1.33.0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade to Gitaly v1.33.0 -merge_request: 27065 -author: -type: changed diff --git a/changelogs/unreleased/graphql-prometheus.yml b/changelogs/unreleased/graphql-prometheus.yml deleted file mode 100644 index 180577f3aec..00000000000 --- a/changelogs/unreleased/graphql-prometheus.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added prometheus monitoring to GraphQL -merge_request: -author: -type: added diff --git a/changelogs/unreleased/gt-externalize-app-views-projects-pipelines.yml b/changelogs/unreleased/gt-externalize-app-views-projects-pipelines.yml deleted file mode 100644 index 094cd3ab751..00000000000 --- a/changelogs/unreleased/gt-externalize-app-views-projects-pipelines.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Externalize strings from `/app/views/projects/pipelines` -merge_request: 26035 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/id-51433-sort-wiki-by-date.yml b/changelogs/unreleased/id-51433-sort-wiki-by-date.yml deleted file mode 100644 index 86fcf195fa7..00000000000 --- a/changelogs/unreleased/id-51433-sort-wiki-by-date.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow to sort wiki pages by date and title -merge_request: 25365 -author: -type: added diff --git a/changelogs/unreleased/ide-fix-detect-mr-from-fork.yml b/changelogs/unreleased/ide-fix-detect-mr-from-fork.yml deleted file mode 100644 index 8f4f49896d7..00000000000 --- a/changelogs/unreleased/ide-fix-detect-mr-from-fork.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix IDE detection of MR from fork with same branch name -merge_request: 26986 -author: -type: fixed diff --git a/changelogs/unreleased/issue_58547.yml b/changelogs/unreleased/issue_58547.yml deleted file mode 100644 index 553c752e72d..00000000000 --- a/changelogs/unreleased/issue_58547.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add API access check to Graphql -merge_request: 26570 -author: -type: other diff --git a/changelogs/unreleased/jc-guard-against-empty-dereferenced_target.yml b/changelogs/unreleased/jc-guard-against-empty-dereferenced_target.yml deleted file mode 100644 index 94e5b4a81b7..00000000000 --- a/changelogs/unreleased/jc-guard-against-empty-dereferenced_target.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Guard against nil dereferenced_target -merge_request: 27192 -author: -type: fixed diff --git a/changelogs/unreleased/jc-upgrade-gitaly-1-34-0.yml b/changelogs/unreleased/jc-upgrade-gitaly-1-34-0.yml deleted file mode 100644 index c1669a484aa..00000000000 --- a/changelogs/unreleased/jc-upgrade-gitaly-1-34-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade Gitaly to 1.34.0 -merge_request: 27494 -author: -type: fixed diff --git a/changelogs/unreleased/jv-dedup-activerecord.yml b/changelogs/unreleased/jv-dedup-activerecord.yml new file mode 100644 index 00000000000..7b440c7c0db --- /dev/null +++ b/changelogs/unreleased/jv-dedup-activerecord.yml @@ -0,0 +1,6 @@ +--- +title: Fix wrong use of ActiveRecord in PoolRepository +merge_request: 27464 +author: +type: fixed + diff --git a/changelogs/unreleased/k8s_new_deployment_labels.yml b/changelogs/unreleased/k8s_new_deployment_labels.yml deleted file mode 100644 index e9ef3ee0082..00000000000 --- a/changelogs/unreleased/k8s_new_deployment_labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update deploy boards to additionally select on "app.gitlab.com" annotations -merge_request: 25623 -author: -type: changed diff --git a/changelogs/unreleased/knative-prometheus.yml b/changelogs/unreleased/knative-prometheus.yml deleted file mode 100644 index e24f53b7225..00000000000 --- a/changelogs/unreleased/knative-prometheus.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add Knative metrics to Prometheus -merge_request: 24663 -author: Chris Baumbauer <cab@cabnetworks.net> -type: added diff --git a/changelogs/unreleased/knative-update.yml b/changelogs/unreleased/knative-update.yml deleted file mode 100644 index e84940ae7e0..00000000000 --- a/changelogs/unreleased/knative-update.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Knative version bump 0.2.2 -> 0.3.0 -merge_request: 26459 -author: Chris Baumbauer -type: changed diff --git a/changelogs/unreleased/kube_helm_auto_devops_213.yml b/changelogs/unreleased/kube_helm_auto_devops_213.yml deleted file mode 100644 index 3c718d4a22c..00000000000 --- a/changelogs/unreleased/kube_helm_auto_devops_213.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump kubectl to 1.11.9 and Helm to 2.13.1 in Auto-DevOps.gitlab-ci.yml -merge_request: 26534 -author: -type: other diff --git a/changelogs/unreleased/limit-amount-of-created-pipelines.yml b/changelogs/unreleased/limit-amount-of-created-pipelines.yml deleted file mode 100644 index 51fdbb4d7ff..00000000000 --- a/changelogs/unreleased/limit-amount-of-created-pipelines.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Process at most 4 pipelines during push -merge_request: 27205 -author: -type: performance diff --git a/changelogs/unreleased/localize-notification-dropdown.yml b/changelogs/unreleased/localize-notification-dropdown.yml deleted file mode 100644 index 9599aaf344b..00000000000 --- a/changelogs/unreleased/localize-notification-dropdown.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Localize notifications dropdown -merge_request: 26844 -author: -type: changed diff --git a/changelogs/unreleased/minimized-multiple-queries-ce.yml b/changelogs/unreleased/minimized-multiple-queries-ce.yml deleted file mode 100644 index d8c20d492d6..00000000000 --- a/changelogs/unreleased/minimized-multiple-queries-ce.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Support multiple queries per chart on metrics dash -merge_request: 25758 -author: -type: added diff --git a/changelogs/unreleased/move-allow-developers-to-create-projects-in-groups-to-core.yml b/changelogs/unreleased/move-allow-developers-to-create-projects-in-groups-to-core.yml deleted file mode 100644 index 34fd0c1b787..00000000000 --- a/changelogs/unreleased/move-allow-developers-to-create-projects-in-groups-to-core.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move allow developers to create projects in groups to Core -merge_request: 25975 -author: -type: added diff --git a/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml b/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml deleted file mode 100644 index 8cde0958f7a..00000000000 --- a/changelogs/unreleased/nfriend-css-updates-for-gitlab-design-system-compliance.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update `border-radius` of form controls and remove extra space above page titles -merge_request: 24497 -author: -type: fixed diff --git a/changelogs/unreleased/nfriend-update-job-detail-view-sidebar.yml b/changelogs/unreleased/nfriend-update-job-detail-view-sidebar.yml deleted file mode 100644 index 5364d29710a..00000000000 --- a/changelogs/unreleased/nfriend-update-job-detail-view-sidebar.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update job detail sidebar to accommodate post-merge pipeline information -merge_request: 25777 -author: -type: added diff --git a/changelogs/unreleased/nfriend-update-merge-request-widget-for-post-merge-pipelines.yml b/changelogs/unreleased/nfriend-update-merge-request-widget-for-post-merge-pipelines.yml deleted file mode 100644 index 420c8f2923c..00000000000 --- a/changelogs/unreleased/nfriend-update-merge-request-widget-for-post-merge-pipelines.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add two new warning messages to the MR widget about merge request pipelines -merge_request: 25983 -author: -type: added diff --git a/changelogs/unreleased/nfriend-update-merge-request-widget-pipeline-block.yml b/changelogs/unreleased/nfriend-update-merge-request-widget-pipeline-block.yml deleted file mode 100644 index bd4120eb06f..00000000000 --- a/changelogs/unreleased/nfriend-update-merge-request-widget-pipeline-block.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Update pipeline block on merge request page to accommodate post-merge pipeline - information -merge_request: 25745 -author: -type: added diff --git a/changelogs/unreleased/nfriend-update-pipeline-detail-view.yml b/changelogs/unreleased/nfriend-update-pipeline-detail-view.yml deleted file mode 100644 index a24325c4eb6..00000000000 --- a/changelogs/unreleased/nfriend-update-pipeline-detail-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update pipeline detail view to accommodate post-merge pipelines -merge_request: 25775 -author: -type: added diff --git a/changelogs/unreleased/nfriend-update-pipeline-list-view.yml b/changelogs/unreleased/nfriend-update-pipeline-list-view.yml deleted file mode 100644 index 34e43162b5c..00000000000 --- a/changelogs/unreleased/nfriend-update-pipeline-list-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update pipeline list view to accommodate post-merge pipeline information -merge_request: 25690 -author: -type: added diff --git a/changelogs/unreleased/only-counted-active-milestones-as-started.yml b/changelogs/unreleased/only-counted-active-milestones-as-started.yml deleted file mode 100644 index 1a9c4b9023b..00000000000 --- a/changelogs/unreleased/only-counted-active-milestones-as-started.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Only consider active milestones when using the special Started milestone filter -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/osw-multi-line-suggestions-creation-strategy.yml b/changelogs/unreleased/osw-multi-line-suggestions-creation-strategy.yml deleted file mode 100644 index 01bd7ede270..00000000000 --- a/changelogs/unreleased/osw-multi-line-suggestions-creation-strategy.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Implements the creation strategy for multi-line suggestions -merge_request: 26057 -author: -type: changed diff --git a/changelogs/unreleased/osw-multi-line-suggestions-parsing.yml b/changelogs/unreleased/osw-multi-line-suggestions-parsing.yml deleted file mode 100644 index 985b01e9254..00000000000 --- a/changelogs/unreleased/osw-multi-line-suggestions-parsing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prepare multi-line suggestions for rendering in Markdown -merge_request: 26107 -author: -type: other diff --git a/changelogs/unreleased/osw-support-multi-line-suggestions.yml b/changelogs/unreleased/osw-support-multi-line-suggestions.yml deleted file mode 100644 index 8c8206c3822..00000000000 --- a/changelogs/unreleased/osw-support-multi-line-suggestions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Support multi-line suggestions -merge_request: 25211 -author: -type: added diff --git a/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml b/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml deleted file mode 100644 index ca42a26e8ff..00000000000 --- a/changelogs/unreleased/persist-fulll-ref-path-for-mr-pipelines.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create MR pipelines with `refs/merge-requests/:iid/head` -merge_request: 25504 -author: -type: changed diff --git a/changelogs/unreleased/pravi-gitlab-ce-update-recaptcha.yml b/changelogs/unreleased/pravi-gitlab-ce-update-recaptcha.yml deleted file mode 100644 index 95379fb2ec1..00000000000 --- a/changelogs/unreleased/pravi-gitlab-ce-update-recaptcha.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Apply recaptcha API change in 4.0 -merge_request: 25921 -author: Praveen Arimbrathodiyil -type: other diff --git a/changelogs/unreleased/prevent-running-mr-pipelines-when-target-updated.yml b/changelogs/unreleased/prevent-running-mr-pipelines-when-target-updated.yml deleted file mode 100644 index d003ca55feb..00000000000 --- a/changelogs/unreleased/prevent-running-mr-pipelines-when-target-updated.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create pipelines for merge requests only when source branch is updated -merge_request: 26921 -author: -type: fixed diff --git a/changelogs/unreleased/rails5-1.yml b/changelogs/unreleased/rails5-1.yml new file mode 100644 index 00000000000..da16735bb0d --- /dev/null +++ b/changelogs/unreleased/rails5-1.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade to Rails 5.1 +merge_request: 27480 +author: Jasper Maes +type: other diff --git a/changelogs/unreleased/related-mr-link-cutoff.yml b/changelogs/unreleased/related-mr-link-cutoff.yml deleted file mode 100644 index 8cf77b6231a..00000000000 --- a/changelogs/unreleased/related-mr-link-cutoff.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't cutoff letters in MR and Issue links -merge_request: 25910 -author: gfyoung -type: fixed diff --git a/changelogs/unreleased/remove-ci-charts-undescriptive-header.yml b/changelogs/unreleased/remove-ci-charts-undescriptive-header.yml deleted file mode 100644 index 0e090592101..00000000000 --- a/changelogs/unreleased/remove-ci-charts-undescriptive-header.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes the undescriptive CI Charts header -merge_request: !26869 -author: -type: changed diff --git a/changelogs/unreleased/security-55503-fix-pdf-js-vulnerability.yml b/changelogs/unreleased/security-55503-fix-pdf-js-vulnerability.yml deleted file mode 100644 index e5d0cd4fee1..00000000000 --- a/changelogs/unreleased/security-55503-fix-pdf-js-vulnerability.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix PDF.js vulnerability -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-56224.yml b/changelogs/unreleased/security-56224.yml deleted file mode 100644 index a4e274e6ca5..00000000000 --- a/changelogs/unreleased/security-56224.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Hide "related branches" when user does not have permission -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-56927-xss-resolve-conflicts-branch-name.yml b/changelogs/unreleased/security-56927-xss-resolve-conflicts-branch-name.yml deleted file mode 100644 index f92d2c0dcb1..00000000000 --- a/changelogs/unreleased/security-56927-xss-resolve-conflicts-branch-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix XSS in resolve conflicts form -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-exif-migration.yml b/changelogs/unreleased/security-exif-migration.yml deleted file mode 100644 index cc529099df5..00000000000 --- a/changelogs/unreleased/security-exif-migration.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added rake task for removing EXIF data from existing uploads. -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-id-potential-denial-languages.yml b/changelogs/unreleased/security-id-potential-denial-languages.yml deleted file mode 100644 index 2194ecb97dc..00000000000 --- a/changelogs/unreleased/security-id-potential-denial-languages.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Return cached languages if they've been detected before -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-mass-assignment-on-project-update.yml b/changelogs/unreleased/security-mass-assignment-on-project-update.yml deleted file mode 100644 index 93561cd91b3..00000000000 --- a/changelogs/unreleased/security-mass-assignment-on-project-update.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disallow updating namespace when updating a project -merge_request: -author: -type: security diff --git a/changelogs/unreleased/sh-add-gitaly-duration-logs.yml b/changelogs/unreleased/sh-add-gitaly-duration-logs.yml deleted file mode 100644 index eea50384278..00000000000 --- a/changelogs/unreleased/sh-add-gitaly-duration-logs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Log Gitaly RPC duration to api_json.log and production_json.log -merge_request: 26652 -author: -type: other diff --git a/changelogs/unreleased/sh-add-gitaly-ref-name-caching-tree-controller.yml b/changelogs/unreleased/sh-add-gitaly-ref-name-caching-tree-controller.yml deleted file mode 100644 index a051c1f70a8..00000000000 --- a/changelogs/unreleased/sh-add-gitaly-ref-name-caching-tree-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable Gitaly FindCommit caching for TreeController -merge_request: 27100 -author: -type: performance diff --git a/changelogs/unreleased/sh-avoid-fetching-temp-refs-within-project.yml b/changelogs/unreleased/sh-avoid-fetching-temp-refs-within-project.yml new file mode 100644 index 00000000000..7511543f7f6 --- /dev/null +++ b/changelogs/unreleased/sh-avoid-fetching-temp-refs-within-project.yml @@ -0,0 +1,5 @@ +--- +title: Don't create a temp reference for branch comparisons within project +merge_request: 24038 +author: +type: fixed diff --git a/changelogs/unreleased/sh-backport-list-commits-by-oid-rugged.yml b/changelogs/unreleased/sh-backport-list-commits-by-oid-rugged.yml deleted file mode 100644 index eb8774d652f..00000000000 --- a/changelogs/unreleased/sh-backport-list-commits-by-oid-rugged.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bring back Rugged implementation of ListCommitsByOid -merge_request: 27441 -author: -type: performance diff --git a/changelogs/unreleased/sh-bump-ruby-required-version-check.yml b/changelogs/unreleased/sh-bump-ruby-required-version-check.yml deleted file mode 100644 index b5b6eb87650..00000000000 --- a/changelogs/unreleased/sh-bump-ruby-required-version-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump required Ruby version check to 2.5.3 -merge_request: 27495 -author: -type: other diff --git a/changelogs/unreleased/sh-cache-pipeline-find-commits.yml b/changelogs/unreleased/sh-cache-pipeline-find-commits.yml deleted file mode 100644 index 2acf180d6fa..00000000000 --- a/changelogs/unreleased/sh-cache-pipeline-find-commits.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cache FindCommit results in pipelines view -merge_request: 26776 -author: -type: performance diff --git a/changelogs/unreleased/sh-cache-root-ref-asymetrically.yml b/changelogs/unreleased/sh-cache-root-ref-asymetrically.yml deleted file mode 100644 index 106d070cc05..00000000000 --- a/changelogs/unreleased/sh-cache-root-ref-asymetrically.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cache Repository#root_ref within a request -merge_request: 25903 -author: -type: performance diff --git a/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml b/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml deleted file mode 100644 index 55779f0f9d3..00000000000 --- a/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clear pipeline status cache after destruction of pipeline -merge_request: 26575 -author: -type: fixed diff --git a/changelogs/unreleased/sh-disable-internal-ids-available-check.yml b/changelogs/unreleased/sh-disable-internal-ids-available-check.yml new file mode 100644 index 00000000000..069a9ba7d69 --- /dev/null +++ b/changelogs/unreleased/sh-disable-internal-ids-available-check.yml @@ -0,0 +1,5 @@ +--- +title: Always use internal ID tables in development and production +merge_request: 27544 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml b/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml deleted file mode 100644 index 16d349c407c..00000000000 --- a/changelogs/unreleased/sh-fix-gitaly-find-commit-caching.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow ref name caching CommitService#find_commit -merge_request: 26248 -author: -type: performance diff --git a/changelogs/unreleased/sh-fix-issue-59065.yml b/changelogs/unreleased/sh-fix-issue-59065.yml deleted file mode 100644 index 41cd5ce0960..00000000000 --- a/changelogs/unreleased/sh-fix-issue-59065.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Error 500 when user commits Wiki page with no commit message -merge_request: 26247 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-merge-requests-api-remove-branch-param.yml b/changelogs/unreleased/sh-fix-merge-requests-api-remove-branch-param.yml deleted file mode 100644 index d13c972ccc9..00000000000 --- a/changelogs/unreleased/sh-fix-merge-requests-api-remove-branch-param.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix remove_source_branch merge request API handling -merge_request: 27392 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-realtime-changes-with-reserved-words.yml b/changelogs/unreleased/sh-fix-realtime-changes-with-reserved-words.yml deleted file mode 100644 index 3d1501cd667..00000000000 --- a/changelogs/unreleased/sh-fix-realtime-changes-with-reserved-words.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix real-time updates for projects that contain a reserved word -merge_request: 27060 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-ref-name-caching.yml b/changelogs/unreleased/sh-fix-ref-name-caching.yml deleted file mode 100644 index 6abd86688b4..00000000000 --- a/changelogs/unreleased/sh-fix-ref-name-caching.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix and expand Gitaly FindCommit caching -merge_request: 27018 -author: -type: performance diff --git a/changelogs/unreleased/sh-git-gc-after-initial-fetch.yml b/changelogs/unreleased/sh-git-gc-after-initial-fetch.yml deleted file mode 100644 index 867d7e6b9df..00000000000 --- a/changelogs/unreleased/sh-git-gc-after-initial-fetch.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'GitHub import: Run housekeeping after initial import' -merge_request: 26600 -author: -type: performance diff --git a/changelogs/unreleased/sh-improve-find-commit-caching.yml b/changelogs/unreleased/sh-improve-find-commit-caching.yml deleted file mode 100644 index 1b38684d018..00000000000 --- a/changelogs/unreleased/sh-improve-find-commit-caching.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expand FindCommit caching to blob and refs -merge_request: 27084 -author: -type: performance diff --git a/changelogs/unreleased/sh-reject-info-refs-head-requests.yml b/changelogs/unreleased/sh-reject-info-refs-head-requests.yml deleted file mode 100644 index 0dca18e2fd8..00000000000 --- a/changelogs/unreleased/sh-reject-info-refs-head-requests.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reject HEAD requests to info/refs endpoint -merge_request: 26334 -author: -type: fixed diff --git a/changelogs/unreleased/sh-skip-sti-tables-reltuples.yml b/changelogs/unreleased/sh-skip-sti-tables-reltuples.yml deleted file mode 100644 index 5bf0ccf3e9d..00000000000 --- a/changelogs/unreleased/sh-skip-sti-tables-reltuples.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix counting of groups in admin dashboard -merge_request: 26009 -author: -type: fixed diff --git a/changelogs/unreleased/sh-update-rails-5-0-7-2.yml b/changelogs/unreleased/sh-update-rails-5-0-7-2.yml deleted file mode 100644 index b0bc08d4760..00000000000 --- a/changelogs/unreleased/sh-update-rails-5-0-7-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update Rails to 5.0.7.2 -merge_request: 27022 -author: -type: security diff --git a/changelogs/unreleased/sh-upgrade-grpc-and-protobuf.yml b/changelogs/unreleased/sh-upgrade-grpc-and-protobuf.yml new file mode 100644 index 00000000000..a43a59a4f8a --- /dev/null +++ b/changelogs/unreleased/sh-upgrade-grpc-and-protobuf.yml @@ -0,0 +1,5 @@ +--- +title: Bump gRPC to 1.19.0 and protobuf to 3.7.1 +merge_request: 27086 +author: +type: other diff --git a/changelogs/unreleased/stop-signing-avatar-paths.yml b/changelogs/unreleased/stop-signing-avatar-paths.yml deleted file mode 100644 index 2c2493f0f21..00000000000 --- a/changelogs/unreleased/stop-signing-avatar-paths.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Speed up generation of avatar URLs when using object storage -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/support-negative-matches.yml b/changelogs/unreleased/support-negative-matches.yml new file mode 100644 index 00000000000..8d3f2d3cbae --- /dev/null +++ b/changelogs/unreleased/support-negative-matches.yml @@ -0,0 +1,5 @@ +--- +title: Support negative matches +merge_request: +author: +type: added diff --git a/changelogs/unreleased/tpresa-add-highest-role-to-user.yml b/changelogs/unreleased/tpresa-add-highest-role-to-user.yml deleted file mode 100644 index 9714d8dcc99..00000000000 --- a/changelogs/unreleased/tpresa-add-highest-role-to-user.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adding highest role property to admin's user details page -merge_request: -author: -type: added diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml deleted file mode 100644 index 2e1adb1e1e9..00000000000 --- a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update GitLab Runner Helm Chart to 0.3.0/11.9.0 -merge_request: 26467 -author: -type: other diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-4-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-4-0.yml new file mode 100644 index 00000000000..7eb5bd58035 --- /dev/null +++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-4-0.yml @@ -0,0 +1,5 @@ +--- +title: Update GitLab Runner Helm Chart to 0.4.0 +merge_request: 27508 +author: +type: other diff --git a/changelogs/unreleased/update-gitlab-shell.yml b/changelogs/unreleased/update-gitlab-shell.yml deleted file mode 100644 index 446a5fe1ea9..00000000000 --- a/changelogs/unreleased/update-gitlab-shell.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update GitLab Shell to v9.0.0 -merge_request: 27002 -author: -type: other diff --git a/changelogs/unreleased/update-rack-oauth2.yml b/changelogs/unreleased/update-rack-oauth2.yml deleted file mode 100644 index dc2e7017695..00000000000 --- a/changelogs/unreleased/update-rack-oauth2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update rack-oauth2 1.2.1 -> 1.9.3 -merge_request: 17868 -author: -type: other diff --git a/changelogs/unreleased/update-workhorse-8-5-1.yml b/changelogs/unreleased/update-workhorse-8-5-1.yml deleted file mode 100644 index 18193701678..00000000000 --- a/changelogs/unreleased/update-workhorse-8-5-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update GitLab Workhorse to v8.5.1 -merge_request: 27217 -author: -type: fixed diff --git a/changelogs/unreleased/update-workhorse-master.yml b/changelogs/unreleased/update-workhorse-master.yml new file mode 100644 index 00000000000..97e2e891ab1 --- /dev/null +++ b/changelogs/unreleased/update-workhorse-master.yml @@ -0,0 +1,5 @@ +--- +title: Update Workhorse to v8.7.0 +merge_request: 27630 +author: +type: fixed diff --git a/changelogs/unreleased/use-only-all-pipelines.yml b/changelogs/unreleased/use-only-all-pipelines.yml deleted file mode 100644 index 68364d2a923..00000000000 --- a/changelogs/unreleased/use-only-all-pipelines.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Refactor all_pipelines in Merge request -merge_request: 25676 -author: -type: other diff --git a/changelogs/unreleased/use-untrusted-regexp.yml b/changelogs/unreleased/use-untrusted-regexp.yml deleted file mode 100644 index dd7f1bcaca1..00000000000 --- a/changelogs/unreleased/use-untrusted-regexp.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use UntrustedRegexp for matching refs policy -merge_request: -author: -type: security diff --git a/changelogs/unreleased/winh-toggle-comment-draft.yml b/changelogs/unreleased/winh-toggle-comment-draft.yml deleted file mode 100644 index 6b4aad55a05..00000000000 --- a/changelogs/unreleased/winh-toggle-comment-draft.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Display draft when toggling replies -merge_request: 25563 -author: -type: fixed diff --git a/changelogs/unreleased/xanf-gitlab-ce-improve-project-overview.yml b/changelogs/unreleased/xanf-gitlab-ce-improve-project-overview.yml new file mode 100644 index 00000000000..9755540953a --- /dev/null +++ b/changelogs/unreleased/xanf-gitlab-ce-improve-project-overview.yml @@ -0,0 +1,5 @@ +--- +title: Improve icons and button order in project overview +merge_request: 26796 +author: +type: other diff --git a/changelogs/unreleased/xanf-gitlab-ce-move-project-tags.yml b/changelogs/unreleased/xanf-gitlab-ce-move-project-tags.yml deleted file mode 100644 index 124584c9bd4..00000000000 --- a/changelogs/unreleased/xanf-gitlab-ce-move-project-tags.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move project tags to separate line -merge_request: 26797 -author: -type: other diff --git a/changelogs/unreleased/xanf-gitlab-ce-transfer-disables-js.yml b/changelogs/unreleased/xanf-gitlab-ce-transfer-disables-js.yml deleted file mode 100644 index 57c9a1aaa48..00000000000 --- a/changelogs/unreleased/xanf-gitlab-ce-transfer-disables-js.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Group transfer now properly redirects to edit on failure -merge_request: 26837 -author: -type: fixed diff --git a/config/application.rb b/config/application.rb index cbcfef34e01..cddd91f267a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -164,9 +164,6 @@ module Gitlab # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' - # Can be removed once upgraded to Rails 5.1 or higher - config.action_controller.raise_on_unfiltered_parameters = true - # Nokogiri is significantly faster and uses less memory than REXML ActiveSupport::XmlMini.backend = 'Nokogiri' diff --git a/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb b/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb deleted file mode 100644 index 228ced32188..00000000000 --- a/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb +++ /dev/null @@ -1,94 +0,0 @@ -# This is a monkey patch which must be removed when migrating to Rails 5.1 from 5.0. -# -# In Rails 5.0 there was introduced a bug which casts types in the uniqueness validator. -# https://github.com/rails/rails/pull/23523/commits/811a4fa8eb6ceea841e61e8ac05747ffb69595ae -# -# That causes to bugs like this: -# -# 1) API::Users POST /user/:id/gpg_keys/:key_id/revoke when authenticated revokes existing key -# Failure/Error: let(:gpg_key) { create(:gpg_key, user: user) } -# -# TypeError: -# can't cast Hash -# # ./spec/requests/api/users_spec.rb:7:in `block (2 levels) in <top (required)>' -# # ./spec/requests/api/users_spec.rb:908:in `block (4 levels) in <top (required)>' -# # ------------------ -# # --- Caused by: --- -# # TypeError: -# # TypeError -# # ./spec/requests/api/users_spec.rb:7:in `block (2 levels) in <top (required)>' -# -# This bug was fixed in Rails 5.1 by https://github.com/rails/rails/pull/24745/commits/aa062318c451512035c10898a1af95943b1a3803 - -if Rails.gem_version >= Gem::Version.new("5.1") - raise "Remove this monkey patch: #{__FILE__}" -end - -# Copy-paste from https://github.com/kamipo/rails/blob/aa062318c451512035c10898a1af95943b1a3803/activerecord/lib/active_record/validations/uniqueness.rb -# including local fixes to make Rubocop happy again. -module ActiveRecord - module Validations - class UniquenessValidator < ActiveModel::EachValidator # :nodoc: - def validate_each(record, attribute, value) - finder_class = find_finder_class_for(record) - table = finder_class.arel_table - value = map_enum_attribute(finder_class, attribute, value) - - relation = build_relation(finder_class, table, attribute, value) - - if record.persisted? - if finder_class.primary_key - relation = relation.where.not(finder_class.primary_key => record.id_was || record.id) - else - raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.") - end - end - - relation = scope_relation(record, table, relation) - relation = relation.merge(options[:conditions]) if options[:conditions] - - if relation.exists? - error_options = options.except(:case_sensitive, :scope, :conditions) - error_options[:value] = value - - record.errors.add(attribute, :taken, error_options) - end - rescue RangeError - end - - protected - - def build_relation(klass, table, attribute, value) #:nodoc: - if reflection = klass._reflect_on_association(attribute) - attribute = reflection.foreign_key - value = value.attributes[reflection.klass.primary_key] unless value.nil? - end - - # the attribute may be an aliased attribute - if klass.attribute_alias?(attribute) - attribute = klass.attribute_alias(attribute) - end - - attribute_name = attribute.to_s - - column = klass.columns_hash[attribute_name] - cast_type = klass.type_for_attribute(attribute_name) - - comparison = - if !options[:case_sensitive] && !value.nil? - # will use SQL LOWER function before comparison, unless it detects a case insensitive collation - klass.connection.case_insensitive_comparison(table, attribute, column, value) - else - klass.connection.case_sensitive_comparison(table, attribute, column, value) - end - - if value.nil? - klass.unscoped.where(comparison) - else - bind = Relation::QueryAttribute.new(attribute_name, value, cast_type) - klass.unscoped.where(comparison, bind) - end - end - end - end -end diff --git a/config/initializers/active_record_build_select.rb b/config/initializers/active_record_build_select.rb new file mode 100644 index 00000000000..ab5a872cac6 --- /dev/null +++ b/config/initializers/active_record_build_select.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# rubocop:disable Gitlab/ModuleWithInstanceVariables + +# build_select only selects the required fields if the model has ignored_columns. +# This is incompatible with some migrations or background migration specs because +# rails keeps a statement cache in memory. So if a model with ignored_columns in a +# migration is used, the query with select table.col1, table.col2 is stored in the +# statement cache. If a different migration is then run and one of these columns is +# removed in the meantime, the query is invalid. + +module ActiveRecord + module QueryMethods + private + + def build_select(arel) + if select_values.any? + arel.project(*arel_columns(select_values.uniq)) + else + arel.project(@klass.arel_table[Arel.star]) + end + end + end +end diff --git a/config/initializers/active_record_locking.rb b/config/initializers/active_record_locking.rb deleted file mode 100644 index 1bd1a12e4b7..00000000000 --- a/config/initializers/active_record_locking.rb +++ /dev/null @@ -1,76 +0,0 @@ -# rubocop:disable Lint/RescueException - -# Remove this monkey patch when we move to Rails 5.1, because the bug has been fixed in https://github.com/rails/rails/pull/26050. -if Rails.gem_version >= Gem::Version.new("5.1") - raise "Remove this monkey patch: #{__FILE__}" -end - -module ActiveRecord - module Locking - module Optimistic - # We overwrite this method because we don't want to have default value - # for newly created records - def _create_record(attribute_names = self.attribute_names, *) # :nodoc: - super - end - - def _update_record(attribute_names = self.attribute_names) #:nodoc: - return super unless locking_enabled? - return 0 if attribute_names.empty? - - lock_col = self.class.locking_column - previous_lock_value = send(lock_col).to_i - increment_lock - - attribute_names += [lock_col] - attribute_names.uniq! - - begin - relation = self.class.unscoped - - affected_rows = relation.where( - self.class.primary_key => id, - # Patched because when `lock_version` is read as `0`, it may actually be `NULL` in the DB. - lock_col => previous_lock_value == 0 ? [nil, 0] : previous_lock_value - ).update_all( - attributes_for_update(attribute_names).map do |name| - [name, _read_attribute(name)] - end.to_h - ) - - unless affected_rows == 1 - raise ActiveRecord::StaleObjectError.new(self, "update") - end - - affected_rows - - # If something went wrong, revert the version. - rescue Exception - send(lock_col + '=', previous_lock_value) - raise - end - end - - # This is patched because we need it to query `lock_version IS NULL` - # rather than `lock_version = 0` whenever lock_version is NULL. - def relation_for_destroy - return super unless locking_enabled? - - column_name = self.class.locking_column - super.where(self.class.arel_table[column_name].eq(self[column_name])) - end - end - - # This is patched because we want `lock_version` default to `NULL` - # rather than `0` - class LockingType - def deserialize(value) - super - end - - def serialize(value) - super - end - end - end -end diff --git a/config/initializers/ar_native_database_types.rb b/config/initializers/ar_native_database_types.rb index 3522b1db536..6d397661f75 100644 --- a/config/initializers/ar_native_database_types.rb +++ b/config/initializers/ar_native_database_types.rb @@ -4,7 +4,8 @@ module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter NATIVE_DATABASE_TYPES.merge!( - bigserial: { name: 'bigint(20) auto_increment PRIMARY KEY' } + bigserial: { name: 'bigint(20) auto_increment PRIMARY KEY' }, + serial: { name: 'int auto_increment PRIMARY KEY' } ) end end diff --git a/config/initializers/postgresql_opclasses_support.rb b/config/initializers/postgresql_opclasses_support.rb index b066f3788ec..7e912180820 100644 --- a/config/initializers/postgresql_opclasses_support.rb +++ b/config/initializers/postgresql_opclasses_support.rb @@ -78,7 +78,7 @@ module ActiveRecord if index_name.length > max_index_length raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" end - if data_source_exists?(table_name) && index_name_exists?(table_name, index_name, false) + if data_source_exists?(table_name) && index_name_exists?(table_name, index_name) raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" end index_columns = quoted_columns_for_index(column_names, options).join(", ") diff --git a/config/prometheus/common_metrics.yml b/config/prometheus/common_metrics.yml index 356f573c5e9..3c67ca36791 100644 --- a/config/prometheus/common_metrics.yml +++ b/config/prometheus/common_metrics.yml @@ -1,42 +1,33 @@ - # NGINX Ingress metrics for pre-0.16.0 versions +dashboard: 'Environment metrics' +priority: 1 +panel_groups: +# NGINX Ingress metrics for pre-0.16.0 versions - group: Response metrics (NGINX Ingress VTS) priority: 10 - metrics: + panels: - title: "Throughput" + type: "area-chart" y_label: "Requests / Sec" - required_metrics: - - nginx_upstream_responses_total weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_throughput_status_code query_range: 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code)' unit: req / sec label: Status Code - series: - - label: status_code - when: - - value: 2xx - color: green - - value: 4xx - color: orange - - value: 5xx - color: red - title: "Latency" + type: "area-chart" y_label: "Latency (ms)" - required_metrics: - - nginx_upstream_response_msecs_avg weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_latency_pod_average query_range: 'avg(nginx_upstream_response_msecs_avg{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"})' label: Pod average unit: ms - title: "HTTP Error Rate" + type: "area-chart" y_label: "HTTP Errors" - required_metrics: - - nginx_upstream_responses_total weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_http_error_rate query_range: 'sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) * 100' label: 5xx Errors @@ -44,227 +35,179 @@ # NGINX Ingress metrics for post-0.16.0 versions - group: Response metrics (NGINX Ingress) priority: 10 - metrics: + panels: - title: "Throughput" + type: "area-chart" y_label: "Requests / Sec" - required_metrics: - - nginx_ingress_controller_requests weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_16_throughput_status_code query_range: 'sum(label_replace(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m]), "status_code", "${1}xx", "status", "(.)..")) by (status_code)' unit: req / sec label: Status Code - series: - - label: status_code - when: - - value: 2xx - color: green - - value: 3xx - color: blue - - value: 4xx - color: orange - - value: 5xx - color: red - title: "Latency" + type: "area-chart" y_label: "Latency (ms)" - required_metrics: - - nginx_ingress_controller_ingress_upstream_latency_seconds_sum weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_16_latency_pod_average query_range: 'sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 1000' label: Pod average unit: ms - title: "HTTP Error Rate" + type: "area-chart" y_label: "HTTP Errors" - required_metrics: - - nginx_ingress_controller_requests weight: 1 - queries: + metrics: - id: response_metrics_nginx_ingress_16_http_error_rate query_range: 'sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 100' label: 5xx Errors unit: "%" - group: Response metrics (HA Proxy) priority: 10 - metrics: + panels: - title: "Throughput" + type: "area-chart" y_label: "Requests / Sec" - required_metrics: - - haproxy_frontend_http_requests_total weight: 1 - queries: + metrics: - id: response_metrics_ha_proxy_throughput_status_code query_range: 'sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) by (code)' unit: req / sec label: Status Code - series: - - label: status_code - when: - - value: 2xx - color: green - - value: 4xx - color: yellow - - value: 5xx - color: red - title: "HTTP Error Rate" + type: "area-chart" y_label: "Error Rate (%)" - required_metrics: - - haproxy_frontend_http_responses_total weight: 1 - queries: + metrics: - id: response_metrics_ha_proxy_http_error_rate query_range: 'sum(rate(haproxy_frontend_http_responses_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_responses_total{%{environment_filter}}[2m]))' label: HTTP Errors unit: "%" - group: Response metrics (AWS ELB) priority: 10 - metrics: + panels: - title: "Throughput" + type: "area-chart" y_label: "Requests / Sec" - required_metrics: - - aws_elb_request_count_sum weight: 1 - queries: + metrics: - id: response_metrics_aws_elb_throughput_requests query_range: 'sum(aws_elb_request_count_sum{%{environment_filter}}) / 60' label: Total unit: req / sec - title: "Latency" + type: "area-chart" y_label: "Latency (ms)" - required_metrics: - - aws_elb_latency_average weight: 1 - queries: + metrics: - id: response_metrics_aws_elb_latency_average query_range: 'avg(aws_elb_latency_average{%{environment_filter}}) * 1000' label: Average unit: ms - title: "HTTP Error Rate" + type: "area-chart" y_label: "Error Rate (%)" - required_metrics: - - aws_elb_request_count_sum - - aws_elb_httpcode_backend_5_xx_sum weight: 1 - queries: + metrics: - id: response_metrics_aws_elb_http_error_rate query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}})' label: HTTP Errors unit: "%" - group: Response metrics (NGINX) priority: 10 - metrics: + panels: - title: "Throughput" + type: "area-chart" y_label: "Requests / Sec" - required_metrics: - - nginx_server_requests weight: 1 - queries: + metrics: - id: response_metrics_nginx_throughput_status_code query_range: 'sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (code)' unit: req / sec label: Status Code - series: - - label: status_code - when: - - value: 2xx - color: green - - value: 4xx - color: orange - - value: 5xx - color: red - title: "Latency" + type: "area-chart" y_label: "Latency (ms)" - required_metrics: - - nginx_server_requestMsec weight: 1 - queries: + metrics: - id: response_metrics_nginx_latency query_range: 'avg(nginx_server_requestMsec{%{environment_filter}})' label: Upstream unit: ms - title: "HTTP Error Rate" + type: "area-chart" y_label: "HTTP 500 Errors / Sec" - required_metrics: - - nginx_server_requests weight: 1 - queries: + metrics: - id: response_metrics_nginx_http_error_rate query_range: 'sum(rate(nginx_server_requests{code="5xx", %{environment_filter}}[2m]))' label: HTTP Errors unit: "errors / sec" - group: System metrics (Kubernetes) priority: 5 - metrics: + panels: - title: "Memory Usage (Total)" + type: "area-chart" y_label: "Total Memory Used" - required_metrics: - - container_memory_usage_bytes weight: 4 - queries: + metrics: - id: system_metrics_kubernetes_container_memory_total query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024' label: Total unit: GB - title: "Core Usage (Total)" + type: "area-chart" y_label: "Total Cores" - required_metrics: - - container_cpu_usage_seconds_total weight: 3 - queries: + metrics: - id: system_metrics_kubernetes_container_cores_total query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)' label: Total unit: "cores" - title: "Memory Usage (Pod average)" + type: "area-chart" y_label: "Memory Used per Pod" - required_metrics: - - container_memory_usage_bytes weight: 2 - queries: + metrics: - id: system_metrics_kubernetes_container_memory_average query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' label: Pod average unit: MB - title: "Canary: Memory Usage (Pod Average)" + type: "area-chart" y_label: "Memory Used per Pod" - required_metrics: - - container_memory_usage_bytes weight: 2 - queries: + metrics: - id: system_metrics_kubernetes_container_memory_average_canary query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' label: Pod average unit: MB track: canary - title: "Core Usage (Pod Average)" + type: "area-chart" y_label: "Cores per Pod" - required_metrics: - - container_cpu_usage_seconds_total weight: 1 - queries: + metrics: - id: system_metrics_kubernetes_container_core_usage query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' label: Pod average unit: "cores" - title: "Canary: Core Usage (Pod Average)" + type: "area-chart" y_label: "Cores per Pod" - required_metrics: - - container_cpu_usage_seconds_total weight: 1 - queries: + metrics: - id: system_metrics_kubernetes_container_core_usage_canary query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' label: Pod average unit: "cores" track: canary - title: "Knative function invocations" + type: "area-chart" y_label: "Invocations" - required_metrics: - - istio_revision_request_count weight: 1 - queries: + metrics: - id: system_metrics_knative_function_invocation_count query_range: 'floor(sum(rate(istio_revision_request_count{destination_configuration="%{function_name}", destination_namespace="%{kube_namespace}"}[1m])/3))' label: invocations / minute diff --git a/danger/ce_ee_vue_templates/Dangerfile b/danger/ce_ee_vue_templates/Dangerfile new file mode 100644 index 00000000000..f7715eb2a89 --- /dev/null +++ b/danger/ce_ee_vue_templates/Dangerfile @@ -0,0 +1,56 @@ +# frozen_string_literal: true +require 'cgi' + +def get_vue_files_with_ce_and_ee_versions(files) + files.select do |file| + if file.end_with?('.vue') + counterpart_path = if file.start_with?('ee/') + file.delete_prefix('ee/') + else + "ee/#{file}" + end + + escaped_path = CGI.escape(counterpart_path) + api_endpoint = "https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-ee/repository/files/#{escaped_path}?ref=master" + response = HTTParty.get(api_endpoint) # rubocop:disable Gitlab/HTTParty + response.code != 404 + else + false + end + end +end + +vue_candidates = get_vue_files_with_ce_and_ee_versions(helper.all_changed_files) + +return if vue_candidates.empty? + +message 'This merge request includes changes to Vue files that have both CE and EE versions.' + +markdown(<<~MARKDOWN) + ## Vue `<template>` in CE and EE + + Some Vue files in CE have a counterpart in EE. + (For example, `path/to/file.vue` and `ee/path/to/file.vue`.) + + When run in the context of CE, the `<template>` of the CE Vue file is used. + When run in the context of EE, the `<template>` of the EE Vue file is used. + + It's easy to accidentally make a change to a CE `<template>` that _should_ + appear in both CE and EE without making the change in both places. + When this happens, the change only takes effect in CE. + + The following Vue files were changed as part of this merge request that + include both a CE and EE version of the file: + + * #{vue_candidates.map { |path| "`#{path}`" }.join("\n* ")} + + If you made a change to the `<template>` of any of these Vue files that + should be visible in both CE and EE, please ensure you have made your + change to both versions of the file. + + ### A better alternative + + An even _better_ alternative is to refactor this component to only use + a single template for both CE and EE. More info on this approach here: + https://docs.gitlab.com/ee/development/ee_features.html#template-tag +MARKDOWN diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb index 926401d8b9e..582a5203d1d 100644 --- a/db/fixtures/development/09_issues.rb +++ b/db/fixtures/development/09_issues.rb @@ -1,23 +1,5 @@ require './spec/support/sidekiq' Gitlab::Seeder.quiet do - Project.all.each do |project| - 10.times do - label_ids = project.labels.pluck(:id).sample(3) - label_ids += project.group.labels.sample(3) if project.group - - issue_params = { - title: FFaker::Lorem.sentence(6), - description: FFaker::Lorem.sentence, - state: ['opened', 'closed'].sample, - milestone: project.milestones.sample, - assignees: [project.team.users.sample], - created_at: rand(12).months.ago, - label_ids: label_ids - } - - Issues::CreateService.new(project, project.team.users.sample, issue_params).execute - print '.' - end - end + Rake::Task["gitlab:seed:issues"].invoke end diff --git a/db/importers/common_metrics_importer.rb b/db/importers/common_metrics_importer.rb index deadd653ae9..195bde8f34a 100644 --- a/db/importers/common_metrics_importer.rb +++ b/db/importers/common_metrics_importer.rb @@ -53,7 +53,7 @@ module Importers private def process_content(&blk) - content.map do |group| + content['panel_groups'].map do |group| process_group(group, &blk) end end @@ -63,28 +63,28 @@ module Importers group: find_group_title_key(group['group']) } - group['metrics'].map do |metric| - process_metric(metric, attributes, &blk) + group['panels'].map do |panel| + process_panel(panel, attributes, &blk) end end - def process_metric(metric, attributes, &blk) + def process_panel(panel, attributes, &blk) attributes = attributes.merge( - title: metric['title'], - y_label: metric['y_label']) + title: panel['title'], + y_label: panel['y_label']) - metric['queries'].map do |query| - process_metric_query(query, attributes, &blk) + panel['metrics'].map do |metric_details| + process_metric_details(metric_details, attributes, &blk) end end - def process_metric_query(query, attributes, &blk) + def process_metric_details(metric_details, attributes, &blk) attributes = attributes.merge( - legend: query['label'], - query: query['query_range'], - unit: query['unit']) + legend: metric_details['label'], + query: metric_details['query_range'], + unit: metric_details['unit']) - yield(query['id'], attributes) + yield(metric_details['id'], attributes) end def find_or_build_metric!(id) diff --git a/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb b/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb index 23a775d6282..9005b42b41f 100644 --- a/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb +++ b/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb @@ -9,11 +9,11 @@ class AddUniqueIndexToSubscriptions < ActiveRecord::Migration[4.2] def up add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id, :project_id], { unique: true, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' } - remove_index :subscriptions, name: 'subscriptions_user_id_and_ref_fields' if index_name_exists?(:subscriptions, 'subscriptions_user_id_and_ref_fields', false) + remove_index :subscriptions, name: 'subscriptions_user_id_and_ref_fields' if index_name_exists?(:subscriptions, 'subscriptions_user_id_and_ref_fields') end def down add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id], { unique: true, name: 'subscriptions_user_id_and_ref_fields' } - remove_index :subscriptions, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' if index_name_exists?(:subscriptions, 'index_subscriptions_on_subscribable_and_user_id_and_project_id', false) + remove_index :subscriptions, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' if index_name_exists?(:subscriptions, 'index_subscriptions_on_subscribable_and_user_id_and_project_id') end end diff --git a/db/migrate/20190322164830_add_auto_ssl_enabled_to_pages_domain.rb b/db/migrate/20190322164830_add_auto_ssl_enabled_to_pages_domain.rb new file mode 100644 index 00000000000..e74a9535ddf --- /dev/null +++ b/db/migrate/20190322164830_add_auto_ssl_enabled_to_pages_domain.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddAutoSslEnabledToPagesDomain < ActiveRecord::Migration[5.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :pages_domains, :auto_ssl_enabled, :boolean, default: false + end + + def down + remove_column :pages_domains, :auto_ssl_enabled + end +end diff --git a/db/schema.rb b/db/schema.rb index c0399529deb..3a5d567ac57 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -16,7 +16,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do enable_extension "plpgsql" enable_extension "pg_trgm" - create_table "abuse_reports", force: :cascade do |t| + create_table "abuse_reports", id: :serial, force: :cascade do |t| t.integer "reporter_id" t.integer "user_id" t.text "message" @@ -26,7 +26,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.integer "cached_markdown_version" end - create_table "appearances", force: :cascade do |t| + create_table "appearances", id: :serial, force: :cascade do |t| t.string "title", null: false t.text "description", null: false t.string "header_logo" @@ -47,13 +47,13 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.boolean "email_header_and_footer_enabled", default: false, null: false end - create_table "application_setting_terms", force: :cascade do |t| + create_table "application_setting_terms", id: :serial, force: :cascade do |t| t.integer "cached_markdown_version" t.text "terms", null: false t.text "terms_html" end - create_table "application_settings", force: :cascade do |t| + create_table "application_settings", id: :serial, force: :cascade do |t| t.integer "default_projects_limit" t.boolean "signup_enabled" t.boolean "gravatar_enabled" @@ -190,7 +190,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree end - create_table "audit_events", force: :cascade do |t| + create_table "audit_events", id: :serial, force: :cascade do |t| t.integer "author_id", null: false t.string "type", null: false t.integer "entity_id", null: false @@ -201,7 +201,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["entity_id", "entity_type"], name: "index_audit_events_on_entity_id_and_entity_type", using: :btree end - create_table "award_emoji", force: :cascade do |t| + create_table "award_emoji", id: :serial, force: :cascade do |t| t.string "name" t.integer "user_id" t.integer "awardable_id" @@ -212,7 +212,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree end - create_table "badges", force: :cascade do |t| + create_table "badges", id: :serial, force: :cascade do |t| t.string "link_url", null: false t.string "image_url", null: false t.integer "project_id" @@ -224,7 +224,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_badges_on_project_id", using: :btree end - create_table "board_group_recent_visits", id: :bigserial, force: :cascade do |t| + create_table "board_group_recent_visits", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id" @@ -236,7 +236,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_board_group_recent_visits_on_user_id", using: :btree end - create_table "board_project_recent_visits", id: :bigserial, force: :cascade do |t| + create_table "board_project_recent_visits", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id" @@ -248,7 +248,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_board_project_recent_visits_on_user_id", using: :btree end - create_table "boards", force: :cascade do |t| + create_table "boards", id: :serial, force: :cascade do |t| t.integer "project_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -257,7 +257,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_boards_on_project_id", using: :btree end - create_table "broadcast_messages", force: :cascade do |t| + create_table "broadcast_messages", id: :serial, force: :cascade do |t| t.text "message", null: false t.datetime "starts_at", null: false t.datetime "ends_at", null: false @@ -270,7 +270,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree end - create_table "chat_names", force: :cascade do |t| + create_table "chat_names", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.integer "service_id", null: false t.string "team_id", null: false @@ -284,7 +284,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id", "service_id"], name: "index_chat_names_on_user_id_and_service_id", unique: true, using: :btree end - create_table "chat_teams", force: :cascade do |t| + create_table "chat_teams", id: :serial, force: :cascade do |t| t.integer "namespace_id", null: false t.string "team_id" t.string "name" @@ -293,7 +293,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree end - create_table "ci_build_trace_chunks", id: :bigserial, force: :cascade do |t| + create_table "ci_build_trace_chunks", force: :cascade do |t| t.integer "build_id", null: false t.integer "chunk_index", null: false t.integer "data_store", null: false @@ -301,13 +301,13 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["build_id", "chunk_index"], name: "index_ci_build_trace_chunks_on_build_id_and_chunk_index", unique: true, using: :btree end - create_table "ci_build_trace_section_names", force: :cascade do |t| + create_table "ci_build_trace_section_names", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.index ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true, using: :btree end - create_table "ci_build_trace_sections", force: :cascade do |t| + create_table "ci_build_trace_sections", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.datetime_with_timezone "date_start", null: false t.datetime_with_timezone "date_end", null: false @@ -320,7 +320,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["section_name_id"], name: "index_ci_build_trace_sections_on_section_name_id", using: :btree end - create_table "ci_builds", force: :cascade do |t| + create_table "ci_builds", id: :serial, force: :cascade do |t| t.string "status" t.datetime "finished_at" t.text "trace" @@ -387,7 +387,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_ci_builds_on_user_id", using: :btree end - create_table "ci_builds_metadata", force: :cascade do |t| + create_table "ci_builds_metadata", id: :serial, force: :cascade do |t| t.integer "build_id", null: false t.integer "project_id", null: false t.integer "timeout" @@ -398,7 +398,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_ci_builds_metadata_on_project_id", using: :btree end - create_table "ci_builds_runner_session", id: :bigserial, force: :cascade do |t| + create_table "ci_builds_runner_session", force: :cascade do |t| t.integer "build_id", null: false t.string "url", null: false t.string "certificate" @@ -406,7 +406,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["build_id"], name: "index_ci_builds_runner_session_on_build_id", unique: true, using: :btree end - create_table "ci_group_variables", force: :cascade do |t| + create_table "ci_group_variables", id: :serial, force: :cascade do |t| t.string "key", null: false t.text "value" t.text "encrypted_value" @@ -420,7 +420,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree end - create_table "ci_job_artifacts", force: :cascade do |t| + create_table "ci_job_artifacts", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "job_id", null: false t.integer "file_type", null: false @@ -439,7 +439,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id", using: :btree end - create_table "ci_pipeline_chat_data", id: :bigserial, force: :cascade do |t| + create_table "ci_pipeline_chat_data", force: :cascade do |t| t.integer "pipeline_id", null: false t.integer "chat_name_id", null: false t.text "response_url", null: false @@ -459,7 +459,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree end - create_table "ci_pipeline_schedules", force: :cascade do |t| + create_table "ci_pipeline_schedules", id: :serial, force: :cascade do |t| t.string "description" t.string "ref" t.string "cron" @@ -475,7 +475,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree end - create_table "ci_pipeline_variables", force: :cascade do |t| + create_table "ci_pipeline_variables", id: :serial, force: :cascade do |t| t.string "key", null: false t.text "value" t.text "encrypted_value" @@ -485,7 +485,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree end - create_table "ci_pipelines", force: :cascade do |t| + create_table "ci_pipelines", id: :serial, force: :cascade do |t| t.string "ref" t.string "sha" t.string "before_sha" @@ -525,14 +525,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree end - create_table "ci_runner_namespaces", force: :cascade do |t| + create_table "ci_runner_namespaces", id: :serial, force: :cascade do |t| t.integer "runner_id" t.integer "namespace_id" t.index ["namespace_id"], name: "index_ci_runner_namespaces_on_namespace_id", using: :btree t.index ["runner_id", "namespace_id"], name: "index_ci_runner_namespaces_on_runner_id_and_namespace_id", unique: true, using: :btree end - create_table "ci_runner_projects", force: :cascade do |t| + create_table "ci_runner_projects", id: :serial, force: :cascade do |t| t.integer "runner_id", null: false t.datetime "created_at" t.datetime "updated_at" @@ -541,7 +541,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree end - create_table "ci_runners", force: :cascade do |t| + create_table "ci_runners", id: :serial, force: :cascade do |t| t.string "token" t.datetime "created_at" t.datetime "updated_at" @@ -569,7 +569,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["token_encrypted"], name: "index_ci_runners_on_token_encrypted", using: :btree end - create_table "ci_stages", force: :cascade do |t| + create_table "ci_stages", id: :serial, force: :cascade do |t| t.integer "project_id" t.integer "pipeline_id" t.datetime "created_at" @@ -584,7 +584,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_ci_stages_on_project_id", using: :btree end - create_table "ci_trigger_requests", force: :cascade do |t| + create_table "ci_trigger_requests", id: :serial, force: :cascade do |t| t.integer "trigger_id", null: false t.text "variables" t.datetime "created_at" @@ -594,7 +594,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["trigger_id"], name: "index_ci_trigger_requests_on_trigger_id", using: :btree end - create_table "ci_triggers", force: :cascade do |t| + create_table "ci_triggers", id: :serial, force: :cascade do |t| t.string "token" t.datetime "created_at" t.datetime "updated_at" @@ -606,7 +606,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_ci_triggers_on_project_id", using: :btree end - create_table "ci_variables", force: :cascade do |t| + create_table "ci_variables", id: :serial, force: :cascade do |t| t.string "key", null: false t.text "value" t.text "encrypted_value" @@ -619,14 +619,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree end - create_table "cluster_groups", force: :cascade do |t| + create_table "cluster_groups", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "group_id", null: false t.index ["cluster_id", "group_id"], name: "index_cluster_groups_on_cluster_id_and_group_id", unique: true, using: :btree t.index ["group_id"], name: "index_cluster_groups_on_group_id", using: :btree end - create_table "cluster_platforms_kubernetes", force: :cascade do |t| + create_table "cluster_platforms_kubernetes", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -642,7 +642,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_cluster_platforms_kubernetes_on_cluster_id", unique: true, using: :btree end - create_table "cluster_projects", force: :cascade do |t| + create_table "cluster_projects", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false @@ -651,7 +651,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_cluster_projects_on_project_id", using: :btree end - create_table "cluster_providers_gcp", force: :cascade do |t| + create_table "cluster_providers_gcp", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "status" t.integer "num_nodes", null: false @@ -669,7 +669,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree end - create_table "clusters", force: :cascade do |t| + create_table "clusters", id: :serial, force: :cascade do |t| t.integer "user_id" t.integer "provider_type" t.integer "platform_type" @@ -685,7 +685,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_clusters_on_user_id", using: :btree end - create_table "clusters_applications_cert_managers", force: :cascade do |t| + create_table "clusters_applications_cert_managers", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "status", null: false t.string "version", null: false @@ -696,7 +696,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_clusters_applications_cert_managers_on_cluster_id", unique: true, using: :btree end - create_table "clusters_applications_helm", force: :cascade do |t| + create_table "clusters_applications_helm", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -709,7 +709,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_clusters_applications_helm_on_cluster_id", unique: true, using: :btree end - create_table "clusters_applications_ingress", force: :cascade do |t| + create_table "clusters_applications_ingress", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -723,7 +723,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true, using: :btree end - create_table "clusters_applications_jupyter", force: :cascade do |t| + create_table "clusters_applications_jupyter", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "oauth_application_id" t.integer "status", null: false @@ -736,7 +736,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["oauth_application_id"], name: "index_clusters_applications_jupyter_on_oauth_application_id", using: :btree end - create_table "clusters_applications_knative", force: :cascade do |t| + create_table "clusters_applications_knative", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -749,7 +749,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_clusters_applications_knative_on_cluster_id", unique: true, using: :btree end - create_table "clusters_applications_prometheus", force: :cascade do |t| + create_table "clusters_applications_prometheus", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "status", null: false t.string "version", null: false @@ -759,7 +759,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["cluster_id"], name: "index_clusters_applications_prometheus_on_cluster_id", unique: true, using: :btree end - create_table "clusters_applications_runners", force: :cascade do |t| + create_table "clusters_applications_runners", id: :serial, force: :cascade do |t| t.integer "cluster_id", null: false t.integer "runner_id" t.integer "status", null: false @@ -772,7 +772,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["runner_id"], name: "index_clusters_applications_runners_on_runner_id", using: :btree end - create_table "clusters_kubernetes_namespaces", id: :bigserial, force: :cascade do |t| + create_table "clusters_kubernetes_namespaces", force: :cascade do |t| t.integer "cluster_id", null: false t.integer "project_id" t.integer "cluster_project_id" @@ -788,7 +788,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_clusters_kubernetes_namespaces_on_project_id", using: :btree end - create_table "container_repositories", force: :cascade do |t| + create_table "container_repositories", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at", null: false @@ -797,7 +797,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_container_repositories_on_project_id", using: :btree end - create_table "conversational_development_index_metrics", force: :cascade do |t| + create_table "conversational_development_index_metrics", id: :serial, force: :cascade do |t| t.float "leader_issues", null: false t.float "instance_issues", null: false t.float "leader_notes", null: false @@ -832,7 +832,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.float "percentage_service_desk_issues", default: 0.0, null: false end - create_table "deploy_keys_projects", force: :cascade do |t| + create_table "deploy_keys_projects", id: :serial, force: :cascade do |t| t.integer "deploy_key_id", null: false t.integer "project_id", null: false t.datetime "created_at" @@ -841,7 +841,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree end - create_table "deploy_tokens", force: :cascade do |t| + create_table "deploy_tokens", id: :serial, force: :cascade do |t| t.boolean "revoked", default: false t.boolean "read_repository", default: false, null: false t.boolean "read_registry", default: false, null: false @@ -853,7 +853,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["token"], name: "index_deploy_tokens_on_token", unique: true, using: :btree end - create_table "deployments", force: :cascade do |t| + create_table "deployments", id: :serial, force: :cascade do |t| t.integer "iid", null: false t.integer "project_id", null: false t.integer "environment_id", null: false @@ -879,7 +879,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "status"], name: "index_deployments_on_project_id_and_status", using: :btree end - create_table "emails", force: :cascade do |t| + create_table "emails", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.string "email", null: false t.datetime "created_at" @@ -892,7 +892,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_emails_on_user_id", using: :btree end - create_table "environments", force: :cascade do |t| + create_table "environments", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at" @@ -905,7 +905,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "slug"], name: "index_environments_on_project_id_and_slug", unique: true, using: :btree end - create_table "events", force: :cascade do |t| + create_table "events", id: :serial, force: :cascade do |t| t.integer "project_id" t.integer "author_id", null: false t.integer "target_id" @@ -920,7 +920,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree end - create_table "feature_gates", force: :cascade do |t| + create_table "feature_gates", id: :serial, force: :cascade do |t| t.string "feature_key", null: false t.string "key", null: false t.string "value" @@ -929,14 +929,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["feature_key", "key", "value"], name: "index_feature_gates_on_feature_key_and_key_and_value", unique: true, using: :btree end - create_table "features", force: :cascade do |t| + create_table "features", id: :serial, force: :cascade do |t| t.string "key", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["key"], name: "index_features_on_key", unique: true, using: :btree end - create_table "fork_network_members", force: :cascade do |t| + create_table "fork_network_members", id: :serial, force: :cascade do |t| t.integer "fork_network_id", null: false t.integer "project_id", null: false t.integer "forked_from_project_id" @@ -945,13 +945,13 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_fork_network_members_on_project_id", unique: true, using: :btree end - create_table "fork_networks", force: :cascade do |t| + create_table "fork_networks", id: :serial, force: :cascade do |t| t.integer "root_project_id" t.string "deleted_root_project_name" t.index ["root_project_id"], name: "index_fork_networks_on_root_project_id", unique: true, using: :btree end - create_table "forked_project_links", force: :cascade do |t| + create_table "forked_project_links", id: :serial, force: :cascade do |t| t.integer "forked_to_project_id", null: false t.integer "forked_from_project_id", null: false t.datetime "created_at" @@ -959,7 +959,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree end - create_table "gpg_key_subkeys", force: :cascade do |t| + create_table "gpg_key_subkeys", id: :serial, force: :cascade do |t| t.integer "gpg_key_id", null: false t.binary "keyid" t.binary "fingerprint" @@ -968,7 +968,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["keyid"], name: "index_gpg_key_subkeys_on_keyid", unique: true, using: :btree end - create_table "gpg_keys", force: :cascade do |t| + create_table "gpg_keys", id: :serial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id" @@ -980,7 +980,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree end - create_table "gpg_signatures", force: :cascade do |t| + create_table "gpg_signatures", id: :serial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "project_id" @@ -998,7 +998,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree end - create_table "group_custom_attributes", force: :cascade do |t| + create_table "group_custom_attributes", id: :serial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "group_id", null: false @@ -1008,7 +1008,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["key", "value"], name: "index_group_custom_attributes_on_key_and_value", using: :btree end - create_table "identities", force: :cascade do |t| + create_table "identities", id: :serial, force: :cascade do |t| t.string "extern_uid" t.string "provider" t.integer "user_id" @@ -1017,7 +1017,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_identities_on_user_id", using: :btree end - create_table "import_export_uploads", force: :cascade do |t| + create_table "import_export_uploads", id: :serial, force: :cascade do |t| t.datetime_with_timezone "updated_at", null: false t.integer "project_id" t.text "import_file" @@ -1026,7 +1026,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["updated_at"], name: "index_import_export_uploads_on_updated_at", using: :btree end - create_table "internal_ids", id: :bigserial, force: :cascade do |t| + create_table "internal_ids", force: :cascade do |t| t.integer "project_id" t.integer "usage", null: false t.integer "last_value", null: false @@ -1044,7 +1044,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_issue_assignees_on_user_id", using: :btree end - create_table "issue_metrics", force: :cascade do |t| + create_table "issue_metrics", id: :serial, force: :cascade do |t| t.integer "issue_id", null: false t.datetime "first_mentioned_in_commit_at" t.datetime "first_associated_with_milestone_at" @@ -1054,7 +1054,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["issue_id"], name: "index_issue_metrics", using: :btree end - create_table "issues", force: :cascade do |t| + create_table "issues", id: :serial, force: :cascade do |t| t.string "title" t.integer "author_id" t.integer "project_id" @@ -1097,7 +1097,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree end - create_table "keys", force: :cascade do |t| + create_table "keys", id: :serial, force: :cascade do |t| t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" @@ -1111,7 +1111,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_keys_on_user_id", using: :btree end - create_table "label_links", force: :cascade do |t| + create_table "label_links", id: :serial, force: :cascade do |t| t.integer "label_id" t.integer "target_id" t.string "target_type" @@ -1121,7 +1121,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["target_id", "target_type"], name: "index_label_links_on_target_id_and_target_type", using: :btree end - create_table "label_priorities", force: :cascade do |t| + create_table "label_priorities", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "label_id", null: false t.integer "priority", null: false @@ -1132,7 +1132,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "label_id"], name: "index_label_priorities_on_project_id_and_label_id", unique: true, using: :btree end - create_table "labels", force: :cascade do |t| + create_table "labels", id: :serial, force: :cascade do |t| t.string "title" t.string "color" t.integer "project_id" @@ -1151,7 +1151,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["type", "project_id"], name: "index_labels_on_type_and_project_id", using: :btree end - create_table "lfs_file_locks", force: :cascade do |t| + create_table "lfs_file_locks", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "user_id", null: false t.datetime "created_at", null: false @@ -1160,7 +1160,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_lfs_file_locks_on_user_id", using: :btree end - create_table "lfs_objects", force: :cascade do |t| + create_table "lfs_objects", id: :serial, force: :cascade do |t| t.string "oid", null: false t.bigint "size", null: false t.datetime "created_at" @@ -1171,7 +1171,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["oid"], name: "index_lfs_objects_on_oid", unique: true, using: :btree end - create_table "lfs_objects_projects", force: :cascade do |t| + create_table "lfs_objects_projects", id: :serial, force: :cascade do |t| t.integer "lfs_object_id", null: false t.integer "project_id", null: false t.datetime "created_at" @@ -1179,7 +1179,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree end - create_table "lists", force: :cascade do |t| + create_table "lists", id: :serial, force: :cascade do |t| t.integer "board_id", null: false t.integer "label_id" t.integer "list_type", default: 1, null: false @@ -1191,7 +1191,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["list_type"], name: "index_lists_on_list_type", using: :btree end - create_table "members", force: :cascade do |t| + create_table "members", id: :serial, force: :cascade do |t| t.integer "access_level", null: false t.integer "source_id", null: false t.string "source_type", null: false @@ -1254,7 +1254,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree end - create_table "merge_request_diffs", force: :cascade do |t| + create_table "merge_request_diffs", id: :serial, force: :cascade do |t| t.string "state" t.integer "merge_request_id", null: false t.datetime "created_at" @@ -1271,7 +1271,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id_partial", where: "((NOT stored_externally) OR (stored_externally IS NULL))", using: :btree end - create_table "merge_request_metrics", force: :cascade do |t| + create_table "merge_request_metrics", id: :serial, force: :cascade do |t| t.integer "merge_request_id", null: false t.datetime "latest_build_started_at" t.datetime "latest_build_finished_at" @@ -1292,7 +1292,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["pipeline_id"], name: "index_merge_request_metrics_on_pipeline_id", using: :btree end - create_table "merge_requests", force: :cascade do |t| + create_table "merge_requests", id: :serial, force: :cascade do |t| t.string "target_branch", null: false t.string "source_branch", null: false t.integer "source_project_id" @@ -1350,7 +1350,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["updated_by_id"], name: "index_merge_requests_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree end - create_table "merge_requests_closing_issues", force: :cascade do |t| + create_table "merge_requests_closing_issues", id: :serial, force: :cascade do |t| t.integer "merge_request_id", null: false t.integer "issue_id", null: false t.datetime "created_at", null: false @@ -1359,7 +1359,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["merge_request_id"], name: "index_merge_requests_closing_issues_on_merge_request_id", using: :btree end - create_table "milestones", force: :cascade do |t| + create_table "milestones", id: :serial, force: :cascade do |t| t.string "title", null: false t.integer "project_id" t.text "description" @@ -1381,7 +1381,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} end - create_table "namespaces", force: :cascade do |t| + create_table "namespaces", id: :serial, force: :cascade do |t| t.string "name", null: false t.string "path", null: false t.integer "owner_id" @@ -1416,7 +1416,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["type"], name: "index_namespaces_on_type", using: :btree end - create_table "note_diff_files", force: :cascade do |t| + create_table "note_diff_files", id: :serial, force: :cascade do |t| t.integer "diff_note_id", null: false t.text "diff", null: false t.boolean "new_file", null: false @@ -1429,7 +1429,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["diff_note_id"], name: "index_note_diff_files_on_diff_note_id", unique: true, using: :btree end - create_table "notes", force: :cascade do |t| + create_table "notes", id: :serial, force: :cascade do |t| t.text "note" t.string "noteable_type" t.integer "author_id" @@ -1464,7 +1464,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree end - create_table "notification_settings", force: :cascade do |t| + create_table "notification_settings", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.integer "source_id" t.string "source_type" @@ -1490,7 +1490,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_notification_settings_on_user_id", using: :btree end - create_table "oauth_access_grants", force: :cascade do |t| + create_table "oauth_access_grants", id: :serial, force: :cascade do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false t.string "token", null: false @@ -1502,7 +1502,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end - create_table "oauth_access_tokens", force: :cascade do |t| + create_table "oauth_access_tokens", id: :serial, force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" t.string "token", null: false @@ -1516,7 +1516,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end - create_table "oauth_applications", force: :cascade do |t| + create_table "oauth_applications", id: :serial, force: :cascade do |t| t.string "name", null: false t.string "uid", null: false t.string "secret", null: false @@ -1531,13 +1531,13 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end - create_table "oauth_openid_requests", force: :cascade do |t| + create_table "oauth_openid_requests", id: :serial, force: :cascade do |t| t.integer "access_grant_id", null: false t.string "nonce", null: false t.index ["access_grant_id"], name: "index_oauth_openid_requests_on_access_grant_id", using: :btree end - create_table "pages_domains", force: :cascade do |t| + create_table "pages_domains", id: :serial, force: :cascade do |t| t.integer "project_id" t.text "certificate" t.text "encrypted_key" @@ -1548,6 +1548,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.string "verification_code", null: false t.datetime_with_timezone "enabled_until" t.datetime_with_timezone "remove_at" + t.boolean "auto_ssl_enabled", default: false, null: false t.index ["domain"], name: "index_pages_domains_on_domain", unique: true, using: :btree t.index ["project_id", "enabled_until"], name: "index_pages_domains_on_project_id_and_enabled_until", using: :btree t.index ["project_id"], name: "index_pages_domains_on_project_id", using: :btree @@ -1556,7 +1557,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["verified_at"], name: "index_pages_domains_on_verified_at", using: :btree end - create_table "personal_access_tokens", force: :cascade do |t| + create_table "personal_access_tokens", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.string "name", null: false t.boolean "revoked", default: false @@ -1570,7 +1571,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_personal_access_tokens_on_user_id", using: :btree end - create_table "pool_repositories", id: :bigserial, force: :cascade do |t| + create_table "pool_repositories", force: :cascade do |t| t.integer "shard_id", null: false t.string "disk_path" t.string "state" @@ -1580,7 +1581,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["source_project_id"], name: "index_pool_repositories_on_source_project_id", unique: true, using: :btree end - create_table "programming_languages", force: :cascade do |t| + create_table "programming_languages", id: :serial, force: :cascade do |t| t.string "name", null: false t.string "color", null: false t.datetime_with_timezone "created_at", null: false @@ -1595,7 +1596,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id", "project_id", "access_level"], name: "index_project_authorizations_on_user_id_project_id_access_level", unique: true, using: :btree end - create_table "project_auto_devops", force: :cascade do |t| + create_table "project_auto_devops", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -1605,14 +1606,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree end - create_table "project_ci_cd_settings", force: :cascade do |t| + create_table "project_ci_cd_settings", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.boolean "group_runners_enabled", default: true, null: false t.boolean "merge_pipelines_enabled" t.index ["project_id"], name: "index_project_ci_cd_settings_on_project_id", unique: true, using: :btree end - create_table "project_custom_attributes", force: :cascade do |t| + create_table "project_custom_attributes", id: :serial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "project_id", null: false @@ -1622,14 +1623,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "key"], name: "index_project_custom_attributes_on_project_id_and_key", unique: true, using: :btree end - create_table "project_daily_statistics", id: :bigserial, force: :cascade do |t| + create_table "project_daily_statistics", force: :cascade do |t| t.integer "project_id", null: false t.integer "fetch_count", null: false t.date "date" t.index ["project_id", "date"], name: "index_project_daily_statistics_on_project_id_and_date", unique: true, order: { date: :desc }, using: :btree end - create_table "project_deploy_tokens", force: :cascade do |t| + create_table "project_deploy_tokens", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "deploy_token_id", null: false t.datetime_with_timezone "created_at", null: false @@ -1637,7 +1638,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree end - create_table "project_error_tracking_settings", primary_key: "project_id", id: :integer, force: :cascade do |t| + create_table "project_error_tracking_settings", primary_key: "project_id", id: :integer, default: nil, force: :cascade do |t| t.boolean "enabled", default: false, null: false t.string "api_url" t.string "encrypted_token" @@ -1646,7 +1647,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.string "organization_name" end - create_table "project_features", force: :cascade do |t| + create_table "project_features", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "merge_requests_access_level" t.integer "issues_access_level" @@ -1660,7 +1661,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree end - create_table "project_group_links", force: :cascade do |t| + create_table "project_group_links", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "group_id", null: false t.datetime "created_at" @@ -1671,7 +1672,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_project_group_links_on_project_id", using: :btree end - create_table "project_import_data", force: :cascade do |t| + create_table "project_import_data", id: :serial, force: :cascade do |t| t.integer "project_id" t.text "data" t.text "encrypted_credentials" @@ -1680,7 +1681,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_project_import_data_on_project_id", using: :btree end - create_table "project_mirror_data", force: :cascade do |t| + create_table "project_mirror_data", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "status" t.string "jid" @@ -1690,7 +1691,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["status"], name: "index_project_mirror_data_on_status", using: :btree end - create_table "project_repositories", id: :bigserial, force: :cascade do |t| + create_table "project_repositories", force: :cascade do |t| t.integer "shard_id", null: false t.string "disk_path", null: false t.integer "project_id", null: false @@ -1699,7 +1700,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["shard_id"], name: "index_project_repositories_on_shard_id", using: :btree end - create_table "project_statistics", force: :cascade do |t| + create_table "project_statistics", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "namespace_id", null: false t.bigint "commit_count", default: 0, null: false @@ -1711,7 +1712,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_project_statistics_on_project_id", unique: true, using: :btree end - create_table "projects", force: :cascade do |t| + create_table "projects", id: :serial, force: :cascade do |t| t.string "name" t.string "path" t.text "description" @@ -1791,7 +1792,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree end - create_table "prometheus_metrics", force: :cascade do |t| + create_table "prometheus_metrics", id: :serial, force: :cascade do |t| t.integer "project_id" t.string "title", null: false t.string "query", null: false @@ -1809,7 +1810,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_prometheus_metrics_on_project_id", using: :btree end - create_table "protected_branch_merge_access_levels", force: :cascade do |t| + create_table "protected_branch_merge_access_levels", id: :serial, force: :cascade do |t| t.integer "protected_branch_id", null: false t.integer "access_level", default: 40, null: false t.datetime "created_at", null: false @@ -1817,7 +1818,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["protected_branch_id"], name: "index_protected_branch_merge_access", using: :btree end - create_table "protected_branch_push_access_levels", force: :cascade do |t| + create_table "protected_branch_push_access_levels", id: :serial, force: :cascade do |t| t.integer "protected_branch_id", null: false t.integer "access_level", default: 40, null: false t.datetime "created_at", null: false @@ -1825,7 +1826,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["protected_branch_id"], name: "index_protected_branch_push_access", using: :btree end - create_table "protected_branches", force: :cascade do |t| + create_table "protected_branches", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at" @@ -1833,7 +1834,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_protected_branches_on_project_id", using: :btree end - create_table "protected_tag_create_access_levels", force: :cascade do |t| + create_table "protected_tag_create_access_levels", id: :serial, force: :cascade do |t| t.integer "protected_tag_id", null: false t.integer "access_level", default: 40 t.integer "user_id" @@ -1845,7 +1846,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_protected_tag_create_access_levels_on_user_id", using: :btree end - create_table "protected_tags", force: :cascade do |t| + create_table "protected_tags", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false t.datetime "created_at", null: false @@ -1866,7 +1867,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["event_id"], name: "index_push_event_payloads_on_event_id", unique: true, using: :btree end - create_table "redirect_routes", force: :cascade do |t| + create_table "redirect_routes", id: :serial, force: :cascade do |t| t.integer "source_id", null: false t.string "source_type", null: false t.string "path", null: false @@ -1876,7 +1877,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree end - create_table "release_links", id: :bigserial, force: :cascade do |t| + create_table "release_links", force: :cascade do |t| t.integer "release_id", null: false t.string "url", null: false t.string "name", null: false @@ -1886,7 +1887,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["release_id", "url"], name: "index_release_links_on_release_id_and_url", unique: true, using: :btree end - create_table "releases", force: :cascade do |t| + create_table "releases", id: :serial, force: :cascade do |t| t.string "tag" t.text "description" t.integer "project_id" @@ -1902,7 +1903,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id"], name: "index_releases_on_project_id", using: :btree end - create_table "remote_mirrors", force: :cascade do |t| + create_table "remote_mirrors", id: :serial, force: :cascade do |t| t.integer "project_id" t.string "url" t.boolean "enabled", default: false @@ -1930,7 +1931,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["project_id", "programming_language_id"], name: "index_repository_languages_on_project_and_languages_id", unique: true, using: :btree end - create_table "resource_label_events", id: :bigserial, force: :cascade do |t| + create_table "resource_label_events", force: :cascade do |t| t.integer "action", null: false t.integer "issue_id" t.integer "merge_request_id" @@ -1946,7 +1947,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_resource_label_events_on_user_id", using: :btree end - create_table "routes", force: :cascade do |t| + create_table "routes", id: :serial, force: :cascade do |t| t.integer "source_id", null: false t.string "source_type", null: false t.string "path", null: false @@ -1958,7 +1959,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree end - create_table "sent_notifications", force: :cascade do |t| + create_table "sent_notifications", id: :serial, force: :cascade do |t| t.integer "project_id" t.integer "noteable_id" t.string "noteable_type" @@ -1972,7 +1973,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree end - create_table "services", force: :cascade do |t| + create_table "services", id: :serial, force: :cascade do |t| t.string "type" t.string "title" t.integer "project_id" @@ -1999,12 +2000,12 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["type"], name: "index_services_on_type", using: :btree end - create_table "shards", force: :cascade do |t| + create_table "shards", id: :serial, force: :cascade do |t| t.string "name", null: false t.index ["name"], name: "index_shards_on_name", unique: true, using: :btree end - create_table "snippets", force: :cascade do |t| + create_table "snippets", id: :serial, force: :cascade do |t| t.string "title" t.text "content" t.integer "author_id", null: false @@ -2027,7 +2028,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree end - create_table "spam_logs", force: :cascade do |t| + create_table "spam_logs", id: :serial, force: :cascade do |t| t.integer "user_id" t.string "source_ip" t.string "user_agent" @@ -2041,7 +2042,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.boolean "recaptcha_verified", default: false, null: false end - create_table "subscriptions", force: :cascade do |t| + create_table "subscriptions", id: :serial, force: :cascade do |t| t.integer "user_id" t.integer "subscribable_id" t.string "subscribable_type" @@ -2053,7 +2054,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["subscribable_id", "subscribable_type", "user_id", "project_id"], name: "index_subscriptions_on_subscribable_and_user_id_and_project_id", unique: true, using: :btree end - create_table "suggestions", id: :bigserial, force: :cascade do |t| + create_table "suggestions", force: :cascade do |t| t.integer "note_id", null: false t.integer "relative_order", limit: 2, null: false t.boolean "applied", default: false, null: false @@ -2066,7 +2067,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["note_id", "relative_order"], name: "index_suggestions_on_note_id_and_relative_order", unique: true, using: :btree end - create_table "system_note_metadata", force: :cascade do |t| + create_table "system_note_metadata", id: :serial, force: :cascade do |t| t.integer "note_id", null: false t.integer "commit_count" t.string "action" @@ -2075,7 +2076,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["note_id"], name: "index_system_note_metadata_on_note_id", unique: true, using: :btree end - create_table "taggings", force: :cascade do |t| + create_table "taggings", id: :serial, force: :cascade do |t| t.integer "tag_id" t.integer "taggable_id" t.string "taggable_type" @@ -2089,14 +2090,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree end - create_table "tags", force: :cascade do |t| + create_table "tags", id: :serial, force: :cascade do |t| t.string "name" t.integer "taggings_count", default: 0 t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree t.index ["name"], name: "index_tags_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} end - create_table "term_agreements", force: :cascade do |t| + create_table "term_agreements", id: :serial, force: :cascade do |t| t.integer "term_id", null: false t.integer "user_id", null: false t.boolean "accepted", default: false, null: false @@ -2107,7 +2108,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_term_agreements_on_user_id", using: :btree end - create_table "timelogs", force: :cascade do |t| + create_table "timelogs", id: :serial, force: :cascade do |t| t.integer "time_spent", null: false t.integer "user_id" t.datetime "created_at", null: false @@ -2120,7 +2121,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_timelogs_on_user_id", using: :btree end - create_table "todos", force: :cascade do |t| + create_table "todos", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.integer "project_id" t.integer "target_id" @@ -2144,12 +2145,12 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_todos_on_user_id", using: :btree end - create_table "trending_projects", force: :cascade do |t| + create_table "trending_projects", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.index ["project_id"], name: "index_trending_projects_on_project_id", unique: true, using: :btree end - create_table "u2f_registrations", force: :cascade do |t| + create_table "u2f_registrations", id: :serial, force: :cascade do |t| t.text "certificate" t.string "key_handle" t.string "public_key" @@ -2162,7 +2163,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree end - create_table "uploads", force: :cascade do |t| + create_table "uploads", id: :serial, force: :cascade do |t| t.bigint "size", null: false t.string "path", limit: 511, null: false t.string "checksum", limit: 64 @@ -2179,7 +2180,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["uploader", "path"], name: "index_uploads_on_uploader_and_path", using: :btree end - create_table "user_agent_details", force: :cascade do |t| + create_table "user_agent_details", id: :serial, force: :cascade do |t| t.string "user_agent", null: false t.string "ip_address", null: false t.integer "subject_id", null: false @@ -2190,14 +2191,14 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree end - create_table "user_callouts", force: :cascade do |t| + create_table "user_callouts", id: :serial, force: :cascade do |t| t.integer "feature_name", null: false t.integer "user_id", null: false t.index ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree t.index ["user_id"], name: "index_user_callouts_on_user_id", using: :btree end - create_table "user_custom_attributes", force: :cascade do |t| + create_table "user_custom_attributes", id: :serial, force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.integer "user_id", null: false @@ -2214,7 +2215,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_user_interacted_projects_on_user_id", using: :btree end - create_table "user_preferences", force: :cascade do |t| + create_table "user_preferences", id: :serial, force: :cascade do |t| t.integer "user_id", null: false t.integer "issue_notes_filter", limit: 2, default: 0, null: false t.integer "merge_request_notes_filter", limit: 2, default: 0, null: false @@ -2226,7 +2227,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true, using: :btree end - create_table "user_statuses", primary_key: "user_id", force: :cascade do |t| + create_table "user_statuses", primary_key: "user_id", id: :serial, force: :cascade do |t| t.integer "cached_markdown_version" t.string "emoji", default: "speech_balloon", null: false t.string "message", limit: 100 @@ -2234,7 +2235,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_user_statuses_on_user_id", using: :btree end - create_table "user_synced_attributes_metadata", force: :cascade do |t| + create_table "user_synced_attributes_metadata", id: :serial, force: :cascade do |t| t.boolean "name_synced", default: false t.boolean "email_synced", default: false t.boolean "location_synced", default: false @@ -2243,7 +2244,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id"], name: "index_user_synced_attributes_metadata_on_user_id", unique: true, using: :btree end - create_table "users", force: :cascade do |t| + create_table "users", id: :serial, force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" @@ -2329,7 +2330,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["username"], name: "index_users_on_username_trigram", using: :gin, opclasses: {"username"=>"gin_trgm_ops"} end - create_table "users_star_projects", force: :cascade do |t| + create_table "users_star_projects", id: :serial, force: :cascade do |t| t.integer "project_id", null: false t.integer "user_id", null: false t.datetime "created_at" @@ -2338,7 +2339,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["user_id", "project_id"], name: "index_users_star_projects_on_user_id_and_project_id", unique: true, using: :btree end - create_table "web_hook_logs", force: :cascade do |t| + create_table "web_hook_logs", id: :serial, force: :cascade do |t| t.integer "web_hook_id", null: false t.string "trigger" t.string "url" @@ -2355,7 +2356,7 @@ ActiveRecord::Schema.define(version: 20190408163745) do t.index ["web_hook_id"], name: "index_web_hook_logs_on_web_hook_id", using: :btree end - create_table "web_hooks", force: :cascade do |t| + create_table "web_hooks", id: :serial, force: :cascade do |t| t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" diff --git a/doc/api/projects.md b/doc/api/projects.md index 0a950352ecf..951961e45ff 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -494,7 +494,9 @@ GET /projects/:id "name": "Diaspora", "path": "diaspora", "kind": "group", - "full_path": "diaspora" + "full_path": "diaspora", + "avatar_url": "http://localhost:3000/uploads/group/avatar/3/foo.jpg", + "web_url": "http://localhost:3000/groups/diaspora" }, "import_status": "none", "import_error": null, @@ -561,6 +563,8 @@ GET /projects/:id } ``` +**Note**: The `web_url` and `avatar_url` attributes on `namespace` were [introduced][ce-27427] in GitLab 11.11. + If the project is a fork, and you provide a valid token to authenticate, the `forked_from_project` field will appear in the response. @@ -1587,3 +1591,4 @@ GET /projects/:id/snapshot [eep]: https://about.gitlab.com/pricing/ "Available only in GitLab Premium" [ee-6137]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137 +[ce-27427]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27427 diff --git a/doc/api/runners.md b/doc/api/runners.md index 46f7b1d2a25..2d91428d1c1 100644 --- a/doc/api/runners.md +++ b/doc/api/runners.md @@ -486,6 +486,7 @@ POST /runners | `locked` | boolean| no | Whether the Runner should be locked for current project | | `run_untagged` | boolean | no | Whether the Runner should handle untagged jobs | | `tag_list` | Array[String] | no | List of Runner's tags | +| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` | | `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job | ``` diff --git a/doc/ci/examples/code_quality.md b/doc/ci/examples/code_quality.md index 3e7d6e7e3f7..186d4527bb6 100644 --- a/doc/ci/examples/code_quality.md +++ b/doc/ci/examples/code_quality.md @@ -1,7 +1,7 @@ # Analyze your project's Code Quality CAUTION: **Caution:** -The job definition shown below is supported on GitLab 11.5 and later versions. +The job definition shown below is supported on GitLab 11.11 and later versions. It also requires the GitLab Runner 11.5 or later. For earlier versions, use the [previous job definitions](#previous-job-definitions). @@ -11,27 +11,11 @@ and Docker. First, you need GitLab Runner with [docker-in-docker executor](../docker/using_docker_build.md#use-docker-in-docker-executor). -Once you set up the Runner, add a new job to `.gitlab-ci.yml` that -generates the expected report: +Once you set up the Runner, include the CodeQuality template in your CI config: ```yaml -code_quality: - image: docker:stable - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true - services: - - docker:stable-dind - script: - - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - docker run - --env SOURCE_CODE="$PWD" - --volume "$PWD":/code - --volume /var/run/docker.sock:/var/run/docker.sock - "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code - artifacts: - reports: - codequality: gl-code-quality-report.json +include: + - template: Code-Quality.gitlab-ci.yml ``` The above example will create a `code_quality` job in your CI/CD pipeline which @@ -54,6 +38,28 @@ While these old job definitions are still maintained they have been deprecated and may be removed in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml` configuration to reflect that change. +For GitLab 11.5 and earlier, the job should look like: + +```yaml +code_quality: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SOURCE_CODE="$PWD" + --volume "$PWD":/code + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code + artifacts: + reports: + codequality: gl-code-quality-report.json +``` + For GitLab 11.4 and earlier, the job should look like: ```yaml diff --git a/doc/ci/large_repositories/index.md b/doc/ci/large_repositories/index.md index cfe638c0a22..244ccbb92b0 100644 --- a/doc/ci/large_repositories/index.md +++ b/doc/ci/large_repositories/index.md @@ -72,8 +72,9 @@ done by GitLab, requiring you to do them. > Introduced in GitLab Runner 11.10. -`GIT_CLONE_PATH` allows you to control where you clone your sources. -This can have implications if you heavily use big repositories with fork workflow. +[`GIT_CLONE_PATH`](../yaml/README.md#custom-build-directories) allows you to +control where you clone your sources. This can have implications if you +heavily use big repositories with fork workflow. Fork workflow from GitLab Runner's perspective is stored as a separate repository with separate worktree. That means that GitLab Runner cannot optimize the usage @@ -83,29 +84,31 @@ In such cases, ideally you want to make the GitLab Runner executor be used only for the given project and not shared across different projects to make this process more efficient. -The `GIT_CLONE_PATH` has to be within the `$CI_BUILDS_DIR`. Currently, -it is impossible to pick any path from disk. +The [`GIT_CLONE_PATH`](../yaml/README.md#custom-build-directories) has to be +within the `$CI_BUILDS_DIR`. Currently, it is impossible to pick any path +from disk. ## Git clean flags > Introduced in GitLab Runner 11.10. -`GIT_CLEAN_FLAGS` allows you to control whether or not you require -the `git clean` command to be executed for each CI job. -By default, GitLab ensures that you have your worktree on the given SHA, +[`GIT_CLEAN_FLAGS`](../yaml/README.md#git-clean-flags) allows you to control +whether or not you require the `git clean` command to be executed for each CI +job. By default, GitLab ensures that you have your worktree on the given SHA, and that your repository is clean. -`GIT_CLEAN_FLAGS` is disabled when set to `none`. On very big repositories, this -might be desired because `git clean` is disk I/O intensive. Controlling that -with `GIT_CLEAN_FLAGS: -ffdx -e .build/`, for example, allows you to control and -disable removal of some directories within the worktree between subsequent runs, -which can speed-up the incremental builds. This has the biggest effect -if you re-use existing machines, and have an existing worktree that you can re-use -for builds. - -For exact parameters accepted by `GIT_CLEAN_FLAGS`, see the documentation -for [git clean](https://git-scm.com/docs/git-clean). The -available parameters are dependent on Git version. +[`GIT_CLEAN_FLAGS`](../yaml/README.md#git-clean-flags) is disabled when set +to `none`. On very big repositories, this might be desired because `git +clean` is disk I/O intensive. Controlling that with `GIT_CLEAN_FLAGS: -ffdx +-e .build/`, for example, allows you to control and disable removal of some +directories within the worktree between subsequent runs, which can speed-up +the incremental builds. This has the biggest effect if you re-use existing +machines, and have an existing worktree that you can re-use for builds. + +For exact parameters accepted by +[`GIT_CLEAN_FLAGS`](../yaml/README.md#git-clean-flags), see the documentation +for [git clean](https://git-scm.com/docs/git-clean). The available parameters +are dependent on Git version. ## Fork-based workflow diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md index 6a03ab910fc..3c26a38e3de 100644 --- a/doc/ci/merge_request_pipelines/index.md +++ b/doc/ci/merge_request_pipelines/index.md @@ -67,7 +67,7 @@ when a merge request was created or updated. For example: ![Merge request page](img/merge_request.png) -## Combined ref pipelines **[PREMIUM]** +## Pipelines for Merged Results **[PREMIUM]** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7380) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10. @@ -93,7 +93,7 @@ The detached state serves to warn you that you are working in a situation subjected to merge problems, and helps to highlight that you should get out of WIP status or resolve merge conflicts as soon as possible. -### Enabling combined ref pipelines +### Enabling Pipelines for Merged Results This feature disabled by default until we resolve issues with [contention handling](https://gitlab.com/gitlab-org/gitlab-ee/issues/9186). It can be enabled at the project level: @@ -103,7 +103,7 @@ This feature disabled by default until we resolve issues with [contention handli ![Merge request pipeline config](img/merge_request_pipeline_config.png) -### Combined ref pipeline's limitations +### Pipelines for Merged Result's limitations - This feature requires [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) 11.9 or newer. - This feature requires [Gitaly](https://gitlab.com/gitlab-org/gitaly) 1.21.0 or newer. diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index afd578e2621..9983b015b31 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -142,7 +142,7 @@ By default, variables will be created as masked variables. This means that the value of the variable will be hidden in job logs, though it must match certain requirements to do so: -- The value must be a single line. +- The value must be in a single line. - The value must not have escape characters. - The value must not use variables. - The value must not have any whitespace. @@ -434,8 +434,9 @@ Below you can find supported syntax reference: 1. Equality matching using a string > Example: `$VARIABLE == "some value"` + > Example: `$VARIABLE != "some value"` _(added in 11.11)_ - You can use equality operator `==` to compare a variable content to a + You can use equality operator `==` or `!=` to compare a variable content to a string. We support both, double quotes and single quotes to define a string value, so both `$VARIABLE == "some value"` and `$VARIABLE == 'some value'` are supported. `"some value" == $VARIABLE` is correct too. @@ -443,22 +444,26 @@ Below you can find supported syntax reference: 1. Checking for an undefined value > Example: `$VARIABLE == null` + > Example: `$VARIABLE != null` _(added in 11.11)_ It sometimes happens that you want to check whether a variable is defined or not. To do that, you can compare a variable to `null` keyword, like `$VARIABLE == null`. This expression is going to evaluate to truth if - variable is not defined. + variable is not defined when `==` is used, or to falsey if `!=` is used. 1. Checking for an empty variable > Example: `$VARIABLE == ""` + > Example: `$VARIABLE != ""` _(added in 11.11)_ If you want to check whether a variable is defined, but is empty, you can - simply compare it against an empty string, like `$VAR == ''`. + simply compare it against an empty string, like `$VAR == ''` or non-empty + string `$VARIABLE != ""`. 1. Comparing two variables > Example: `$VARIABLE_1 == $VARIABLE_2` + > Example: `$VARIABLE_1 != $VARIABLE_2` _(added in 11.11)_ It is possible to compare two variables. This is going to compare values of these variables. @@ -477,9 +482,11 @@ Below you can find supported syntax reference: 1. Pattern matching _(added in 11.0)_ > Example: `$VARIABLE =~ /^content.*/` + > Example: `$VARIABLE_1 !~ /^content.*/` _(added in 11.11)_ It is possible perform pattern matching against a variable and regular - expression. Expression like this evaluates to truth if matches are found. + expression. Expression like this evaluates to truth if matches are found + when using `=~`. It evaluates to truth if matches are not found when `!~` is used. Pattern matching is case-sensitive by default. Use `i` flag modifier, like `/pattern/i` to make a pattern case-insensitive. diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index 846c539daab..40458137752 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -49,23 +49,23 @@ future GitLab releases.** | `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` | | `CI_JOB_TOKEN` | 9.0 | 1.2 | Token used for authenticating with the [GitLab Container Registry][registry] and downloading [dependent repositories][dependent-repositories] | | `CI_JOB_URL` | 11.1 | 0.5 | Job details URL | -| `CI_MERGE_REQUEST_ID` | 11.6 | all | The ID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_IID` | 11.6 | all | The IID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_PROJECT_ID` | 11.6 | all | The ID of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `namespace/awesome-project`) | -| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `http://192.168.10.15:3000/namespace/awesome-project`) | -| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). (e.g. `refs/merge-requests/1/head`) | -| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD sha of the source branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD sha of the target branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_ASSIGNEES` | 11.9 | all | Comma-separated list of usernames of assignees for the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). [Multiple assignees for merge requests](https://gitlab.com/gitlab-org/gitlab-ee/issues/2004) is scheduled for a future release | -| `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | -| `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) | +| `CI_MERGE_REQUEST_ID` | 11.6 | all | The ID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_IID` | 11.6 | all | The IID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_PROJECT_ID` | 11.6 | all | The ID of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `http://192.168.10.15:3000/namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). (e.g. `refs/merge-requests/1/head`). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD sha of the source branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD sha of the target branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_ASSIGNEES` | 11.9 | all | Comma-separated list of username(s) of assignee(s) for the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | +| `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. | | `CI_NODE_INDEX` | 11.5 | all | Index of the job in the job set. If the job is not parallelized, this variable is not set. | | `CI_NODE_TOTAL` | 11.5 | all | Total number of instances of this job running in parallel. If the job is not parallelized, this variable is set to `1`. | | `CI_API_V4_URL` | 11.7 | all | The GitLab API v4 root URL | @@ -84,6 +84,7 @@ future GitLab releases.** | `CI_PROJECT_PATH_SLUG` | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. | | `CI_PROJECT_URL` | 8.10 | 0.5 | The HTTP(S) address to access project | | `CI_PROJECT_VISIBILITY` | 10.3 | all | The project visibility (internal, private, public) | +| `CI_COMMIT_REF_PROTECTED` | 11.11 | all | If the job is running on a protected branch | | `CI_REGISTRY` | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry | | `CI_REGISTRY_IMAGE` | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project | | `CI_REGISTRY_PASSWORD` | 9.0 | all | The password to use to push containers to the GitLab Container Registry | diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md index 827b3d7681a..0e1ab8663ed 100644 --- a/doc/development/contributing/issue_workflow.md +++ b/doc/development/contributing/issue_workflow.md @@ -340,13 +340,14 @@ addressed. In order to track things that can be improved in GitLab's codebase, we use the ~"technical debt" label in [GitLab's issue tracker][ce-tracker]. -For user experience improvements, we use the ~"UX debt" label. +For missed user experience requirements, we use the ~"UX debt" label. These labels should be added to issues that describe things that can be improved, shortcuts that have been taken, features that need additional attention, and all other things that have been left behind due to high velocity of development. For example, code that needs refactoring should use the ~"technical debt" label, -user experience refinements should use the ~"UX debt" label. +something that didn't ship according to our Design System guidelines should +use the ~"UX debt" label. Everyone can create an issue, though you may need to ask for adding a specific label, if you do not have permissions to do it by yourself. Additional labels diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md index e36ad01d4f8..fbca99fbfea 100644 --- a/doc/development/documentation/styleguide.md +++ b/doc/development/documentation/styleguide.md @@ -6,7 +6,7 @@ description: 'Writing styles, markup, formatting, and other standards for GitLab This document defines the standards for GitLab's documentation content and files. -For broader information about the documentation, see the [Documentation guidelines](index.md). +For broader information about the documentation, see the [Documentation guidelines](index.md). For programmatic help adhering to the guidelines, see [linting](index.md#linting). @@ -38,7 +38,7 @@ Include any media types/sources if the content is relevant to readers. You can f - If you use an image that has a separate source file (for example, a vector or diagram format), link the image to the source file so that it may be reused or updated by anyone. - Do not copy and paste content from other sources unless it is a limited quotation with the source cited. Typically it is better to either rephrase relevant information in your own words or link out to the other source. - + ### No special types In the software industry, it is a best practice to organize documentatioin in different types. For example, [Divio recommends](https://www.divio.com/blog/documentation/): @@ -77,7 +77,7 @@ and cross-link between any related content. We employ a **docs-first methodology** to help ensure that the docs remain a complete and trusted resource, and to make communicating about the use of GitLab more efficient. * If the answer to a question exists in documentation, share the link to the docs instead of rephrasing the information. -* When you encounter new information not available in GitLab’s documentation (for example, when working on a support case or testing a feature), your first step should be to create a merge request to add this information to the docs. You can then share the MR in order to communicate this information. +* When you encounter new information not available in GitLab’s documentation (for example, when working on a support case or testing a feature), your first step should be to create a merge request to add this information to the docs. You can then share the MR in order to communicate this information. New information that would be useful toward the future usage or troubleshooting of GitLab should not be written directly in a forum or other messaging system, but added to a docs MR and then referenced, as described above. Note that among any other doc changes, you can always add a Troubleshooting section to a doc if none exists, or un-comment and use the placeholder Troubleshooting section included as part of our [doc template](structure.md#template-for-new-docs), if present. @@ -96,7 +96,7 @@ The [documentation website](https://docs.gitlab.com) uses GitLab Kramdown as its The [`gitlab-kramdown`](https://gitlab.com/gitlab-org/gitlab_kramdown) Ruby gem will support all [GFM markup](../../user/markdown.md) in the future. That is, all markup that is supported for display in the GitLab application itself. For now, -use regular Markdown markup, following the rules in the linked style guide. +use regular Markdown markup, following the rules in the linked style guide. Note that Kramdown-specific markup (e.g., `{:.class}`) will not render properly on GitLab instances under [`/help`](index.md#gitlab-help). @@ -651,6 +651,12 @@ keyword "only": - For GitLab Premium: `**[PREMIUM ONLY]**`. - For GitLab Ultimate: `**[ULTIMATE ONLY]**`. +For GitLab.com only tiers (when the feature is not available for self-hosted instances): + +- For GitLab Bronze and higher tiers: `**[BRONZE ONLY]**`. +- For GitLab Silver and higher tiers: `**[SILVER ONLY]**`. +- For GitLab Gold: `**[GOLD ONLY]**`. + The tier should be ideally added to headers, so that the full badge will be displayed. However, it can be also mentioned from paragraphs, list items, and table cells. For these cases, the tier mention will be represented by an orange question mark that will show the tiers on hover. @@ -659,6 +665,7 @@ For example: - `**[STARTER]**` renders as **[STARTER]** - `**[STARTER ONLY]**` renders as **[STARTER ONLY]** +- `**[SILVER ONLY]**` renders as **[SILVER ONLY]** The absence of tiers' mentions mean that the feature is available in GitLab Core, GitLab.com Free, and all higher tiers. diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md index 131e3edf35e..aa463e467d4 100644 --- a/doc/development/i18n/proofreader.md +++ b/doc/development/i18n/proofreader.md @@ -13,14 +13,17 @@ are very appreciative of the work done by translators and proofreaders! - Lyubomir Vasilev - [Crowdin](https://crowdin.com/profile/lyubomirv) - Catalan - David Planella - [GitLab](https://gitlab.com/dplanella), [Crowdin](https://crowdin.com/profile/dplanella) -- Chinese Simplified - - Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve) -- Chinese Traditional +- Chinese Simplified 简体中文 - Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve) + - Victor Wu - [GitLab](https://gitlab.com/victorwuky), [Crowdin](https://crowdin.com/profile/victorwu) + - Xiaogang Wen - [GitLab](https://gitlab.com/xiaogang_gitlab), [Crowdin](https://crowdin.com/profile/xiaogang_gitlab) +- Chinese Traditional 繁體中文 - Weizhe Ding - [GitLab](https://gitlab.com/d.weizhe), [Crowdin](https://crowdin.com/profile/d.weizhe) - Yi-Jyun Pan - [GitLab](https://gitlab.com/pan93412), [Crowdin](https://crowdin.com/profile/pan93412) -- Chinese Traditional, Hong Kong - - Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve) + - Victor Wu - [GitLab](https://gitlab.com/victorwuky), [Crowdin](https://crowdin.com/profile/victorwu) +- Chinese Traditional, Hong Kong 繁體中文 (香港) + - Victor Wu - [GitLab](https://gitlab.com/victorwuky), [Crowdin](https://crowdin.com/profile/victorwu) + - Ivan Ip - [GitLab](https://gitlab.com/lifehome), [Crowdin](https://crowdin.com/profile/lifehome) - Czech - Proofreaders needed. - Danish @@ -56,7 +59,6 @@ are very appreciative of the work done by translators and proofreaders! - Hiroyuki Sato - [GitLab](https://gitlab.com/hiroponz), [Crowdin](https://crowdin.com/profile/hiroponz) - Korean - Chang-Ho Cha - [GitLab](https://gitlab.com/changho-cha), [Crowdin](https://crowdin.com/profile/zzazang) - - Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve) - Ji Hun Oh - [GitLab](https://gitlab.com/Baw-Appie), [Crowdin](https://crowdin.com/profile/BawAppie) - Jeongwhan Choi - [GitLab](https://gitlab.com/jeongwhanchoi), [Crowdin](https://crowdin.com/profile/jeongwhanchoi) - Mongolian diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md index dcb32c89f65..1ae69127295 100644 --- a/doc/development/rake_tasks.md +++ b/doc/development/rake_tasks.md @@ -12,6 +12,22 @@ The `setup` task is an alias for `gitlab:setup`. This tasks calls `db:reset` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and finally it calls `db:seed_fu` to seed the database. Note: `db:setup` calls `db:seed` but this does nothing. +### Seeding issues for all or a given project + +You can seed issues for all or a given project with the `gitlab:seed:issues` +task: + +```shell +# All projects +bin/rake gitlab:seed:issues + +# A specific project +bin/rake "gitlab:seed:issues[group-path/project-path]" +``` + +By default, this seeds an average of 2 issues per week for the last 5 weeks per +project. + ### Automation If you're very sure that you want to **wipe the current database** and refill diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md index b497cc414af..0d7bbb0af79 100644 --- a/doc/user/profile/account/delete_account.md +++ b/doc/user/profile/account/delete_account.md @@ -14,7 +14,7 @@ Deleting a user will delete all projects in that user namespace. [GitLab 9.1][ce-10273], and from the API in [GitLab 9.3][ce-11853]. When a user account is deleted, not all associated records are deleted with it. -Here's a list of things that will not be deleted: +Here's a list of things that will **not** be deleted: - Issues that the user created - Merge requests that the user created diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index ccd60b9761f..0db95e5a64c 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -124,26 +124,26 @@ To add an existing Kubernetes cluster to your project: 1. Create a file called `gitlab-admin-service-account.yaml` with contents: - ```yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: gitlab-admin - namespace: kube-system - --- - apiVersion: rbac.authorization.k8s.io/v1beta1 - kind: ClusterRoleBinding - metadata: - name: gitlab-admin - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin - subjects: - - kind: ServiceAccount - name: gitlab-admin - namespace: kube-system - ``` + ```yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: gitlab-admin + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleBinding + metadata: + name: gitlab-admin + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + subjects: + - kind: ServiceAccount + name: gitlab-admin + namespace: kube-system + ``` 1. Apply the service account and cluster role binding to your cluster: diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md new file mode 100644 index 00000000000..8e062ca627b --- /dev/null +++ b/doc/user/project/integrations/gitlab_slack_application.md @@ -0,0 +1,65 @@ +# GitLab Slack application **[FREE ONLY]** + +NOTE: **Note:** +The GitLab Slack application is only configurable for GitLab.com. It will **not** +work for on-premises installations where you can configure the +[Slack slash commands](slack_slash_commands.md) service instead. We're working +with Slack on making this configurable for all GitLab installations, but there's +no ETA. +It was first introduced in GitLab 9.4 and distributed to Slack App Directory in +GitLab 10.2. + +Slack provides a native application which you can enable via your project's +integrations on GitLab.com. + +## Slack App Directory + +The simplest way to enable the GitLab Slack application for your workspace is to +install the [GitLab application](https://slack-platform.slack.com/apps/A676ADMV5-gitlab) from +the [Slack App Directory](https://slack.com/apps). + +Clicking install will take you to the +[GitLab Slack application landing page](https://gitlab.com/profile/slack/edit) +where you can select a project to enable the GitLab Slack application for. + +![GitLab Slack application landing page](img/gitlab_slack_app_landing_page.png) + +## Configuration + +Alternatively, you can configure the Slack application with a project's +integration settings. + +Keep in mind that you need to have the appropriate permissions for your Slack +team in order to be able to install a new application, read more in Slack's +docs on [Adding an app to your team][slack-docs]. + +To enable GitLab's service for your Slack team: + +1. Go to your project's **Settings > Integration > Slack application** (only + visible on GitLab.com) +1. Click the "Add to Slack" button + +That's all! You can now start using the Slack slash commands. + +## Usage + +After confirming the installation, you, and everyone else in your Slack team, +can use all the [slash commands]. + +When you perform your first slash command you will be asked to authorize your +Slack user on GitLab.com. + +The only difference with the [manually configurable Slack slash commands][slack-manual] +is that all the commands should be prefixed with the `/gitlab` keyword. +We are working on making this configurable in the future. + +For example, to show the issue number `1001` under the `gitlab-org/gitlab-ce` +project, you would do: + +``` +/gitlab gitlab-org/gitlab-ce issue show 1001 +``` + +[slack-docs]: https://get.slack.help/hc/en-us/articles/202035138-Adding-apps-to-your-team +[slash commands]: ../../../integration/slash_commands.md +[slack-manual]: slack_slash_commands.md diff --git a/doc/user/project/integrations/img/gitlab_slack_app_landing_page.png b/doc/user/project/integrations/img/gitlab_slack_app_landing_page.png Binary files differnew file mode 100644 index 00000000000..57cd35c9f5d --- /dev/null +++ b/doc/user/project/integrations/img/gitlab_slack_app_landing_page.png diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md index 42c7824a125..339e6873c41 100644 --- a/doc/user/project/integrations/project_services.md +++ b/doc/user/project/integrations/project_services.md @@ -14,8 +14,7 @@ want to configure. ![Project services list](img/project_services.png) -Below, you will find a list of the currently supported ones accompanied with -comprehensive documentation. +Below, you will find a list of the currently supported ones accompanied with comprehensive documentation. ## Services @@ -46,7 +45,8 @@ Click on the service links to see further configuration instructions and details | Packagist | Update your project on Packagist, the main Composer repository | | Pipelines emails | Email the pipeline status to a list of recipients | | [Slack Notifications](slack.md) | Send GitLab events (e.g. issue created) to Slack as notifications | -| [Slack slash commands](slack_slash_commands.md) | Use slash commands in Slack to control GitLab | +| [Slack slash commands](slack_slash_commands.md) **[CORE ONLY]** | Use slash commands in Slack to control GitLab | +| [GitLab Slack application](gitlab_slack_application.md) **[FREE ONLY]** | Use Slack's official application | | PivotalTracker | Project Management Software (Source Commits Endpoint) | | [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | | Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md index c267da69bb3..371e78ca3a4 100644 --- a/doc/user/project/integrations/slack_slash_commands.md +++ b/doc/user/project/integrations/slack_slash_commands.md @@ -1,10 +1,15 @@ -# Slack slash commands +# Slack slash commands **[CORE ONLY]** -> Introduced in GitLab 8.15 +> Introduced in GitLab 8.15. -Slack slash commands allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab. +Slack slash commands allow you to control GitLab and view content right inside +Slack, without having to leave it. This requires configurations in both Slack and GitLab. -> Note: GitLab can also send events (e.g. issue created) to Slack as notifications. This is the separately configured [Slack Notifications Service](slack.md). +GitLab can also send events (e.g., `issue created`) to Slack as notifications. +This is the separately configured [Slack Notifications Service](slack.md). + +NOTE: **Note:** +For GitLab.com, use the [Slack app](gitlab_slack_application.md) instead. ## Configuration diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md index a3f40c20192..629b5e1fde4 100644 --- a/doc/user/project/pipelines/job_artifacts.md +++ b/doc/user/project/pipelines/job_artifacts.md @@ -55,7 +55,8 @@ For more examples on artifacts, follow the [artifacts reference in > **Note:** > With [GitLab 10.1][ce-14399], HTML files in a public project can be previewed > directly in a new tab without the need to download them when -> [GitLab Pages](../../../administration/pages/index.md) is enabled +> [GitLab Pages](../../../administration/pages/index.md) is enabled. +> The same holds for textual formats (currently supported extensions: `.txt`, `.json`, and `.log`). After a job finishes, if you visit the job's specific page, there are three buttons. You can download the artifacts archive or browse its contents, whereas diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index 718566a539f..97ecc4c0d65 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -97,7 +97,7 @@ Some things to note about precedence: > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2508) in GitLab 9.1 -[Jupyter][jupyter] Notebook (previously IPython Notebook) files are used for +[Jupyter](https://jupyter.org) Notebook (previously IPython Notebook) files are used for interactive computing in many fields and contain a complete record of the user's sessions and include code, narrative text, equations and rich output. @@ -220,14 +220,10 @@ Select branches to compare using the [branch filter search box](branches/index.m Find it under your project's **Repository > Compare**. -## Locked files +## Locked files **[PREMIUM]** -> Available in [GitLab Premium](https://about.gitlab.com/pricing/). - -Lock your files to prevent any conflicting changes. - -[File Locking](https://docs.gitlab.com/ee/user/project/file_lock.html) is available only in -[GitLab Premium](https://about.gitlab.com/pricing/). +Use [File Locking](https://docs.gitlab.com/ee/user/project/file_lock.html) to +lock your files to prevent any conflicting changes. ## Repository's API @@ -243,22 +239,19 @@ used for cloning your project. The button is only shown on macOS. ## Download Source Code -Source code stored in the repository can be downloaded. +> Support for directory download was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24704) in GitLab 11.11. +The source code stored in a repository can be downloaded from the UI. By clicking the download icon, a dropdown will open with links to download the following: ![Download source code](img/download_source_code.png) -- **Source Code:** - This allows users to download the source code on branch they're currently - viewing. Available zip, tar, tar.gz and tar.bz2. +- **Source code:** + allows users to download the source code on branch they're currently + viewing. Available extensions: `zip`, `tar`, `tar.gz`, and `tar.bz2`. - **Directory:** - > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/24704) in GitLab 11.10 - - Only shows up when viewing a sub-directory. This allows users to download - the specific directory they're currently viewing. Also available in zip, tar, - tar.gz and tar.bz2. + only shows up when viewing a sub-directory. This allows users to download + the specific directory they're currently viewing. Also available in `zip`, + `tar`, `tar.gz`, and `tar.bz2`. - **Artifacts:** - This allows users to download the artifacts of the latest CI build. - -[jupyter]: https://jupyter.org + allows users to download the artifacts of the latest CI build. diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 5c98b0ad56c..65d7f68bbf9 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -162,8 +162,8 @@ module API result = DeleteBranchService.new(user_project, current_user) .execute(params[:branch]) - if result[:status] != :success - render_api_error!(result[:message], result[:return_code]) + if result.error? + render_api_error!(result.message, result.http_status) end end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4bdac278add..ee8480122c4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -922,7 +922,15 @@ module API end class NamespaceBasic < Grape::Entity - expose :id, :name, :path, :kind, :full_path, :parent_id + expose :id, :name, :path, :kind, :full_path, :parent_id, :avatar_url + + expose :web_url do |namespace| + if namespace.user? + Gitlab::Routing.url_helpers.user_url(namespace.owner) + else + namespace.web_url + end + end end class Namespace < NamespaceBasic diff --git a/lib/api/runner.rb b/lib/api/runner.rb index c60d25b88cb..ea36c24eca2 100644 --- a/lib/api/runner.rb +++ b/lib/api/runner.rb @@ -15,12 +15,14 @@ module API optional :info, type: Hash, desc: %q(Runner's metadata) optional :active, type: Boolean, desc: 'Should Runner be active' optional :locked, type: Boolean, desc: 'Should Runner be locked for current project' + optional :access_level, type: String, values: Ci::Runner.access_levels.keys, + desc: 'The access_level of the runner' optional :run_untagged, type: Boolean, desc: 'Should Runner handle untagged jobs' optional :tag_list, type: Array[String], desc: %q(List of Runner's tags) optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this Runner will handle the job' end post '/' do - attributes = attributes_for_keys([:description, :active, :locked, :run_untagged, :tag_list, :maximum_timeout]) + attributes = attributes_for_keys([:description, :active, :locked, :run_untagged, :tag_list, :access_level, :maximum_timeout]) .merge(get_runner_details_from_request) attributes = diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 77e4c438bd0..4d67140b0a1 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -82,16 +82,18 @@ module Banzai def object_link_text(object, matches) label_suffix = '' + parent = project || group if project || full_path_ref?(matches) project_path = full_project_path(matches[:namespace], matches[:project]) parent_from_ref = from_ref_cached(project_path) - reference = parent_from_ref.to_human_reference(project || group) + reference = parent_from_ref.to_human_reference(parent) label_suffix = " <i>in #{reference}</i>" if reference.present? end - LabelsHelper.render_colored_label(object, label_suffix: label_suffix, title: tooltip_title(object)) + presenter = object.present(issuable_subject: parent) + LabelsHelper.render_colored_label(presenter, label_suffix: label_suffix, title: tooltip_title(presenter)) end def tooltip_title(label) diff --git a/lib/gitlab/checks/branch_check.rb b/lib/gitlab/checks/branch_check.rb index 1dbd564fb6f..4ddc1c718c7 100644 --- a/lib/gitlab/checks/branch_check.rb +++ b/lib/gitlab/checks/branch_check.rb @@ -48,7 +48,7 @@ module Gitlab if project.empty_repo? protected_branch_push_checks - elsif creation? && protected_branch_creation_enabled? + elsif creation? protected_branch_creation_checks elsif deletion? protected_branch_deletion_checks @@ -124,10 +124,6 @@ module Gitlab Gitlab::Routing.url_helpers.project_project_members_url(project) end - def protected_branch_creation_enabled? - Feature.enabled?(:protected_branch_creation, project, default_enabled: true) - end - def matching_merge_request? Checks::MatchingMergeRequest.new(newrev, branch_name, project).match? end diff --git a/lib/gitlab/checks/lfs_check.rb b/lib/gitlab/checks/lfs_check.rb index cc6a14d2d9a..67a65d61441 100644 --- a/lib/gitlab/checks/lfs_check.rb +++ b/lib/gitlab/checks/lfs_check.rb @@ -7,6 +7,7 @@ module Gitlab ERROR_MESSAGE = 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".'.freeze def validate! + return unless Feature.enabled?(:lfs_check, default_enabled: true) return unless project.lfs_enabled? return if skip_lfs_integrity_check diff --git a/lib/gitlab/ci/pipeline/expression/lexeme/not_equals.rb b/lib/gitlab/ci/pipeline/expression/lexeme/not_equals.rb new file mode 100644 index 00000000000..5fcc9406cc8 --- /dev/null +++ b/lib/gitlab/ci/pipeline/expression/lexeme/not_equals.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Pipeline + module Expression + module Lexeme + class NotEquals < Lexeme::Operator + PATTERN = /!=/.freeze + + def initialize(left, right) + @left = left + @right = right + end + + def evaluate(variables = {}) + @left.evaluate(variables) != @right.evaluate(variables) + end + + def self.build(_value, behind, ahead) + new(behind, ahead) + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/pipeline/expression/lexeme/not_matches.rb b/lib/gitlab/ci/pipeline/expression/lexeme/not_matches.rb new file mode 100644 index 00000000000..14544d33e25 --- /dev/null +++ b/lib/gitlab/ci/pipeline/expression/lexeme/not_matches.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Pipeline + module Expression + module Lexeme + class NotMatches < Lexeme::Operator + PATTERN = /\!~/.freeze + + def initialize(left, right) + @left = left + @right = right + end + + def evaluate(variables = {}) + text = @left.evaluate(variables) + regexp = @right.evaluate(variables) + + regexp.scan(text.to_s).none? + end + + def self.build(_value, behind, ahead) + new(behind, ahead) + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/pipeline/expression/lexer.rb b/lib/gitlab/ci/pipeline/expression/lexer.rb index f26542361a2..e14edfae51d 100644 --- a/lib/gitlab/ci/pipeline/expression/lexer.rb +++ b/lib/gitlab/ci/pipeline/expression/lexer.rb @@ -15,7 +15,9 @@ module Gitlab Expression::Lexeme::Pattern, Expression::Lexeme::Null, Expression::Lexeme::Equals, - Expression::Lexeme::Matches + Expression::Lexeme::Matches, + Expression::Lexeme::NotEquals, + Expression::Lexeme::NotMatches ].freeze MAX_TOKENS = 100 diff --git a/lib/gitlab/ci/pipeline/expression/statement.rb b/lib/gitlab/ci/pipeline/expression/statement.rb index b03611f756e..ab5ae9caeea 100644 --- a/lib/gitlab/ci/pipeline/expression/statement.rb +++ b/lib/gitlab/ci/pipeline/expression/statement.rb @@ -8,13 +8,24 @@ module Gitlab StatementError = Class.new(Expression::ExpressionError) GRAMMAR = [ + # presence matchers %w[variable], + + # positive matchers %w[variable equals string], %w[variable equals variable], %w[variable equals null], %w[string equals variable], %w[null equals variable], - %w[variable matches pattern] + %w[variable matches pattern], + + # negative matchers + %w[variable notequals string], + %w[variable notequals variable], + %w[variable notequals null], + %w[string notequals variable], + %w[null notequals variable], + %w[variable notmatches pattern] ].freeze def initialize(statement, variables = {}) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a22e3c4b9dd..c12cb6a6434 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -732,18 +732,29 @@ module Gitlab end def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:) + reachable_ref = + if source_repository == self + source_branch_name + else + # If a tmp ref was created before for a separate repo comparison (forks), + # we're able to short-circuit the tmp ref re-creation: + # 1. Take the SHA from the source repo + # 2. Read that in the current "target" repo + # 3. If that SHA is still known (readable), it means GC hasn't + # cleaned it up yet, so we can use it instead re-writing the tmp ref. + source_commit_id = source_repository.commit(source_branch_name)&.sha + commit(source_commit_id)&.sha if source_commit_id + end + + return compare(target_branch_name, reachable_ref, straight: straight) if reachable_ref + tmp_ref = "refs/tmp/#{SecureRandom.hex}" return unless fetch_source_branch!(source_repository, source_branch_name, tmp_ref) - Gitlab::Git::Compare.new( - self, - target_branch_name, - tmp_ref, - straight: straight - ) + compare(target_branch_name, tmp_ref, straight: straight) ensure - delete_refs(tmp_ref) + delete_refs(tmp_ref) if tmp_ref end def write_ref(ref_path, ref, old_ref: nil) @@ -999,6 +1010,13 @@ module Gitlab private + def compare(base_ref, head_ref, straight:) + Gitlab::Git::Compare.new(self, + base_ref, + head_ref, + straight: straight) + end + def empty_diff_stats Gitlab::Git::DiffStatsCollection.new([]) end diff --git a/lib/gitlab/graphql/authorize.rb b/lib/gitlab/graphql/authorize.rb index f62813db82c..f8d0208e275 100644 --- a/lib/gitlab/graphql/authorize.rb +++ b/lib/gitlab/graphql/authorize.rb @@ -8,7 +8,7 @@ module Gitlab extend ActiveSupport::Concern def self.use(schema_definition) - schema_definition.instrument(:field, Instrumentation.new) + schema_definition.instrument(:field, Instrumentation.new, after_built_ins: true) end end end diff --git a/lib/gitlab/graphql/authorize/authorize_field_service.rb b/lib/gitlab/graphql/authorize/authorize_field_service.rb index 8deff79fc84..619ce100421 100644 --- a/lib/gitlab/graphql/authorize/authorize_field_service.rb +++ b/lib/gitlab/graphql/authorize/authorize_field_service.rb @@ -15,15 +15,10 @@ module Gitlab def authorized_resolve proc do |parent_typed_object, args, ctx| - resolved_obj = @old_resolve_proc.call(parent_typed_object, args, ctx) - authorizing_obj = authorize_against(parent_typed_object) - checker = build_checker(ctx[:current_user], authorizing_obj) - - if resolved_obj.respond_to?(:then) - resolved_obj.then(&checker) - else - checker.call(resolved_obj) - end + resolved_type = @old_resolve_proc.call(parent_typed_object, args, ctx) + authorizing_object = authorize_against(parent_typed_object, resolved_type) + + filter_allowed(ctx[:current_user], resolved_type, authorizing_object) end end @@ -38,7 +33,7 @@ module Gitlab type = @field.type # When the return type of @field is a collection, find the singular type - if type.get_field('edges') + if @field.connection? type = node_type_for_relay_connection(type) elsif type.list? type = node_type_for_basic_connection(type) @@ -52,43 +47,60 @@ module Gitlab Array.wrap(@field.metadata[:authorize]) end - # If it's a built-in/scalar type, authorize using its parent object. - # nil means authorize using the resolved object - def authorize_against(parent_typed_object) - parent_typed_object.object if built_in_type? && parent_typed_object.respond_to?(:object) + def authorize_against(parent_typed_object, resolved_type) + if scalar_type? + # The field is a built-in/scalar type, or a list of scalars + # authorize using the parent's object + parent_typed_object.object + elsif resolved_type.respond_to?(:object) + # The field is a type representing a single object, we'll authorize + # against the object directly + resolved_type.object + elsif @field.connection? || resolved_type.is_a?(Array) + # The field is a connection or a list of non-built-in types, we'll + # authorize each element when rendering + nil + else + # Resolved type is a single object that might not be loaded yet by + # the batchloader, we'll authorize that + resolved_type + end end - def build_checker(current_user, authorizing_obj) - lambda do |resolved_obj| - # Load the elements if they were not loaded by BatchLoader yet - resolved_obj = resolved_obj.sync if resolved_obj.respond_to?(:sync) - - check = lambda do |object| - authorizations.all? do |ability| - Ability.allowed?(current_user, ability, authorizing_obj || object) - end + def filter_allowed(current_user, resolved_type, authorizing_object) + if authorizing_object + # Authorizing fields representing scalars, or a simple field with an object + resolved_type if allowed_access?(current_user, authorizing_object) + elsif @field.connection? + # A connection with pagination, modify the visible nodes in on the + # connection type in place + resolved_type.edge_nodes.to_a.keep_if { |node| allowed_access?(current_user, node) } + resolved_type + elsif resolved_type.is_a? Array + # A simple list of rendered types each object being an object to authorize + resolved_type.select do |single_object_type| + allowed_access?(current_user, single_object_type.object) end + elsif resolved_type.nil? + # We're not rendering anything, for example when a record was not found + # no need to do anything + else + raise "Can't authorize #{@field}" + end + end - case resolved_obj - when Array, ActiveRecord::Relation - resolved_obj.select(&check) - else - resolved_obj if check.call(resolved_obj) - end + def allowed_access?(current_user, object) + object = object.sync if object.respond_to?(:sync) + + authorizations.all? do |ability| + Ability.allowed?(current_user, ability, object) end end # Returns the singular type for relay connections. # This will be the type class of edges.node def node_type_for_relay_connection(type) - type = type.get_field('edges').type.unwrap.get_field('node')&.type - - if type.nil? - raise Gitlab::Graphql::Errors::ConnectionDefinitionError, - 'Connection Type must conform to the Relay Cursor Connections Specification' - end - - type + type.unwrap.get_field('edges').type.unwrap.get_field('node').type end # Returns the singular type for basic connections, for example `[Types::ProjectType]` @@ -96,8 +108,8 @@ module Gitlab type.unwrap end - def built_in_type? - GraphQL::Schema::BUILT_IN_TYPES.has_value?(node_type_for_basic_connection(@field.type)) + def scalar_type? + node_type_for_basic_connection(@field.type).kind.scalar? end end end diff --git a/lib/gitlab/graphql/connections/keyset_connection.rb b/lib/gitlab/graphql/connections/keyset_connection.rb index 851054c0393..715963a44c1 100644 --- a/lib/gitlab/graphql/connections/keyset_connection.rb +++ b/lib/gitlab/graphql/connections/keyset_connection.rb @@ -22,8 +22,17 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord - # rubocop: disable CodeReuse/ActiveRecord def paged_nodes + # These are the nodes that will be loaded into memory for rendering + # So we're ok loading them into memory here as that's bound to happen + # anyway. Having them ready means we can modify the result while + # rendering the fields. + @paged_nodes ||= load_paged_nodes.to_a + end + + private + + def load_paged_nodes if first && last raise Gitlab::Graphql::Errors::ArgumentError.new("Can only provide either `first` or `last`, not both") end @@ -31,12 +40,9 @@ module Gitlab if last sliced_nodes.last(limit_value) else - sliced_nodes.limit(limit_value) + sliced_nodes.limit(limit_value) # rubocop: disable CodeReuse/ActiveRecord end end - # rubocop: enable CodeReuse/ActiveRecord - - private def before_slice if sort_direction == :asc diff --git a/lib/gitlab/graphql/errors.rb b/lib/gitlab/graphql/errors.rb index bcbba72e017..fe74549e322 100644 --- a/lib/gitlab/graphql/errors.rb +++ b/lib/gitlab/graphql/errors.rb @@ -6,7 +6,6 @@ module Gitlab BaseError = Class.new(GraphQL::ExecutionError) ArgumentError = Class.new(BaseError) ResourceNotAvailable = Class.new(BaseError) - ConnectionDefinitionError = Class.new(BaseError) end end end diff --git a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb index fcf6a25ab00..acb7f225b17 100644 --- a/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb +++ b/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb @@ -30,10 +30,7 @@ module Gitlab def handle_response_error(response) unless response.success? - error_code = response.dig('Error', 'Code') || response.code - error_message = response.dig('Error', 'Message') || response.message - - raise StrategyError.new("Error uploading the project. Code #{error_code}: #{error_message}") + raise StrategyError.new("Error uploading the project. Code #{response.code}: #{response.message}") end end diff --git a/lib/gitlab/performance_bar/peek_query_tracker.rb b/lib/gitlab/performance_bar/peek_query_tracker.rb index ac392432427..16c16aa0265 100644 --- a/lib/gitlab/performance_bar/peek_query_tracker.rb +++ b/lib/gitlab/performance_bar/peek_query_tracker.rb @@ -26,11 +26,7 @@ module Gitlab subscribe('sql.active_record') do |_, start, finish, _, data| if Gitlab::SafeRequestStore.store[:peek_enabled] - # data[:cached] is only available starting from Rails 5.1.0 - # https://github.com/rails/rails/blob/v5.1.0/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb#L113 - # Before that, data[:name] was set to 'CACHE' - # https://github.com/rails/rails/blob/v4.2.9/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb#L80 - unless data.fetch(:cached, data[:name] == 'CACHE') + unless data[:cached] track_query(data[:sql].strip, data[:binds], start, finish) end end diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 8988b9ad7be..a29517e068f 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -113,7 +113,7 @@ module Gitlab issues.full_search(query) end - issues.reorder('updated_at DESC') + issues.reorder('issues.updated_at DESC') end # rubocop: enable CodeReuse/ActiveRecord @@ -121,7 +121,7 @@ module Gitlab def milestones milestones = Milestone.where(project_id: project_ids_relation) milestones = milestones.search(query) - milestones.reorder('updated_at DESC') + milestones.reorder('milestones.updated_at DESC') end # rubocop: enable CodeReuse/ActiveRecord @@ -139,7 +139,7 @@ module Gitlab merge_requests.full_search(query) end - merge_requests.reorder('updated_at DESC') + merge_requests.reorder('merge_requests.updated_at DESC') end # rubocop: enable CodeReuse/ActiveRecord diff --git a/lib/quality/kubernetes_client.rb b/lib/quality/kubernetes_client.rb index 2ff9e811425..190b48ba7cb 100644 --- a/lib/quality/kubernetes_client.rb +++ b/lib/quality/kubernetes_client.rb @@ -18,6 +18,8 @@ module Quality 'delete', 'ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa', '--now', + '--ignore-not-found', + '--include-uninitialized', %(-l release="#{release_name}") ] diff --git a/lib/quality/seeders/issues.rb b/lib/quality/seeders/issues.rb new file mode 100644 index 00000000000..4c8cb6e97cc --- /dev/null +++ b/lib/quality/seeders/issues.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# rubocop:disable CodeReuse/ActiveRecord +module Quality + module Seeders + class Issues + DEFAULT_BACKFILL_WEEKS = 52 + DEFAULT_AVERAGE_ISSUES_PER_WEEK = 10 + + attr_reader :project, :user + + def initialize(project:) + @project = project + end + + def seed(backfill_weeks: DEFAULT_BACKFILL_WEEKS, average_issues_per_week: DEFAULT_AVERAGE_ISSUES_PER_WEEK) + created_at = backfill_weeks.to_i.weeks.ago + team = project.team.users + created_issues_count = 0 + + loop do + rand(average_issues_per_week * 2).times do + params = { + title: FFaker::Lorem.sentence(6), + description: FFaker::Lorem.sentence, + created_at: created_at + rand(6).days, + state: %w[opened closed].sample, + milestone: project.milestones.sample, + assignee_ids: Array(team.pluck(:id).sample(3)), + labels: labels.join(',') + } + issue = ::Issues::CreateService.new(project, team.sample, params).execute + + if issue.persisted? + created_issues_count += 1 + print '.' # rubocop:disable Rails/Output + end + end + + created_at += 1.week + + break if created_at > Time.now + end + + created_issues_count + end + + private + + def labels + @labels_pool ||= project.labels.limit(rand(3)).pluck(:title).tap do |labels_array| + labels_array.concat(project.group.labels.limit(rand(3)).pluck(:title)) if project.group + end + end + end + end +end +# rubocop:enable CodeReuse/ActiveRecord diff --git a/lib/tasks/gitlab/seed.rake b/lib/tasks/gitlab/seed.rake new file mode 100644 index 00000000000..155ba979b36 --- /dev/null +++ b/lib/tasks/gitlab/seed.rake @@ -0,0 +1,34 @@ +namespace :gitlab do + namespace :seed do + desc "GitLab | Seed | Seeds issues" + task :issues, [:project_full_path] => :environment do |t, args| + projects = + if args.project_full_path + project = Project.find_by_full_path(args.project_full_path) + + unless project + error_message = "Project '#{args.project_full_path}' does not exist!" + potential_projects = Project.search(args.project_full_path) + + if potential_projects.present? + error_message += " Did you mean '#{potential_projects.first.full_path}'?" + end + + puts error_message.color(:red) + exit 1 + end + + [project] + else + Project.find_each + end + + projects.each do |project| + puts "\nSeeding issues for the '#{project.full_path}' project" + seeder = Quality::Seeders::Issues.new(project: project) + issues_created = seeder.seed(backfill_weeks: 5, average_issues_per_week: 2) + puts "\n#{issues_created} issues created!" + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 54c40e48084..06f2f848925 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -372,6 +372,9 @@ msgstr "" msgid "A deleted user" msgstr "" +msgid "A fork is a copy of a project.<br />Forking a repository allows you to make changes without affecting the original project." +msgstr "" + msgid "A member of GitLab's abuse team will review your report as soon as possible." msgstr "" @@ -4140,6 +4143,15 @@ msgstr "" msgid "For public projects, anyone can view pipelines and access job details (output logs and artifacts)" msgstr "" +msgid "Fork" +msgstr "" + +msgid "Fork Error!" +msgstr "" + +msgid "Fork project" +msgstr "" + msgid "ForkedFromProjectPath|Forked from" msgstr "" @@ -4149,6 +4161,9 @@ msgstr "" msgid "Forking in progress" msgstr "" +msgid "Forking repository" +msgstr "" + msgid "Forks" msgstr "" @@ -4311,6 +4326,9 @@ msgstr "" msgid "Go to project" msgstr "" +msgid "Go to your fork" +msgstr "" + msgid "Google Code import" msgstr "" @@ -5775,6 +5793,9 @@ msgstr "" msgid "Name" msgstr "" +msgid "Name has already been taken" +msgstr "" + msgid "Name new label" msgstr "" @@ -5927,6 +5948,9 @@ msgstr "" msgid "No activities found" msgstr "" +msgid "No available namespaces to fork the project." +msgstr "" + msgid "No branches found" msgstr "" @@ -7835,6 +7859,9 @@ msgstr "" msgid "Search for projects, issues, etc." msgstr "" +msgid "Search forks" +msgstr "" + msgid "Search groups" msgstr "" @@ -9709,6 +9736,9 @@ msgstr "" msgid "Try again?" msgstr "" +msgid "Try to fork again" +msgstr "" + msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now." msgstr "" @@ -10533,6 +10563,9 @@ msgstr "" msgid "You must have maintainer access to force delete a lock" msgstr "" +msgid "You must have permission to create a project in a namespace before forking." +msgstr "" + msgid "You need permission." msgstr "" @@ -10548,6 +10581,9 @@ msgstr "" msgid "You need to upload a Google Takeout archive." msgstr "" +msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:" +msgstr "" + msgid "You will lose all changes you've made to this file. This action cannot be undone." msgstr "" @@ -11199,6 +11235,9 @@ msgstr "" msgid "sign in" msgstr "" +msgid "sort:" +msgstr "" + msgid "source" msgstr "" diff --git a/package.json b/package.json index 1cb9f7a9ade..e04470109be 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@babel/preset-env": "^7.3.1", "@gitlab/csslab": "^1.9.0", "@gitlab/svgs": "^1.59.0", - "@gitlab/ui": "^3.3.0", + "@gitlab/ui": "^3.4.0", "apollo-cache-inmemory": "^1.5.1", "apollo-client": "^2.5.1", "apollo-upload-client": "^10.0.0", diff --git a/qa/Gemfile b/qa/Gemfile index 38e95ba2d65..64215b24cf1 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -7,6 +7,6 @@ gem 'rake', '~> 12.3.0' gem 'rspec', '~> 3.7' gem 'selenium-webdriver', '~> 3.12' gem 'airborne', '~> 0.2.13' -gem 'nokogiri', '~> 1.10.1' +gem 'nokogiri', '~> 1.10.3' gem 'rspec-retry', '~> 0.6.1' gem 'faker', '~> 1.6', '>= 1.6.6' diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 9d3d42fb6ae..a06c88b6f0a 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -49,7 +49,7 @@ GEM mini_portile2 (2.4.0) minitest (5.11.1) netrc (0.11.0) - nokogiri (1.10.2) + nokogiri (1.10.3) mini_portile2 (~> 2.4.0) pry (0.11.3) coderay (~> 1.1.0) @@ -102,7 +102,7 @@ DEPENDENCIES capybara (~> 2.16.1) capybara-screenshot (~> 1.0.18) faker (~> 1.6, >= 1.6.6) - nokogiri (~> 1.10.1) + nokogiri (~> 1.10.3) pry-byebug (~> 3.5.1) rake (~> 12.3.0) rspec (~> 3.7) diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb index 71c06b3410f..cf225a639b6 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb @@ -7,16 +7,12 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.act { sign_in_using_credentials } - # TODO, since `Signed in successfully` message was removed - # this is the only way to tell if user is signed in correctly. - # Page::Main::Menu.perform do |menu| expect(menu).to have_personal_area end Page::Main::Menu.perform do |menu| menu.sign_out - expect(menu).not_to have_personal_area end Page::Main::Login.perform do |form| diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb index a397df03bd2..72dde4e5bd8 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb @@ -7,9 +7,6 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.act { sign_in_using_credentials } - # TODO, since `Signed in successfully` message was removed - # this is the only way to tell if user is signed in correctly. - # Page::Main::Menu.perform do |menu| expect(menu).to have_personal_area end diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb index 185837edacf..a0e3fe0d91a 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb @@ -7,9 +7,6 @@ module QA Resource::User.fabricate_via_browser_ui! - # TODO, since `Signed in successfully` message was removed - # this is the only way to tell if user is signed in correctly. - # Page::Main::Menu.perform do |menu| expect(menu).to have_personal_area end diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh index 51cfd145ba8..b55ce1af55e 100755 --- a/scripts/review_apps/review-apps.sh +++ b/scripts/review_apps/review-apps.sh @@ -68,7 +68,7 @@ function delete() { echoinfo "Deleting release '$name'..." true - helm delete --purge "$name" || true + helm delete --purge "$name" } function cleanup() { @@ -81,8 +81,8 @@ function cleanup() { kubectl -n "$KUBE_NAMESPACE" delete \ ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa \ - -l release="$CI_ENVIRONMENT_SLUG" \ - || true + --now --ignore-not-found --include-uninitialized \ + -l release="$CI_ENVIRONMENT_SLUG" } function get_pod() { diff --git a/spec/controllers/concerns/issuable_collections_spec.rb b/spec/controllers/concerns/issuable_collections_spec.rb index f9d15d04719..fb2cd5ca955 100644 --- a/spec/controllers/concerns/issuable_collections_spec.rb +++ b/spec/controllers/concerns/issuable_collections_spec.rb @@ -108,51 +108,77 @@ describe IssuableCollections do end describe '#finder_options' do - let(:params) do - { - assignee_id: '1', - assignee_username: 'user1', - author_id: '2', - author_username: 'user2', - authorized_only: 'yes', - confidential: true, - due_date: '2017-01-01', - group_id: '3', - iids: '4', - label_name: ['foo'], - milestone_title: 'bar', - my_reaction_emoji: 'thumbsup', - non_archived: 'true', - project_id: '5', - scope: 'all', - search: 'baz', - sort: 'priority', - state: 'opened', - invalid_param: 'invalid_param' - } - end - - it 'only allows whitelisted params' do + before do allow(controller).to receive(:cookies).and_return({}) allow(controller).to receive(:current_user).and_return(nil) + end + + subject { controller.send(:finder_options).to_h } + + context 'scalar params' do + let(:params) do + { + assignee_id: '1', + assignee_username: 'user1', + author_id: '2', + author_username: 'user2', + authorized_only: 'yes', + confidential: true, + due_date: '2017-01-01', + group_id: '3', + iids: '4', + label_name: 'foo', + milestone_title: 'bar', + my_reaction_emoji: 'thumbsup', + non_archived: 'true', + project_id: '5', + scope: 'all', + search: 'baz', + sort: 'priority', + state: 'opened', + invalid_param: 'invalid_param' + } + end + + it 'only allows whitelisted params' do + is_expected.to include({ + 'assignee_id' => '1', + 'assignee_username' => 'user1', + 'author_id' => '2', + 'author_username' => 'user2', + 'confidential' => true, + 'label_name' => 'foo', + 'milestone_title' => 'bar', + 'my_reaction_emoji' => 'thumbsup', + 'due_date' => '2017-01-01', + 'scope' => 'all', + 'search' => 'baz', + 'sort' => 'priority', + 'state' => 'opened' + }) + + is_expected.not_to include('invalid_param') + end + end + + context 'array params' do + let(:params) do + { + assignee_username: %w[user1 user2], + label_name: %w[label1 label2], + invalid_param: 'invalid_param', + invalid_array: ['param'] + } + end + + it 'only allows whitelisted params' do + is_expected.to include({ + 'label_name' => %w[label1 label2], + 'assignee_username' => %w[user1 user2] + }) - finder_options = controller.send(:finder_options) - - expect(finder_options).to eq(ActionController::Parameters.new({ - 'assignee_id' => '1', - 'assignee_username' => 'user1', - 'author_id' => '2', - 'author_username' => 'user2', - 'confidential' => true, - 'label_name' => ['foo'], - 'milestone_title' => 'bar', - 'my_reaction_emoji' => 'thumbsup', - 'due_date' => '2017-01-01', - 'scope' => 'all', - 'search' => 'baz', - 'sort' => 'priority', - 'state' => 'opened' - }).permit!) + is_expected.not_to include('invalid_param', 'invalid_array') + end end end end diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index 0af0eb4f942..6e374a8daa7 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -9,10 +9,14 @@ describe OmniauthCallbacksController, type: :controller do let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) } before do - mock_auth_hash(provider.to_s, +extern_uid, user.email) + @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, +extern_uid, user.email) stub_omniauth_provider(provider, context: request) end + after do + Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth + end + context 'when the user is on the last sign in attempt' do let(:extern_uid) { 'my-uid' } diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 1818809518d..92380a2bf09 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -82,7 +82,7 @@ describe Projects::CompareController do show_request expect(response).to be_success - expect(assigns(:diffs).diff_files.to_a).to eq([]) + expect(assigns(:diffs)).to eq([]) expect(assigns(:commits)).to eq([]) end end diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index fc9a0adeed2..db53e5bc8a4 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -191,6 +191,15 @@ describe Projects::Settings::CiCdController do expect(project.build_timeout).to eq(5400) end end + + context 'when build_timeout_human_readable is invalid' do + let(:params) { { build_timeout_human_readable: '5m' } } + + it 'set specified timeout' do + expect(subject).to set_flash[:alert] + expect(response).to redirect_to(namespace_project_settings_ci_cd_path) + end + end end end end diff --git a/spec/db/importers/common_metrics_importer_spec.rb b/spec/db/importers/common_metrics_importer_spec.rb index 6133b17ac61..a717c8cd04d 100644 --- a/spec/db/importers/common_metrics_importer_spec.rb +++ b/spec/db/importers/common_metrics_importer_spec.rb @@ -23,10 +23,10 @@ describe Importers::CommonMetricsImporter do subject { described_class.new } context "does import common_metrics.yml" do - let(:groups) { subject.content } - let(:metrics) { groups.map { |group| group['metrics'] }.flatten } - let(:queries) { metrics.map { |group| group['queries'] }.flatten } - let(:query_ids) { queries.map { |query| query['id'] } } + let(:groups) { subject.content['panel_groups'] } + let(:panels) { groups.map { |group| group['panels'] }.flatten } + let(:metrics) { panels.map { |group| group['metrics'] }.flatten } + let(:metric_ids) { metrics.map { |metric| metric['id'] } } before do subject.execute @@ -36,20 +36,20 @@ describe Importers::CommonMetricsImporter do expect(PrometheusMetric.common.group(:group).count.count).to eq(groups.count) end - it "has the same amount of metrics" do - expect(PrometheusMetric.common.group(:group, :title).count.count).to eq(metrics.count) + it "has the same amount of panels" do + expect(PrometheusMetric.common.group(:group, :title).count.count).to eq(panels.count) end - it "has the same amount of queries" do - expect(PrometheusMetric.common.count).to eq(queries.count) + it "has the same amount of metrics" do + expect(PrometheusMetric.common.count).to eq(metrics.count) end it "does not have duplicate IDs" do - expect(query_ids).to eq(query_ids.uniq) + expect(metric_ids).to eq(metric_ids.uniq) end it "imports all IDs" do - expect(PrometheusMetric.common.pluck(:identifier)).to contain_exactly(*query_ids) + expect(PrometheusMetric.common.pluck(:identifier)).to contain_exactly(*metric_ids) end end @@ -65,24 +65,26 @@ describe Importers::CommonMetricsImporter do context 'does import properly all fields' do let(:query_identifier) { 'response-metric' } - let(:group) do + let(:dashboard) do { - group: 'Response metrics (NGINX Ingress)', - metrics: [{ - title: "Throughput", - y_label: "Requests / Sec", - queries: [{ - id: query_identifier, - query_range: 'my-query', - unit: 'my-unit', - label: 'status code' + panel_groups: [{ + group: 'Response metrics (NGINX Ingress)', + panels: [{ + title: "Throughput", + y_label: "Requests / Sec", + metrics: [{ + id: query_identifier, + query_range: 'my-query', + unit: 'my-unit', + label: 'status code' + }] }] }] } end before do - expect(subject).to receive(:content) { [group.deep_stringify_keys] } + expect(subject).to receive(:content) { dashboard.deep_stringify_keys } end shared_examples 'stores metric' do diff --git a/spec/factories/pool_repositories.rb b/spec/factories/pool_repositories.rb index 36e54cf44b4..8cac666069c 100644 --- a/spec/factories/pool_repositories.rb +++ b/spec/factories/pool_repositories.rb @@ -5,6 +5,7 @@ FactoryBot.define do before(:create) do |pool| pool.source_project = create(:project, :repository) + pool.source_project.update!(pool_repository: pool) end trait :scheduled do diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index b1c6f308bc6..29545779a34 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -34,14 +34,11 @@ describe "Admin::Users" do expect(page).to have_button('Delete user and contributions') end - describe "view extra user information", :js do - it 'does not have the user popover open' do + describe "view extra user information" do + it 'shows the user popover on hover', :js, :quarantine do expect(page).not_to have_selector('#__BV_popover_1__') - end - it 'shows the user popover on hover' do first_user_link = page.first('.js-user-link') - first_user_link.hover expect(page).to have_selector('#__BV_popover_1__') diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index fd8677feab5..d58e3b2841e 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -17,6 +17,26 @@ describe 'Dashboard Todos' do end end + context 'when the todo references a merge request' do + let(:referenced_mr) { create(:merge_request, source_project: project) } + let(:note) { create(:note, project: project, note: "Check out #{referenced_mr.to_reference}") } + let!(:todo) { create(:todo, :mentioned, user: user, project: project, author: author, note: note) } + + before do + sign_in(user) + visit dashboard_todos_path + end + + it 'renders the mr link with the extra attributes' do + link = page.find_link(referenced_mr.to_reference) + + expect(link).not_to be_nil + expect(link['data-iid']).to eq(referenced_mr.iid.to_s) + expect(link['data-project-path']).to eq(referenced_mr.project.full_path) + expect(link['data-mr-title']).to eq(referenced_mr.title) + end + end + context 'User has a todo', :js do before do create(:todo, :mentioned, user: user, project: project, target: issue, author: author) diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb index 65de0afae0c..5db54f42264 100644 --- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb +++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb @@ -191,29 +191,119 @@ describe 'Merge request > User creates image diff notes', :js do end end - describe 'image view modes' do - before do - visit project_commit_path(project, '2f63565e7aac07bcdadb654e253078b727143ec4') + shared_examples 'swipe view' do + it 'moves the swipe handle' do + # Simulate dragging swipe view slider + expect { drag_and_drop_by(find('.swipe-bar'), 20, 0) } + .to change { find('.swipe-bar')['style'] } + .from(a_string_matching('left: 1px')) end - it 'resizes image in onion skin view mode' do - find('.view-modes-menu .onion-skin').click + it 'shows both images at the same position' do + drag_and_drop_by(find('.swipe-bar'), 40, 0) - expect(find('.onion-skin-frame')['style']).to match('width: 228px; height: 240px;') + expect(left_position('.frame.added img')) + .to eq(left_position('.frame.deleted img')) end + end - it 'resets onion skin view mode opacity when toggling between view modes' do - find('.view-modes-menu .onion-skin').click - + shared_examples 'onion skin' do + it 'resets opacity when toggling between view modes' do # Simulate dragging onion-skin slider drag_and_drop_by(find('.dragger'), -30, 0) expect(find('.onion-skin-frame .frame.added', visible: false)['style']).not_to match('opacity: 1;') + switch_to_swipe_view + switch_to_onion_skin + + expect(find('.onion-skin-frame .frame.added', visible: false)['style']).to match('opacity: 1;') + end + end + + describe 'changes tab image diff' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, target_branch: 'master', source_branch: 'deleted-image-test', author: user) } + + before do + visit diffs_project_merge_request_path(project, merge_request) + click_link "Changes" + end + + def set_image_diff_sources + # set path of added and deleted images to something the spec can view + page.execute_script("document.querySelector('.frame.added img').src = '/apple-touch-icon.png';") + page.execute_script("document.querySelector('.frame.deleted img').src = '/favicon.png';") + + wait_for_requests + + expect(find('.frame.added img', visible: false)['src']).to match('/apple-touch-icon.png') + expect(find('.frame.deleted img', visible: false)['src']).to match('/favicon.png') + end + + def switch_to_swipe_view + # it isn't given the .swipe class in the merge request diff + find('.view-modes-menu li:nth-child(2)').click + expect(find('.view-modes-menu li.active')).to have_content('Swipe') + + set_image_diff_sources + end + + def switch_to_onion_skin + # it isn't given the .onion-skin class in the merge request diff + find('.view-modes-menu li:nth-child(3)').click + expect(find('.view-modes-menu li.active')).to have_content('Onion skin') + + set_image_diff_sources + end + + describe 'onion skin' do + before do + switch_to_onion_skin + end + + it_behaves_like 'onion skin' + end + + describe 'swipe view' do + before do + switch_to_swipe_view + end + + it_behaves_like 'swipe view' + end + end + + describe 'image view modes' do + before do + visit project_commit_path(project, '2f63565e7aac07bcdadb654e253078b727143ec4') + end + + def switch_to_swipe_view find('.view-modes-menu .swipe').click + end + + def switch_to_onion_skin find('.view-modes-menu .onion-skin').click + end - expect(find('.onion-skin-frame .frame.added', visible: false)['style']).to match('opacity: 1;') + describe 'onion skin' do + before do + switch_to_onion_skin + end + + it 'resizes image' do + expect(find('.onion-skin-frame')['style']).to match('width: 228px; height: 240px;') + end + + it_behaves_like 'onion skin' + end + + describe 'swipe view' do + before do + switch_to_swipe_view + end + + it_behaves_like 'swipe view' end end @@ -232,4 +322,8 @@ describe 'Merge request > User creates image diff notes', :js do click_button 'Comment' wait_for_requests end + + def left_position(element) + page.evaluate_script("document.querySelectorAll('#{element}')[0].getBoundingClientRect().left;") + end end diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index d36f043f880..f32b155790f 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -138,29 +138,41 @@ describe 'Prioritize labels' do end context 'as a guest' do - it 'does not prioritize labels' do + before do + create(:label_priority, project: project, label: bug, priority: 1) + create(:label_priority, project: project, label: feature, priority: 2) + guest = create(:user) sign_in guest visit project_labels_path(project) + end + it 'cannot prioritize labels' do expect(page).to have_content 'bug' expect(page).to have_content 'wontfix' expect(page).to have_content 'feature' - expect(page).not_to have_css('.prioritized-labels') expect(page).not_to have_content 'Star a label' end + + it 'cannot sort prioritized labels', :js do + drag_to(selector: '.prioritized-labels .label-list-item', from_index: 1, to_index: 2) + + page.within('.prioritized-labels') do + expect(first('.label-list-item')).to have_content('bug') + expect(page.all('.label-list-item').last).to have_content('feature') + end + end end context 'as a non signed in user' do - it 'does not prioritize labels' do + it 'cannot prioritize labels' do visit project_labels_path(project) expect(page).to have_content 'bug' expect(page).to have_content 'wontfix' expect(page).to have_content 'feature' - expect(page).not_to have_css('.prioritized-labels') expect(page).not_to have_content 'Star a label' end end diff --git a/spec/features/projects/labels/user_views_labels_spec.rb b/spec/features/projects/labels/user_views_labels_spec.rb index 2c8267764bd..a6f7968c535 100644 --- a/spec/features/projects/labels/user_views_labels_spec.rb +++ b/spec/features/projects/labels/user_views_labels_spec.rb @@ -7,6 +7,7 @@ describe "User views labels" do set(:user) { create(:user) } let(:label_titles) { %w[bug enhancement feature] } + let!(:prioritized_label) { create(:label, project: project, title: 'prioritized-label-name', priority: 1) } before do label_titles.each { |title| create(:label, project: project, title: title) } @@ -18,6 +19,10 @@ describe "User views labels" do end it "shows all labels" do + page.within('.prioritized-labels .manage-labels-list') do + expect(page).to have_content('prioritized-label-name') + end + page.within('.other-labels .manage-labels-list') do label_titles.each { |title| expect(page).to have_content(title) } end diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb index 88f3397608f..e9dd1dc0f66 100644 --- a/spec/features/projects/show/user_manages_notifications_spec.rb +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -20,6 +20,16 @@ describe 'Projects > Show > User manages notifications', :js do click_notifications_button expect(find('.update-notification.is-active')).to have_content('On mention') + expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications') + end + + it 'changes the notification setting to disabled' do + click_notifications_button + click_link 'Disabled' + + wait_for_requests + + expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications-off') end context 'custom notification settings' do diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index 9d5780d29b0..efba303033b 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -137,7 +137,7 @@ describe 'Login' do enter_code(user.current_otp) - expect(page).not_to have_content('You are already signed in.') + expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated')) end context 'using one-time code' do @@ -317,7 +317,17 @@ describe 'Login' do gitlab_sign_in(user) expect(current_path).to eq root_path - expect(page).not_to have_content('You are already signed in.') + expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated')) + end + + it 'does not show already signed in message when opening sign in page after login' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + + gitlab_sign_in(user) + visit new_user_session_path + + expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated')) end end @@ -579,7 +589,7 @@ describe 'Login' do click_button 'Accept terms' expect(current_path).to eq(root_path) - expect(page).not_to have_content('You are already signed in.') + expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated')) end it 'does not ask for terms when the user already accepted them' do diff --git a/spec/fixtures/api/schemas/entities/issue.json b/spec/fixtures/api/schemas/entities/issue.json index 162fb9c8108..9898819ef75 100644 --- a/spec/fixtures/api/schemas/entities/issue.json +++ b/spec/fixtures/api/schemas/entities/issue.json @@ -5,7 +5,7 @@ "iid": { "type": "integer" }, "author_id": { "type": "integer" }, "description": { "type": ["string", "null"] }, - "lock_version": { "type": ["string", "null"] }, + "lock_version": { "type": ["integer", "null"] }, "milestone_id": { "type": ["string", "null"] }, "title": { "type": "string" }, "moved_to_id": { "type": ["integer", "null"] }, diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json index 88a600398b1..ac0a0314455 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_basic.json +++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json @@ -23,7 +23,7 @@ }, "task_status": { "type": "string" }, "task_status_short": { "type": "string" }, - "lock_version": { "type": ["string", "null"] } + "lock_version": { "type": ["integer", "null"] } }, "additionalProperties": false } diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js index 841aff0d7ff..fba7c41df94 100644 --- a/spec/frontend/gfm_auto_complete_spec.js +++ b/spec/frontend/gfm_auto_complete_spec.js @@ -1,7 +1,7 @@ /* eslint no-param-reassign: "off" */ import $ from 'jquery'; -import GfmAutoComplete from '~/gfm_auto_complete'; +import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import 'jquery.caret'; import 'at.js'; diff --git a/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js b/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js index 8e8b7f06ca2..6a1a826093c 100644 --- a/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js +++ b/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js @@ -2,6 +2,9 @@ import createState from '~/ide/stores/modules/file_templates/state'; import * as types from '~/ide/stores/modules/file_templates/mutation_types'; import mutations from '~/ide/stores/modules/file_templates/mutations'; +const mockFileTemplates = [['MIT'], ['CC']]; +const mockTemplateType = 'test'; + describe('IDE file templates mutations', () => { let state; @@ -10,11 +13,21 @@ describe('IDE file templates mutations', () => { }); describe(`${types.REQUEST_TEMPLATE_TYPES}`, () => { - it('sets isLoading', () => { + it('sets loading to true', () => { + state.isLoading = false; + mutations[types.REQUEST_TEMPLATE_TYPES](state); expect(state.isLoading).toBe(true); }); + + it('sets templates to an empty array', () => { + state.templates = mockFileTemplates; + + mutations[types.REQUEST_TEMPLATE_TYPES](state); + + expect(state.templates).toEqual([]); + }); }); describe(`${types.RECEIVE_TEMPLATE_TYPES_ERROR}`, () => { @@ -31,29 +44,33 @@ describe('IDE file templates mutations', () => { it('sets isLoading to false', () => { state.isLoading = true; - mutations[types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, []); + mutations[types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, mockFileTemplates); expect(state.isLoading).toBe(false); }); - it('sets templates', () => { - mutations[types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, ['test']); + it('sets templates to payload', () => { + state.templates = ['test']; + + mutations[types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, mockFileTemplates); - expect(state.templates).toEqual(['test']); + expect(state.templates).toEqual(mockFileTemplates); }); }); describe(`${types.SET_SELECTED_TEMPLATE_TYPE}`, () => { - it('sets selectedTemplateType', () => { - mutations[types.SET_SELECTED_TEMPLATE_TYPE](state, 'type'); + it('sets templates type to selected type', () => { + state.selectedTemplateType = ''; - expect(state.selectedTemplateType).toBe('type'); + mutations[types.SET_SELECTED_TEMPLATE_TYPE](state, mockTemplateType); + + expect(state.selectedTemplateType).toBe(mockTemplateType); }); - it('clears templates', () => { - state.templates = ['test']; + it('sets templates to empty array', () => { + state.templates = mockFileTemplates; - mutations[types.SET_SELECTED_TEMPLATE_TYPE](state, 'type'); + mutations[types.SET_SELECTED_TEMPLATE_TYPE](state, mockTemplateType); expect(state.templates).toEqual([]); }); @@ -61,6 +78,8 @@ describe('IDE file templates mutations', () => { describe(`${types.SET_UPDATE_SUCCESS}`, () => { it('sets updateSuccess', () => { + state.updateSuccess = false; + mutations[types.SET_UPDATE_SUCCESS](state, true); expect(state.updateSuccess).toBe(true); diff --git a/spec/frontend/mr_popover/index_spec.js b/spec/frontend/mr_popover/index_spec.js index 8c33e52a04b..b9db2342687 100644 --- a/spec/frontend/mr_popover/index_spec.js +++ b/spec/frontend/mr_popover/index_spec.js @@ -7,18 +7,28 @@ createDefaultClient.default = jest.fn(); describe('initMRPopovers', () => { let mr1; let mr2; + let mr3; beforeEach(() => { setHTMLFixture(` - <div id="one" class="gfm-merge_request">MR1</div> - <div id="two" class="gfm-merge_request">MR2</div> + <div id="one" class="gfm-merge_request" data-mr-title="title" data-iid="1" data-project-path="group/project"> + MR1 + </div> + <div id="two" class="gfm-merge_request" data-mr-title="title" data-iid="1" data-project-path="group/project"> + MR2 + </div> + <div id="three" class="gfm-merge_request"> + MR3 + </div> `); mr1 = document.querySelector('#one'); mr2 = document.querySelector('#two'); + mr3 = document.querySelector('#three'); mr1.addEventListener = jest.fn(); mr2.addEventListener = jest.fn(); + mr3.addEventListener = jest.fn(); }); it('does not add the same event listener twice', () => { @@ -27,4 +37,10 @@ describe('initMRPopovers', () => { expect(mr1.addEventListener).toHaveBeenCalledTimes(1); expect(mr2.addEventListener).toHaveBeenCalledTimes(1); }); + + it('does not add listener if it does not have the necessary data attributes', () => { + initMRPopovers([mr1, mr2, mr3]); + + expect(mr3.addEventListener).not.toHaveBeenCalled(); + }); }); diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb index 00e31568a9e..f5eb628a982 100644 --- a/spec/graphql/features/authorization_spec.rb +++ b/spec/graphql/features/authorization_spec.rb @@ -177,6 +177,7 @@ describe 'Gitlab::Graphql::Authorization' do describe 'type authorizations when applied to a relay connection' do let(:query_string) { '{ object() { edges { node { name } } } }' } + let(:second_test_object) { double(name: 'Second thing') } let(:type) do type_factory do |type| @@ -186,22 +187,41 @@ describe 'Gitlab::Graphql::Authorization' do let(:query_type) do query_factory do |query| - query.field :object, type.connection_type, null: true, resolve: ->(obj, args, ctx) { [test_object] } + query.field :object, type.connection_type, null: true, resolve: ->(obj, args, ctx) { [test_object, second_test_object] } end end subject { result.dig('object', 'edges') } - it 'returns the protected field when user has permission' do + it 'returns only the elements visible to the user' do permit(permission_single) - expect(subject).not_to be_empty + expect(subject.size).to eq 1 expect(subject.first['node']).to eq('name' => test_object.name) end it 'returns nil when user is not authorized' do expect(subject).to be_empty end + + describe 'limiting connections with multiple objects' do + let(:query_type) do + query_factory do |query| + query.field :object, type.connection_type, null: true, resolve: ->(obj, args, ctx) do + [test_object, second_test_object] + end + end + end + + let(:query_string) { '{ object(first: 1) { edges { node { name } } } }' } + + it 'only checks permissions for the first object' do + expect(Ability).to receive(:allowed?).with(user, permission_single, test_object) { true } + expect(Ability).not_to receive(:allowed?).with(user, permission_single, second_test_object) + + expect(subject.size).to eq(1) + end + end end describe 'type authorizations when applied to a basic connection' do @@ -222,28 +242,53 @@ describe 'Gitlab::Graphql::Authorization' do include_examples 'authorization with a single permission' end - describe 'when connections do not follow the correct specification' do - let(:query_string) { '{ object() { edges { node { name }} } }' } + describe 'Authorizations on active record relations' do + let!(:visible_project) { create(:project, :private) } + let!(:other_project) { create(:project, :private) } + let!(:visible_issues) { create_list(:issue, 2, project: visible_project) } + let!(:other_issues) { create_list(:issue, 2, project: other_project) } + let!(:user) { visible_project.owner } - let(:type) do - bad_node = type_factory do |type| - type.graphql_name 'BadNode' - type.field :bad_node, GraphQL::STRING_TYPE, null: true + let(:issue_type) do + type_factory do |type| + type.graphql_name 'FakeIssueType' + type.authorize :read_issue + type.field :id, GraphQL::ID_TYPE, null: false end - + end + let(:project_type) do |type| type_factory do |type| - type.field :edges, [bad_node], null: true + type.graphql_name 'FakeProjectType' + type.field :test_issues, issue_type.connection_type, null: false, resolve: -> (_, _, _) { Issue.where(project: [visible_project, other_project]) } end end - let(:query_type) do query_factory do |query| - query.field :object, type, null: true + query.field :test_project, project_type, null: false, resolve: -> (_, _, _) { visible_project } end end + let(:query_string) do + <<~QRY + { testProject { testIssues(first: 3) { edges { node { id } } } } } + QRY + end + + before do + allow(Ability).to receive(:allowed?).and_call_original + end + + it 'renders the issues the user has access to' do + issue_edges = result['testProject']['testIssues']['edges'] + issue_ids = issue_edges.map { |issue_edge| issue_edge['node']&.fetch('id') } + + expect(issue_edges.size).to eq(visible_issues.size) + expect(issue_ids).to eq(visible_issues.map { |i| i.id.to_s }) + end + + it 'does not check access on fields that will not be rendered' do + expect(Ability).not_to receive(:allowed?).with(user, :read_issue, other_issues.last) - it 'throws an error' do - expect { result }.to raise_error(Gitlab::Graphql::Errors::ConnectionDefinitionError) + result end end @@ -276,6 +321,8 @@ describe 'Gitlab::Graphql::Authorization' do def execute_query(query_type) schema = Class.new(GraphQL::Schema) do use Gitlab::Graphql::Authorize + use Gitlab::Graphql::Connections + query(query_type) end diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 74e93b2c4df..05f10fb40f0 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -74,6 +74,6 @@ describe GitlabSchema do end def field_instrumenters - described_class.instrumenters[:field] + described_class.instrumenters[:field] + described_class.instrumenters[:field_after_built_ins] end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index a049b5a6133..58eaf991d6e 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -67,27 +67,29 @@ describe LabelsHelper do describe 'link_to_label' do let(:project) { create(:project) } let(:label) { create(:label, project: project) } + let(:subject) { nil } + let(:label_presenter) { label.present(issuable_subject: subject) } context 'without subject' do it "uses the label's project" do - expect(link_to_label(label)).to match %r{<a href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}">.*</a>} end end context 'with a project as subject' do let(:namespace) { build(:namespace, name: 'foo3') } - let(:another_project) { build(:project, namespace: namespace, name: 'bar3') } + let(:subject) { build(:project, namespace: namespace, name: 'bar3') } it 'links to project issues page' do - expect(link_to_label(label, subject: another_project)).to match %r{<a href="/foo3/bar3/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a href="/foo3/bar3/issues\?label_name%5B%5D=#{label.name}">.*</a>} end end context 'with a group as subject' do - let(:group) { build(:group, name: 'bar') } + let(:subject) { build(:group, name: 'bar') } it 'links to group issues page' do - expect(link_to_label(label, subject: group)).to match %r{<a href="/groups/bar/-/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a href="/groups/bar/-/issues\?label_name%5B%5D=#{label.name}">.*</a>} end end @@ -95,7 +97,7 @@ describe LabelsHelper do ['issue', :issue, 'merge_request', :merge_request].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter, type: type)).to match %r{<a href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} end end end @@ -104,14 +106,14 @@ describe LabelsHelper do context 'with a tooltip argument' do context 'set to false' do it 'does not include the has-tooltip class' do - expect(link_to_label(label, tooltip: false)).not_to match /has-tooltip/ + expect(link_to_label(label_presenter, tooltip: false)).not_to match /has-tooltip/ end end end context 'with block' do it 'passes the block to link_to' do - link = link_to_label(label) { 'Foo' } + link = link_to_label(label_presenter) { 'Foo' } expect(link).to match('Foo') end end @@ -119,8 +121,8 @@ describe LabelsHelper do context 'without block' do it 'uses render_colored_label as the link content' do expect(self).to receive(:render_colored_label) - .with(label, tooltip: true).and_return('Foo') - expect(link_to_label(label)).to match('Foo') + .with(label_presenter, tooltip: true).and_return('Foo') + expect(link_to_label(label_presenter)).to match('Foo') end end end @@ -237,16 +239,24 @@ describe LabelsHelper do end end - describe 'labels_sorted_by_title' do + describe 'presented_labels_sorted_by_title' do + let(:labels) do + [build(:label, title: 'a'), + build(:label, title: 'B'), + build(:label, title: 'c'), + build(:label, title: 'D')] + end + it 'sorts labels alphabetically' do - label1 = double(:label, title: 'a') - label2 = double(:label, title: 'B') - label3 = double(:label, title: 'c') - label4 = double(:label, title: 'D') - labels = [label1, label2, label3, label4] - - expect(labels_sorted_by_title(labels)) - .to match_array([label2, label4, label1, label3]) + sorted_ids = presented_labels_sorted_by_title(labels, nil).map(&:id) + + expect(sorted_ids) + .to match_array([labels[1].id, labels[3].id, labels[0].id, labels[2].id]) + end + + it 'returns an array of label presenters' do + expect(presented_labels_sorted_by_title(labels, nil)) + .to all(be_a(LabelPresenter)) end end diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js index 0d462a6f872..bb6fc6c693d 100644 --- a/spec/javascripts/boards/list_spec.js +++ b/spec/javascripts/boards/list_spec.js @@ -45,6 +45,7 @@ describe('List model', () => { id: _.random(10000), title: 'test', color: 'red', + text_color: 'white', }, }); list.save(); @@ -53,6 +54,8 @@ describe('List model', () => { expect(list.id).toBe(listObj.id); expect(list.type).toBe('label'); expect(list.position).toBe(0); + expect(list.label.color).toBe('red'); + expect(list.label.textColor).toBe('white'); done(); }, 0); }); diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js index 14fff9223f4..93a0f29af0a 100644 --- a/spec/javascripts/boards/mock_data.js +++ b/spec/javascripts/boards/mock_data.js @@ -16,6 +16,7 @@ export const listObj = { title: 'Testing', color: 'red', description: 'testing;', + textColor: 'white', }, }; diff --git a/spec/javascripts/ide/components/new_dropdown/upload_spec.js b/spec/javascripts/ide/components/new_dropdown/upload_spec.js index 878e17ac805..d19af6af2d7 100644 --- a/spec/javascripts/ide/components/new_dropdown/upload_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/upload_spec.js @@ -78,6 +78,8 @@ describe('new dropdown upload', () => { type: 'blob', content: 'plain text', base64: false, + binary: false, + rawPath: '', }); }); @@ -89,6 +91,8 @@ describe('new dropdown upload', () => { type: 'blob', content: binaryTarget.result.split('base64,')[1], base64: true, + binary: true, + rawPath: binaryTarget.result, }); }); }); diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js index abc97f3072c..cdeb9b4b896 100644 --- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js @@ -4,6 +4,7 @@ import service from '~/ide/services'; import router from '~/ide/ide_router'; import eventHub from '~/ide/eventhub'; import consts from '~/ide/stores/modules/commit/constants'; +import { commitActionTypes } from '~/ide/constants'; import { resetStore, file } from 'spec/ide/helpers'; describe('IDE commit module actions', () => { @@ -294,7 +295,7 @@ describe('IDE commit module actions', () => { commit_message: 'testing 123', actions: [ { - action: 'update', + action: commitActionTypes.update, file_path: jasmine.anything(), content: undefined, encoding: jasmine.anything(), @@ -321,7 +322,7 @@ describe('IDE commit module actions', () => { commit_message: 'testing 123', actions: [ { - action: 'update', + action: commitActionTypes.update, file_path: jasmine.anything(), content: undefined, encoding: jasmine.anything(), diff --git a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js index 734233100ab..548962c7a92 100644 --- a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js @@ -69,18 +69,16 @@ describe('IDE file templates actions', () => { describe('fetchTemplateTypes', () => { describe('success', () => { - let nextPage; + const pages = [[{ name: 'MIT' }], [{ name: 'Apache' }], [{ name: 'CC' }]]; beforeEach(() => { - mock.onGet(/api\/(.*)\/templates\/licenses/).replyOnce(() => [ - 200, - [ - { - name: 'MIT', - }, - ], - { 'X-NEXT-PAGE': nextPage }, - ]); + mock.onGet(/api\/(.*)\/templates\/licenses/).reply(({ params }) => { + const pageNum = params.page; + const page = pages[pageNum - 1]; + const hasNextPage = pageNum < pages.length; + + return [200, page, hasNextPage ? { 'X-NEXT-PAGE': pageNum + 1 } : {}]; + }); }); it('rejects if selectedTemplateType is empty', done => { @@ -112,43 +110,15 @@ describe('IDE file templates actions', () => { }, { type: 'receiveTemplateTypesSuccess', - payload: [ - { - name: 'MIT', - }, - ], - }, - ], - done, - ); - }); - - it('dispatches actions for next page', done => { - nextPage = '2'; - state.selectedTemplateType = { - key: 'licenses', - }; - - testAction( - actions.fetchTemplateTypes, - null, - state, - [], - [ - { - type: 'requestTemplateTypes', + payload: pages[0], }, { type: 'receiveTemplateTypesSuccess', - payload: [ - { - name: 'MIT', - }, - ], + payload: pages[0].concat(pages[1]), }, { - type: 'fetchTemplateTypes', - payload: 2, + type: 'receiveTemplateTypesSuccess', + payload: pages[0].concat(pages[1]).concat(pages[2]), }, ], done, diff --git a/spec/javascripts/ide/stores/utils_spec.js b/spec/javascripts/ide/stores/utils_spec.js index c4f122efdda..debe1c4acee 100644 --- a/spec/javascripts/ide/stores/utils_spec.js +++ b/spec/javascripts/ide/stores/utils_spec.js @@ -1,4 +1,5 @@ import * as utils from '~/ide/stores/utils'; +import { commitActionTypes } from '~/ide/constants'; import { file } from '../helpers'; describe('Multi-file store utils', () => { @@ -107,7 +108,7 @@ describe('Multi-file store utils', () => { commit_message: 'commit message', actions: [ { - action: 'update', + action: commitActionTypes.update, file_path: 'staged', content: 'updated file content', encoding: 'text', @@ -115,7 +116,7 @@ describe('Multi-file store utils', () => { previous_path: undefined, }, { - action: 'create', + action: commitActionTypes.create, file_path: 'added', content: 'new file content', encoding: 'base64', @@ -123,7 +124,7 @@ describe('Multi-file store utils', () => { previous_path: undefined, }, { - action: 'delete', + action: commitActionTypes.delete, file_path: 'deletedFile', content: undefined, encoding: 'text', @@ -170,7 +171,7 @@ describe('Multi-file store utils', () => { commit_message: 'prebuilt test commit message', actions: [ { - action: 'update', + action: commitActionTypes.update, file_path: 'staged', content: 'updated file content', encoding: 'text', @@ -178,7 +179,7 @@ describe('Multi-file store utils', () => { previous_path: undefined, }, { - action: 'create', + action: commitActionTypes.create, file_path: 'added', content: 'new file content', encoding: 'base64', @@ -193,19 +194,19 @@ describe('Multi-file store utils', () => { describe('commitActionForFile', () => { it('returns deleted for deleted file', () => { - expect(utils.commitActionForFile({ deleted: true })).toBe('delete'); + expect(utils.commitActionForFile({ deleted: true })).toBe(commitActionTypes.delete); }); it('returns create for tempFile', () => { - expect(utils.commitActionForFile({ tempFile: true })).toBe('create'); + expect(utils.commitActionForFile({ tempFile: true })).toBe(commitActionTypes.create); }); it('returns move for moved file', () => { - expect(utils.commitActionForFile({ prevPath: 'test' })).toBe('move'); + expect(utils.commitActionForFile({ prevPath: 'test' })).toBe(commitActionTypes.move); }); it('returns update by default', () => { - expect(utils.commitActionForFile({})).toBe('update'); + expect(utils.commitActionForFile({})).toBe(commitActionTypes.update); }); }); diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index 431798c6ec3..cadcc15385f 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -58,7 +58,7 @@ describe('MergeRequest', function() { { merge_request: { description: '- [ ] Task List Item', - lock_version: undefined, + lock_version: 0, update_task: { line_number: lineNumber, line_source: lineSource, index, checked }, }, }, diff --git a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js index 4da8c6196b1..bdf802052b9 100644 --- a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js +++ b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js @@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils'; import contentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; import { GREEN_BOX_IMAGE_URL } from 'spec/test_constants'; +import '~/behaviors/markdown/render_gfm'; describe('ContentViewer', () => { let vm; @@ -29,6 +30,7 @@ describe('ContentViewer', () => { path: 'test.md', content: '* Test', projectPath: 'testproject', + type: 'markdown', }); const previewContainer = vm.$el.querySelector('.md-previewer'); @@ -44,6 +46,7 @@ describe('ContentViewer', () => { createComponent({ path: GREEN_BOX_IMAGE_URL, fileSize: 1024, + type: 'image', }); setTimeout(() => { diff --git a/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js b/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js index 7f2e246d656..97c870f27d9 100644 --- a/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js +++ b/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js @@ -138,22 +138,6 @@ describe('ImageDiffViewer', () => { done(); }); }); - - it('drag handler is working', done => { - vm.$el.querySelector('.view-modes-menu li:nth-child(2)').click(); - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.swipe-bar').style.left).toBe('1px'); - expect(vm.$el.querySelector('.top-handle')).not.toBeNull(); - - dragSlider(vm.$el.querySelector('.swipe-bar'), 40); - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.swipe-bar').style.left).toBe('-20px'); - done(); - }); - }); - }); }); describe('onionSkin', () => { 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 e7ff9169f1b..d3f7f1ded16 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 @@ -177,7 +177,7 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m end before do - allow_any_instance_of(described_class::MergeRequestDiff::ActiveRecord_Relation) + allow_any_instance_of(ActiveRecord::Relation) .to receive(:update_all).and_raise(exception) end diff --git a/spec/lib/gitlab/checks/branch_check_spec.rb b/spec/lib/gitlab/checks/branch_check_spec.rb index 8d5ab27a17c..71b64a3b9df 100644 --- a/spec/lib/gitlab/checks/branch_check_spec.rb +++ b/spec/lib/gitlab/checks/branch_check_spec.rb @@ -77,117 +77,85 @@ describe Gitlab::Checks::BranchCheck do let(:oldrev) { '0000000000000000000000000000000000000000' } let(:ref) { 'refs/heads/feature' } - context 'protected branch creation feature is disabled' do + context 'user can push to branch' do before do - stub_feature_flags(protected_branch_creation: false) + allow(user_access) + .to receive(:can_push_to_branch?) + .with('feature') + .and_return(true) end - context 'user is not allowed to push to protected branch' do - before do - allow(user_access) - .to receive(:can_push_to_branch?) - .and_return(false) - end - - it 'raises an error' do - expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to protected branches on this project.') - end + it 'does not raise an error' do + expect { subject.validate! }.not_to raise_error end + end - context 'user is allowed to push to protected branch' do - before do - allow(user_access) - .to receive(:can_push_to_branch?) - .and_return(true) - end - - it 'does not raise an error' do - expect { subject.validate! }.not_to raise_error - end + context 'user cannot push to branch' do + before do + allow(user_access) + .to receive(:can_push_to_branch?) + .with('feature') + .and_return(false) end - end - context 'protected branch creation feature is enabled' do - context 'user can push to branch' do + context 'user cannot merge to branch' do before do allow(user_access) - .to receive(:can_push_to_branch?) + .to receive(:can_merge_to_branch?) .with('feature') - .and_return(true) + .and_return(false) end - it 'does not raise an error' do - expect { subject.validate! }.not_to raise_error + it 'raises an error' do + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.') end end - context 'user cannot push to branch' do + context 'user can merge to branch' do before do allow(user_access) - .to receive(:can_push_to_branch?) + .to receive(:can_merge_to_branch?) .with('feature') - .and_return(false) + .and_return(true) + + allow(project.repository) + .to receive(:branch_names_contains_sha) + .with(newrev) + .and_return(['branch']) end - context 'user cannot merge to branch' do + context "newrev isn't in any protected branches" do before do - allow(user_access) - .to receive(:can_merge_to_branch?) - .with('feature') + allow(ProtectedBranch) + .to receive(:any_protected?) + .with(project, ['branch']) .and_return(false) end it 'raises an error' do - expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.') + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only use an existing protected branch ref as the basis of a new protected branch.') end end - context 'user can merge to branch' do + context 'newrev is included in a protected branch' do before do - allow(user_access) - .to receive(:can_merge_to_branch?) - .with('feature') + allow(ProtectedBranch) + .to receive(:any_protected?) + .with(project, ['branch']) .and_return(true) - - allow(project.repository) - .to receive(:branch_names_contains_sha) - .with(newrev) - .and_return(['branch']) end - context "newrev isn't in any protected branches" do - before do - allow(ProtectedBranch) - .to receive(:any_protected?) - .with(project, ['branch']) - .and_return(false) - end + context 'via web interface' do + let(:protocol) { 'web' } - it 'raises an error' do - expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only use an existing protected branch ref as the basis of a new protected branch.') + it 'allows branch creation' do + expect { subject.validate! }.not_to raise_error end end - context 'newrev is included in a protected branch' do - before do - allow(ProtectedBranch) - .to receive(:any_protected?) - .with(project, ['branch']) - .and_return(true) - end - - context 'via web interface' do - let(:protocol) { 'web' } - - it 'allows branch creation' do - expect { subject.validate! }.not_to raise_error - end - end - - context 'via SSH' do - it 'raises an error' do - expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only create protected branches using the web interface and API.') - end + context 'via SSH' do + it 'raises an error' do + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only create protected branches using the web interface and API.') end end end diff --git a/spec/lib/gitlab/checks/lfs_check_spec.rb b/spec/lib/gitlab/checks/lfs_check_spec.rb index 35f8069c8a4..dad14e100a7 100644 --- a/spec/lib/gitlab/checks/lfs_check_spec.rb +++ b/spec/lib/gitlab/checks/lfs_check_spec.rb @@ -27,6 +27,18 @@ describe Gitlab::Checks::LfsCheck do allow(project).to receive(:lfs_enabled?).and_return(true) end + context 'with lfs_check feature disabled' do + before do + stub_feature_flags(lfs_check: false) + end + + it 'skips integrity check' do + expect_any_instance_of(Gitlab::Git::LfsChanges).not_to receive(:new_pointers) + + subject.validate! + end + end + context 'deletion' do let(:changes) { { oldrev: oldrev, ref: ref } } diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb new file mode 100644 index 00000000000..9aa2f4efd67 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotEquals do + let(:left) { double('left') } + let(:right) { double('right') } + + describe '.build' do + it 'creates a new instance of the token' do + expect(described_class.build('!=', left, right)) + .to be_a(described_class) + end + end + + describe '.type' do + it 'is an operator' do + expect(described_class.type).to eq :operator + end + end + + describe '#evaluate' do + it 'returns true when left and right are not equal' do + allow(left).to receive(:evaluate).and_return(1) + allow(right).to receive(:evaluate).and_return(2) + + operator = described_class.new(left, right) + + expect(operator.evaluate(VARIABLE: 3)).to eq true + end + + it 'returns false when left and right are equal' do + allow(left).to receive(:evaluate).and_return(1) + allow(right).to receive(:evaluate).and_return(1) + + operator = described_class.new(left, right) + + expect(operator.evaluate(VARIABLE: 3)).to eq false + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb new file mode 100644 index 00000000000..fa3b9651fb4 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb @@ -0,0 +1,80 @@ +require 'fast_spec_helper' +require_dependency 're2' + +describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotMatches do + let(:left) { double('left') } + let(:right) { double('right') } + + describe '.build' do + it 'creates a new instance of the token' do + expect(described_class.build('!~', left, right)) + .to be_a(described_class) + end + end + + describe '.type' do + it 'is an operator' do + expect(described_class.type).to eq :operator + end + end + + describe '#evaluate' do + it 'returns true when left and right do not match' do + allow(left).to receive(:evaluate).and_return('my-string') + allow(right).to receive(:evaluate) + .and_return(Gitlab::UntrustedRegexp.new('something')) + + operator = described_class.new(left, right) + + expect(operator.evaluate).to eq true + end + + it 'returns false when left and right match' do + allow(left).to receive(:evaluate).and_return('my-awesome-string') + allow(right).to receive(:evaluate) + .and_return(Gitlab::UntrustedRegexp.new('awesome.string$')) + + operator = described_class.new(left, right) + + expect(operator.evaluate).to eq false + end + + it 'supports matching against a nil value' do + allow(left).to receive(:evaluate).and_return(nil) + allow(right).to receive(:evaluate) + .and_return(Gitlab::UntrustedRegexp.new('pattern')) + + operator = described_class.new(left, right) + + expect(operator.evaluate).to eq true + end + + it 'supports multiline strings' do + allow(left).to receive(:evaluate).and_return <<~TEXT + My awesome contents + + My-text-string! + TEXT + + allow(right).to receive(:evaluate) + .and_return(Gitlab::UntrustedRegexp.new('text-string')) + + operator = described_class.new(left, right) + + expect(operator.evaluate).to eq false + end + + it 'supports regexp flags' do + allow(left).to receive(:evaluate).and_return <<~TEXT + My AWESOME content + TEXT + + allow(right).to receive(:evaluate) + .and_return(Gitlab::UntrustedRegexp.new('(?i)awesome')) + + operator = described_class.new(left, right) + + expect(operator.evaluate).to eq false + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb index 11e73294f18..a9fd809409b 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb @@ -101,6 +101,18 @@ describe Gitlab::Ci::Pipeline::Expression::Statement do "$EMPTY_VARIABLE =~ /var.*/" | false "$UNDEFINED_VARIABLE =~ /var.*/" | false "$PRESENT_VARIABLE =~ /VAR.*/i" | true + '$PRESENT_VARIABLE != "my variable"' | false + '"my variable" != $PRESENT_VARIABLE' | false + '$PRESENT_VARIABLE != null' | true + '$EMPTY_VARIABLE != null' | true + '"" != $EMPTY_VARIABLE' | false + '$UNDEFINED_VARIABLE != null' | false + 'null != $UNDEFINED_VARIABLE' | false + "$PRESENT_VARIABLE !~ /var.*e$/" | false + "$PRESENT_VARIABLE !~ /^var.*/" | true + "$EMPTY_VARIABLE !~ /var.*/" | true + "$UNDEFINED_VARIABLE !~ /var.*/" | true + "$PRESENT_VARIABLE !~ /VAR.*/i" | false end with_them do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 778950c95e4..45fe5d72937 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1966,6 +1966,70 @@ describe Gitlab::Git::Repository, :seed_helper do end end + describe '#compare_source_branch' do + let(:repository) { Gitlab::Git::Repository.new('default', TEST_GITATTRIBUTES_REPO_PATH, '', 'group/project') } + + context 'within same repository' do + it 'does not create a temp ref' do + expect(repository).not_to receive(:fetch_source_branch!) + expect(repository).not_to receive(:delete_refs) + + compare = repository.compare_source_branch('master', repository, 'feature', straight: false) + expect(compare).to be_a(Gitlab::Git::Compare) + expect(compare.commits.count).to be > 0 + end + + it 'returns empty commits when source ref does not exist' do + compare = repository.compare_source_branch('master', repository, 'non-existent-branch', straight: false) + + expect(compare.commits).to be_empty + end + end + + context 'with different repositories' do + context 'when ref is known by source repo, but not by target' do + before do + mutable_repository.write_ref('another-branch', 'feature') + end + + it 'creates temp ref' do + expect(repository).not_to receive(:fetch_source_branch!) + expect(repository).not_to receive(:delete_refs) + + compare = repository.compare_source_branch('master', mutable_repository, 'another-branch', straight: false) + expect(compare).to be_a(Gitlab::Git::Compare) + expect(compare.commits.count).to be > 0 + end + end + + context 'when ref is known by source and target repos' do + before do + mutable_repository.write_ref('another-branch', 'feature') + repository.write_ref('another-branch', 'feature') + end + + it 'does not create a temp ref' do + expect(repository).not_to receive(:fetch_source_branch!) + expect(repository).not_to receive(:delete_refs) + + compare = repository.compare_source_branch('master', mutable_repository, 'another-branch', straight: false) + expect(compare).to be_a(Gitlab::Git::Compare) + expect(compare.commits.count).to be > 0 + end + end + + context 'when ref is unknown by source repo' do + it 'returns nil when source ref does not exist' do + expect(repository).to receive(:fetch_source_branch!).and_call_original + expect(repository).to receive(:delete_refs).and_call_original + + compare = repository.compare_source_branch('master', mutable_repository, 'non-existent-branch', straight: false) + expect(compare).to be_nil + end + end + end + end + describe '#checksum' do it 'calculates the checksum for non-empty repo' do expect(repository.checksum).to eq '51d0a9662681f93e1fee547a6b7ba2bcaf716059' diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb index 6114aca0616..aec9c4baf0a 100644 --- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb +++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb @@ -5,92 +5,118 @@ require 'spec_helper' # Also see spec/graphql/features/authorization_spec.rb for # integration tests of AuthorizeFieldService describe Gitlab::Graphql::Authorize::AuthorizeFieldService do - describe '#build_checker' do - let(:current_user) { double(:current_user) } - let(:abilities) { [double(:first_ability), double(:last_ability)] } - - context 'when authorizing against the object' do - let(:checker) do - service = described_class.new(double(resolve_proc: proc {})) - allow(service).to receive(:authorizations).and_return(abilities) - service.__send__(:build_checker, current_user, nil) - end + def type(type_authorizations = []) + Class.new(Types::BaseObject) do + graphql_name "TestType" - it 'returns a checker which checks for a single object' do - object = double(:object) + authorize type_authorizations + end + end - abilities.each do |ability| - spy_ability_check_for(ability, object, passed: true) - end + def type_with_field(field_type, field_authorizations = [], resolved_value = "Resolved value") + Class.new(Types::BaseObject) do + graphql_name "TestTypeWithField" + field :test_field, field_type, null: true, authorize: field_authorizations, resolve: -> (_, _, _) { resolved_value} + end + end - expect(checker.call(object)).to eq(object) - end + let(:current_user) { double(:current_user) } + subject(:service) { described_class.new(field) } - it 'returns a checker which checks for all objects' do - objects = [double(:first), double(:last)] + describe "#authorized_resolve" do + let(:presented_object) { double("presented object") } + let(:presented_type) { double("parent type", object: presented_object) } + subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) } - abilities.each do |ability| - objects.each do |object| - spy_ability_check_for(ability, object, passed: true) + context "scalar types" do + shared_examples "checking permissions on the presented object" do + it "checks the abilities on the object being presented and returns the value" do + expected_permissions.each do |permission| + spy_ability_check_for(permission, presented_object, passed: true) end + + expect(resolved).to eq("Resolved value") end - expect(checker.call(objects)).to eq(objects) + it "returns nil if the value wasn't authorized" do + allow(Ability).to receive(:allowed?).and_return false + + expect(resolved).to be_nil + end end - context 'when some objects would not pass the check' do - it 'returns nil when it is single object' do - disallowed = double(:object) + context "when the field is a built-in scalar type" do + let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields["testField"].to_graphql } + let(:expected_permissions) { [:read_field] } - spy_ability_check_for(abilities.first, disallowed, passed: false) + it_behaves_like "checking permissions on the presented object" + end - expect(checker.call(disallowed)).to be_nil - end + context "when the field is a list of scalar types" do + let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields["testField"].to_graphql } + let(:expected_permissions) { [:read_field] } + + it_behaves_like "checking permissions on the presented object" + end - it 'returns only objects which passed when there are more than one' do - allowed = double(:allowed) - disallowed = double(:disallowed) + context "when the field is sub-classed scalar type" do + let(:field) { type_with_field(Types::TimeType, :read_field).fields["testField"].to_graphql } + let(:expected_permissions) { [:read_field] } - spy_ability_check_for(abilities.first, disallowed, passed: false) + it_behaves_like "checking permissions on the presented object" + end - abilities.each do |ability| - spy_ability_check_for(ability, allowed, passed: true) - end + context "when the field is a list of sub-classed scalar types" do + let(:field) { type_with_field([Types::TimeType], :read_field).fields["testField"].to_graphql } + let(:expected_permissions) { [:read_field] } - expect(checker.call([disallowed, allowed])).to contain_exactly(allowed) - end + it_behaves_like "checking permissions on the presented object" end end - context 'when authorizing against another object' do - let(:authorizing_obj) { double(:object) } + context "when the field is a specific type" do + let(:custom_type) { type(:read_type) } + let(:object_in_field) { double("presented in field") } + let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields["testField"].to_graphql } - let(:checker) do - service = described_class.new(double(resolve_proc: proc {})) - allow(service).to receive(:authorizations).and_return(abilities) - service.__send__(:build_checker, current_user, authorizing_obj) - end + it "checks both field & type permissions" do + spy_ability_check_for(:read_field, object_in_field, passed: true) + spy_ability_check_for(:read_type, object_in_field, passed: true) - it 'returns a checker which checks for a single object' do - object = double(:object) + expect(resolved).to eq(object_in_field) + end - abilities.each do |ability| - spy_ability_check_for(ability, authorizing_obj, passed: true) - end + it "returns nil if viewing was not allowed" do + spy_ability_check_for(:read_field, object_in_field, passed: false) + spy_ability_check_for(:read_type, object_in_field, passed: true) - expect(checker.call(object)).to eq(object) + expect(resolved).to be_nil end - it 'returns a checker which checks for all objects' do - objects = [double(:first), double(:last)] + context "when the field is a list" do + let(:object_1) { double("presented in field 1") } + let(:object_2) { double("presented in field 2") } + let(:presented_types) { [double(object: object_1), double(object: object_2)] } + let(:field) { type_with_field([custom_type], :read_field, presented_types).fields["testField"].to_graphql } - abilities.each do |ability| - objects.each do |object| - spy_ability_check_for(ability, authorizing_obj, passed: true) - end + it "checks all permissions" do + allow(Ability).to receive(:allowed?) { true } + + spy_ability_check_for(:read_field, object_1, passed: true) + spy_ability_check_for(:read_type, object_1, passed: true) + spy_ability_check_for(:read_field, object_2, passed: true) + spy_ability_check_for(:read_type, object_2, passed: true) + + expect(resolved).to eq(presented_types) end - expect(checker.call(objects)).to eq(objects) + it "filters out objects that the user cannot see" do + allow(Ability).to receive(:allowed?) { true } + + spy_ability_check_for(:read_type, object_1, passed: false) + + expect(resolved.map(&:object)).to contain_exactly(object_2) + end end end end diff --git a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb index 9bcc1e78a78..fefa2881b18 100644 --- a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb +++ b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb @@ -85,6 +85,11 @@ describe Gitlab::Graphql::Connections::KeysetConnection do expect(subject.paged_nodes.size).to eq(3) end + it 'is a loaded memoized array' do + expect(subject.paged_nodes).to be_an(Array) + expect(subject.paged_nodes.object_id).to eq(subject.paged_nodes.object_id) + end + context 'when `first` is passed' do let(:arguments) { { first: 2 } } diff --git a/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb b/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb index ec17ad8541f..7c4ac62790e 100644 --- a/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb +++ b/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb @@ -32,5 +32,17 @@ describe Gitlab::ImportExport::AfterExportStrategies::WebUploadStrategy do strategy.execute(user, project) end + + context 'when upload fails' do + it 'stores the export error' do + stub_request(:post, example_url).to_return(status: [404, 'Page not found']) + + strategy.execute(user, project) + + errors = project.import_export_shared.errors + expect(errors).not_to be_empty + expect(errors.first).to eq "Error uploading the project. Code 404: Page not found" + end + end end end diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb index 87ab81d8169..ddfbb020a55 100644 --- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb @@ -29,7 +29,7 @@ describe 'Import/Export attribute configuration' do it 'has no new columns' do relation_names.each do |relation_name| relation_class = relation_class_for_name(relation_name) - relation_attributes = relation_class.new.attributes.keys + relation_attributes = relation_class.new.attributes.keys - relation_class.encrypted_attributes.keys.map(&:to_s) current_attributes = parsed_attributes(relation_name, relation_attributes) safe_attributes = safe_model_attributes[relation_class.to_s].dup || [] diff --git a/spec/lib/quality/kubernetes_client_spec.rb b/spec/lib/quality/kubernetes_client_spec.rb index f35d9464d48..4e77dcc97e6 100644 --- a/spec/lib/quality/kubernetes_client_spec.rb +++ b/spec/lib/quality/kubernetes_client_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Quality::KubernetesClient do expect(Gitlab::Popen).to receive(:popen_with_detail) .with([%(kubectl --namespace "#{namespace}" delete ) \ 'ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa ' \ - "--now -l release=\"#{release_name}\""]) + "--now --ignore-not-found --include-uninitialized -l release=\"#{release_name}\""]) .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: false))) expect { subject.cleanup(release_name: release_name) }.to raise_error(described_class::CommandFailedError) @@ -23,7 +23,7 @@ RSpec.describe Quality::KubernetesClient do expect(Gitlab::Popen).to receive(:popen_with_detail) .with([%(kubectl --namespace "#{namespace}" delete ) \ 'ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa ' \ - "--now -l release=\"#{release_name}\""]) + "--now --ignore-not-found --include-uninitialized -l release=\"#{release_name}\""]) .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true))) # We're not verifying the output here, just silencing it diff --git a/spec/lib/quality/seeders/issues_spec.rb b/spec/lib/quality/seeders/issues_spec.rb new file mode 100644 index 00000000000..e17414a541a --- /dev/null +++ b/spec/lib/quality/seeders/issues_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Quality::Seeders::Issues do + let(:project) { create(:project) } + + subject { described_class.new(project: project) } + + describe '#seed' do + it 'seeds issues' do + issues_created = subject.seed(backfill_weeks: 1, average_issues_per_week: 1) + + expect(issues_created).to be_between(0, 2) + expect(project.issues.count).to eq(issues_created) + end + end +end diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index aacfbe3f180..44b5af5e5aa 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -33,7 +33,7 @@ describe Ci::Bridge do CI_PROJECT_ID CI_PROJECT_NAME CI_PROJECT_PATH CI_PROJECT_PATH_SLUG CI_PROJECT_NAMESPACE CI_PIPELINE_IID CI_CONFIG_PATH CI_PIPELINE_SOURCE CI_COMMIT_MESSAGE - CI_COMMIT_TITLE CI_COMMIT_DESCRIPTION + CI_COMMIT_TITLE CI_COMMIT_DESCRIPTION CI_COMMIT_REF_PROTECTED ] expect(bridge.scoped_variables_hash.keys).to include(*variables) diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 66be192ab21..3a7d20a58c8 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -31,6 +31,10 @@ describe Ci::Build do it { is_expected.to be_a(ArtifactMigratable) } + it_behaves_like 'UpdateProjectStatistics' do + subject { FactoryBot.build(:ci_build, pipeline: pipeline, artifacts_size: 23) } + end + describe 'associations' do it 'has a bidirectional relationship with projects' do expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:builds) @@ -2119,54 +2123,6 @@ describe Ci::Build do end end - context 'when updating the build' do - let(:build) { create(:ci_build, artifacts_size: 23) } - - it 'updates project statistics' do - build.artifacts_size = 42 - - expect(build).to receive(:update_project_statistics_after_save).and_call_original - - expect { build.save! } - .to change { build.project.statistics.reload.build_artifacts_size } - .by(19) - end - - context 'when the artifact size stays the same' do - it 'does not update project statistics' do - build.name = 'changed' - - expect(build).not_to receive(:update_project_statistics_after_save) - - build.save! - end - end - end - - context 'when destroying the build' do - let!(:build) { create(:ci_build, artifacts_size: 23) } - - it 'updates project statistics' do - expect(ProjectStatistics) - .to receive(:increment_statistic) - .and_call_original - - expect { build.destroy! } - .to change { build.project.statistics.reload.build_artifacts_size } - .by(-23) - end - - context 'when the build is destroyed due to the project being destroyed' do - it 'does not update the project statistics' do - expect(ProjectStatistics) - .not_to receive(:increment_statistic) - - build.project.update(pending_delete: true) - build.project.destroy! - end - end - end - describe '#variables' do let(:container_registry_enabled) { false } @@ -2227,7 +2183,8 @@ describe Ci::Build do { key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true, masked: false }, { key: 'CI_COMMIT_MESSAGE', value: pipeline.git_commit_message, public: true, masked: false }, { key: 'CI_COMMIT_TITLE', value: pipeline.git_commit_title, public: true, masked: false }, - { key: 'CI_COMMIT_DESCRIPTION', value: pipeline.git_commit_description, public: true, masked: false } + { key: 'CI_COMMIT_DESCRIPTION', value: pipeline.git_commit_description, public: true, masked: false }, + { key: 'CI_COMMIT_REF_PROTECTED', value: (!!pipeline.protected_ref?).to_s, public: true, masked: false } ] end diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb index d7abd54eec1..5964f66c398 100644 --- a/spec/models/ci/job_artifact_spec.rb +++ b/spec/models/ci/job_artifact_spec.rb @@ -5,6 +5,10 @@ require 'spec_helper' describe Ci::JobArtifact do let(:artifact) { create(:ci_job_artifact, :archive) } + it_behaves_like 'UpdateProjectStatistics' do + subject { build(:ci_job_artifact, :archive, size: 106365) } + end + describe "Associations" do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:job) } @@ -102,12 +106,6 @@ describe Ci::JobArtifact do it 'sets the size from the file size' do expect(artifact.size).to eq(106365) end - - it 'updates the project statistics' do - expect { artifact } - .to change { project.statistics.reload.build_artifacts_size } - .by(106365) - end end context 'updating the artifact file' do @@ -115,12 +113,6 @@ describe Ci::JobArtifact do artifact.update!(file: fixture_file_upload('spec/fixtures/dk.png')) expect(artifact.size).to eq(1062) end - - it 'updates the project statistics' do - expect { artifact.update!(file: fixture_file_upload('spec/fixtures/dk.png')) } - .to change { artifact.project.statistics.reload.build_artifacts_size } - .by(1062 - 106365) - end end describe 'validates file format' do @@ -259,34 +251,6 @@ describe Ci::JobArtifact do end end - context 'when destroying the artifact' do - let(:project) { create(:project, :repository) } - let(:pipeline) { create(:ci_pipeline, project: project) } - let!(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } - - it 'updates the project statistics' do - artifact = build.job_artifacts.first - - expect(ProjectStatistics) - .to receive(:increment_statistic) - .and_call_original - - expect { artifact.destroy } - .to change { project.statistics.reload.build_artifacts_size } - .by(-106365) - end - - context 'when it is destroyed from the project level' do - it 'does not update the project statistics' do - expect(ProjectStatistics) - .not_to receive(:increment_statistic) - - project.update(pending_delete: true) - project.destroy! - end - end - end - describe 'file is being stored' do subject { create(:ci_job_artifact, :archive) } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index fd66e344d63..3c823b78be7 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -690,7 +690,8 @@ describe Ci::Pipeline, :mailer do CI_PIPELINE_SOURCE CI_COMMIT_MESSAGE CI_COMMIT_TITLE - CI_COMMIT_DESCRIPTION] + CI_COMMIT_DESCRIPTION + CI_COMMIT_REF_PROTECTED] end context 'when source is merge request' do diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 2cb581696a0..f735a89f69f 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -73,9 +73,8 @@ describe Ci::Runner do end it 'fails to save a group assigned to a project runner even if the runner is already saved' do - group_runner - - expect { create(:group, runners: [project_runner]) } + group.runners << project_runner + expect { group.save! } .to raise_error(ActiveRecord::RecordInvalid) end end diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index 399a13f82cb..de406211a5b 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -24,7 +24,7 @@ describe Clusters::Applications::Runner do it 'is initialized with 4 arguments' do expect(subject.name).to eq('runner') expect(subject.chart).to eq('runner/gitlab-runner') - expect(subject.version).to eq('0.3.0') + expect(subject.version).to eq('0.4.0') expect(subject).to be_rbac expect(subject.repository).to eq('https://charts.gitlab.io') expect(subject.files).to eq(gitlab_runner.files) @@ -42,7 +42,7 @@ describe Clusters::Applications::Runner do let(:gitlab_runner) { create(:clusters_applications_runner, :errored, runner: ci_runner, version: '0.1.13') } it 'is initialized with the locked version' do - expect(subject.version).to eq('0.3.0') + expect(subject.version).to eq('0.4.0') end end end diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb index 0ed4e146caa..806b4f61bd8 100644 --- a/spec/models/internal_id_spec.rb +++ b/spec/models/internal_id_spec.rb @@ -93,7 +93,7 @@ describe InternalId do before do described_class.reset_column_information # Project factory will also call the current_version - expect(ActiveRecord::Migrator).to receive(:current_version).twice.and_return(InternalId::REQUIRED_SCHEMA_VERSION - 1) + expect(ActiveRecord::Migrator).to receive(:current_version).at_least(:once).and_return(InternalId::REQUIRED_SCHEMA_VERSION - 1) end let(:init) { double('block') } @@ -104,6 +104,15 @@ describe InternalId do expect(init).to receive(:call).with(issue).and_return(val) expect(subject).to eq(val + 1) end + + it 'always attempts to generate internal IDs in production mode' do + allow(Rails.env).to receive(:test?).and_return(false) + val = rand(1..100) + generator = double(generate: val) + expect(InternalId::InternalIdGenerator).to receive(:new).and_return(generator) + + expect(subject).to eq(val) + end end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 387d1221c76..95a4b0f6d71 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -63,6 +63,11 @@ describe Namespace do end end + describe 'delegate' do + it { is_expected.to delegate_method(:name).to(:owner).with_prefix.with_arguments(allow_nil: true) } + it { is_expected.to delegate_method(:avatar_url).to(:owner).with_arguments(allow_nil: true) } + end + describe "Respond to" do it { is_expected.to respond_to(:human_name) } it { is_expected.to respond_to(:to_param) } @@ -801,4 +806,21 @@ describe Namespace do end end end + + describe '#user?' do + subject { namespace.user? } + + context 'when type is a user' do + let(:user) { create(:user) } + let(:namespace) { user.namespace } + + it { is_expected.to be_truthy } + end + + context 'when type is a group' do + let(:namespace) { create(:group) } + + it { is_expected.to be_falsy } + end + end end diff --git a/spec/models/pool_repository_spec.rb b/spec/models/pool_repository_spec.rb index e5a3a3ad66e..ae00f9df89e 100644 --- a/spec/models/pool_repository_spec.rb +++ b/spec/models/pool_repository_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe PoolRepository do describe 'associations' do it { is_expected.to belong_to(:shard) } - it { is_expected.to have_one(:source_project) } + it { is_expected.to belong_to(:source_project) } it { is_expected.to have_many(:member_projects) } end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9f6a0b53281..bb0257e7456 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -4702,6 +4702,8 @@ describe Project do it 'returns that pool repository' do expect(subject).not_to be_empty expect(subject[:pool_repository]).to be_persisted + + expect(project.reload.pool_repository).to eq(subject[:pool_repository]) end end end diff --git a/spec/presenters/label_presenter_spec.rb b/spec/presenters/label_presenter_spec.rb new file mode 100644 index 00000000000..fae8188670f --- /dev/null +++ b/spec/presenters/label_presenter_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe LabelPresenter do + include Gitlab::Routing.url_helpers + + set(:group) { create(:group) } + set(:project) { create(:project, group: group) } + let(:label) { build_stubbed(:label, project: project).present(issuable_subject: project) } + let(:group_label) { build_stubbed(:group_label, group: group).present(issuable_subject: project) } + + describe '#edit_path' do + context 'with group label' do + subject { group_label.edit_path } + + it { is_expected.to eq(edit_group_label_path(group, group_label)) } + end + + context 'with project label' do + subject { label.edit_path } + + it { is_expected.to eq(edit_project_label_path(project, label)) } + end + end + + describe '#destroy_path' do + context 'with group label' do + subject { group_label.destroy_path } + + it { is_expected.to eq(group_label_path(group, group_label)) } + end + + context 'with project label' do + subject { label.destroy_path } + + it { is_expected.to eq(project_label_path(project, label)) } + end + end + + describe '#filter_path' do + context 'with group as context subject' do + let(:label_in_group) { build_stubbed(:label, project: project).present(issuable_subject: group) } + subject { label_in_group.filter_path } + + it { is_expected.to eq(issues_group_path(group, label_name: [label_in_group.title])) } + end + + context 'with project as context subject' do + subject { label.filter_path } + + it { is_expected.to eq(namespace_project_issues_path(group, project, label_name: [label.title])) } + end + end + + describe '#can_subscribe_to_label_in_different_levels?' do + it 'returns true for group labels in project context' do + expect(group_label.can_subscribe_to_label_in_different_levels?).to be_truthy + end + + it 'returns false for project labels in project context' do + expect(label.can_subscribe_to_label_in_different_levels?).to be_falsey + end + end +end diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb index 456de5f1b9a..5bf80f6e318 100644 --- a/spec/presenters/project_presenter_spec.rb +++ b/spec/presenters/project_presenter_spec.rb @@ -411,4 +411,23 @@ describe ProjectPresenter do end end end + + describe '#statistics_buttons' do + let(:project) { build(:project) } + let(:presenter) { described_class.new(project, current_user: user) } + + it 'orders the items correctly' do + allow(project.repository).to receive(:readme).and_return(double(name: 'readme')) + allow(project.repository).to receive(:changelog).and_return(nil) + allow(project.repository).to receive(:contribution_guide).and_return(double(name: 'foo')) + allow(presenter).to receive(:filename_path).and_return('fake/path') + allow(presenter).to receive(:contribution_guide_path).and_return('fake_path') + + buttons = presenter.statistics_buttons(show_auto_devops_callout: false) + expect(buttons.map(&:label)).to start_with( + a_string_including('README'), + a_string_including('CONTRIBUTING') + ) + end + end end diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb index 1271324a2ba..1dd0cb4817c 100644 --- a/spec/requests/api/badges_spec.rb +++ b/spec/requests/api/badges_spec.rb @@ -73,7 +73,7 @@ describe API::Badges do let(:badge) { source.badges.first } context "as a #{type}" do - it 'returns 200' do + it 'returns 200', :quarantine do user = public_send(type) get api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", user) @@ -193,7 +193,7 @@ describe API::Badges do end context 'when authenticated as a maintainer/owner' do - it 'updates the member' do + it 'updates the member', :quarantine do put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer), params: { link_url: example_url, image_url: example_url2 } @@ -239,7 +239,7 @@ describe API::Badges do end end - context 'when authenticated as a maintainer/owner' do + context 'when authenticated as a maintainer/owner', :quarantine do it 'deletes the badge' do expect do delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer) diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index c2934430821..4f9f916f22e 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -7,8 +7,8 @@ describe 'getting an issue list for a project' do let(:current_user) { create(:user) } let(:issues_data) { graphql_data['project']['issues']['edges'] } let!(:issues) do - create(:issue, project: project, discussion_locked: true) - create(:issue, project: project) + [create(:issue, project: project, discussion_locked: true), + create(:issue, project: project)] end let(:fields) do <<~QUERY @@ -47,6 +47,30 @@ describe 'getting an issue list for a project' do expect(issues_data[1]['node']['discussionLocked']).to eq true end + context 'when limiting the number of results' do + let(:query) do + graphql_query_for( + 'project', + { 'fullPath' => project.full_path }, + "issues(first: 1) { #{fields} }" + ) + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + + it "is expected to check permissions on the first issue only" do + allow(Ability).to receive(:allowed?).and_call_original + # Newest first, we only want to see the newest checked + expect(Ability).not_to receive(:allowed?).with(current_user, :read_issue, issues.first) + + post_graphql(query, current_user: current_user) + end + end + context 'when the user does not have access to the issue' do it 'returns nil' do project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 352ea448c00..577f61ae8d0 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1047,7 +1047,6 @@ describe API::Projects do expect(json_response['http_url_to_repo']).to be_present expect(json_response['web_url']).to be_present expect(json_response['owner']).to be_a Hash - expect(json_response['owner']).to be_a Hash expect(json_response['name']).to eq(project.name) expect(json_response['path']).to be_present expect(json_response['issues_enabled']).to be_present @@ -1135,7 +1134,9 @@ describe API::Projects do 'path' => user.namespace.path, 'kind' => user.namespace.kind, 'full_path' => user.namespace.full_path, - 'parent_id' => nil + 'parent_id' => nil, + 'avatar_url' => user.avatar_url, + 'web_url' => Gitlab::Routing.url_helpers.user_url(user) }) end @@ -1337,6 +1338,37 @@ describe API::Projects do end end end + + context 'when project belongs to a group namespace' do + let(:group) { create(:group, :with_avatar) } + let(:project) { create(:project, namespace: group) } + let!(:project_member) { create(:project_member, :developer, user: user, project: project) } + + it 'returns group web_url and avatar_url' do + get api("/projects/#{project.id}", user) + + expect(response).to have_gitlab_http_status(200) + + group_data = json_response['namespace'] + expect(group_data['web_url']).to eq(group.web_url) + expect(group_data['avatar_url']).to eq(group.avatar_url) + end + end + + context 'when project belongs to a user namespace' do + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + it 'returns user web_url and avatar_url' do + get api("/projects/#{project.id}", user) + + expect(response).to have_gitlab_http_status(200) + + user_data = json_response['namespace'] + expect(user_data['web_url']).to eq("http://localhost/#{user.username}") + expect(user_data['avatar_url']).to eq(user.avatar_url) + end + end end context 'with external authorization' do diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index 3585a827838..b331da1acba 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -68,7 +68,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do post api('/runners'), params: { token: group.runners_token } expect(response).to have_http_status 201 - expect(group.runners.size).to eq(1) + expect(group.runners.reload.size).to eq(1) runner = Ci::Runner.first expect(runner.token).not_to eq(registration_token) expect(runner.token).not_to eq(group.runners_token) @@ -168,6 +168,32 @@ describe API::Runner, :clean_gitlab_redis_shared_state do end end + context 'when access_level is provided for Runner' do + context 'when access_level is set to ref_protected' do + it 'creates runner' do + post api('/runners'), params: { + token: registration_token, + access_level: 'ref_protected' + } + + expect(response).to have_gitlab_http_status 201 + expect(Ci::Runner.first.ref_protected?).to be true + end + end + + context 'when access_level is set to not_protected' do + it 'creates runner' do + post api('/runners'), params: { + token: registration_token, + access_level: 'not_protected' + } + + expect(response).to have_gitlab_http_status 201 + expect(Ci::Runner.first.ref_protected?).to be false + end + end + end + context 'when maximum job timeout is specified' do it 'creates runner' do post api('/runners'), params: { diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index 49021f5d1b7..a12646ea222 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -251,8 +251,8 @@ describe 'Rack Attack global throttles' do let(:throttle_setting_prefix) { 'throttle_authenticated_web' } context 'with the token in the query string' do - let(:get_args) { [rss_url(user), nil] } - let(:other_user_get_args) { [rss_url(other_user), nil] } + let(:get_args) { [rss_url(user), params: nil] } + let(:other_user_get_args) { [rss_url(other_user), params: nil] } it_behaves_like 'rate-limited token-authenticated requests' end diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb index 0e4ef69ec19..fadd43635a6 100644 --- a/spec/services/compare_service_spec.rb +++ b/spec/services/compare_service_spec.rb @@ -19,5 +19,18 @@ describe CompareService do it { expect(subject.diffs.size).to eq(3) } end + + context 'compare with target branch that does not exist' do + subject { service.execute(project, 'non-existent-ref') } + + it { expect(subject).to be_nil } + end + + context 'compare with source branch that does not exist' do + let(:service) { described_class.new(project, 'non-existent-branch') } + subject { service.execute(project, 'non-existent-ref') } + + it { expect(subject).to be_nil } + end end end diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/delete_branch_service_spec.rb index 43a70d33d2d..b8064c2cbc1 100644 --- a/spec/services/delete_branch_service_spec.rb +++ b/spec/services/delete_branch_service_spec.rb @@ -8,20 +8,24 @@ describe DeleteBranchService do let(:user) { create(:user) } let(:service) { described_class.new(project, user) } + shared_examples 'a deleted branch' do |branch_name| + it 'removes the branch' do + expect(branch_exists?(branch_name)).to be true + + result = service.execute(branch_name) + + expect(result.status).to eq :success + expect(branch_exists?(branch_name)).to be false + end + end + describe '#execute' do context 'when user has access to push to repository' do before do project.add_developer(user) end - it 'removes the branch' do - expect(branch_exists?('feature')).to be true - - result = service.execute('feature') - - expect(result[:status]).to eq :success - expect(branch_exists?('feature')).to be false - end + it_behaves_like 'a deleted branch', 'feature' end context 'when user does not have access to push to repository' do @@ -30,8 +34,8 @@ describe DeleteBranchService do result = service.execute('feature') - expect(result[:status]).to eq :error - expect(result[:message]).to eq 'You dont have push access to repo' + expect(result.status).to eq :error + expect(result.message).to eq 'You dont have push access to repo' expect(branch_exists?('feature')).to be true end end diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb index 24d09c1fd00..0ac23050caf 100644 --- a/spec/services/merge_requests/merge_to_ref_service_spec.rb +++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb @@ -104,7 +104,7 @@ describe MergeRequests::MergeToRefService do it_behaves_like 'MergeService for target ref' end - context 'when merge commit with squash' do + context 'when merge commit with squash', :quarantine do before do merge_request.update!(squash: true, source_branch: 'master', target_branch: 'feature') end diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index c37147e7d3b..5ad30b58511 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -440,6 +440,8 @@ describe Projects::UpdateService do context 'when auto devops is set to instance setting' do before do project.create_auto_devops!(enabled: nil) + project.reload + allow(project.auto_devops).to receive(:previous_changes).and_return('enabled' => true) end diff --git a/spec/services/service_response_spec.rb b/spec/services/service_response_spec.rb new file mode 100644 index 00000000000..30bd4d6820b --- /dev/null +++ b/spec/services/service_response_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +ActiveSupport::Dependencies.autoload_paths << 'app/services' + +describe ServiceResponse do + describe '.success' do + it 'creates a successful response without a message' do + expect(described_class.success).to be_success + end + + it 'creates a successful response with a message' do + response = described_class.success(message: 'Good orange') + + expect(response).to be_success + expect(response.message).to eq('Good orange') + end + end + + describe '.error' do + it 'creates a failed response without HTTP status' do + response = described_class.error(message: 'Bad apple') + + expect(response).to be_error + expect(response.message).to eq('Bad apple') + end + + it 'creates a failed response with HTTP status' do + response = described_class.error(message: 'Bad apple', http_status: 400) + + expect(response).to be_error + expect(response.message).to eq('Bad apple') + expect(response.http_status).to eq(400) + end + end + + describe '#success?' do + it 'returns true for a successful response' do + expect(described_class.success.success?).to eq(true) + end + + it 'returns false for a failed response' do + expect(described_class.error(message: 'Bad apple').success?).to eq(false) + end + end + + describe '#error?' do + it 'returns false for a successful response' do + expect(described_class.success.error?).to eq(false) + end + + it 'returns true for a failed response' do + expect(described_class.error(message: 'Bad apple').error?).to eq(true) + end + end +end diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index 1c79af34538..4a5f4509a7b 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -210,6 +210,8 @@ describe Users::DestroyService do describe "calls the before/after callbacks" do it 'of project_members' do + expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:find).once + expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:initialize).once expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:destroy).once service.execute(user) @@ -219,6 +221,8 @@ describe Users::DestroyService do group_member = create(:group_member) group_member.group.group_members.create(user: user, access_level: 40) + expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:find).once + expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:initialize).once expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:destroy).once service.execute(user) diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb index b808fa6d91a..40206775aed 100644 --- a/spec/services/users/migrate_to_ghost_user_service_spec.rb +++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb @@ -80,7 +80,7 @@ describe Users::MigrateToGhostUserService do context "when record migration fails with a rollback exception" do before do - expect_any_instance_of(MergeRequest::ActiveRecord_Associations_CollectionProxy) + expect_any_instance_of(ActiveRecord::Associations::CollectionProxy) .to receive(:update_all).and_raise(ActiveRecord::Rollback) end diff --git a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb index 72912ffb89d..a0c77eecb61 100644 --- a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb +++ b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb @@ -25,9 +25,13 @@ shared_context 'Ldap::OmniauthCallbacksController' do described_class.define_providers! Rails.application.reload_routes! - mock_auth_hash(provider.to_s, uid, user.email) + @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, uid, user.email) stub_omniauth_provider(provider, context: request) allow(Gitlab::Auth::LDAP::Access).to receive(:allowed?).and_return(valid_login?) end + + after do + Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth + end end diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb index 4a0cf62a661..0bb2d2510c2 100644 --- a/spec/support/helpers/login_helpers.rb +++ b/spec/support/helpers/login_helpers.rb @@ -118,7 +118,10 @@ module LoginHelpers response_object: response_object } }) + original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth'] Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider.to_sym] + + original_env_config_omniauth_auth end def saml_xml(raw_saml_response) diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb index 7ce63375d34..c4ae62b25e4 100644 --- a/spec/support/helpers/query_recorder.rb +++ b/spec/support/helpers/query_recorder.rb @@ -17,7 +17,7 @@ module ActiveRecord def callback(name, start, finish, message_id, values) show_backtrace(values) if ENV['QUERY_RECORDER_DEBUG'] - if values[:name]&.include?("CACHE") && skip_cached + if values[:cached] && skip_cached @cached << values[:sql] elsif !values[:name]&.include?("SCHEMA") @log << values[:sql] diff --git a/spec/support/helpers/test_request_helpers.rb b/spec/support/helpers/test_request_helpers.rb index 5a84d67bdfc..39e5dafb059 100644 --- a/spec/support/helpers/test_request_helpers.rb +++ b/spec/support/helpers/test_request_helpers.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module TestRequestHelpers - def test_request(remote_ip: '127.0.0.1') - ActionController::TestRequest.new({ remote_ip: remote_ip }, ActionController::TestSession.new) + def test_request(remote_ip: '127.0.0.1', controller: nil) + ActionController::TestRequest.new({ remote_ip: remote_ip }, ActionController::TestSession.new, controller) end end diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb index 62ae95df8c0..1284415da1f 100644 --- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb +++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb @@ -45,7 +45,7 @@ shared_examples "migrating a deleted user's associated records to the ghost user context "race conditions" do context "when #{record_class_name} migration fails and is rolled back" do before do - expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy) + expect_any_instance_of(ActiveRecord::Associations::CollectionProxy) .to receive(:update_all).and_raise(ActiveRecord::Rollback) end @@ -66,7 +66,7 @@ shared_examples "migrating a deleted user's associated records to the ghost user context "when #{record_class_name} migration fails with a non-rollback exception" do before do - expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy) + expect_any_instance_of(ActiveRecord::Associations::CollectionProxy) .to receive(:update_all).and_raise(ArgumentError) end diff --git a/spec/support/shared_examples/models/update_project_statistics_spec.rb b/spec/support/shared_examples/models/update_project_statistics_spec.rb new file mode 100644 index 00000000000..7a04e940ee5 --- /dev/null +++ b/spec/support/shared_examples/models/update_project_statistics_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' + +shared_examples_for 'UpdateProjectStatistics' do + let(:project) { subject.project } + let(:stat) { described_class.statistic_name } + let(:attribute) { described_class.statistic_attribute } + + def reload_stat + project.statistics.reload.send(stat).to_i + end + + def read_attribute + subject.read_attribute(attribute).to_i + end + + it { is_expected.to be_new_record } + + context 'when creating' do + it 'updates the project statistics' do + delta = read_attribute + + expect { subject.save! } + .to change { reload_stat } + .by(delta) + end + end + + context 'when updating' do + before do + subject.save! + end + + it 'updates project statistics' do + delta = 42 + + expect(ProjectStatistics) + .to receive(:increment_statistic) + .and_call_original + + subject.write_attribute(attribute, read_attribute + delta) + expect { subject.save! } + .to change { reload_stat } + .by(delta) + end + end + + context 'when destroying' do + before do + subject.save! + end + + it 'updates the project statistics' do + delta = -read_attribute + + expect(ProjectStatistics) + .to receive(:increment_statistic) + .and_call_original + + expect { subject.destroy } + .to change { reload_stat } + .by(delta) + end + + context 'when it is destroyed from the project level' do + it 'does not update the project statistics' do + expect(ProjectStatistics) + .not_to receive(:increment_statistic) + + project.update(pending_delete: true) + project.destroy! + end + end + end +end diff --git a/yarn.lock b/yarn.lock index ebbb670db0c..8a23aabba20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -663,10 +663,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.59.0.tgz#affcf9596d736836d37469bb4aea2226ac03e087" integrity sha512-dokGyyLRRsoBKO70KP1g+ZsDGyTK/RIHWDmvWI6Bx5AxQ3UqAzVXn2OIb3owjJAexyRG1uBmJrriiVVyHznQ4g== -"@gitlab/ui@^3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-3.3.0.tgz#32112c8eb53a0fd893f8fa431a02ceaf55279323" - integrity sha512-VVInZmcAe0L0lRMb6II3ED4DYm4OpzSmcxdwt18CqpDMw3EEoUqxd58EAxBFy70isgFTd6cHYhyS8rw5GOULyg== +"@gitlab/ui@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-3.4.0.tgz#174681f210eb16c3d101a36968d5e4d163c0d014" + integrity sha512-joXNz80IHMQxEGrqcNUTEKofjfZtkOKUe34HAFI71NEeYT6H0r/lYmJ5Gcz+MmwM1CvZOVbB3DnKzxQPDbN/hQ== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "^2.0.0-rc.11" |