diff options
author | Lin Jen-Shin <godfat@godfat.org> | 2018-12-26 18:03:21 +0800 |
---|---|---|
committer | Lin Jen-Shin <godfat@godfat.org> | 2018-12-26 18:03:21 +0800 |
commit | 82bf55c8db3d149c27807e5646ff8ff4454a5ea7 (patch) | |
tree | 65e2523a9288ec64421b19ccf27cbce0c371c40c | |
parent | cc06bb2c6ec1facf2b1eb50803dbedc076abe017 (diff) | |
parent | 145079b3540ca832e1d981bbc685cc8c27d47ea0 (diff) | |
download | gitlab-ce-82bf55c8db3d149c27807e5646ff8ff4454a5ea7.tar.gz |
Merge remote-tracking branch 'upstream/master' into 54953-error-500-viewing-merge-request-due-to-nil-commit_email_hostname
* upstream/master: (115 commits)
[CE] Speed up login page usage
Add new line and comments
Fix the seeder 24_forks.rb cannot find public project
Milestones on community contribution issues
Removed Gitlab Upgrader found in /lib/gitlab/upgrader.rb
Fix and move specs into admin_disables_git_access_protocol_spec.rb
Fix HTTP/SSH clone panel for mobile
Add spec for HTTP/SSH clone panel
Fix missing Git clone button when protocol restriction setting enabled
Fix deprecation: Using positional arguments in integration tests
Extend override check to also check arity
Update tm cli version
Bump Gitaly version to v1.12.0
Add @dbalexandre to CODEOWNERS
Update verbiage for clarity
Change group-cluster beta to regular note
Change alpha states to use note instead of warning
Update registry section. Update serverless.yaml formatting
Clarify obtaining application URL
Add @godfat to CODEOWNERS
...
591 files changed, 4396 insertions, 2931 deletions
diff --git a/.gitlab/CODEOWNERS.disabled b/.gitlab/CODEOWNERS.disabled index 82e914a502f..b9f886c1d47 100644 --- a/.gitlab/CODEOWNERS.disabled +++ b/.gitlab/CODEOWNERS.disabled @@ -1,6 +1,6 @@ # Backend Maintainers are the default for all ruby files -*.rb @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern -*.rake @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern +*.rb @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern +*.rake @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern # Technical writing team are the default reviewers for everything in `doc/` /doc/ @axil @marcia diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md index ad517f0457d..639a236631d 100644 --- a/.gitlab/issue_templates/Feature proposal.md +++ b/.gitlab/issue_templates/Feature proposal.md @@ -4,7 +4,7 @@ ### Target audience -<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/#/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" --> +<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" --> ### Further details diff --git a/CHANGELOG.md b/CHANGELOG.md index a51ac887aed..b4fa22ad70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,290 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 11.6.0 (2018-12-22) + +### Security (24 changes, 1 of them is from the community) + +- Fix possible XSS attack in Markdown urls with spaces. !2599 +- Update rack to 2.0.6 (for QA environments). !23171 (Takuya Noguchi) +- Bump nokogiri, loofah, and rack gems for security updates. !23204 +- Encrypt runners tokens. !23412 +- Encrypt CI/CD builds authentication tokens. !23436 +- Configure mermaid to not render HTML content in diagrams. +- Fix a possible symlink time of check to time of use race condition in GitLab Pages. +- Removed ability to see private group names when the group id is entered in the url. +- Fix stored XSS for Environments. +- Fix persistent symlink in project import. +- Fixed ability of guest users to edit/delete comments on locked or confidential issues. +- Fixed ability to comment on locked/confidential issues. +- Fix CRLF vulnerability in Project hooks. +- Fix SSRF in project integrations. +- Resolve reflected XSS in Ouath authorize window. +- Restrict Personal Access Tokens to API scope on web requests. +- Provide email notification when a user changes their email address. +- Don't expose confidential information in commit message list. +- Validate LFS hrefs before downloading them. +- Do not follow redirects in Prometheus service when making http requests to the configured api url. +- Escape user fullname while rendering autocomplete template to prevent XSS. +- Redact sensitive information on gitlab-workhorse log. +- Fix milestone promotion authorization check. +- Prevent a path traversal attack on global file templates. + +### Removed (1 change) + +- Remove obsolete gitlab_shell rake tasks. !22417 + +### Fixed (86 changes, 13 of them are from the community) + +- Remove limit of 100 when searching repository code. !8671 +- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi) +- Fix a bug where internal email pattern wasn't respected. !22516 +- Fix project selector consistency in groups issues / MRs / boards pages. !22612 (Heinrich Lee Yu) +- Add empty state for graphs with no values. !22630 +- Fix navigating by unresolved discussions on Merge Request page. !22789 +- Fix "merged with [commit]" info for merge requests being merged automatically by other actions. !22794 +- Fixing regression issues on pages settings and details. !22821 +- Remove duplicate primary button in dashboard snippets on small viewports. !22902 (George Tsiolis) +- Fix API::Namespaces routing to accept namepaces with dots. !22912 +- Switch kubernetes:active with checking in Auto-DevOps.gitlab-ci.yml. !22929 +- Avoid Gitaly RPC errors when fetching diff stats. !22995 +- Removes promote to group label for anonymous user. !23042 (Jacopo Beschi @jacopo-beschi) +- Fix enabling project deploy key for admins. !23043 +- Align issue status label and confidential icon. !23046 (George Tsiolis) +- Fix default sorting for subgroups and projects list. !23058 (Jacopo Beschi @jacopo-beschi) +- Hashed Storage: allow migration to be retried in partially migrated projects. !23087 +- Fix line height of numbers in file blame view. !23090 (Johann Hubert Sonntagbauer) +- Fixes an issue where default values from models would override values set in the interface (e.g. users would be set to external even though their emails matches the internal email address pattern). !23114 +- Remove display of local Sidekiq process in /admin/sidekiq. !23118 +- Fix unrelated deployment status in MR widget. !23175 +- Respect confirmed flag on secondary emails. !23181 +- Restrict member access level to be higher than that of any parent group. !23226 +- Return real deployment status to frontend. !23270 +- Handle force_remove_source_branch when creating merge request. !23281 +- Avoid creating invalid refs using rugged, shelling out for writing refs. !23286 +- Remove needless auto-capitalization on Wiki page titles. !23288 +- Modify the wording for the knative cluster application to match upstream. !23289 (Chris Baumbauer) +- Change container width for project import. !23318 (George Tsiolis) +- Validate chunk size when persist. !23341 +- Resolve Main navbar is broken in certain viewport widths. !23348 +- Gracefully handle references with null bytes. !23365 +- Display commit ID for commit diff discussion on merge request. !23370 +- Pass commit when posting diff discussions. !23371 +- Fix flash notice styling for fluid layout. !23382 +- Add monkey patch to unicorn to fix eof? problem. !23385 +- Commits API: Preserve file content in move operations if unspecified. !23387 +- Disable password autocomplete in mirror form fill. !23402 +- Fix "protected branches only" checkbox not set properly at init. !23409 +- Support RSA and ECDSA algorithms in Omniauth JWT provider. !23411 (Michael Tsyganov) +- Make KUBECONFIG nil if KUBE_TOKEN is nil. !23414 +- Allow search and sort users at same time on admin users page. !23439 +- Fix: Unstar icon button is misaligned. !23444 +- Fix error when searching for group issues with priority or popularity sort. !23445 +- Fix Order By dropdown menu styling in tablet and mobile screens. !23446 +- Fix collapsing discussion replies. !23462 +- Gracefully handle unknown/invalid GPG keys. !23492 +- Fix multiple commits shade overlapping vertical discussion line. !23515 +- Use read_repository scope on read-only files API. !23534 +- Avoid 500's when serializing legacy diff notes. !23544 +- Fix web hook functionality when the database encryption key is too short. !23573 +- Hide Knative from group cluster applications until supported. !23577 +- Add top padding for nested environment items loading icon. !23580 (George Tsiolis) +- Improve help and validation sections of maximum build timeout inputs. !23586 +- Fix milestone select in issue sidebar of issue boards. !23625 +- Fix gitlab:web_hook tasks. !23635 +- Avoid caching BroadcastMessage as an ActiveRecord object. !23662 +- Only allow strings in URL::Sanitizer.valid?. !23675 +- Fix a frozen string error in app/mailers/notify.rb. !23683 +- Fix a frozen string error in lib/gitlab/utils.rb. !23690 +- Fix MR resolved discussion counts being too low. !23710 +- Fix a potential frozen string error in app/mailers/notify.rb. !23728 +- Remove unnecessary div from MarkdownField to apply list styles correctly. !23733 +- Display reply field if resolved discussion has no replies. !23801 +- Restore kubernetes:active in Auto-DevOps.gitlab-ci.yml (reverts 22929). !23826 +- Fix mergeUrlParams with fragment URL. !54218 (Thomas Holder) +- Fixed multiple diff line discussions not expanding. +- Fixed diff files expanding not loading commit content. +- Fixed styling of image comment badges on commits. +- Resolve possible cherry pick API race condition. +- When user clicks linenumber in MR changes, highlight that line. +- Remove old webhook logs after 90 days, as documented, instead of after 2. +- Add an external IP address to the knative cluster application page. (Chris Baumbauer) +- Fixed duplicate discussions getting added to diff lines. +- Fix deadlock on ChunkedIO. +- Show tree collapse button for merge request commit diffs. +- Use approximate count for big tables for usage statistics. +- Lock writes to trace stream. +- Ensure that SVG sprite icons are properly rendered in IE11. +- Make new branch form fields' fonts consistent. +- Open first 10 merge request files in IDE. +- Prevent user from navigating away from file edit without commit. +- Prevent empty button being rendered in empty state. +- Adds margins between tags when a job is stuck. +- Fix Image Lazy Loader for some older browsers. +- Correctly styles tags in sidebar for job page. + +### Changed (34 changes, 9 of them are from the community) + +- Include new link in breadcrumb for issues, merge requests, milestones, and labels. !18515 (George Tsiolis) +- Allow sorting issues and MRs in reverse order. !21438 +- Design improvements to project overview page. !22196 +- Remove auto deactivation when failed to create a pipeline via pipeline schedules. !22243 +- Use group clusters when deploying (DeploymentPlatform). !22308 +- Improve initial discussion rendering performance. !22607 +- removes partially matching of No Label filter and makes it case-insensitive. !22622 (Jacopo Beschi @jacopo-beschi) +- Use search bar for filtering in dashboard issues / MRs. !22641 (Heinrich Lee Yu) +- Show different empty state for filtered issues and MRs. !22775 (Heinrich Lee Yu) +- Relocate JSONWebToken::HMACToken from EE. !22906 +- Resolve Add border around the repository file tree. !23018 +- Change breadcrumb title for contribution charts. !23071 (George Tsiolis) +- Update environments metrics empty state. !23074 (George Tsiolis) +- Refine cursor positioning in Markdown Editor for wrap tags. !23085 (Johann Hubert Sonntagbauer) +- Use reports syntax for SAST in Auto DevOps. !23163 +- SystemCheck: Use a more reliable way to detect current Ruby version. !23291 +- Changed frontmatter filtering to support YAML, JSON, TOML, and arbitrary languages. !23331 (Travis Miller) +- Don't remove failed install pods after installing GitLab managed applications. !23350 +- Expose merge request pipeline variables. !23398 +- Scope default MR search in WebIDE dropdown to current project. !23400 +- Show user contributions in correct timezone within user profile. !23419 +- Redesign of MR header sections (CE). !23465 +- Auto DevOps: Add echo for each branch of the deploy() function where we run helm upgrade. !23499 +- Updates service to update Kubernetes project namespaces and restricted service account if present. !23525 +- Adjust divider margin to comply with design specs. !23548 +- Adjust dropdown item and header padding to comply with design specs. !23552 +- Truncate merge request titles with periods instead of ellipsis. !23558 +- Remove close icon from projects dropdown in issue boards. !23567 +- Change dropdown divider color to gray-200 (#dfdfdf). !23592 +- Define the default value for only/except policies. !23765 +- Don't show Memory Usage for unmerged MRs. +- reorder notification settings by noisy-ness. (C.J. Jameson) +- Changed merge request filtering to be by path instead of name. +- Make diff file headers sticky. + +### Performance (22 changes, 6 of them are from the community) + +- Upgrade to Ruby 2.5.3. !2806 +- Removes all the irrelevant code and columns that were migrated from the Project table over to the ProjectImportState table. !21497 +- Approximate counting strategy with TABLESAMPLE. !22650 +- Replace tooltip directive with gl-tooltip diretive in badges, cycle analytics, and diffs. !22770 (George Tsiolis) +- Validate foreign keys being created and indexed for column with _id. !22808 +- Remove monospace extend. !23089 (George Tsiolis) +- Use Nokogiri as the ActiveSupport XML backend. !23136 +- Improve memory performance by reducing dirty pages after fork(). !23169 +- Add partial index for ci_builds on project_id and status. !23268 +- Reduce Gitaly calls in projects dashboard. !23307 +- Batch load only data from same repository when lazy object is accessed. !23309 +- Add index for events on project_id and created_at. !23354 +- Remove index for notes on updated_at. !23356 +- Improves performance of Project#readme_url by caching the README path. !23357 +- Populate MR metrics with events table information (migration). !23564 +- Remove unused data from discussions endpoint. !23570 +- Speed up issue board lists in groups with many projects. +- Use cached size when passing artifacts to Runner. +- Enable even more frozen string for lib/gitlab. (gfyoung) +- Enable even more frozen string in lib/gitlab/**/*.rb. (gfyoung) +- Enable even more frozen string in lib/gitlab/**/*.rb. (gfyoung) +- Enable even more frozen string for lib/gitlab. (gfyoung) + +### Added (32 changes, 13 of them are from the community) + +- Add ability to create group level clusters and install gitlab managed applications. !22450 +- Creates /create_merge_request quickaction. !22485 (Jacopo Beschi @jacopo-beschi) +- Filter by None/Any for labels in issues/mrs API. !22622 (Jacopo Beschi @jacopo-beschi) +- Chat message push notifications now include links back to GitLab branches. !22651 (Tony Castrogiovanni) +- Added feature flag to signal content headers detection by Workhorse. !22667 +- Add Discord integration. !22684 (@blackst0ne) +- Upgrade helm to 2.11.0 and upgrade on every install. !22693 +- Add knative client to kubeclient library. !22968 (cab105) +- Allow SSH public-key authentication for push mirroring. !22982 +- Allow deleting a Pipeline via the API. !22988 +- #40635: Adds support for cert-manager. !23036 (Amit Rathi) +- WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action. !23049 (Thomas Pathier) +- Adds Any option to label filters. !23111 (Jacopo Beschi @jacopo-beschi) +- Added glob for CI changes detection. !23128 (Kirill Zaitsev) +- Add model and relation to store repo full path in database. !23143 +- Add ability to render suggestions. !23147 +- Introduce Knative and Serverless Components. !23174 (Chris Baumbauer) +- Use BFG object maps to clean projects. !23189 +- Merge request pipelines. !23217 +- Extended user centric tooltips on issue and MR page. !23231 +- Add a rebase API endpoint for merge requests. !23296 +- Add config to prohibit impersonation. !23338 +- Merge request pipeline tag, and adds tags to pipeline view. !23364 +- #52753: HTTPS for JupyterHub installation. !23479 (Amit Rathi) +- Fill project_repositories for hashed storage projects. !23482 +- Ability to override email for cert-manager. !23503 (Amit Rathi) +- Allow public forks to be deduplicated. !23508 +- Pipeline trigger variable values are hidden in the UI by default. Maintainers have the option to reveal them. !23518 (jhampton) +- Add new endpoint to download single artifact file for a ref. !23538 +- Log and pass correlation-id between Unicorn, Sidekiq and Gitaly. +- Allow user to scroll to top of tab on MR page. +- Adds states to the deployment widget. + +### Other (54 changes, 30 of them are from the community) + +- Switch to Rails 5. !21492 +- Migration to write fullpath in all repository configs. !22322 +- Rails5: env is deprecated and will be removed from Rails 5.1. !22626 (Jasper Maes) +- Update haml_lint to 0.28.0. !22660 (Takuya Noguchi) +- Update ffaker to 2.10.0. !22661 (Takuya Noguchi) +- Drop gcp_clusters table. !22713 +- Upgrade minimum required Git version to 2.18.0. !22803 +- Adds new icon size to Vue icon component. !22899 +- Make sure there's only one slash as path separator. !22954 +- Show HTTP response code for Kubernetes errors. !22964 +- Update config map for gitlab managed application if already present on install. !22969 +- Drop default value on status column in deployments table. !22971 +- UI improvements to user's profile. !22977 +- Update asana to 0.8.1. !23039 (Takuya Noguchi) +- Update asciidoctor to 1.5.8. !23047 (Takuya Noguchi) +- Make auto-generated icons for subgroups in the breadcrumb dropdown display as a circle. !23062 (Thomas Pathier) +- Make reply shortcut only quote selected discussion text. !23096 (Thomas Pathier) +- Fix typo in notebook props. !23103 (George Tsiolis) +- Fix typos in lib. !23106 (George Tsiolis) +- Rename diffs store variable. !23123 (George Tsiolis) +- Fix overlapping navbar separator and overflowing navbar dropdown on small displays. !23126 (Thomas Pathier) +- Show what RPC is called in the performance bar. !23140 +- Updated Gitaly to v0.133.0. !23148 +- Rails5: Passing a class as a value in an Active Record query is deprecated. !23164 (Jasper Maes) +- Fix project identicon aligning Harry Kiselev. !23166 (Harry Kiselev) +- Fix horizontal scrollbar overlapping on horizontal scrolling-tabs. !23167 (Harry Kiselev) +- Fix bottom paddings of profile header and some markup updates of profile. !23168 (Harry Kiselev) +- Fixes to AWS documentation spelling and grammar. !23198 (Brendan O'Leary) +- Adds a PHILOSOPHY.md which references GitLab Product Handbook. !23200 +- Externalize strings from `/app/views/invites`. !23205 (Tao Wang) +- Externalize strings from `/app/views/project/runners`. !23208 (Tao Wang) +- Fix typo for scheduled pipeline. !23218 (Davy Defaud) +- Force content disposition attachment to several endpoints. !23223 +- Upgrade kubeclient to 4.0.0. !23261 (Praveen Arimbrathodiyil @pravi) +- Update used version of Runner Helm Chart to 0.1.38. !23304 +- render :nothing option is deprecated, Use head method to respond with empty response body. !23311 (Jasper Maes) +- Passing an argument to force an association to reload is now deprecated. !23334 (Jasper Maes) +- Externalize strings from `/app/views/snippets`. !23351 (Tao Wang) +- Fix deprecation: You are passing an instance of ActiveRecord::Base to. !23369 (Jasper Maes) +- Resolve status emoji being replaced by avatar on mobile. !23408 +- Fix deprecation: render :text is deprecated because it does not actually render a text/plain response. !23425 (Jasper Maes) +- Fix lack of documentation on how to fetch a snippet's content using API. !23448 (Colin Leroy) +- Upgrade GitLab Workhorse to v7.3.0. !23489 +- Fallback to admin KUBE_TOKEN for project clusters only. !23527 +- Update used version of Runner Helm Chart to 0.1.39. !23633 +- Show primary button when all labels are prioritized. !23648 (George Tsiolis) +- Upgrade workhorse to 7.6.0. !23694 +- Upgrade Gitaly to v1.7.1 for correlation-id logging. !23732 +- Fix due date test. !23845 +- Remove unused project method. !54103 (George Tsiolis) +- Uses new gitlab-ui components in Jobs and Pipelines components. +- Replaces tooltip directive with the new gl-tooltip directive for consistency in some ci/cd code. +- Bump gpgme gem version from 2.0.13 to 2.0.18. (asaparov) +- Enable Rubocop on lib/gitlab. (gfyoung) + + +## 11.5.5 (2018-12-20) + +### Security (1 change) + +- Fix persistent symlink in project import. + + ## 11.5.3 (2018-12-06) ### Security (1 change) @@ -628,6 +912,13 @@ entry. - Check frozen string in style builds. (gfyoung) +## 11.3.14 (2018-12-20) + +### Security (1 change) + +- Fix persistent symlink in project import. + + ## 11.3.13 (2018-12-13) ### Security (1 change) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index f8e233b2733..0eed1a29efd 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -1.9.0 +1.12.0 @@ -130,7 +130,7 @@ gem 'asciidoctor-plantuml', '0.0.8' gem 'rouge', '~> 3.1' gem 'truncato', '~> 0.7.9' gem 'bootstrap_form', '~> 2.7.0' -gem 'nokogiri', '~> 1.8.2' +gem 'nokogiri', '~> 1.8.4' gem 'escape_utils', '~> 1.1' # Calendar rendering @@ -165,7 +165,7 @@ gem 'acts-as-taggable-on', '~> 5.0' gem 'sidekiq', '~> 5.2.1' gem 'sidekiq-cron', '~> 0.6.0' gem 'redis-namespace', '~> 1.6.0' -gem 'gitlab-sidekiq-fetcher', '~> 0.1.0', require: 'sidekiq-reliable-fetch' +gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch' # Cron Parser gem 'rufus-scheduler', '~> 3.4' @@ -419,7 +419,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 1.3.0', require: 'gitaly' +gem 'gitaly-proto', '~> 1.5.0', require: 'gitaly' gem 'grpc', '~> 1.15.0' gem 'google-protobuf', '~> 3.6' diff --git a/Gemfile.lock b/Gemfile.lock index 6d21089c82c..f2d265d835c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -274,13 +274,13 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (1.3.0) + gitaly-proto (1.5.0) grpc (~> 1.0) github-markup (1.7.0) gitlab-default_value_for (3.1.1) activerecord (>= 3.2.0, < 6.0) gitlab-markup (1.6.5) - gitlab-sidekiq-fetcher (0.1.0) + gitlab-sidekiq-fetcher (0.4.0) sidekiq (~> 5) gitlab-styles (2.4.1) rubocop (~> 0.54.0) @@ -1008,11 +1008,11 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 1.3.0) + gitaly-proto (~> 1.5.0) github-markup (~> 1.7.0) gitlab-default_value_for (~> 3.1.1) gitlab-markup (~> 1.6.5) - gitlab-sidekiq-fetcher (~> 0.1.0) + gitlab-sidekiq-fetcher (~> 0.4.0) gitlab-styles (~> 2.4) gitlab_omniauth-ldap (~> 2.0.4) gon (~> 6.2) @@ -1059,7 +1059,7 @@ DEPENDENCIES nakayoshi_fork (~> 0.0.4) net-ldap net-ssh (~> 5.0) - nokogiri (~> 1.8.2) + nokogiri (~> 1.8.4) oauth2 (~> 1.4) octokit (~> 4.9) omniauth (~> 1.8) diff --git a/PROCESS.md b/PROCESS.md index 800b268b2a6..5aafbd33daf 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -58,6 +58,18 @@ their contributions accepted by meeting our [Definition of done][done]. What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/. +### Milestones on community contribution issues + +The milestone of an issue that is currently being worked on by a community contributor +should not be set to a named GitLab milestone (e.g. 11.7, 11.8), until the associated +merge request is very close to being merged, and we will likely know in which named +GitLab milestone the issue will land. There are many factors that influence when +a community contributor finishes an issue, or even at all. So we should set this +milestone only when we have more certainty. + +Note this only applies to issues currently assigned to community contributors. For +issues assigned to GitLabbers, we are [ambitious in assigning milestones to issues](https://about.gitlab.com/direction/#how-we-plan-releases). + ## Assigning issues If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover. @@ -1 +1 @@ -11.6.0-pre +11.7.0-pre diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 7607c4b3b79..d1396b6c4bc 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -29,6 +29,7 @@ const Api = { commitPipelinesPath: '/:project_id/commit/:sha/pipelines', branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch', createBranchPath: '/api/:version/projects/:id/repository/branches', + releasesPath: '/api/:version/projects/:id/releases', group(groupId, callback) { const url = Api.buildUrl(Api.groupPath).replace(':id', groupId); @@ -307,6 +308,12 @@ const Api = { }); }, + releases(id) { + const url = Api.buildUrl(this.releasesPath).replace(':id', encodeURIComponent(id)); + + return axios.get(url); + }, + buildUrl(url) { let urlRoot = ''; if (gon.relative_url_root != null) { diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js index ee0f7cda189..5b20fa141cd 100644 --- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js +++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js @@ -36,7 +36,9 @@ export default class VariableList { }, protected: { selector: '.js-ci-variable-input-protected', - default: 'false', + // use `attr` instead of `data` as we don't want the value to be + // converted. we need the value as a string. + default: $('.js-ci-variable-input-protected').attr('data-default'), }, environment_scope: { // We can't use a `.js-` class here because diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index 9310e2b7ca9..e781397214d 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -49,7 +49,7 @@ export default { :is-bottom="index + 1 === diffLinesLength" /> <inline-diff-comment-row - :key="`icr-${index}`" + :key="`icr-${line.line_code || index}`" :diff-file-hash="diffFile.file_hash" :line="line" :help-page-path="helpPagePath" diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index e6bc0daebb3..1bf693380db 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -43,14 +43,14 @@ export default { <tbody> <template v-for="(line, index) in diffLines"> <parallel-diff-table-row - :key="index" + :key="line.line_code" :file-hash="diffFile.file_hash" :context-lines-path="diffFile.context_lines_path" :line="line" :is-bottom="index + 1 === diffLinesLength" /> <parallel-diff-comment-row - :key="`dcr-${index}`" + :key="`dcr-${line.line_code || index}`" :line="line" :diff-file-hash="diffFile.file_hash" :line-index="index" diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index cbaa0e26395..2fe20551642 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -196,6 +196,15 @@ export function trimFirstCharOfLineContent(line = {}) { return parsedLine; } +function getLineCode({ left, right }, index) { + if (left && left.line_code) { + return left.line_code; + } else if (right && right.line_code) { + return right.line_code; + } + return index; +} + // This prepares and optimizes the incoming diff data from the server // by setting up incremental rendering and removing unneeded data export function prepareDiffData(diffData) { @@ -208,6 +217,8 @@ export function prepareDiffData(diffData) { const linesLength = file.parallel_diff_lines.length; for (let u = 0; u < linesLength; u += 1) { const line = file.parallel_diff_lines[u]; + + line.line_code = getLineCode(line, u); if (line.left) { line.left = trimFirstCharOfLineContent(line.left); line.left.hasForm = false; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index cd2f46fd07a..f44806d82a6 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -14,6 +14,7 @@ import MonitoringButtonComponent from './environment_monitoring.vue'; import CommitComponent from '../../vue_shared/components/commit.vue'; import eventHub from '../event_hub'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { CLUSTER_TYPE } from '~/clusters/constants'; /** * Environment Item Component @@ -85,6 +86,15 @@ export default { }, /** + * Hide group cluster features which are not currently implemented. + * + * @returns {Boolean} + */ + disableGroupClusterFeatures() { + return this.model && this.model.cluster_type === CLUSTER_TYPE.GROUP; + }, + + /** * Returns whether the environment can be stopped. * * @returns {Boolean} @@ -547,6 +557,7 @@ export default { <terminal-button-component v-if="model && model.terminal_path" :terminal-path="model.terminal_path" + :disabled="disableGroupClusterFeatures" /> <rollback-component diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue index 83727caad16..6d74d136a94 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.vue +++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue @@ -19,6 +19,11 @@ export default { required: false, default: '', }, + disabled: { + type: Boolean, + required: false, + default: false, + }, }, computed: { title() { @@ -33,6 +38,7 @@ export default { :title="title" :aria-label="title" :href="terminalPath" + :class="{ disabled: disabled }" class="btn terminal-button d-none d-sm-none d-md-block" > <icon name="terminal" /> diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue index 309b7427b9e..0bce860df91 100644 --- a/app/assets/javascripts/jobs/components/artifacts_block.vue +++ b/app/assets/javascripts/jobs/components/artifacts_block.vue @@ -28,27 +28,29 @@ export default { </script> <template> <div class="block"> - <div class="title">{{ s__('Job|Job artifacts') }}</div> + <div class="title font-weight-bold">{{ s__('Job|Job artifacts') }}</div> - <p v-if="isExpired" class="js-artifacts-removed build-detail-row"> - {{ s__('Job|The artifacts were removed') }} + <p + v-if="isExpired || willExpire" + :class="{ + 'js-artifacts-removed': isExpired, + 'js-artifacts-will-be-removed': willExpire, + }" + class="build-detail-row" + > + <span v-if="isExpired">{{ s__('Job|The artifacts were removed') }}</span> + <span v-if="willExpire">{{ s__('Job|The artifacts will be removed') }}</span> + <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" /> </p> - <p v-else-if="willExpire" class="js-artifacts-will-be-removed build-detail-row"> - {{ s__('Job|The artifacts will be removed in') }} - </p> - - <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" /> - - <div class="btn-group d-flex" role="group"> + <div class="btn-group d-flex prepend-top-10" role="group"> <gl-link v-if="artifact.keep_path" :href="artifact.keep_path" class="js-keep-artifacts btn btn-sm btn-default" data-method="post" + >{{ s__('Job|Keep') }}</gl-link > - {{ s__('Job|Keep') }} - </gl-link> <gl-link v-if="artifact.download_path" @@ -56,17 +58,15 @@ export default { class="js-download-artifacts btn btn-sm btn-default" download rel="nofollow" + >{{ s__('Job|Download') }}</gl-link > - {{ s__('Job|Download') }} - </gl-link> <gl-link v-if="artifact.browse_path" :href="artifact.browse_path" class="js-browse-artifacts btn btn-sm btn-default" + >{{ s__('Job|Browse') }}</gl-link > - {{ s__('Job|Browse') }} - </gl-link> </div> </div> </template> diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue index 3b9c61bd48c..e0f55518eef 100644 --- a/app/assets/javascripts/jobs/components/commit_block.vue +++ b/app/assets/javascripts/jobs/components/commit_block.vue @@ -31,12 +31,12 @@ export default { block: !isLastBlock, }" > - <p> - {{ __('Commit') }} + <p class="append-bottom-5"> + <span class="font-weight-bold">{{ __('Commit') }}</span> - <gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">{{ - commit.short_id - }}</gl-link> + <gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit"> + {{ commit.short_id }} + </gl-link> <clipboard-button :text="commit.short_id" @@ -44,11 +44,14 @@ export default { css-class="btn btn-clipboard btn-transparent" /> - <gl-link v-if="mergeRequest" :href="mergeRequest.path" class="js-link-commit link-commit" - >!{{ mergeRequest.iid }}</gl-link - > + <span v-if="mergeRequest"> + {{ __('in') }} + <gl-link :href="mergeRequest.path" class="js-link-commit link-commit" + >!{{ mergeRequest.iid }}</gl-link + > + </span> </p> - <p class="build-light-text append-bottom-0">{{ commit.title }}</p> + <p class="append-bottom-0">{{ commit.title }}</p> </div> </template> diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index 934ecd0e3ec..ad3e7dabc79 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -110,22 +110,20 @@ export default { <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix"> <div class="sidebar-container"> <div class="blocks-container"> - <div class="block"> - <strong class="inline prepend-top-8"> {{ job.name }} </strong> + <div class="block d-flex align-items-center"> + <h4 class="flex-grow-1 prepend-top-8 m-0">{{ job.name }}</h4> <gl-link v-if="job.retry_path" :class="retryButtonClass" :href="job.retry_path" data-method="post" rel="nofollow" + >{{ __('Retry') }}</gl-link > - {{ __('Retry') }} - </gl-link> <gl-link v-if="job.terminal_path" :href="job.terminal_path" - class="js-terminal-link pull-right btn btn-primary - btn-inverted visible-md-block visible-lg-block" + class="js-terminal-link pull-right btn btn-primary btn-inverted visible-md-block visible-lg-block" target="_blank" > {{ __('Debug') }} <icon name="external-link" /> @@ -133,8 +131,7 @@ export default { <gl-button :aria-label="__('Toggle Sidebar')" type="button" - class="btn btn-blank gutter-toggle - float-right d-block d-md-none js-sidebar-build-toggle" + class="btn btn-blank gutter-toggle float-right d-block d-md-none js-sidebar-build-toggle" @click="toggleSidebar" > <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i> @@ -145,25 +142,18 @@ export default { v-if="job.new_issue_path" :href="job.new_issue_path" class="js-new-issue btn btn-success btn-inverted" + >{{ __('New issue') }}</gl-link > - {{ __('New issue') }} - </gl-link> <gl-link v-if="job.retry_path" :href="job.retry_path" class="js-retry-job btn btn-inverted-secondary" data-method="post" rel="nofollow" + >{{ __('Retry') }}</gl-link > - {{ __('Retry') }} - </gl-link> </div> <div :class="{ block: renderBlock }"> - <p v-if="job.merge_request" class="build-detail-row js-job-mr"> - <span class="build-light-text"> {{ __('Merge Request:') }} </span> - <gl-link :href="job.merge_request.path"> !{{ job.merge_request.iid }} </gl-link> - </p> - <detail-row v-if="job.duration" :value="duration" @@ -198,10 +188,10 @@ export default { title="Coverage" /> <p v-if="job.tags.length" class="build-detail-row js-job-tags"> - <span class="build-light-text"> {{ __('Tags:') }} </span> - <span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary"> - {{ tag }} - </span> + <span class="font-weight-bold">{{ __('Tags:') }}</span> + <span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary mr-1">{{ + tag + }}</span> </p> <div v-if="job.cancel_path" class="btn-group prepend-top-5" role="group"> @@ -210,9 +200,8 @@ export default { class="js-cancel-job btn btn-sm btn-default" data-method="post" rel="nofollow" + >{{ __('Cancel') }}</gl-link > - {{ __('Cancel') }} - </gl-link> </div> </div> diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue index 77be295e802..b826007ec2c 100644 --- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue +++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue @@ -34,8 +34,7 @@ export default { </script> <template> <p class="build-detail-row"> - <span v-if="hasTitle" class="build-light-text"> {{ title }}: </span> {{ value }} - + <span v-if="hasTitle" class="font-weight-bold">{{ title }}:</span> {{ value }} <span v-if="hasHelpURL" class="help-button float-right"> <gl-link :href="helpUrl" target="_blank" rel="noopener noreferrer nofollow"> <i class="fa fa-question-circle" aria-hidden="true"></i> diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue index 90482500bbf..7f79e92067f 100644 --- a/app/assets/javascripts/jobs/components/stages_dropdown.vue +++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue @@ -38,11 +38,11 @@ export default { <div class="block-last dropdown"> <ci-icon :status="pipeline.details.status" class="vertical-align-middle" /> - {{ __('Pipeline') }} - <a :href="pipeline.path" class="js-pipeline-path link-commit"> #{{ pipeline.id }} </a> + <span class="font-weight-bold">{{ __('Pipeline') }}</span> + <a :href="pipeline.path" class="js-pipeline-path link-commit">#{{ pipeline.id }}</a> <template v-if="hasRef"> {{ __('from') }} - <a :href="pipeline.ref.path" class="link-commit ref-name"> {{ pipeline.ref.name }} </a> + <a :href="pipeline.ref.path" class="link-commit ref-name">{{ pipeline.ref.name }}</a> </template> <button diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue index 3cd3b743108..997737b3e23 100644 --- a/app/assets/javascripts/jobs/components/trigger_block.vue +++ b/app/assets/javascripts/jobs/components/trigger_block.vue @@ -43,23 +43,24 @@ export default { <template> <div class="build-widget block"> - <h4 class="title">{{ __('Trigger') }}</h4> - <p v-if="trigger.short_token" class="js-short-token" - :class="{ 'append-bottom-0': !hasVariables }" + :class="{ 'append-bottom-5': hasVariables, 'append-bottom-0': !hasVariables }" > - <span class="build-light-text"> {{ __('Token') }} </span> {{ trigger.short_token }} + <span class="font-weight-bold">{{ __('Trigger token:') }}</span> {{ trigger.short_token }} </p> <template v-if="hasVariables"> <p class="trigger-variables-btn-container"> - <span class="build-light-text"> {{ __('Variables:') }} </span> + <span class="font-weight-bold">{{ __('Trigger variables:') }}</span> - <gl-button v-if="hasValues" class="group js-reveal-variables" @click="toggleValues"> - {{ getToggleButtonText }} - </gl-button> + <gl-button + v-if="hasValues" + class="btn-sm group js-reveal-variables trigger-variables-btn" + @click="toggleValues" + >{{ getToggleButtonText }}</gl-button + > </p> <table class="js-build-variables trigger-build-variables"> diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index c095a017866..1254ec798a6 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -82,7 +82,7 @@ export function insertMarkdownText({ tag, cursorOffset, blockTag, - selected, + selected = '', wrap, select, }) { @@ -212,7 +212,7 @@ export function addMarkdownListeners(form) { blockTag: $this.data('mdBlock'), wrap: !$this.data('mdPrepend'), select: $this.data('mdSelect'), - tagContent: $this.data('mdTagContent').toString(), + tagContent: $this.data('mdTagContent'), }); }); } diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index d9dd08a7a6b..7c3f5d00308 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -178,31 +178,32 @@ export default { commitId = `<span class="commit-sha">${truncateSha(commitId)}</span>`; } - let text = s__('MergeRequests|started a discussion'); + const { + for_commit: isForCommit, + diff_discussion: isDiffDiscussion, + active: isActive, + } = this.discussion; - if (this.discussion.for_commit) { + let text = s__('MergeRequests|started a discussion'); + if (isForCommit) { text = s__( 'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}', ); - } else if (this.discussion.diff_discussion) { - if (this.discussion.active) { - text = s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}'); - } else { - text = s__( - 'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}', - ); - } + } else if (isDiffDiscussion && commitId) { + text = isActive + ? s__('MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}') + : s__( + 'MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}', + ); + } else if (isDiffDiscussion) { + text = isActive + ? s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}') + : s__( + 'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}', + ); } - return sprintf( - text, - { - commitId, - linkStart, - linkEnd, - }, - false, - ); + return sprintf(text, { commitId, linkStart, linkEnd }, false); }, diffLine() { if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) { diff --git a/app/assets/javascripts/pages/projects/releases/index/index.js b/app/assets/javascripts/pages/projects/releases/index/index.js new file mode 100644 index 00000000000..c183fbb9610 --- /dev/null +++ b/app/assets/javascripts/pages/projects/releases/index/index.js @@ -0,0 +1,3 @@ +import initReleases from '~/releases'; + +document.addEventListener('DOMContentLoaded', initReleases); diff --git a/app/assets/javascripts/releases/components/app.vue b/app/assets/javascripts/releases/components/app.vue new file mode 100644 index 00000000000..0ad5ee2915c --- /dev/null +++ b/app/assets/javascripts/releases/components/app.vue @@ -0,0 +1,82 @@ +<script> +import { mapState, mapActions } from 'vuex'; +import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui'; +import ReleaseBlock from './release_block.vue'; + +export default { + name: 'ReleasesApp', + components: { + GlLoadingIcon, + GlEmptyState, + ReleaseBlock, + }, + props: { + projectId: { + type: String, + required: true, + }, + documentationLink: { + type: String, + required: true, + }, + illustrationPath: { + type: String, + required: true, + }, + }, + computed: { + ...mapState(['isLoading', 'releases', 'hasError']), + shouldRenderEmptyState() { + return !this.releases.length && !this.hasError && !this.isLoading; + }, + shouldRenderSuccessState() { + return this.releases.length && !this.isLoading && !this.hasError; + }, + }, + created() { + this.fetchReleases(this.projectId); + }, + methods: { + ...mapActions(['fetchReleases']), + }, +}; +</script> +<template> + <div class="prepend-top-default"> + <gl-loading-icon v-if="isLoading" :size="2" class="js-loading prepend-top-20" /> + + <gl-empty-state + v-else-if="shouldRenderEmptyState" + class="js-empty-state" + :title="__('Getting started with releases')" + :svg-path="illustrationPath" + :description=" + __( + 'Releases mark specific points in a project\'s development history, communicate information about the type of change, and deliver on prepared, often compiled, versions of the software to be reused elsewhere. Currently, releases can only be created through the API.', + ) + " + :primary-button-link="documentationLink" + :primary-button-text="__('Open Documentation')" + /> + + <div v-else-if="shouldRenderSuccessState" class="js-success-state"> + <release-block + v-for="(release, index) in releases" + :key="release.tag_name" + :release="release" + :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" + /> + </div> + </div> +</template> +<style> +.linked-card::after { + width: 1px; + content: ' '; + border: 1px solid #e5e5e5; + height: 17px; + top: 100%; + position: absolute; + left: 32px; +} +</style> diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue index bd65a225d8f..34b97826cdb 100644 --- a/app/assets/javascripts/releases/components/release_block.vue +++ b/app/assets/javascripts/releases/components/release_block.vue @@ -1,4 +1,5 @@ <script> +import _ from 'underscore'; import { GlTooltipDirective, GlLink } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; @@ -17,52 +18,16 @@ export default { }, mixins: [timeagoMixin], props: { - name: { - type: String, - required: true, - }, - tag: { - type: String, - required: true, - }, - commit: { - type: Object, - required: true, - }, - description: { - type: String, - required: false, - default: '', - }, - author: { + release: { type: Object, required: true, - }, - createdAt: { - type: String, - required: false, - default: '', - }, - assetsCount: { - type: Number, - required: false, - default: 0, - }, - sources: { - type: Array, - required: false, - default: () => [], - }, - links: { - type: Array, - required: false, - default: () => [], + default: () => ({}), }, }, computed: { releasedTimeAgo() { return sprintf('released %{time}', { - time: this.timeFormated(this.createdAt), + time: this.timeFormated(this.release.created_at), }); }, userImageAltDescription() { @@ -70,13 +35,25 @@ export default { ? sprintf("%{username}'s avatar", { username: this.author.username }) : null; }, + commit() { + return this.release.commit || {}; + }, + assets() { + return this.release.assets || {}; + }, + author() { + return this.release.author || {}; + }, + hasAuthor() { + return _.isEmpty(this.author); + }, }, }; </script> <template> <div class="card"> <div class="card-body"> - <h2 class="card-title mt-0">{{ name }}</h2> + <h2 class="card-title mt-0">{{ release.name }}</h2> <div class="card-subtitle d-flex flex-wrap text-secondary"> <div class="append-right-8"> @@ -86,15 +63,17 @@ export default { <div class="append-right-8"> <icon name="tag" class="align-middle" /> - <span v-gl-tooltip.bottom :title="__('Tag')">{{ tag }}</span> + <span v-gl-tooltip.bottom :title="__('Tag')">{{ release.tag_name }}</span> </div> <div class="append-right-4"> • - <span v-gl-tooltip.bottom :title="tooltipTitle(createdAt)">{{ releasedTimeAgo }}</span> + <span v-gl-tooltip.bottom :title="tooltipTitle(release.created_at)">{{ + releasedTimeAgo + }}</span> </div> - <div class="d-flex"> + <div v-if="hasAuthor" class="d-flex"> by <user-avatar-link class="prepend-left-4" @@ -106,20 +85,25 @@ export default { </div> </div> - <div class="card-text prepend-top-default"> + <div + v-if="assets.links.length || assets.sources.length" + Sclass="card-text prepend-top-default" + > <b> - {{ __('Assets') }} <span class="js-assets-count badge badge-pill">{{ assetsCount }}</span> + {{ __('Assets') }} + <span class="js-assets-count badge badge-pill">{{ assets.count }}</span> </b> - <ul class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list"> - <li v-for="link in links" :key="link.name" class="append-bottom-8"> + <ul v-if="assets.links.length" class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list"> + <li v-for="link in assets.links" :key="link.name" class="append-bottom-8"> <gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.url"> - <icon name="package" class="align-middle append-right-4" /> {{ link.name }} + <icon name="package" class="align-middle append-right-4 align-text-bottom" /> + {{ link.name }} </gl-link> </li> </ul> - <div class="dropdown"> + <div v-if="assets.sources.length" class="dropdown"> <button type="button" class="btn btn-link" @@ -132,14 +116,14 @@ export default { </button> <div class="js-sources-dropdown dropdown-menu"> - <li v-for="asset in sources" :key="asset.url"> + <li v-for="asset in assets.sources" :key="asset.url"> <gl-link :href="asset.url">{{ __('Download') }} {{ asset.format }}</gl-link> </li> </div> </div> </div> - <div class="card-text prepend-top-default"><div v-html="description"></div></div> + <div class="card-text prepend-top-default"><div v-html="release.description_html"></div></div> </div> </div> </template> diff --git a/app/assets/javascripts/releases/index.js b/app/assets/javascripts/releases/index.js new file mode 100644 index 00000000000..adbed3cb8e2 --- /dev/null +++ b/app/assets/javascripts/releases/index.js @@ -0,0 +1,24 @@ +import Vue from 'vue'; +import App from './components/app.vue'; +import createStore from './store'; + +export default () => { + const element = document.getElementById('js-releases-page'); + + return new Vue({ + el: element, + store: createStore(), + components: { + App, + }, + render(createElement) { + return createElement('app', { + props: { + projectId: element.dataset.projectId, + documentationLink: element.dataset.documentationPath, + illustrationPath: element.dataset.illustrationPath, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/releases/store/actions.js b/app/assets/javascripts/releases/store/actions.js new file mode 100644 index 00000000000..baa2251403e --- /dev/null +++ b/app/assets/javascripts/releases/store/actions.js @@ -0,0 +1,37 @@ +import * as types from './mutation_types'; +import createFlash from '~/flash'; +import { __ } from '~/locale'; +import api from '~/api'; + +/** + * Commits a mutation to update the state while the main endpoint is being requested. + */ +export const requestReleases = ({ commit }) => commit(types.REQUEST_RELEASES); + +/** + * Fetches the main endpoint. + * Will dispatch requestNamespace action before starting the request. + * Will dispatch receiveNamespaceSuccess if the request is successfull + * Will dispatch receiveNamesapceError if the request returns an error + * + * @param {String} projectId + */ +export const fetchReleases = ({ dispatch }, projectId) => { + dispatch('requestReleases'); + + api + .releases(projectId) + .then(({ data }) => dispatch('receiveReleasesSuccess', data)) + .catch(() => dispatch('receiveReleasesError')); +}; + +export const receiveReleasesSuccess = ({ commit }, data) => + commit(types.RECEIVE_RELEASES_SUCCESS, data); + +export const receiveReleasesError = ({ commit }) => { + commit(types.RECEIVE_RELEASES_ERROR); + createFlash(__('An error occured while fetching the releases. Please try again.')); +}; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/app/assets/javascripts/releases/store/index.js b/app/assets/javascripts/releases/store/index.js new file mode 100644 index 00000000000..968b94f0e0d --- /dev/null +++ b/app/assets/javascripts/releases/store/index.js @@ -0,0 +1,14 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import state from './state'; +import * as actions from './actions'; +import mutations from './mutations'; + +Vue.use(Vuex); + +export default () => + new Vuex.Store({ + actions, + mutations, + state: state(), + }); diff --git a/app/assets/javascripts/releases/store/mutation_types.js b/app/assets/javascripts/releases/store/mutation_types.js new file mode 100644 index 00000000000..a74bf15c515 --- /dev/null +++ b/app/assets/javascripts/releases/store/mutation_types.js @@ -0,0 +1,3 @@ +export const REQUEST_RELEASES = 'REQUEST_RELEASES'; +export const RECEIVE_RELEASES_SUCCESS = 'RECEIVE_RELEASES_SUCCESS'; +export const RECEIVE_RELEASES_ERROR = 'RECEIVE_RELEASES_ERROR'; diff --git a/app/assets/javascripts/releases/store/mutations.js b/app/assets/javascripts/releases/store/mutations.js new file mode 100644 index 00000000000..b97dc6cb0ab --- /dev/null +++ b/app/assets/javascripts/releases/store/mutations.js @@ -0,0 +1,37 @@ +import * as types from './mutation_types'; + +export default { + /** + * Sets isLoading to true while the request is being made. + * @param {Object} state + */ + [types.REQUEST_RELEASES](state) { + state.isLoading = true; + }, + + /** + * Sets isLoading to false. + * Sets hasError to false. + * Sets the received data + * @param {Object} state + * @param {Object} data + */ + [types.RECEIVE_RELEASES_SUCCESS](state, data) { + state.hasError = false; + state.isLoading = false; + state.releases = data; + }, + + /** + * Sets isLoading to false. + * Sets hasError to true. + * Resets the data + * @param {Object} state + * @param {Object} data + */ + [types.RECEIVE_RELEASES_ERROR](state) { + state.isLoading = false; + state.releases = []; + state.hasError = true; + }, +}; diff --git a/app/assets/javascripts/releases/store/state.js b/app/assets/javascripts/releases/store/state.js new file mode 100644 index 00000000000..bf25e651c99 --- /dev/null +++ b/app/assets/javascripts/releases/store/state.js @@ -0,0 +1,5 @@ +export default () => ({ + isLoading: false, + hasError: false, + releases: [], +}); diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index 225e21ad322..9a0cdc02952 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -79,11 +79,12 @@ Sidebar.prototype.sidebarToggleClicked = function(e, triggered) { Sidebar.prototype.toggleTodo = function(e) { var $btnText, $this, $todoLoading, ajaxType, url; $this = $(e.currentTarget); - ajaxType = $this.attr('data-delete-path') ? 'delete' : 'post'; - if ($this.attr('data-delete-path')) { - url = '' + $this.attr('data-delete-path'); + ajaxType = $this.data('deletePath') ? 'delete' : 'post'; + + if ($this.data('deletePath')) { + url = '' + $this.data('deletePath'); } else { - url = '' + $this.data('url'); + url = '' + $this.data('createPath'); } $this.tooltip('hide'); @@ -119,14 +120,14 @@ Sidebar.prototype.todoUpdateDone = function(data) { .removeClass('is-loading') .enable() .attr('aria-label', $el.data(`${attrPrefix}Text`)) - .attr('data-delete-path', deletePath) - .attr('title', $el.data(`${attrPrefix}Text`)); + .attr('title', $el.data(`${attrPrefix}Text`)) + .data('deletePath', deletePath); if ($el.hasClass('has-tooltip')) { $el.tooltip('_fixTitle'); } - if ($el.data(`${attrPrefix}Icon`)) { + if (typeof $el.data('isCollapsed') !== 'undefined') { $elText.html($el.data(`${attrPrefix}Icon`)); } else { $elText.text($el.data(`${attrPrefix}Text`)); diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue index 7874a7b6b6a..349e14670b1 100644 --- a/app/assets/javascripts/serverless/components/functions.vue +++ b/app/assets/javascripts/serverless/components/functions.vue @@ -81,7 +81,7 @@ export default { </p> <ul> <li>Your repository does not have a corresponding <code>serverless.yml</code> file.</li> - <li>Your <code>gitlab-ci.yml</code> file is not properly configured.</li> + <li>Your <code>.gitlab-ci.yml</code> file is not properly configured.</li> <li> The functions listed in the <code>serverless.yml</code> file don't match the namespace of your cluster. diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js index f20cc6d8cca..7b8b4c5d856 100644 --- a/app/assets/javascripts/sidebar/stores/sidebar_store.js +++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js @@ -71,7 +71,7 @@ export default class SidebarStore { } findAssignee(findAssignee) { - return this.assignees.filter(assignee => assignee.id === findAssignee.id)[0]; + return this.assignees.find(assignee => assignee.id === findAssignee.id); } removeAssignee(removeAssignee) { diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue index fad1a2f3f56..d24fe1b547e 100644 --- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue +++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue @@ -1,6 +1,5 @@ <script> import { GlPopover, GlSkeletonLoading } from '@gitlab/ui'; -import { __, sprintf } from '~/locale'; import UserAvatarImage from '../user_avatar/user_avatar_image.vue'; import { glEmojiTag } from '../../../emoji'; @@ -28,23 +27,6 @@ export default { }, }, computed: { - jobLine() { - if (this.user.bio && this.user.organization) { - return sprintf( - __('%{bio} at %{organization}'), - { - bio: this.user.bio, - organization: this.user.organization, - }, - false, - ); - } else if (this.user.bio) { - return this.user.bio; - } else if (this.user.organization) { - return this.user.organization; - } - return null; - }, statusHtml() { if (this.user.status.emoji && this.user.status.message) { return `${glEmojiTag(this.user.status.emoji)} ${this.user.status.message}`; @@ -86,7 +68,8 @@ export default { <gl-skeleton-loading v-else :lines="1" class="animation-container-small mb-1" /> </div> <div class="text-secondary"> - {{ jobLine }} + <div v-if="user.bio" class="js-bio">{{ user.bio }}</div> + <div v-if="user.organization" class="js-organization">{{ user.organization }}</div> <gl-skeleton-loading v-if="jobInfoIsLoading" :lines="1" diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 3ac7b6b704b..037a5adfb7e 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -24,7 +24,7 @@ } } - &:not(.use-csslab) table { + table { @extend .table; } diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 73533571a2f..946f575ac13 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -42,7 +42,6 @@ padding: 10px; text-align: right; float: left; - line-height: 1; a { font-family: $monospace-font; @@ -69,3 +68,9 @@ } } } + +// Vertically aligns <table> line numbers (eg. blame view) +// see https://gitlab.com/gitlab-org/gitlab-ce/issues/54048 +td.line-numbers { + line-height: 1; +} diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index 7e30747963a..95291b4a9ad 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -25,8 +25,8 @@ &.w-100 { // after upgrading to Bootstrap 4.2 we can use $modal-header-padding-x here // https://github.com/twbs/bootstrap/pull/26976 - margin-right: -2rem; - padding-right: 2rem; + margin-right: -28px; + padding-right: 28px; } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index ce5aaa8963c..343c09b4a3e 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -198,7 +198,7 @@ $well-light-text-color: #5b6169; $gl-font-size: 14px; $gl-font-size-xs: 11px; $gl-font-size-small: 12px; -$gl-font-size-medium: 1.43rem; +$gl-font-size-medium: 20px; $gl-font-size-large: 16px; $gl-font-weight-normal: 400; $gl-font-weight-bold: 600; diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss index 5ca76bb6c5a..069f45bff49 100644 --- a/app/assets/stylesheets/framework/variables_overrides.scss +++ b/app/assets/stylesheets/framework/variables_overrides.scss @@ -28,3 +28,9 @@ $popover-border-width: 1px; $popover-border-color: $border-color; $popover-box-shadow: 0 $border-radius-small $border-radius-default 0 $shadow-color; $popover-arrow-outer-color: $shadow-color; +$h1-font-size: 14px * 2.5; +$h2-font-size: 14px * 2; +$h3-font-size: 14px * 1.75; +$h4-font-size: 14px * 1.5; +$h5-font-size: 14px * 1.25; +$h6-font-size: 14px; diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index 57918eafd6f..09235661cea 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -135,6 +135,7 @@ .build-loader-animation { @include build-loader-animation; float: left; + padding-left: $gl-padding-8; } } @@ -232,6 +233,11 @@ @extend .d-flex; justify-content: space-between; align-items: center; + + .trigger-variables-btn { + margin-top: -5px; + margin-bottom: -5px; + } } .trigger-build-variables { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6f0dc2a3a20..140a625d333 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -403,7 +403,7 @@ class ApplicationController < ActionController::Base end def manifest_import_enabled? - Group.supports_nested_groups? && Gitlab::CurrentSettings.import_sources.include?('manifest') + Group.supports_nested_objects? && Gitlab::CurrentSettings.import_sources.include?('manifest') end # U2F (universal 2nd factor) devices need a unique identifier for the application diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb index 4f56346832c..e9a7d6a3152 100644 --- a/app/controllers/concerns/group_tree.rb +++ b/app/controllers/concerns/group_tree.rb @@ -32,14 +32,14 @@ module GroupTree def filtered_groups_with_ancestors(groups) filtered_groups = groups.search(params[:filter]).page(params[:page]) - if Group.supports_nested_groups? + if Group.supports_nested_objects? # We find the ancestors by ID of the search results here. # Otherwise the ancestors would also have filters applied, # which would cause them not to be preloaded. # # Pagination needs to be applied before loading the ancestors to # make sure ancestors are not cut off by pagination. - Gitlab::GroupHierarchy.new(Group.where(id: filtered_groups.select(:id))) + Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id))) .base_and_ancestors else filtered_groups diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index ad9cc0925b7..3d64ae8b775 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -5,7 +5,6 @@ module IssuableActions include Gitlab::Utils::StrongMemoize included do - before_action :labels, only: [:show, :new, :edit] before_action :authorize_destroy_issuable!, only: :destroy before_action :authorize_admin_issuable!, only: :bulk_update end @@ -25,7 +24,10 @@ module IssuableActions def show respond_to do |format| - format.html + format.html do + @issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables + end + format.json do render json: serializer.represent(issuable, serializer: params[:serializer]) end @@ -168,10 +170,6 @@ module IssuableActions end end - def labels - @labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute # rubocop:disable Gitlab/ModuleWithInstanceVariables - end - def authorize_destroy_issuable! unless can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable) return access_denied! diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb index 9576eb14fdd..5572c3cee2d 100644 --- a/app/controllers/concerns/lfs_request.rb +++ b/app/controllers/concerns/lfs_request.rb @@ -94,6 +94,7 @@ module LfsRequest def lfs_upload_access? return false unless project.lfs_enabled? return false unless has_authentication_ability?(:push_code) + return false if limit_exceeded? lfs_deploy_token? || can?(user, :push_code, project) end @@ -121,4 +122,9 @@ module LfsRequest def has_authentication_ability?(capability) (authentication_abilities || []).include?(capability) end + + # Overriden in EE + def limit_exceeded? + false + end end diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index 0a593bd35b6..6824a07dc76 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -24,7 +24,7 @@ class Projects::DeployKeysController < Projects::ApplicationController end def create - @key = DeployKeys::CreateService.new(current_user, create_params).execute + @key = DeployKeys::CreateService.new(current_user, create_params).execute(project: @project) unless @key.valid? flash[:alert] = @key.errors.full_messages.join(', ').html_safe diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb index ac1969adc6e..045a4e974fe 100644 --- a/app/controllers/projects/merge_requests/conflicts_controller.rb +++ b/app/controllers/projects/merge_requests/conflicts_controller.rb @@ -8,7 +8,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap def show respond_to do |format| format.html do - labels + @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar') end format.json do @@ -60,9 +60,15 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap end end + private + def authorize_can_resolve_conflicts! @conflicts_list = ::MergeRequests::Conflicts::ListService.new(@merge_request) return render_404 unless @conflicts_list.can_be_resolved_by?(current_user) end + + def serializer + MergeRequestSerializer.new(current_user: current_user, project: project) + end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index da9316d5f22..8b8eac7ff8e 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -22,8 +22,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo format.html format.json do render json: { - html: view_to_html_string("projects/merge_requests/_merge_requests"), - labels: @labels.as_json(methods: :text_color) + html: view_to_html_string("projects/merge_requests/_merge_requests") } end end @@ -43,8 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @noteable = @merge_request @commits_count = @merge_request.commits_count - - labels + @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar') set_pipeline_variables diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb index a9ce5be13f3..96a36db7ec8 100644 --- a/app/finders/group_descendants_finder.rb +++ b/app/finders/group_descendants_finder.rb @@ -112,7 +112,7 @@ class GroupDescendantsFinder # rubocop: disable CodeReuse/ActiveRecord def ancestors_of_groups(base_for_ancestors) group_ids = base_for_ancestors.except(:select, :sort).select(:id) - Gitlab::GroupHierarchy.new(Group.where(id: group_ids)) + Gitlab::ObjectHierarchy.new(Group.where(id: group_ids)) .base_and_ancestors(upto: parent_group.id) end # rubocop: enable CodeReuse/ActiveRecord @@ -132,7 +132,7 @@ class GroupDescendantsFinder end def subgroups - return Group.none unless Group.supports_nested_groups? + return Group.none unless Group.supports_nested_objects? # When filtering subgroups, we want to find all matches withing the tree of # descendants to show to the user @@ -183,7 +183,7 @@ class GroupDescendantsFinder # rubocop: disable CodeReuse/ActiveRecord def hierarchy_for_parent - @hierarchy ||= Gitlab::GroupHierarchy.new(Group.where(id: parent_group.id)) + @hierarchy ||= Gitlab::ObjectHierarchy.new(Group.where(id: parent_group.id)) end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb index ea954f98220..0080123407d 100644 --- a/app/finders/groups_finder.rb +++ b/app/finders/groups_finder.rb @@ -46,7 +46,7 @@ class GroupsFinder < UnionFinder return [Group.all] if current_user&.full_private_access? && all_available? groups = [] - groups << Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups if current_user + groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects if current_user groups << Group.unscoped.public_to_user(current_user) if include_public_groups? groups << Group.none if groups.empty? groups @@ -66,7 +66,7 @@ class GroupsFinder < UnionFinder .groups .where('members.access_level >= ?', params[:min_access_level]) - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(groups) .base_and_descendants end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 086bb38ce9a..5a7c005fd06 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -26,6 +26,18 @@ module ApplicationSettingsHelper end end + def all_protocols_enabled? + Gitlab::CurrentSettings.enabled_git_access_protocol.blank? + end + + def ssh_enabled? + all_protocols_enabled? || enabled_protocol == 'ssh' + end + + def http_enabled? + all_protocols_enabled? || enabled_protocol == 'http' + end + def enabled_project_button(project, protocol) case protocol when 'ssh' @@ -218,7 +230,8 @@ module ApplicationSettingsHelper :version_check_enabled, :web_ide_clientside_preview_enabled, :diff_max_patch_bytes, - :commit_email_hostname + :commit_email_hostname, + :protected_ci_variables ] end diff --git a/app/helpers/ci_variables_helper.rb b/app/helpers/ci_variables_helper.rb new file mode 100644 index 00000000000..e3728804c2a --- /dev/null +++ b/app/helpers/ci_variables_helper.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CiVariablesHelper + def ci_variable_protected_by_default? + Gitlab::CurrentSettings.current_application_settings.protected_ci_variables + end + + def ci_variable_protected?(variable, only_key_value) + if variable && !only_key_value + variable.protected + else + ci_variable_protected_by_default? + end + end +end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 866fc555856..4a9ed123161 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -126,7 +126,7 @@ module GroupsHelper end def supports_nested_groups? - Group.supports_nested_groups? + Group.supports_nested_objects? end private diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index da991458ea7..5f7147508c7 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -23,30 +23,41 @@ module IssuablesHelper end end - def sidebar_due_date_tooltip_label(issuable) - if issuable.due_date - "#{_('Due date')}<br />#{due_date_remaining_days(issuable)}" - else - _('Due date') - end + def sidebar_milestone_tooltip_label(milestone) + return _('Milestone') unless milestone.present? + + [milestone[:title], sidebar_milestone_remaining_days(milestone) || _('Milestone')].join('<br/>') + end + + def sidebar_milestone_remaining_days(milestone) + due_date_with_remaining_days(milestone[:due_date], milestone[:start_date]) + end + + def sidebar_due_date_tooltip_label(due_date) + [_('Due date'), due_date_with_remaining_days(due_date)].compact.join('<br/>') end - def due_date_remaining_days(issuable) - remaining_days_in_words = remaining_days_in_words(issuable) + def due_date_with_remaining_days(due_date, start_date = nil) + return unless due_date - "#{issuable.due_date.to_s(:medium)} (#{remaining_days_in_words})" + "#{due_date.to_s(:medium)} (#{remaining_days_in_words(due_date, start_date)})" + end + + def sidebar_label_filter_path(base_path, label_name) + query_params = { label_name: [label_name] }.to_query + + "#{base_path}?#{query_params}" end def multi_label_name(current_labels, default_label) - if current_labels && current_labels.any? - title = current_labels.first.try(:title) - if current_labels.size > 1 - "#{title} +#{current_labels.size - 1} more" - else - title - end + return default_label if current_labels.blank? + + title = current_labels.first.try(:title) || current_labels.first[:title] + + if current_labels.size > 1 + "#{title} +#{current_labels.size - 1} more" else - default_label + title end end @@ -197,19 +208,11 @@ module IssuablesHelper output.join.html_safe end - # rubocop: disable CodeReuse/ActiveRecord - def issuable_todo(issuable) - if current_user - current_user.todos.find_by(target: issuable, state: :pending) - end - end - # rubocop: enable CodeReuse/ActiveRecord - def issuable_labels_tooltip(labels, limit: 5) first, last = labels.partition.with_index { |_, i| i < limit } if labels && labels.any? - label_names = first.collect(&:name) + label_names = first.collect { |label| label.fetch(:title) } label_names << "and #{last.size} more" unless last.empty? label_names.join(', ') @@ -356,12 +359,6 @@ module IssuablesHelper issuable.model_name.human.downcase end - def selected_labels - Array(params[:label_name]).map do |label_name| - Label.new(title: label_name) - end - end - def has_filter_bar_param? finder.class.scalar_params.any? { |p| params[p].present? } end @@ -386,19 +383,20 @@ module IssuablesHelper params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] } end - def issuable_todo_button_data(issuable, todo, is_collapsed) + def issuable_todo_button_data(issuable, is_collapsed) { - todo_text: "Add todo", - mark_text: "Mark todo as done", - todo_icon: (is_collapsed ? sprite_icon('todo-add') : nil), - mark_icon: (is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : nil), - issuable_id: issuable.id, - issuable_type: issuable.class.name.underscore, - url: project_todos_path(@project), - delete_path: (dashboard_todo_path(todo) if todo), - placement: (is_collapsed ? 'left' : nil), - container: (is_collapsed ? 'body' : nil), - boundary: 'viewport' + todo_text: _('Add todo'), + mark_text: _('Mark todo as done'), + todo_icon: sprite_icon('todo-add'), + mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'), + issuable_id: issuable[:id], + issuable_type: issuable[:type], + create_path: issuable[:create_todo_path], + delete_path: issuable.dig(:current_user, :todo, :delete_path), + placement: is_collapsed ? 'left' : nil, + container: is_collapsed ? 'body' : nil, + boundary: 'viewport', + is_collapsed: is_collapsed } end @@ -418,27 +416,20 @@ module IssuablesHelper end end - def issuable_sidebar_options(issuable, can_edit_issuable) + def issuable_sidebar_options(issuable) { - endpoint: "#{issuable_json_path(issuable)}?serializer=sidebar", - toggleSubscriptionEndpoint: toggle_subscription_path(issuable), - moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable), - projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id), - editable: can_edit_issuable, - currentUser: UserSerializer.new.represent(current_user), + endpoint: "#{issuable[:issuable_json_path]}?serializer=sidebar_extras", + toggleSubscriptionEndpoint: issuable[:toggle_subscription_path], + moveIssueEndpoint: issuable[:move_issue_path], + projectsAutocompleteEndpoint: issuable[:projects_autocomplete_path], + editable: issuable.dig(:current_user, :can_edit), + currentUser: issuable[:current_user], rootPath: root_path, - fullPath: @project.full_path + fullPath: issuable[:project_full_path] } end def parent @project || @group end - - def issuable_milestone_tooltip_title(issuable) - if issuable.milestone - milestone_tooltip = milestone_tooltip_title(issuable.milestone) - _('Milestone') + (milestone_tooltip ? ': ' + milestone_tooltip : '') - end - end end diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index 9666080092b..327b69e5110 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -114,12 +114,6 @@ module MilestonesHelper end end - def milestone_tooltip_title(milestone) - if milestone - "#{milestone.title}<br />#{milestone_tooltip_due_date(milestone)}" - end - end - def milestone_time_for(date, date_type) title = date_type == :start ? "Start date" : "End date" @@ -173,7 +167,7 @@ module MilestonesHelper def milestone_tooltip_due_date(milestone) if milestone.due_date - "#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone)})" + "#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone.due_date, milestone.start_date)})" else _('Milestone') end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index aa54172e108..0cfc2db3285 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -271,6 +271,20 @@ module ProjectsHelper params[:legacy_render] ? { markdown_engine: :redcarpet } : {} end + def explore_projects_tab? + current_page?(explore_projects_path) || + current_page?(trending_explore_projects_path) || + current_page?(starred_explore_projects_path) + end + + def show_merge_request_count?(disabled: false, compact_mode: false) + !disabled && !compact_mode && Feature.enabled?(:project_list_show_mr_count, default_enabled: true) + end + + def show_issue_count?(disabled: false, compact_mode: false) + !disabled && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true) + end + private def get_project_nav_tabs(project, current_user) @@ -515,20 +529,6 @@ module ProjectsHelper end end - def explore_projects_tab? - current_page?(explore_projects_path) || - current_page?(trending_explore_projects_path) || - current_page?(starred_explore_projects_path) - end - - def show_merge_request_count?(merge_requests, compact_mode) - merge_requests && !compact_mode && Feature.enabled?(:project_list_show_mr_count, default_enabled: true) - end - - def show_issue_count?(issues, compact_mode) - issues && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true) - end - def sidebar_projects_paths %w[ projects#show diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 93b51fb1774..370e6d2f90b 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -56,7 +56,9 @@ module Emails @milestone = milestone @milestone_url = milestone_url(@milestone) - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id, reason)) + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id, reason).merge({ + template_name: 'changed_milestone_email' + })) end def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id, reason = nil) diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 6524d0c2087..9ba8f92fcbf 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -51,7 +51,9 @@ module Emails @milestone = milestone @milestone_url = milestone_url(@milestone) - mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason)) + mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason).merge({ + template_name: 'changed_milestone_email' + })) end def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 15710bee4d4..efa1233b434 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -16,6 +16,7 @@ class Notify < BaseMailer include Emails::AutoDevops include Emails::RemoteMirrors + helper MilestonesHelper helper MergeRequestsHelper helper DiffHelper helper BlobHelper diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 86ffd198ab1..88746375c67 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -302,7 +302,8 @@ class ApplicationSetting < ActiveRecord::Base user_show_add_ssh_key_message: true, usage_stats_set_by_user_id: nil, diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES, - commit_email_hostname: default_commit_email_hostname + commit_email_hostname: default_commit_email_hostname, + protected_ci_variables: false } end diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb index 277f7c2717c..2d237383e60 100644 --- a/app/models/broadcast_message.rb +++ b/app/models/broadcast_message.rb @@ -22,49 +22,30 @@ class BroadcastMessage < ActiveRecord::Base after_commit :flush_redis_cache def self.current - raw_messages = Rails.cache.fetch(CACHE_KEY, expires_in: cache_expires_in) do + messages = cache.fetch(CACHE_KEY, as: BroadcastMessage, expires_in: cache_expires_in) do remove_legacy_cache_key - current_and_future_messages.to_json + current_and_future_messages end - messages = decode_messages(raw_messages) - return [] unless messages&.present? now_or_future = messages.select(&:now_or_future?) # If there are cached entries but none are to be displayed we'll purge the # cache so we don't keep running this code all the time. - Rails.cache.delete(CACHE_KEY) if now_or_future.empty? + cache.expire(CACHE_KEY) if now_or_future.empty? now_or_future.select(&:now?) end - def self.decode_messages(raw_messages) - return unless raw_messages&.present? - - message_list = ActiveSupport::JSON.decode(raw_messages) - - return unless message_list.is_a?(Array) - - valid_attr = BroadcastMessage.attribute_names - - message_list.map do |raw| - BroadcastMessage.new(raw) if valid_cache_entry?(raw, valid_attr) - end.compact - rescue ActiveSupport::JSON.parse_error - end - - def self.valid_cache_entry?(raw, valid_attr) - return false unless raw.is_a?(Hash) - - (raw.keys - valid_attr).empty? - end - def self.current_and_future_messages where('ends_at > :now', now: Time.zone.now).order_id_asc end + def self.cache + Gitlab::JsonCache.new(cache_key_with_version: false) + end + def self.cache_expires_in nil end @@ -74,7 +55,7 @@ class BroadcastMessage < ActiveRecord::Base # environment a one-shot migration would not work because the cache # would be repopulated by a node that has not been upgraded. def self.remove_legacy_cache_key - Rails.cache.delete(LEGACY_CACHE_KEY) + cache.expire(LEGACY_CACHE_KEY) end def active? @@ -102,7 +83,7 @@ class BroadcastMessage < ActiveRecord::Base end def flush_redis_cache - Rails.cache.delete(CACHE_KEY) + self.class.cache.expire(CACHE_KEY) self.class.remove_legacy_cache_key end end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 3e5cedf92b9..8249199e76f 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -66,7 +66,7 @@ module Ci scope :belonging_to_parent_group_of_project, -> (project_id) { project_groups = ::Group.joins(:projects).where(projects: { id: project_id }) - hierarchy_groups = Gitlab::GroupHierarchy.new(project_groups).base_and_ancestors + hierarchy_groups = Gitlab::ObjectHierarchy.new(project_groups).base_and_ancestors joins(:groups).where(namespaces: { id: hierarchy_groups }) } diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 867f0edcb07..6cec497b4e4 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -228,7 +228,7 @@ module Clusters return unless namespace_changed? run_after_commit do - ClusterPlatformConfigureWorker.perform_async(cluster_id) + ClusterConfigureWorker.perform_async(cluster_id) end end end diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb index b42236c1fa2..4687ec7d166 100644 --- a/app/models/concerns/avatarable.rb +++ b/app/models/concerns/avatarable.rb @@ -43,7 +43,18 @@ module Avatarable end def avatar_path(only_path: true, size: nil) - return unless self[:avatar].present? + unless self.try(:id) + return uncached_avatar_path(only_path: only_path, size: size) + end + + # Cache this avatar path only within the request because avatars in + # object storage may be generated with time-limited, signed URLs. + key = "#{self.class.name}:#{self.id}:#{only_path}:#{size}" + Gitlab::SafeRequestStore[key] ||= uncached_avatar_path(only_path: only_path, size: size) + end + + def uncached_avatar_path(only_path: true, size: nil) + return unless self.try(:avatar).present? asset_host = ActionController::Base.asset_host use_asset_host = asset_host.present? diff --git a/app/models/concerns/descendant.rb b/app/models/concerns/descendant.rb new file mode 100644 index 00000000000..4c436522122 --- /dev/null +++ b/app/models/concerns/descendant.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Descendant + extend ActiveSupport::Concern + + class_methods do + def supports_nested_objects? + Gitlab::Database.postgresql? + end + end +end diff --git a/app/models/concerns/discussion_on_diff.rb b/app/models/concerns/discussion_on_diff.rb index 266c37fa3a1..86b61248534 100644 --- a/app/models/concerns/discussion_on_diff.rb +++ b/app/models/concerns/discussion_on_diff.rb @@ -39,6 +39,7 @@ module DiscussionOnDiff # Returns an array of at most 16 highlighted lines above a diff note def truncated_diff_lines(highlight: true, diff_limit: nil) + return [] unless on_text? return [] if diff_line.nil? && first_note.is_a?(LegacyDiffNote) diff_limit = [diff_limit, NUMBER_OF_TRUNCATED_DIFF_LINES].compact.min diff --git a/app/models/dashboard_group_milestone.rb b/app/models/dashboard_group_milestone.rb index 32e8104125c..ad0bb55f0a7 100644 --- a/app/models/dashboard_group_milestone.rb +++ b/app/models/dashboard_group_milestone.rb @@ -5,7 +5,6 @@ class DashboardGroupMilestone < GlobalMilestone attr_reader :group_name - override :initialize def initialize(milestone) super(milestone.title, Array(milestone)) diff --git a/app/models/environment.rb b/app/models/environment.rb index 934828946b9..cdfe3b7c023 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Environment < ActiveRecord::Base + include Gitlab::Utils::StrongMemoize # Used to generate random suffixes for the slug LETTERS = 'a'..'z' NUMBERS = '0'..'9' @@ -231,7 +232,9 @@ class Environment < ActiveRecord::Base end def deployment_platform - project.deployment_platform(environment: self.name) + strong_memoize(:deployment_platform) do + project.deployment_platform(environment: self.name) + end end private diff --git a/app/models/group.rb b/app/models/group.rb index 233747cc2c2..edac2444c4d 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -10,6 +10,7 @@ class Group < Namespace include Referable include SelectForProjectAuthorization include LoadedInGroupList + include Descendant include GroupDescendant include TokenAuthenticatable include WithUploads @@ -63,10 +64,6 @@ class Group < Namespace after_update :path_changed_hook, if: :path_changed? class << self - def supports_nested_groups? - Gitlab::Database.postgresql? - end - def sort_by_attribute(method) if method == 'storage_size_desc' # storage_size is a virtual column so we need to diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 3c9b1d32a53..a0bebc5e9a2 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -175,16 +175,16 @@ class Namespace < ActiveRecord::Base # Returns all ancestors, self, and descendants of the current namespace. def self_and_hierarchy - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(self.class.where(id: id)) - .all_groups + .all_objects end # Returns all the ancestors of the current namespaces. def ancestors return self.class.none unless parent_id - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(self.class.where(id: parent_id)) .base_and_ancestors end @@ -192,27 +192,27 @@ class Namespace < ActiveRecord::Base # returns all ancestors upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned def ancestors_upto(top = nil, hierarchy_order: nil) - Gitlab::GroupHierarchy.new(self.class.where(id: id)) + Gitlab::ObjectHierarchy.new(self.class.where(id: id)) .ancestors(upto: top, hierarchy_order: hierarchy_order) end def self_and_ancestors return self.class.where(id: id) unless parent_id - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(self.class.where(id: id)) .base_and_ancestors end # Returns all the descendants of the current namespace. def descendants - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(self.class.where(parent_id: id)) .base_and_descendants end def self_and_descendants - Gitlab::GroupHierarchy + Gitlab::ObjectHierarchy .new(self.class.where(id: id)) .base_and_descendants end @@ -293,7 +293,7 @@ class Namespace < ActiveRecord::Base end def force_share_with_group_lock_on_descendants - return unless Group.supports_nested_groups? + return unless Group.supports_nested_objects? # We can't use `descendants.update_all` since Rails will throw away the WITH # RECURSIVE statement. We also can't use WHERE EXISTS since we can't use @@ -306,6 +306,7 @@ class Namespace < ActiveRecord::Base def write_projects_repository_config all_projects.find_each do |project| project.write_repository_config + project.track_project_repository end end end diff --git a/app/models/pool_repository.rb b/app/models/pool_repository.rb index 47da0209c2f..ad6a008dee8 100644 --- a/app/models/pool_repository.rb +++ b/app/models/pool_repository.rb @@ -18,6 +18,7 @@ class PoolRepository < ActiveRecord::Base state :scheduled state :ready state :failed + state :obsolete event :schedule do transition none: :scheduled @@ -31,6 +32,10 @@ class PoolRepository < ActiveRecord::Base transition all => :failed end + event :mark_obsolete do + transition all => :obsolete + end + state all - [:ready] do def joinable? false @@ -54,6 +59,12 @@ class PoolRepository < ActiveRecord::Base ::ObjectPool::ScheduleJoinWorker.perform_async(pool.id) end end + + after_transition any => :obsolete do |pool, _| + pool.run_after_commit do + ::ObjectPool::DestroyWorker.perform_async(pool.id) + end + end end def create_object_pool @@ -71,10 +82,10 @@ class PoolRepository < ActiveRecord::Base end # This RPC can cause data loss, as not all objects are present the local repository - # No execution path yet, will be added through: - # https://gitlab.com/gitlab-org/gitaly/issues/1415 - def delete_repository_alternate(repository) + def unlink_repository(repository) object_pool.unlink_repository(repository.raw) + + mark_obsolete unless member_projects.where.not(id: repository.project.id).exists? end def object_pool diff --git a/app/models/project.rb b/app/models/project.rb index 67262ecce85..09e2a6114fe 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -256,7 +256,7 @@ class Project < ActiveRecord::Base # other pipelines, like webide ones, that we won't retrieve # if we use this relation. has_many :ci_pipelines, - -> { Feature.enabled?(:pipeline_ci_sources_only, default_enabled: true) ? ci_sources : all }, + -> { ci_sources }, class_name: 'Ci::Pipeline', inverse_of: :project has_many :stages, class_name: 'Ci::Stage', inverse_of: :project @@ -570,7 +570,7 @@ class Project < ActiveRecord::Base # returns all ancestor-groups upto but excluding the given namespace # when no namespace is given, all ancestors upto the top are returned def ancestors_upto(top = nil, hierarchy_order: nil) - Gitlab::GroupHierarchy.new(Group.where(id: namespace_id)) + Gitlab::ObjectHierarchy.new(Group.where(id: namespace_id)) .base_and_ancestors(upto: top, hierarchy_order: hierarchy_order) end @@ -1244,10 +1244,8 @@ class Project < ActiveRecord::Base end def track_project_repository - return unless hashed_storage?(:repository) - - project_repo = project_repository || build_project_repository - project_repo.update!(shard_name: repository_storage, disk_path: disk_path) + repository = project_repository || build_project_repository + repository.update!(shard_name: repository_storage, disk_path: disk_path) end def create_repository(force: false) @@ -2004,6 +2002,10 @@ class Project < ActiveRecord::Base Feature.enabled?(:object_pools, self) end + def leave_pool_repository + pool_repository&.unlink_repository(repository) + end + private def create_new_pool_repository diff --git a/app/models/user.rb b/app/models/user.rb index f20756d1cc3..26fd2d903a1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -709,13 +709,13 @@ class User < ActiveRecord::Base # Returns the groups a user is a member of, either directly or through a parent group def membership_groups - Gitlab::GroupHierarchy.new(groups).base_and_descendants + Gitlab::ObjectHierarchy.new(groups).base_and_descendants end # Returns a relation of groups the user has access to, including their parent # and child groups (recursively). def all_expanded_groups - Gitlab::GroupHierarchy.new(groups).all_groups + Gitlab::ObjectHierarchy.new(groups).all_objects end def expanded_groups_requiring_two_factor_authentication @@ -1153,7 +1153,7 @@ class User < ActiveRecord::Base end def manageable_groups - Gitlab::GroupHierarchy.new(owned_or_maintainers_groups).base_and_descendants + Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants end def namespaces @@ -1422,6 +1422,10 @@ class User < ActiveRecord::Base todos.where(id: ids) end + def pending_todo_for(target) + todos.find_by(target: target, state: :pending) + end + # @deprecated alias_method :owned_or_masters_groups, :owned_or_maintainers_groups diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index d1264559438..f07bb188265 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -16,7 +16,7 @@ class GroupPolicy < BasePolicy condition(:maintainer) { access_level >= GroupMember::MAINTAINER } condition(:reporter) { access_level >= GroupMember::REPORTER } - condition(:nested_groups_supported, scope: :global) { Group.supports_nested_groups? } + condition(:nested_groups_supported, scope: :global) { Group.supports_nested_objects? } condition(:has_parent, scope: :subject) { @subject.has_parent? } condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? } diff --git a/app/serializers/entity_date_helper.rb b/app/serializers/entity_date_helper.rb index cc0c2abf863..f515abe5917 100644 --- a/app/serializers/entity_date_helper.rb +++ b/app/serializers/entity_date_helper.rb @@ -44,14 +44,14 @@ module EntityDateHelper # It returns "Upcoming" for upcoming entities # If due date is provided, it returns "# days|weeks|months remaining|ago" # If start date is provided and elapsed, with no due date, it returns "# days elapsed" - def remaining_days_in_words(entity) - if entity.try(:expired?) + def remaining_days_in_words(due_date, start_date = nil) + if due_date&.past? content_tag(:strong, 'Past due') - elsif entity.try(:upcoming?) + elsif start_date&.future? content_tag(:strong, 'Upcoming') - elsif entity.due_date - is_upcoming = (entity.due_date - Date.today).to_i > 0 - time_ago = time_ago_in_words(entity.due_date) + elsif due_date + is_upcoming = (due_date - Date.today).to_i > 0 + time_ago = time_ago_in_words(due_date) # https://gitlab.com/gitlab-org/gitlab-ce/issues/49440 # @@ -63,8 +63,8 @@ module EntityDateHelper remaining_or_ago = is_upcoming ? _("remaining") : _("ago") "#{content} #{remaining_or_ago}".html_safe - elsif entity.start_date && entity.start_date.past? - days = entity.elapsed_days + elsif start_date&.past? + days = (Date.today - start_date).to_i "#{content_tag(:strong, days)} #{'day'.pluralize(days)} elapsed".html_safe end end diff --git a/app/serializers/environment_entity.rb b/app/serializers/environment_entity.rb index 07a13c33b89..4a7d13915dd 100644 --- a/app/serializers/environment_entity.rb +++ b/app/serializers/environment_entity.rb @@ -23,6 +23,10 @@ class EnvironmentEntity < Grape::Entity stop_project_environment_path(environment.project, environment) end + expose :cluster_type, if: ->(environment, _) { cluster_platform_kubernetes? } do |environment| + cluster.cluster_type + end + expose :terminal_path, if: ->(*) { environment.has_terminals? && can_access_terminal? } do |environment| terminal_project_environment_path(environment.project, environment) end @@ -48,4 +52,16 @@ class EnvironmentEntity < Grape::Entity def can_access_terminal? can?(request.current_user, :create_environment_terminal, environment) end + + def cluster_platform_kubernetes? + deployment_platform && deployment_platform.is_a?(Clusters::Platforms::Kubernetes) + end + + def deployment_platform + environment.deployment_platform + end + + def cluster + deployment_platform.cluster + end end diff --git a/app/serializers/issuable_sidebar_basic_entity.rb b/app/serializers/issuable_sidebar_basic_entity.rb new file mode 100644 index 00000000000..61de3c93337 --- /dev/null +++ b/app/serializers/issuable_sidebar_basic_entity.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +class IssuableSidebarBasicEntity < Grape::Entity + include RequestAwareEntity + + expose :id + expose :type do |issuable| + issuable.to_ability_name + end + expose :author_id + expose :project_id do |issuable| + issuable.project.id + end + expose :discussion_locked + expose :reference do |issuable| + issuable.to_reference(issuable.project, full: true) + end + + expose :milestone, using: ::API::Entities::Milestone + expose :labels, using: LabelEntity + + expose :current_user, if: lambda { |_issuable| current_user } do + expose :current_user, merge: true, using: API::Entities::UserBasic + + expose :todo, using: IssuableSidebarTodoEntity do |issuable| + current_user.pending_todo_for(issuable) + end + + expose :can_edit do |issuable| + can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project) + end + + expose :can_move do |issuable| + issuable.can_move?(current_user) + end + + expose :can_admin_label do |issuable| + can?(current_user, :admin_label, issuable.project) + end + end + + expose :issuable_json_path do |issuable| + if issuable.is_a?(MergeRequest) + project_merge_request_path(issuable.project, issuable.iid, :json) + else + project_issue_path(issuable.project, issuable.iid, :json) + end + end + + expose :namespace_path do |issuable| + issuable.project.namespace.full_path + end + + expose :project_path do |issuable| + issuable.project.path + end + + expose :project_full_path do |issuable| + issuable.project.full_path + end + + expose :project_issuables_path do |issuable| + project = issuable.project + namespace = project.namespace + + if issuable.is_a?(MergeRequest) + namespace_project_merge_requests_path(namespace, project) + else + namespace_project_issues_path(namespace, project) + end + end + + expose :create_todo_path do |issuable| + project_todos_path(issuable.project) + end + + expose :project_milestones_path do |issuable| + project_milestones_path(issuable.project, :json) + end + + expose :project_labels_path do |issuable| + project_labels_path(issuable.project, :json, include_ancestor_groups: true) + end + + expose :toggle_subscription_path do |issuable| + toggle_subscription_path(issuable) + end + + expose :move_issue_path do |issuable| + move_namespace_project_issue_path( + namespace_id: issuable.project.namespace.to_param, + project_id: issuable.project, + id: issuable + ) + end + + expose :projects_autocomplete_path do |issuable| + autocomplete_projects_path(project_id: issuable.project.id) + end + + private + + def current_user + request.current_user + end +end diff --git a/app/serializers/issuable_sidebar_entity.rb b/app/serializers/issuable_sidebar_extras_entity.rb index 773d78d324c..d60253564e1 100644 --- a/app/serializers/issuable_sidebar_entity.rb +++ b/app/serializers/issuable_sidebar_extras_entity.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class IssuableSidebarEntity < Grape::Entity - include TimeTrackableEntity +class IssuableSidebarExtrasEntity < Grape::Entity include RequestAwareEntity + include TimeTrackableEntity expose :participants, using: ::API::Entities::UserBasic do |issuable| issuable.participants(request.current_user) diff --git a/app/serializers/issuable_sidebar_todo_entity.rb b/app/serializers/issuable_sidebar_todo_entity.rb new file mode 100644 index 00000000000..b2c98433f05 --- /dev/null +++ b/app/serializers/issuable_sidebar_todo_entity.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class IssuableSidebarTodoEntity < Grape::Entity + include Gitlab::Routing + + expose :id + + expose :delete_path do |todo| + dashboard_todo_path(todo) if todo + end +end diff --git a/app/serializers/issue_board_entity.rb b/app/serializers/issue_board_entity.rb index e3dc43240c6..f7719447b92 100644 --- a/app/serializers/issue_board_entity.rb +++ b/app/serializers/issue_board_entity.rb @@ -37,7 +37,7 @@ class IssueBoardEntity < Grape::Entity end expose :issue_sidebar_endpoint, if: -> (issue) { issue.project } do |issue| - project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar') + project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar_extras') end expose :toggle_subscription_endpoint, if: -> (issue) { issue.project } do |issue| diff --git a/app/serializers/issue_serializer.rb b/app/serializers/issue_serializer.rb index d66f0a5acb7..0fa76f098cd 100644 --- a/app/serializers/issue_serializer.rb +++ b/app/serializers/issue_serializer.rb @@ -2,13 +2,15 @@ class IssueSerializer < BaseSerializer # This overrided method takes care of which entity should be used - # to serialize the `issue` based on `basic` key in `opts` param. + # to serialize the `issue` based on `serializer` key in `opts` param. # Hence, `entity` doesn't need to be declared on the class scope. def represent(issue, opts = {}) entity = case opts[:serializer] when 'sidebar' - IssueSidebarEntity + IssueSidebarBasicEntity + when 'sidebar_extras' + IssueSidebarExtrasEntity when 'board' IssueBoardEntity else diff --git a/app/serializers/issue_sidebar_basic_entity.rb b/app/serializers/issue_sidebar_basic_entity.rb new file mode 100644 index 00000000000..723875809ec --- /dev/null +++ b/app/serializers/issue_sidebar_basic_entity.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class IssueSidebarBasicEntity < IssuableSidebarBasicEntity + expose :due_date + expose :confidential +end diff --git a/app/serializers/issue_sidebar_entity.rb b/app/serializers/issue_sidebar_extras_entity.rb index 349ad9d1fef..7b6e860140b 100644 --- a/app/serializers/issue_sidebar_entity.rb +++ b/app/serializers/issue_sidebar_extras_entity.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class IssueSidebarEntity < IssuableSidebarEntity +class IssueSidebarExtrasEntity < IssuableSidebarExtrasEntity expose :assignees, using: API::Entities::UserBasic end diff --git a/app/serializers/merge_request_basic_entity.rb b/app/serializers/merge_request_basic_entity.rb index f7eb74cf392..084627f9dbe 100644 --- a/app/serializers/merge_request_basic_entity.rb +++ b/app/serializers/merge_request_basic_entity.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class MergeRequestBasicEntity < IssuableSidebarEntity +class MergeRequestBasicEntity < Grape::Entity expose :assignee_id expose :merge_status expose :merge_error diff --git a/app/serializers/merge_request_basic_serializer.rb b/app/serializers/merge_request_basic_serializer.rb deleted file mode 100644 index a68b48b00db..00000000000 --- a/app/serializers/merge_request_basic_serializer.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -class MergeRequestBasicSerializer < BaseSerializer - entity MergeRequestBasicEntity -end diff --git a/app/serializers/merge_request_serializer.rb b/app/serializers/merge_request_serializer.rb index 1f8c830e1aa..4cf84336aa4 100644 --- a/app/serializers/merge_request_serializer.rb +++ b/app/serializers/merge_request_serializer.rb @@ -7,9 +7,14 @@ class MergeRequestSerializer < BaseSerializer def represent(merge_request, opts = {}) entity = case opts[:serializer] - when 'basic', 'sidebar' + when 'sidebar' + MergeRequestSidebarBasicEntity + when 'sidebar_extras' + IssuableSidebarExtrasEntity + when 'basic' MergeRequestBasicEntity - else # It's 'widget' + else + # fallback to widget for old poll requests without `serializer` set MergeRequestWidgetEntity end diff --git a/app/serializers/merge_request_sidebar_basic_entity.rb b/app/serializers/merge_request_sidebar_basic_entity.rb new file mode 100644 index 00000000000..0ae7298a7c1 --- /dev/null +++ b/app/serializers/merge_request_sidebar_basic_entity.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class MergeRequestSidebarBasicEntity < IssuableSidebarBasicEntity + expose :assignee, if: lambda { |issuable| issuable.assignee } do + expose :assignee, merge: true, using: API::Entities::UserBasic + + expose :can_merge do |issuable| + issuable.can_be_merged_by?(issuable.assignee) + end + end +end diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 13321b2682e..6707a1363d0 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -118,7 +118,7 @@ module Ci # Workaround for weird Rails bug, that makes `runner.groups.to_sql` to return `runner_id = NULL` groups = ::Group.joins(:runner_namespaces).merge(runner.runner_namespaces) - hierarchy_groups = Gitlab::GroupHierarchy.new(groups).base_and_descendants + hierarchy_groups = Gitlab::ObjectHierarchy.new(groups).base_and_descendants projects = Project.where(namespace_id: hierarchy_groups) .with_group_runners_enabled .with_builds_enabled diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index a4e44d009c0..5525c1b9b7f 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -13,7 +13,7 @@ module Clusters configure_kubernetes cluster.save! - ClusterPlatformConfigureWorker.perform_async(cluster.id) + ClusterConfigureWorker.perform_async(cluster.id) rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e log_service_error(e.class.name, provider.id, e.message) diff --git a/app/services/deploy_keys/create_service.rb b/app/services/deploy_keys/create_service.rb index a25e73666f8..0c935285657 100644 --- a/app/services/deploy_keys/create_service.rb +++ b/app/services/deploy_keys/create_service.rb @@ -2,7 +2,7 @@ module DeployKeys class CreateService < Keys::BaseService - def execute + def execute(project: nil) DeployKey.create(params.merge(user: user)) end end diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb index 50d34d8cb91..f01f5656296 100644 --- a/app/services/groups/nested_create_service.rb +++ b/app/services/groups/nested_create_service.rb @@ -18,7 +18,7 @@ module Groups return namespace end - if group_path.include?('/') && !Group.supports_nested_groups? + if group_path.include?('/') && !Group.supports_nested_objects? raise 'Nested groups are not supported on MySQL' end diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb index 5efa746dfb9..f64e327416a 100644 --- a/app/services/groups/transfer_service.rb +++ b/app/services/groups/transfer_service.rb @@ -40,7 +40,7 @@ module Groups def ensure_allowed_transfer raise_transfer_error(:group_is_already_root) if group_is_already_root? - raise_transfer_error(:database_not_supported) unless Group.supports_nested_groups? + raise_transfer_error(:database_not_supported) unless Group.supports_nested_objects? raise_transfer_error(:same_parent_as_current) if same_parent? raise_transfer_error(:invalid_policies) unless valid_policies? raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path? diff --git a/app/services/projects/after_rename_service.rb b/app/services/projects/after_rename_service.rb index 4131da44f5a..aa9b253eb20 100644 --- a/app/services/projects/after_rename_service.rb +++ b/app/services/projects/after_rename_service.rb @@ -81,6 +81,7 @@ module Projects def update_repository_configuration project.reload_repository! project.write_repository_config + project.track_project_repository end def rename_transferred_documents diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 210571b6b4e..336d029d330 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -137,6 +137,8 @@ module Projects raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') end + project.leave_pool_repository + Project.transaction do log_destroy_event trash_repositories! diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 9db3fd9cf17..5da1e39a1fb 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -81,7 +81,7 @@ module Projects project.old_path_with_namespace = @old_path - write_repository_config(@new_path) + update_repository_configuration(@new_path) execute_system_hooks end @@ -106,8 +106,9 @@ module Projects project.save! end - def write_repository_config(full_path) + def update_repository_configuration(full_path) project.write_repository_config(gl_full_path: full_path) + project.track_project_repository end def refresh_permissions @@ -123,7 +124,7 @@ module Projects rollback_folder_move project.reload update_namespace_and_visibility(@old_namespace) - write_repository_config(@old_path) + update_repository_configuration(@old_path) end def rollback_folder_move diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb index 23b63aaabdf..fe5a82e23fa 100644 --- a/app/services/users/refresh_authorized_projects_service.rb +++ b/app/services/users/refresh_authorized_projects_service.rb @@ -102,7 +102,7 @@ module Users end def fresh_authorizations - klass = if Group.supports_nested_groups? + klass = if Group.supports_nested_objects? Gitlab::ProjectAuthorizations::WithNestedGroups else Gitlab::ProjectAuthorizations::WithoutNestedGroups diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml index 0d42094fc89..fdaad1cf181 100644 --- a/app/views/admin/application_settings/_ci_cd.html.haml +++ b/app/views/admin/application_settings/_ci_cd.html.haml @@ -49,5 +49,12 @@ Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>. + .form-group + .form-check + = f.check_box :protected_ci_variables, class: 'form-check-input' + = f.label :protected_ci_variables, class: 'form-check-label' do + = s_('AdminSettings|Environment variables are protected by default') + .form-text.text-muted + = s_('AdminSettings|When creating a new environment variable it will be protected by default.') = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/ci/variables/_content.html.haml b/app/views/ci/variables/_content.html.haml index d355e7799df..fa82611d9c1 100644 --- a/app/views/ci/variables/_content.html.haml +++ b/app/views/ci/variables/_content.html.haml @@ -1 +1 @@ -= _('Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want.') += _('Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want.') diff --git a/app/views/ci/variables/_header.html.haml b/app/views/ci/variables/_header.html.haml new file mode 100644 index 00000000000..cb7779e2175 --- /dev/null +++ b/app/views/ci/variables/_header.html.haml @@ -0,0 +1,11 @@ +- expanded = local_assigns.fetch(:expanded) + +%h4 + = _('Environment variables') + = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer' + +%button.btn.btn-default.js-settings-toggle{ type: 'button' } + = expanded ? _('Collapse') : _('Expand') + +%p.append-bottom-0 + = render "ci/variables/content" diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml index f34305e94fa..dc9ccb6cc39 100644 --- a/app/views/ci/variables/_index.html.haml +++ b/app/views/ci/variables/_index.html.haml @@ -1,5 +1,10 @@ - save_endpoint = local_assigns.fetch(:save_endpoint, nil) +- if ci_variable_protected_by_default? + %p.settings-message.text-center + - link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protected-variables') } + = s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe } + .row .col-lg-12.js-ci-variable-list-section{ data: { save_endpoint: save_endpoint } } .hide.alert.alert-danger.js-ci-variable-error-box diff --git a/app/views/ci/variables/_variable_row.html.haml b/app/views/ci/variables/_variable_row.html.haml index 6ee55836dd2..16a7527c8ce 100644 --- a/app/views/ci/variables/_variable_row.html.haml +++ b/app/views/ci/variables/_variable_row.html.haml @@ -5,7 +5,8 @@ - id = variable&.id - key = variable&.key - value = variable&.value -- is_protected = variable && !only_key_value ? variable.protected : false +- is_protected_default = ci_variable_protected_by_default? +- is_protected = ci_variable_protected?(variable, only_key_value) - id_input_name = "#{form_field}[variables_attributes][][id]" - destroy_input_name = "#{form_field}[variables_attributes][][_destroy]" @@ -39,7 +40,8 @@ %input{ type: "hidden", class: 'js-ci-variable-input-protected js-project-feature-toggle-input', name: protected_input_name, - value: is_protected } + value: is_protected, + data: { default: is_protected_default.to_s } } %span.toggle-icon = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml index a5e6abdba52..d9332e36ef5 100644 --- a/app/views/groups/settings/ci_cd/show.html.haml +++ b/app/views/groups/settings/ci_cd/show.html.haml @@ -5,13 +5,7 @@ %section.settings#ci-variables.no-animate{ class: ('expanded' if expanded) } .settings-header - %h4 - = _('Variables') - = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer' - %button.btn.btn-default.js-settings-toggle{ type: "button" } - = expanded ? _('Collapse') : _('Expand') - %p.append-bottom-0 - = render "ci/variables/content" + = render 'ci/variables/header', expanded: expanded .settings-content = render 'ci/variables/index', save_endpoint: group_variables_path diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index a86972d8cf3..a6023a1cbb9 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -2,7 +2,7 @@ - group_data_attrs = { group_path: j(@group.path), name: @group.name, issues_path: issues_group_path(j(@group.path)), mr_path: merge_requests_group_path(j(@group.path)) } - if @project && @project.persisted? - project_data_attrs = { project_path: j(@project.path), name: j(@project.name), issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project), issues_disabled: !@project.issues_enabled? } -.search.search-form +.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input" } } = form_tag search_path, method: :get, class: 'form-inline' do |f| .search-input-container .search-input-wrap diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 4f8db74382f..6003d973c88 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -1,7 +1,7 @@ !!! 5 %html.devise-layout-html{ class: system_message_class } = render "layouts/head" - %body.ui-indigo.login-page.application.navless{ data: { page: body_data_page } } + %body.ui-indigo.login-page.application.navless.qa-login-page{ data: { page: body_data_page } } .page-wrap = render "layouts/header/empty" .login-page-broadcast diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index e8d0d809181..a9b85889846 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -60,7 +60,7 @@ .dropdown-menu.dropdown-menu-right = render 'layouts/header/help_dropdown' - if header_link?(:user_dropdown) - %li.nav-item.header-user.dropdown + %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown" } } = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar" = sprite_icon('angle-down', css_class: 'caret-down') diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml index 5cb8aebadb3..e42251f9ec8 100644 --- a/app/views/layouts/header/_new_dropdown.haml +++ b/app/views/layouts/header/_new_dropdown.haml @@ -1,4 +1,4 @@ -%li.header-new.dropdown +%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown" } } = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", title: _("New..."), ref: 'tooltip', aria: { label: _("New...") }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do = sprite_icon('plus-square', size: 16) = sprite_icon('angle-down', css_class: 'caret-down') diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 7057a5a142f..ddd30efe062 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -2,7 +2,7 @@ -# https://gitlab.com/gitlab-org/gitlab-ce/issues/49713 for more information. %ul.list-unstyled.navbar-sub-nav - if dashboard_nav_link?(:projects) - = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown" }) do + = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown" } }) do %button{ type: 'button', data: { toggle: "dropdown" } } = _('Projects') = sprite_icon('angle-down', css_class: 'caret-down') @@ -10,7 +10,7 @@ = render "layouts/nav/projects_dropdown/show" - if dashboard_nav_link?(:groups) - = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown" }) do + = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown" } }) do %button{ type: 'button', data: { toggle: "dropdown" } } = _('Groups') = sprite_icon('angle-down', css_class: 'caret-down') diff --git a/app/views/notify/_note_email.html.haml b/app/views/notify/_note_email.html.haml index 1fbae2f64ed..83c7f548975 100644 --- a/app/views/notify/_note_email.html.haml +++ b/app/views/notify/_note_email.html.haml @@ -4,17 +4,13 @@ - note_style = local_assigns.fetch(:note_style, "") - discussion = note.discussion if note.part_of_discussion? -- diff_discussion = discussion&.diff_discussion? -- on_image = discussion.on_image? if diff_discussion - if discussion - - phrase_end_char = on_image ? "." : ":" - %p{ style: "color: #777777;" } - = succeed phrase_end_char do + = succeed ':' do = link_to note.author_name, user_url(note.author) - - if diff_discussion + - if discussion&.diff_discussion? - if discussion.new_discussion? started a new discussion - else @@ -31,7 +27,7 @@ %p.details #{link_to note.author_name, user_url(note.author)} commented: -- if diff_discussion && !on_image +- if discussion&.diff_discussion? && discussion.on_text? = content_for :head do = stylesheet_link_tag 'mailers/highlighted_diff_email' diff --git a/app/views/notify/_note_email.text.erb b/app/views/notify/_note_email.text.erb index 4bf252b6ce1..50209c46ed1 100644 --- a/app/views/notify/_note_email.text.erb +++ b/app/views/notify/_note_email.text.erb @@ -20,7 +20,7 @@ <% end -%> -<% if discussion&.diff_discussion? -%> +<% if discussion&.diff_discussion? && discussion.on_text? -%> <% discussion.truncated_diff_lines(highlight: false, diff_limit: diff_limit).each do |line| -%> <%= "> #{line.text}\n" -%> <% end -%> diff --git a/app/views/notify/changed_milestone_merge_request_email.html.haml b/app/views/notify/changed_milestone_email.html.haml index 7d5425fc72d..01d27cac36b 100644 --- a/app/views/notify/changed_milestone_merge_request_email.html.haml +++ b/app/views/notify/changed_milestone_email.html.haml @@ -1,3 +1,5 @@ %p Milestone changed to %strong= link_to(@milestone.name, @milestone_url) + - if date_range = milestone_date_range(@milestone) + = "(#{date_range})" diff --git a/app/views/notify/changed_milestone_email.text.erb b/app/views/notify/changed_milestone_email.text.erb new file mode 100644 index 00000000000..a466da4eb19 --- /dev/null +++ b/app/views/notify/changed_milestone_email.text.erb @@ -0,0 +1 @@ +Milestone changed to <%= @milestone.name %><% if date_range = milestone_date_range(@milestone) %> (<%= date_range %>)<% end %> ( <%= @milestone_url %> ) diff --git a/app/views/notify/changed_milestone_issue_email.html.haml b/app/views/notify/changed_milestone_issue_email.html.haml deleted file mode 100644 index 7d5425fc72d..00000000000 --- a/app/views/notify/changed_milestone_issue_email.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%p - Milestone changed to - %strong= link_to(@milestone.name, @milestone_url) diff --git a/app/views/notify/changed_milestone_issue_email.text.erb b/app/views/notify/changed_milestone_issue_email.text.erb deleted file mode 100644 index c5fc0b61518..00000000000 --- a/app/views/notify/changed_milestone_issue_email.text.erb +++ /dev/null @@ -1 +0,0 @@ -Milestone changed to <%= @milestone.name %> ( <%= @milestone_url %> ) diff --git a/app/views/notify/changed_milestone_merge_request_email.text.erb b/app/views/notify/changed_milestone_merge_request_email.text.erb deleted file mode 100644 index c5fc0b61518..00000000000 --- a/app/views/notify/changed_milestone_merge_request_email.text.erb +++ /dev/null @@ -1 +0,0 @@ -Milestone changed to <%= @milestone.name %> ( <%= @milestone_url %> ) diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml index d453a3a9dac..53d427ec40a 100644 --- a/app/views/projects/buttons/_clone.html.haml +++ b/app/views/projects/buttons/_clone.html.haml @@ -1,25 +1,22 @@ - project = project || @project .git-clone-holder.js-git-clone-holder.input-group - - if allowed_protocols_present? - .input-group-text.clone-dropdown-btn.btn - %span.js-clone-dropdown-label - = enabled_project_button(project, enabled_protocol) - - else - %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } } - %span.append-right-4.js-clone-dropdown-label - = _('Clone') - = sprite_icon("arrow-down", css_class: "icon") + %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } } + %span.append-right-4.js-clone-dropdown-label + = _('Clone') + = sprite_icon("arrow-down", css_class: "icon") %form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options - %li.pb-2 - %label.label-bold - = _('Clone with SSH') - .input-group - = text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control qa-ssh-clone-url", readonly: true, aria: { label: 'Project clone URL' } - .input-group-append - = clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard") - = render_if_exists 'projects/buttons/geo' - %li + - if ssh_enabled? + %li.pb-2 + %label.label-bold + = _('Clone with SSH') + .input-group + = text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control qa-ssh-clone-url", readonly: true, aria: { label: 'Project clone URL' } + .input-group-append + = clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard") + = render_if_exists 'projects/buttons/geo' + %li + - if http_enabled? %label.label-bold = _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase } .input-group diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index b50b3ca207b..8c2fe2625c7 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -88,4 +88,4 @@ %section.issuable-discussion = render 'projects/issues/discussion' -= render 'shared/issuable/sidebar', issuable: @issue += render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @issue.assignees diff --git a/app/views/projects/merge_requests/conflicts.html.haml b/app/views/projects/merge_requests/conflicts.html.haml deleted file mode 100644 index a6e2565a485..00000000000 --- a/app/views/projects/merge_requests/conflicts.html.haml +++ /dev/null @@ -1,36 +0,0 @@ -- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" -- content_for :page_specific_javascripts do - = page_specific_javascript_tag('lib/ace.js') -= render "projects/merge_requests/mr_title" - -.merge-request-details.issuable-details - = render "projects/merge_requests/mr_box" - -= render 'shared/issuable/sidebar', issuable: @merge_request - -#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json), - resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } } - .loading{ "v-if" => "isLoading" } - %i.fa.fa-spinner.fa-spin - - .nothing-here-block{ "v-if" => "hasError" } - {{conflictsData.errorMessage}} - - = render partial: "projects/merge_requests/conflicts/commit_stats" - - .files-wrapper{ "v-if" => "!isLoading && !hasError" } - .files - .diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" } - .js-file-title.file-title - %i.fa.fa-fw{ ":class" => "file.iconClass" } - %strong {{file.filePath}} - = render partial: 'projects/merge_requests/conflicts/file_actions' - .diff-content.diff-wrap-lines - .diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "!isParallel && file.resolveMode === 'interactive' && file.type === 'text'" } - = render partial: "projects/merge_requests/conflicts/components/inline_conflict_lines" - .diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "isParallel && file.resolveMode === 'interactive' && file.type === 'text'" } - %parallel-conflict-lines{ ":file" => "file" } - %div{ "v-show" => "file.resolveMode === 'edit' || file.type === 'text-editor'" } - = render partial: "projects/merge_requests/conflicts/components/diff_file_editor" - - = render partial: "projects/merge_requests/conflicts/submit_form" diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml index a6e2565a485..09aeb81671a 100644 --- a/app/views/projects/merge_requests/conflicts/show.html.haml +++ b/app/views/projects/merge_requests/conflicts/show.html.haml @@ -6,7 +6,7 @@ .merge-request-details.issuable-details = render "projects/merge_requests/mr_box" -= render 'shared/issuable/sidebar', issuable: @merge_request += render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees #conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json), resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } } diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index cc9292b54d7..d6f340d0ee2 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -86,7 +86,8 @@ .mr-loading-status = spinner -= render 'shared/issuable/sidebar', issuable: @merge_request += render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees + - if @merge_request.can_be_reverted?(current_user) = render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title - if @merge_request.can_be_cherry_picked? diff --git a/app/views/projects/releases/index.html.haml b/app/views/projects/releases/index.html.haml index 7bc942a3c3c..f01d4e826b9 100644 --- a/app/views/projects/releases/index.html.haml +++ b/app/views/projects/releases/index.html.haml @@ -1,5 +1,5 @@ - @no_container = true - page_title _('Releases') -%div{ 'class' => container_class } - #js-releases-page +%div{ class: container_class } + #js-releases-page{ data: { project_id: @project.id, illustration_path: image_path('illustrations/releases.svg'), documentation_path: help_page_path('user/project/releases') } } diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml index 98e2829ba43..6966bf96724 100644 --- a/app/views/projects/settings/ci_cd/show.html.haml +++ b/app/views/projects/settings/ci_cd/show.html.haml @@ -43,13 +43,7 @@ %section.qa-variables-settings.settings.no-animate{ class: ('expanded' if expanded) } .settings-header - %h4 - = _('Variables') - = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer' - %button.btn.js-settings-toggle{ type: 'button' } - = expanded ? _('Collapse') : _('Expand') - %p.append-bottom-0 - = render "ci/variables/content" + = render 'ci/variables/header', expanded: expanded .settings-content = render 'ci/variables/index', save_endpoint: project_variables_path(@project) diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml index b43662947a8..6e2527bd1a1 100644 --- a/app/views/shared/_mobile_clone_panel.html.haml +++ b/app/views/shared/_mobile_clone_panel.html.haml @@ -7,7 +7,9 @@ %button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { toggle: "dropdown" } } = sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon") %ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } } - %li - = dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true) - %li - = dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' }) + - if ssh_enabled? + %li + = dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true) + - if http_enabled? + %li + = dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' }) diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 9eecfa39390..0520eda37a4 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -1,32 +1,37 @@ -- todo = issuable_todo(issuable) +-# `assignees` is being passed in for populating selected assignee values in the select box and rendering the assignee link + This should be removed when this sidebar is converted to Vue since assignee data is also available in the `issuable_sidebar` hash -%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' } - .issuable-sidebar{ data: { endpoint: "#{issuable_json_path(issuable)}" } } - - can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project) +- issuable_type = issuable_sidebar[:type] +- signed_in = !!issuable_sidebar.dig(:current_user, :id) +- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit) + +%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: signed_in } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' } + .issuable-sidebar .block.issuable-sidebar-header - - if current_user + - if signed_in %span.issuable-header-text.hide-collapsed.float-left = _('Todo') %a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", href: "#", "aria-label" => "Toggle sidebar", title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } } = sidebar_gutter_toggle_icon - - if current_user - = render "shared/issuable/sidebar_todo", todo: todo, issuable: issuable + - if signed_in + = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar - = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f| - - if current_user + = form_for issuable_type, url: issuable_sidebar[:issuable_json_path], remote: true, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f| + - if signed_in .block.todo.hide-expanded - = render "shared/issuable/sidebar_todo", todo: todo, issuable: issuable, is_collapsed: true + = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar, is_collapsed: true .block.assignee.qa-assignee-block - = render "shared/issuable/sidebar_assignees", issuable: issuable, can_edit_issuable: can_edit_issuable, signed_in: current_user.present? + = render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees - = render_if_exists 'shared/issuable/sidebar_item_epic', issuable: issuable + = render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar + - milestone = issuable_sidebar[:milestone] || {} .block.milestone - .sidebar-collapsed-icon.has-tooltip{ title: milestone_tooltip_title(issuable.milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } } + .sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } } = icon('clock-o', 'aria-hidden': 'true') %span.milestone-title.collapse-truncated-title - - if issuable.milestone - = issuable.milestone.title + - if milestone.present? + = milestone[:title] - else = _('None') .title.hide-collapsed @@ -35,49 +40,50 @@ - if can_edit_issuable = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right' .value.hide-collapsed - - if issuable.milestone - = link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_tooltip_due_date(issuable.milestone), data: { container: "body", html: 'true', boundary: 'viewport' } + - if milestone.present? + = link_to milestone[:title], milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport' } - else %span.no-value = _('None') .selectbox.hide-collapsed - = f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil - = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true, display: 'static' }}) - - if issuable.has_attribute?(:time_estimate) - #issuable-time-tracker.block - // Fallback while content is loading - .title.hide-collapsed - = _('Time tracking') - = icon('spinner spin', 'aria-hidden': 'true') - - if issuable.has_attribute?(:due_date) + = f.hidden_field 'milestone_id', value: milestone[:id], id: nil + = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], milestones: issuable_sidebar[:project_milestones_path], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }}) + + #issuable-time-tracker.block + // Fallback while content is loading + .title.hide-collapsed + = _('Time tracking') + = icon('spinner spin', 'aria-hidden': 'true') + + - if issuable_sidebar.has_key?(:due_date) .block.due_date - .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable) } + .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable_sidebar[:due_date]) } = icon('calendar', 'aria-hidden': 'true') %span.js-due-date-sidebar-value - = issuable.due_date.try(:to_s, :medium) || 'None' + = issuable_sidebar[:due_date].try(:to_s, :medium) || 'None' .title.hide-collapsed = _('Due date') = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true') - - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) + - if can_edit_issuable = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right' .value.hide-collapsed %span.value-content - - if issuable.due_date - %span.bold= issuable.due_date.to_s(:medium) + - if issuable_sidebar[:due_date] + %span.bold= issuable_sidebar[:due_date].to_s(:medium) - else %span.no-value = _('No due date') - - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) } + - if can_edit_issuable + %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable_sidebar[:due_date].nil?) } \- %a.js-remove-due-date{ href: "#", role: "button" } = _('remove due date') - - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) + - if can_edit_issuable .selectbox.hide-collapsed - = f.hidden_field :due_date, value: issuable.due_date.try(:strftime, 'yy-mm-dd') + = f.hidden_field :due_date, value: issuable_sidebar[:due_date].try(:strftime, 'yy-mm-dd') .dropdown - %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), display: 'static' } } + %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable_type}[due_date]", ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], display: 'static' } } %span.dropdown-toggle-text = _('Due date') = icon('chevron-down', 'aria-hidden': 'true') @@ -86,56 +92,56 @@ = dropdown_content do .js-due-date-calendar - - if @labels - - selected_labels = issuable.labels - .block.labels - .sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(issuable.labels_array), data: { placement: "left", container: "body", boundary: 'viewport' } } - = icon('tags', 'aria-hidden': 'true') - %span - = selected_labels.size - .title.hide-collapsed - = _('Labels') - = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true') - - if can_edit_issuable - = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right' - .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| - = link_to_label(label, subject: issuable.project, type: issuable.to_ability_name) - - else - %span.no-value - = _('None') - .selectbox.hide-collapsed + - selected_labels = issuable_sidebar[:labels] + .block.labels + .sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(selected_labels), data: { placement: "left", container: "body", boundary: 'viewport' } } + = icon('tags', 'aria-hidden': 'true') + %span + = selected_labels.size + .title.hide-collapsed + = _('Labels') + = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true') + - if can_edit_issuable + = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right' + .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| - = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil - .dropdown - %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path_with_defaults if @project), display: 'static' } } - %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) } - = multi_label_name(selected_labels, "Labels") - = icon('chevron-down', 'aria-hidden': 'true') - .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable - = render partial: "shared/issuable/label_page_default" - - if can? current_user, :admin_label, @project and @project - = render partial: "shared/issuable/label_page_create" - - = render_if_exists 'shared/issuable/sidebar_weight', issuable: issuable - - - if issuable.has_attribute?(:confidential) + = link_to sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label[:title]) do + %span.badge.color-label.has-tooltip{ style: "background-color: #{label[:color]}; color: #{label[:text_color]}", title: label[:description], data: { container: "body" } } + = label[:title] + - else + %span.no-value + = _('None') + .selectbox.hide-collapsed + - selected_labels.each do |label| + = hidden_field_tag "#{issuable_type}[label_names][]", label[:id], id: nil + .dropdown + %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable_type}[label_names][]", ability_name: issuable_type, show_no: "true", show_any: "true", namespace_path: issuable_sidebar[:namespace_path], project_path: issuable_sidebar[:project_path], issue_update: issuable_sidebar[:issuable_json_path], labels: issuable_sidebar[:project_labels_path], display: 'static' } } + %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) } + = multi_label_name(selected_labels, "Labels") + = icon('chevron-down', 'aria-hidden': 'true') + .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable + = render partial: "shared/issuable/label_page_default" + - if issuable_sidebar.dig(:current_user, :can_admin_label) + = render partial: "shared/issuable/label_page_create" + + = render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar + + - if issuable_sidebar.has_key?(:confidential) -# haml-lint:disable InlineJavaScript - %script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: @issue.confidential, is_editable: can_edit_issuable }.to_json.html_safe + %script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: issuable_sidebar[:confidential], is_editable: can_edit_issuable }.to_json.html_safe #js-confidential-entry-point - - if issuable.has_attribute?(:discussion_locked) - -# haml-lint:disable InlineJavaScript - %script#js-lock-issue-data{ type: "application/json" }= { is_locked: issuable.discussion_locked?, is_editable: can_edit_issuable }.to_json.html_safe - #js-lock-entry-point + -# haml-lint:disable InlineJavaScript + %script#js-lock-issue-data{ type: "application/json" }= { is_locked: issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe + #js-lock-entry-point .js-sidebar-participants-entry-point - - if current_user + - if signed_in .js-sidebar-subscriptions-entry-point - - project_ref = cross_project_reference(@project, issuable) + - project_ref = issuable_sidebar[:reference] .block.project-reference .sidebar-collapsed-icon.dont-change-state = clipboard_button(text: project_ref, title: _('Copy reference to clipboard'), placement: "left", boundary: 'viewport') @@ -145,7 +151,8 @@ %cite{ title: project_ref } = project_ref = clipboard_button(text: project_ref, title: _('Copy reference to clipboard'), placement: "left", boundary: 'viewport') - - if current_user && issuable.can_move?(current_user) + + - if issuable_sidebar.dig(:current_user, :can_move) .block.js-sidebar-move-issue-block .sidebar-collapsed-icon{ data: { toggle: 'tooltip', placement: 'left', container: 'body', boundary: 'viewport' }, title: _('Move issue') } = custom_icon('icon_arrow_right') @@ -164,4 +171,4 @@ = icon('spinner spin', class: 'sidebar-move-issue-confirmation-loading-icon') -# haml-lint:disable InlineJavaScript - %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable, can_edit_issuable).to_json.html_safe + %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable_sidebar).to_json.html_safe diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml index 8a13c7a3b83..c5cce1823f0 100644 --- a/app/views/shared/issuable/_sidebar_assignees.html.haml +++ b/app/views/shared/issuable/_sidebar_assignees.html.haml @@ -1,12 +1,17 @@ -- if issuable.is_a?(Issue) - #js-vue-sidebar-assignees{ data: { field: "#{issuable.to_ability_name}[assignee_ids]", signed_in: signed_in } } +- issuable_type = issuable_sidebar[:type] +- signed_in = !!issuable_sidebar.dig(:current_user, :id) +- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit) + +- if issuable_type == "issue" + #js-vue-sidebar-assignees{ data: { field: "#{issuable_type}[assignee_ids]", signed_in: signed_in } } .title.hide-collapsed = _('Assignee') = icon('spinner spin') - else - .sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: sidebar_assignee_tooltip_label(issuable) } - - if issuable.assignee - = link_to_member(@project, issuable.assignee, size: 24) + - assignee = assignees.first + .sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: (issuable_sidebar.dig(:assignee, :name) || _('Assignee')) } + - if issuable_sidebar[:assignee] + = link_to_member(@project, assignee, size: 24) - else = icon('user', 'aria-hidden': 'true') .title.hide-collapsed @@ -18,13 +23,13 @@ %a.gutter-toggle.float-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => _('Toggle sidebar') } = sidebar_gutter_toggle_icon .value.hide-collapsed - - if issuable.assignee - = link_to_member(@project, issuable.assignee, size: 32, extra_class: 'bold') do - - if !issuable.can_be_merged_by?(issuable.assignee) + - if issuable_sidebar[:assignee] + = link_to_member(@project, assignee, size: 32, extra_class: 'bold') do + - if issuable_sidebar[:assignee][:can_merge] %span.float-right.cannot-be-merged{ data: { toggle: 'tooltip', placement: 'left' }, title: _('Not allowed to merge') } = icon('exclamation-triangle', 'aria-hidden': 'true') %span.username - = issuable.assignee.to_reference + @#{issuable_sidebar[:assignee][:username]} - else %span.assign-yourself.no-value = _('No assignee') @@ -34,19 +39,33 @@ = _('assign yourself') .selectbox.hide-collapsed - - issuable.assignees.each do |assignee| - = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username } + - if assignees.none? + = hidden_field_tag "#{issuable_type}[assignee_ids][]", 0, id: nil + - else + - assignees.each do |assignee| + = hidden_field_tag "#{issuable_type}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username } - - options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true, display: 'static' } } + - options = { toggle_class: 'js-user-search js-author-search', + title: _('Assign to'), + filter: true, + dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', + placeholder: _('Search users'), + data: { first_user: issuable_sidebar.dig(:current_user, :username), + current_user: true, + project_id: issuable_sidebar[:project_id], + author_id: issuable_sidebar[:author_id], + field_name: "#{issuable_type}[assignee_ids][]", + issue_update: issuable_sidebar[:issuable_json_path], + ability_name: issuable_type, + null_user: true, + display: 'static' } } - title = _('Select assignee') - - if issuable.is_a?(Issue) - - unless issuable.assignees.any? - = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil + - if issuable_type == "issue" - dropdown_options = issue_assignees_dropdown_options - title = dropdown_options[:title] - options[:toggle_class] += ' js-multiselect js-save-user-data' - - data = { field_name: "#{issuable.to_ability_name}[assignee_ids][]" } + - data = { field_name: "#{issuable_type}[assignee_ids][]" } - data[:multi_select] = true - data['dropdown-title'] = title - data['dropdown-header'] = dropdown_options[:data][:'dropdown-header'] diff --git a/app/views/shared/issuable/_sidebar_todo.html.haml b/app/views/shared/issuable/_sidebar_todo.html.haml index 660ee6d5777..de4df016cfb 100644 --- a/app/views/shared/issuable/_sidebar_todo.html.haml +++ b/app/views/shared/issuable/_sidebar_todo.html.haml @@ -1,15 +1,15 @@ - is_collapsed = local_assigns.fetch(:is_collapsed, false) -- mark_content = is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : _('Mark todo as done') -- todo_content = is_collapsed ? sprite_icon('todo-add') : _('Add todo') +- has_todo = !!issuable_sidebar.dig(:current_user, :todo, :id) + +- todo_button_data = issuable_todo_button_data(issuable_sidebar, is_collapsed) +- button_title = has_todo ? todo_button_data[:mark_text] : todo_button_data[:todo_text] +- button_icon = has_todo ? todo_button_data[:mark_icon] : todo_button_data[:todo_icon] %button.issuable-todo-btn.js-issuable-todo{ type: 'button', class: (is_collapsed ? 'btn-blank sidebar-collapsed-icon dont-change-state has-tooltip' : 'btn btn-default issuable-header-btn float-right'), - title: (todo.nil? ? _('Add todo') : _('Mark todo as done')), - 'aria-label' => (todo.nil? ? _('Add todo') : _('Mark todo as done')), - data: issuable_todo_button_data(issuable, todo, is_collapsed) } + title: button_title, + 'aria-label' => button_title, + data: todo_button_data } %span.issuable-todo-inner.js-issuable-todo-inner< - - if todo - = mark_content - - else - = todo_content + = is_collapsed ? button_icon : button_title = icon('spin spinner', 'aria-hidden': 'true') diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml index ac8d58c0bfe..e370dff9526 100644 --- a/app/views/shared/issuable/form/_metadata.html.haml +++ b/app/views/shared/issuable/form/_metadata.html.haml @@ -19,10 +19,9 @@ .issuable-form-select-holder = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" .form-group.row - - has_labels = @labels && @labels.any? = form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}" = form.hidden_field :label_ids, multiple: true, value: '' - .col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } + .col-sm-10{ class: "#{"col-md-8" if has_due_date}" } .issuable-form-select-holder = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml index becd1c4884e..b24075c7849 100644 --- a/app/views/shared/milestones/_sidebar.html.haml +++ b/app/views/shared/milestones/_sidebar.html.haml @@ -65,7 +65,7 @@ %span.bold= milestone.due_date.to_s(:medium) - else %span.no-value No due date - - remaining_days = remaining_days_in_words(milestone) + - remaining_days = remaining_days_in_words(milestone.due_date, milestone.start_date) - if remaining_days.present? = surround '(', ')' do %span.remaining-days= remaining_days diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 9dde77fccef..fea7e17be3d 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -72,13 +72,13 @@ title: _('Forks'), data: { container: 'body', placement: 'top' } do = sprite_icon('fork', size: 14, css_class: 'append-right-4') = number_with_delimiter(project.forks_count) - - if show_merge_request_count?(merge_requests, compact_mode) + - if show_merge_request_count?(disabled: !merge_requests, compact_mode: compact_mode) = link_to project_merge_requests_path(project), class: "d-none d-lg-flex align-items-center icon-wrapper merge-requests has-tooltip", title: _('Merge Requests'), data: { container: 'body', placement: 'top' } do = sprite_icon('git-merge', size: 14, css_class: 'append-right-4') = number_with_delimiter(project.open_merge_requests_count) - - if show_issue_count?(issues, compact_mode) + - if show_issue_count?(disabled: !issues, compact_mode: compact_mode) = link_to project_issues_path(project), class: "d-none d-lg-flex align-items-center icon-wrapper issues has-tooltip", title: _('Issues'), data: { container: 'body', placement: 'top' } do diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index bc26b3f8ef2..d3cf21db335 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -27,7 +27,7 @@ - gcp_cluster:cluster_wait_for_app_installation - gcp_cluster:wait_for_cluster_creation - gcp_cluster:cluster_wait_for_ingress_ip_address -- gcp_cluster:cluster_platform_configure +- gcp_cluster:cluster_configure - gcp_cluster:cluster_project_configure - github_import_advance_stage @@ -88,6 +88,7 @@ - object_pool:object_pool_create - object_pool:object_pool_schedule_join - object_pool:object_pool_join +- object_pool:object_pool_destroy - default - mailers # ActionMailer::DeliveryJob.queue_name diff --git a/app/workers/cluster_platform_configure_worker.rb b/app/workers/cluster_configure_worker.rb index aa7570caa79..63e6cc147be 100644 --- a/app/workers/cluster_platform_configure_worker.rb +++ b/app/workers/cluster_configure_worker.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class ClusterPlatformConfigureWorker +class ClusterConfigureWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/cluster_provision_worker.rb b/app/workers/cluster_provision_worker.rb index 3d5894b73ec..926ae2b7286 100644 --- a/app/workers/cluster_provision_worker.rb +++ b/app/workers/cluster_provision_worker.rb @@ -10,7 +10,7 @@ class ClusterProvisionWorker Clusters::Gcp::ProvisionService.new.execute(provider) if cluster.gcp? end - ClusterPlatformConfigureWorker.perform_async(cluster.id) if cluster.user? + ClusterConfigureWorker.perform_async(cluster.id) if cluster.user? end end end diff --git a/app/workers/object_pool/destroy_worker.rb b/app/workers/object_pool/destroy_worker.rb new file mode 100644 index 00000000000..ca00d467d9b --- /dev/null +++ b/app/workers/object_pool/destroy_worker.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module ObjectPool + class DestroyWorker + include ApplicationWorker + include ObjectPoolQueue + + def perform(pool_repository_id) + pool = PoolRepository.find_by_id(pool_repository_id) + return unless pool&.obsolete? + + pool.delete_object_pool + pool.destroy + end + end +end diff --git a/app/workers/stuck_merge_jobs_worker.rb b/app/workers/stuck_merge_jobs_worker.rb index 98c81956cba..f34ed6c4844 100644 --- a/app/workers/stuck_merge_jobs_worker.rb +++ b/app/workers/stuck_merge_jobs_worker.rb @@ -4,6 +4,10 @@ class StuckMergeJobsWorker include ApplicationWorker include CronjobQueue + def self.logger + Rails.logger + end + # rubocop: disable CodeReuse/ActiveRecord def perform stuck_merge_requests.find_in_batches(batch_size: 100) do |group| @@ -35,7 +39,7 @@ class StuckMergeJobsWorker # We rely on state machine callbacks to update head_pipeline_id merge_requests_to_reopen.each(&:unlock_mr) - Rails.logger.info("Updated state of locked merge jobs. JIDs: #{completed_jids.join(', ')}") + self.class.logger.info("Updated state of locked merge jobs. JIDs: #{completed_jids.join(', ')}") end # rubocop: enable CodeReuse/ActiveRecord diff --git a/changelogs/unreleased/19376-post-bfg-cleanup.yml b/changelogs/unreleased/19376-post-bfg-cleanup.yml deleted file mode 100644 index fc1bcc30db9..00000000000 --- a/changelogs/unreleased/19376-post-bfg-cleanup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use BFG object maps to clean projects -merge_request: 23189 -author: -type: added diff --git a/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml b/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml deleted file mode 100644 index d05b6054b22..00000000000 --- a/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Redesign of MR header sections (CE) -merge_request: 23465 -author: -type: changed diff --git a/changelogs/unreleased/20422-hide-ui-variables-by-default.yml b/changelogs/unreleased/20422-hide-ui-variables-by-default.yml deleted file mode 100644 index 60285d49718..00000000000 --- a/changelogs/unreleased/20422-hide-ui-variables-by-default.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Pipeline trigger variable values are hidden in the UI by default. Maintainers - have the option to reveal them. -merge_request: 23518 -author: jhampton -type: added diff --git a/changelogs/unreleased/22548-reopen-error-message.yml b/changelogs/unreleased/22548-reopen-error-message.yml deleted file mode 100644 index 79c20eccb12..00000000000 --- a/changelogs/unreleased/22548-reopen-error-message.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Show error message when attempting to reopen an MR and there is an open MR - for the same branch -merge_request: 16447 -author: Akos Gyimesi -type: fixed diff --git a/changelogs/unreleased/23367-clarify-docs-allow-failure.yml b/changelogs/unreleased/23367-clarify-docs-allow-failure.yml new file mode 100644 index 00000000000..221d9e83ffb --- /dev/null +++ b/changelogs/unreleased/23367-clarify-docs-allow-failure.yml @@ -0,0 +1,5 @@ +--- +title: Clarifies docs about CI `allow_failure` +merge_request: 23367 +author: C.J. Jameson +type: other diff --git a/changelogs/unreleased/33705-merge-request-rebase-api.yml b/changelogs/unreleased/33705-merge-request-rebase-api.yml deleted file mode 100644 index 322fe31ce87..00000000000 --- a/changelogs/unreleased/33705-merge-request-rebase-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add a rebase API endpoint for merge requests -merge_request: 23296 -author: -type: added diff --git a/changelogs/unreleased/34758-deployment-cluster.yml b/changelogs/unreleased/34758-deployment-cluster.yml deleted file mode 100644 index 06374098343..00000000000 --- a/changelogs/unreleased/34758-deployment-cluster.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use group clusters when deploying (DeploymentPlatform) -merge_request: 22308 -author: -type: changed diff --git a/changelogs/unreleased/34758-group-cluster-controller.yml b/changelogs/unreleased/34758-group-cluster-controller.yml deleted file mode 100644 index 88c4c872714..00000000000 --- a/changelogs/unreleased/34758-group-cluster-controller.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add ability to create group level clusters and install gitlab managed applications -merge_request: 22450 -author: -type: added diff --git a/changelogs/unreleased/38495-calendar-activities-in-timezone.yml b/changelogs/unreleased/38495-calendar-activities-in-timezone.yml deleted file mode 100644 index 778d637609c..00000000000 --- a/changelogs/unreleased/38495-calendar-activities-in-timezone.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show user contributions in correct timezone within user profile -merge_request: 23419 -author: -type: changed diff --git a/changelogs/unreleased/39849_controller_sorts.yml b/changelogs/unreleased/39849_controller_sorts.yml deleted file mode 100644 index 5fad0cb4ede..00000000000 --- a/changelogs/unreleased/39849_controller_sorts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow sorting issues and MRs in reverse order -merge_request: 21438 -author: -type: changed diff --git a/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml b/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml deleted file mode 100644 index e1614ac7669..00000000000 --- a/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Creates /create_merge_request quickaction -merge_request: 22485 -author: Jacopo Beschi @jacopo-beschi -type: added diff --git a/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml b/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml deleted file mode 100644 index 8ab104e95f5..00000000000 --- a/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reduce Gitaly calls in projects dashboard -merge_request: 23307 -author: -type: performance diff --git a/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml b/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml new file mode 100644 index 00000000000..9ea2157bfb7 --- /dev/null +++ b/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml @@ -0,0 +1,5 @@ +--- +title: Removes all instances of deprecated Gitlab Upgrader calls +merge_request: 23603 +author: '@jwolen' +type: removed diff --git a/changelogs/unreleased/40385-prohibit_impersonation.yml b/changelogs/unreleased/40385-prohibit_impersonation.yml deleted file mode 100644 index dd061b17939..00000000000 --- a/changelogs/unreleased/40385-prohibit_impersonation.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add config to prohibit impersonation -merge_request: 23338 -author: -type: added diff --git a/changelogs/unreleased/41766-vuex-store.yml b/changelogs/unreleased/41766-vuex-store.yml new file mode 100644 index 00000000000..f20fc736a6f --- /dev/null +++ b/changelogs/unreleased/41766-vuex-store.yml @@ -0,0 +1,5 @@ +--- +title: Creates frontend app for releases +merge_request: 23796 +author: +type: added diff --git a/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml b/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml deleted file mode 100644 index 0662ff6f523..00000000000 --- a/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow deleting a Pipeline via the API. -merge_request: 22988 -author: -type: added diff --git a/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml b/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml new file mode 100644 index 00000000000..9892466ca50 --- /dev/null +++ b/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml @@ -0,0 +1,5 @@ +--- +title: Extend override check to also check arity +merge_request: 23498 +author: Jacopo Beschi @jacopo-beschi +type: added diff --git a/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml b/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml new file mode 100644 index 00000000000..ba9edc8740d --- /dev/null +++ b/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml @@ -0,0 +1,5 @@ +--- +title: Refactor issuable sidebar to use serializer +merge_request: 23379 +author: +type: other diff --git a/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml b/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml deleted file mode 100644 index 334c9b3ec9e..00000000000 --- a/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action" -merge_request: 23049 -author: Thomas Pathier -type: added diff --git a/changelogs/unreleased/46950-systemcheck-ruby-version.yml b/changelogs/unreleased/46950-systemcheck-ruby-version.yml deleted file mode 100644 index e556e14223b..00000000000 --- a/changelogs/unreleased/46950-systemcheck-ruby-version.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'SystemCheck: Use a more reliable way to detect current Ruby version' -merge_request: 23291 -author: -type: changed diff --git a/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml b/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml deleted file mode 100644 index f543730a57d..00000000000 --- a/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixing regression issues on pages settings and details -merge_request: 22821 -author: -type: fixed diff --git a/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml b/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml deleted file mode 100644 index cfc74bef638..00000000000 --- a/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: When user clicks linenumber in MR changes, highlight that line -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/48889-populate-merge_commit_sha.yml b/changelogs/unreleased/48889-populate-merge_commit_sha.yml deleted file mode 100644 index 0e25d8ecfb0..00000000000 --- a/changelogs/unreleased/48889-populate-merge_commit_sha.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix "merged with [commit]" info for merge requests being merged automatically - by other actions -merge_request: 22794 -author: -type: fixed diff --git a/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml b/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml deleted file mode 100644 index 5118949f8a3..00000000000 --- a/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't show Memory Usage for unmerged MRs -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/49565-ssh-push-mirroring.yml b/changelogs/unreleased/49565-ssh-push-mirroring.yml deleted file mode 100644 index 2dfeffa4088..00000000000 --- a/changelogs/unreleased/49565-ssh-push-mirroring.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow SSH public-key authentication for push mirroring -merge_request: 22982 -author: -type: added diff --git a/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml b/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml deleted file mode 100644 index 0b5d1a6b05a..00000000000 --- a/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve Main navbar is broken in certain viewport widths -merge_request: 23348 -author: -type: fixed diff --git a/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml b/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml deleted file mode 100644 index dd26af875f5..00000000000 --- a/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade helm to 2.11.0 and upgrade on every install -merge_request: 22693 -author: -type: added diff --git a/changelogs/unreleased/50157-extended-user-centric-tooltips.yml b/changelogs/unreleased/50157-extended-user-centric-tooltips.yml deleted file mode 100644 index 3b55a867b87..00000000000 --- a/changelogs/unreleased/50157-extended-user-centric-tooltips.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Extended user centric tooltips on issue and MR page -merge_request: 23231 -author: -type: added diff --git a/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml b/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml deleted file mode 100644 index 6315c3e7f36..00000000000 --- a/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve Add border around the repository file tree -merge_request: 23018 -author: -type: changed diff --git a/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml b/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml deleted file mode 100644 index 3893f14e15c..00000000000 --- a/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Removes all the irrelevant code and columns that were migrated from the Project - table over to the ProjectImportState table -merge_request: 21497 -author: -type: performance diff --git a/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml b/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml deleted file mode 100644 index c3251fea54d..00000000000 --- a/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow search and sort users at same time on admin users page -merge_request: 23439 -author: -type: fixed diff --git a/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml b/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml deleted file mode 100644 index 1c6c8747197..00000000000 --- a/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Scope default MR search in WebIDE dropdown to current project -merge_request: 23400 -author: -type: changed diff --git a/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml b/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml deleted file mode 100644 index dc11ede5c8d..00000000000 --- a/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve status emoji being replaced by avatar on mobile -merge_request: 23408 -author: -type: other diff --git a/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml b/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml deleted file mode 100644 index 86f91fcb427..00000000000 --- a/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improves performance of Project#readme_url by caching the README path -merge_request: 23357 -author: -type: performance diff --git a/changelogs/unreleased/51083-fix-move-api.yml b/changelogs/unreleased/51083-fix-move-api.yml deleted file mode 100644 index 8838f6f267e..00000000000 --- a/changelogs/unreleased/51083-fix-move-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Commits API: Preserve file content in move operations if unspecified' -merge_request: 23387 -author: -type: fixed diff --git a/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml b/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml deleted file mode 100644 index 96f33a72cc5..00000000000 --- a/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Restrict member access level to be higher than that of any parent group -merge_request: 23226 -author: -type: fixed diff --git a/changelogs/unreleased/51122-fix-navigating-discussions.yml b/changelogs/unreleased/51122-fix-navigating-discussions.yml deleted file mode 100644 index 94d76654589..00000000000 --- a/changelogs/unreleased/51122-fix-navigating-discussions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix navigating by unresolved discussions on Merge Request page -merge_request: 22789 -author: -type: fixed diff --git a/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml b/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml deleted file mode 100644 index f695d5aeff8..00000000000 --- a/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Make auto-generated icons for subgroups in the breadcrumb dropdown display as a circle" -merge_request: 23062 -author: Thomas Pathier -type: fix
\ No newline at end of file diff --git a/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml b/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml deleted file mode 100644 index ddb5eaa89d0..00000000000 --- a/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Design improvements to project overview page -merge_request: 22196 -author: -type: changed diff --git a/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml b/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml deleted file mode 100644 index 1d761d6299c..00000000000 --- a/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Uses new gitlab-ui components in Jobs and Pipelines components -merge_request: -author: -type: other diff --git a/changelogs/unreleased/51259-ci-cd-tooltips.yml b/changelogs/unreleased/51259-ci-cd-tooltips.yml deleted file mode 100644 index fc0010dbeba..00000000000 --- a/changelogs/unreleased/51259-ci-cd-tooltips.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Replaces tooltip directive with the new gl-tooltip directive for consistency - in some ci/cd code -merge_request: -author: -type: other diff --git a/changelogs/unreleased/51606-expanding-a-diff-while-having-an-open-comment-form-will-always-scroll-down-to-the-comment.yml b/changelogs/unreleased/51606-expanding-a-diff-while-having-an-open-comment-form-will-always-scroll-down-to-the-comment.yml new file mode 100644 index 00000000000..a845234b42f --- /dev/null +++ b/changelogs/unreleased/51606-expanding-a-diff-while-having-an-open-comment-form-will-always-scroll-down-to-the-comment.yml @@ -0,0 +1,5 @@ +--- +title: Stop autofocusing on diff comment after initial mount +merge_request: 23849 +author: +type: fixed diff --git a/changelogs/unreleased/51668-fix-line-numbers.yml b/changelogs/unreleased/51668-fix-line-numbers.yml new file mode 100644 index 00000000000..ac6e45e3cc7 --- /dev/null +++ b/changelogs/unreleased/51668-fix-line-numbers.yml @@ -0,0 +1,5 @@ +--- +title: Adjust line-height of blame view line numbers +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml b/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml deleted file mode 100644 index 7a900cbb86e..00000000000 --- a/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't remove failed install pods after installing GitLab managed applications -merge_request: 23350 -author: -type: changed diff --git a/changelogs/unreleased/51959-branch-and-tag-name-links.yml b/changelogs/unreleased/51959-branch-and-tag-name-links.yml deleted file mode 100644 index 64f1522c70d..00000000000 --- a/changelogs/unreleased/51959-branch-and-tag-name-links.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Chat message push notifications now include links back to GitLab branches -merge_request: 22651 -author: Tony Castrogiovanni -type: added diff --git a/changelogs/unreleased/52007-frontmatter-toml-json.yml b/changelogs/unreleased/52007-frontmatter-toml-json.yml deleted file mode 100644 index bdada19f3a7..00000000000 --- a/changelogs/unreleased/52007-frontmatter-toml-json.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Changed frontmatter filtering to support YAML, JSON, TOML, and arbitrary languages -merge_request: 23331 -author: Travis Miller -type: changed diff --git a/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml b/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml deleted file mode 100644 index 3dc95441eec..00000000000 --- a/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow user to scroll to top of tab on MR page -merge_request: -author: -type: added diff --git a/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml b/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml deleted file mode 100644 index 3ef564238c5..00000000000 --- a/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Support RSA and ECDSA algorithms in Omniauth JWT provider -merge_request: 23411 -author: Michael Tsyganov -type: fixed diff --git a/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml b/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml deleted file mode 100644 index 9e1ee3ede5e..00000000000 --- a/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds Any option to label filters -merge_request: 23111 -author: Jacopo Beschi @jacopo-beschi -type: added diff --git a/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml b/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml deleted file mode 100644 index bb196af3e90..00000000000 --- a/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Filter by None/Any for labels in issues/mrs API -merge_request: 22622 -author: Jacopo Beschi @jacopo-beschi -type: added diff --git a/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml b/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml deleted file mode 100644 index c1fc21c641a..00000000000 --- a/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: removes partially matching of No Label filter and makes it case-insensitive -merge_request: 22622 -author: Jacopo Beschi @jacopo-beschi -type: changed diff --git a/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml b/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml deleted file mode 100644 index a437ae560cb..00000000000 --- a/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use search bar for filtering in dashboard issues / MRs -merge_request: 22641 -author: Heinrich Lee Yu -type: changed diff --git a/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml b/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml deleted file mode 100644 index d5877e96d07..00000000000 --- a/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix project selector consistency in groups issues / MRs / boards pages -merge_request: 22612 -author: Heinrich Lee Yu -type: fixed diff --git a/changelogs/unreleased/52620-fix-loader-animation-alignment.yml b/changelogs/unreleased/52620-fix-loader-animation-alignment.yml new file mode 100644 index 00000000000..5cfb7fc019f --- /dev/null +++ b/changelogs/unreleased/52620-fix-loader-animation-alignment.yml @@ -0,0 +1,5 @@ +--- +title: Aligns build loader animation with the job log +merge_request: 23959 +author: +type: fixed diff --git a/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml b/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml deleted file mode 100644 index 65aa9323d2e..00000000000 --- a/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: UI improvements to user's profile -merge_request: 22977 -author: -type: other diff --git a/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml b/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml deleted file mode 100644 index 656a915a281..00000000000 --- a/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Ensure that SVG sprite icons are properly rendered in IE11 -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml b/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml deleted file mode 100644 index 8132dde8636..00000000000 --- a/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make new branch form fields' fonts consistent -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml b/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml deleted file mode 100644 index 98e15a5cc0a..00000000000 --- a/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix a bug where internal email pattern wasn't respected -merge_request: 22516 -author: -type: fixed diff --git a/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml b/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml deleted file mode 100644 index 9a16666c416..00000000000 --- a/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update haml_lint to 0.28.0 -merge_request: 22660 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml b/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml deleted file mode 100644 index d076352a27b..00000000000 --- a/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix default sorting for subgroups and projects list -merge_request: 23058 -author: Jacopo Beschi @jacopo-beschi -type: fixed diff --git a/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml b/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml deleted file mode 100644 index a1b95df5e32..00000000000 --- a/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update ffaker to 2.10.0 -merge_request: 22661 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/53326-improve-issues-empty-state.yml b/changelogs/unreleased/53326-improve-issues-empty-state.yml deleted file mode 100644 index 7632db808b5..00000000000 --- a/changelogs/unreleased/53326-improve-issues-empty-state.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show different empty state for filtered issues and MRs -merge_request: 22775 -author: Heinrich Lee Yu -type: changed diff --git a/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml b/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml deleted file mode 100644 index b393795f491..00000000000 --- a/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Fix: Unstar icon button is misaligned' -merge_request: 23444 -author: -type: fixed diff --git a/changelogs/unreleased/53578-fe-deployment-status.yml b/changelogs/unreleased/53578-fe-deployment-status.yml deleted file mode 100644 index b88bd70ee2e..00000000000 --- a/changelogs/unreleased/53578-fe-deployment-status.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds states to the deployment widget -merge_request: -author: -type: added diff --git a/changelogs/unreleased/53626-update-config-map-on-install-retry.yml b/changelogs/unreleased/53626-update-config-map-on-install-retry.yml deleted file mode 100644 index 38e79c06c89..00000000000 --- a/changelogs/unreleased/53626-update-config-map-on-install-retry.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update config map for gitlab managed application if already present on install -merge_request: 22969 -author: -type: other diff --git a/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml b/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml deleted file mode 100644 index 66301329c52..00000000000 --- a/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml +++ /dev/null @@ -1,4 +0,0 @@ -title: Adds new icon size to Vue icon component -merge_request: 22899 -author: -type: other diff --git a/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml b/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml deleted file mode 100644 index fe9ac7b3dc7..00000000000 --- a/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix web hook functionality when the database encryption key is too short -merge_request: 23573 -author: -type: fixed diff --git a/changelogs/unreleased/53700-hashed-storagemigration.yml b/changelogs/unreleased/53700-hashed-storagemigration.yml deleted file mode 100644 index 899012ffd22..00000000000 --- a/changelogs/unreleased/53700-hashed-storagemigration.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Hashed Storage: allow migration to be retried in partially migrated projects' -merge_request: 23087 -author: -type: fixed diff --git a/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml b/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml deleted file mode 100644 index 8377fdc6133..00000000000 --- a/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent user from navigating away from file edit without commit -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml b/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml deleted file mode 100644 index a9ca56303eb..00000000000 --- a/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removes promote to group label for anonymous user -merge_request: 23042 -author: Jacopo Beschi @jacopo-beschi -type: fixed diff --git a/changelogs/unreleased/53874-navbar-lowres.yml b/changelogs/unreleased/53874-navbar-lowres.yml deleted file mode 100644 index 3b31b8f93fe..00000000000 --- a/changelogs/unreleased/53874-navbar-lowres.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Fix overlapping navbar separator and overflowing navbar dropdown on small displays" -merge_request: 23126 -author: Thomas Pathier -type: fix diff --git a/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml b/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml new file mode 100644 index 00000000000..5c40a1e900c --- /dev/null +++ b/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml @@ -0,0 +1,5 @@ +--- +title: Add date range in milestone change email notifications +merge_request: 23762 +author: +type: changed diff --git a/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml b/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml deleted file mode 100644 index f0bbf69736d..00000000000 --- a/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove index for notes on updated_at -merge_request: 23356 -author: -type: performance diff --git a/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml b/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml deleted file mode 100644 index a2a3fa00f01..00000000000 --- a/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add index for events on project_id and created_at -merge_request: 23354 -author: -type: performance diff --git a/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml b/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml deleted file mode 100644 index 4673ba38bae..00000000000 --- a/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add partial index for ci_builds on project_id and status -merge_request: 23268 -author: -type: performance diff --git a/changelogs/unreleased/54004-update-asana-to-0-8-1.yml b/changelogs/unreleased/54004-update-asana-to-0-8-1.yml deleted file mode 100644 index a47b4f3c4d9..00000000000 --- a/changelogs/unreleased/54004-update-asana-to-0-8-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update asana to 0.8.1 -merge_request: 23039 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml b/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml deleted file mode 100644 index f0b0aa0ee1c..00000000000 --- a/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update asciidoctor to 1.5.8 -merge_request: 23047 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml b/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml deleted file mode 100644 index 28e3fae01a9..00000000000 --- a/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Refine cursor positioning in Markdown Editor for wrap tags -merge_request: 23085 -author: Johann Hubert Sonntagbauer -type: changed diff --git a/changelogs/unreleased/54021-empty-button.yml b/changelogs/unreleased/54021-empty-button.yml deleted file mode 100644 index 3b03665cf95..00000000000 --- a/changelogs/unreleased/54021-empty-button.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent empty button being rendered in empty state -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml b/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml deleted file mode 100644 index 5c1f6e74b39..00000000000 --- a/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make reply shortcut only quote selected discussion text -merge_request: 23096 -author: Thomas Pathier -type: fix diff --git a/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml b/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml deleted file mode 100644 index 8ceac4ec869..00000000000 --- a/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix line height of numbers in file blame view -merge_request: 23090 -author: Johann Hubert Sonntagbauer -type: fixed diff --git a/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml b/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml deleted file mode 100644 index 3d6fd2d065a..00000000000 --- a/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Fixes an issue where default values from models would override values set in - the interface (e.g. users would be set to external even though their emails matches - the internal email address pattern) -merge_request: 23114 -author: -type: fixed diff --git a/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml b/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml deleted file mode 100644 index 86c5a0c5a95..00000000000 --- a/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use reports syntax for SAST in Auto DevOps -merge_request: 23163 -author: -type: changed diff --git a/changelogs/unreleased/54201-update-rack-to-2-0-6.yml b/changelogs/unreleased/54201-update-rack-to-2-0-6.yml deleted file mode 100644 index 020b2bc0957..00000000000 --- a/changelogs/unreleased/54201-update-rack-to-2-0-6.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update rack to 2.0.6 (for QA environments) -merge_request: 23171 -author: Takuya Noguchi -type: security diff --git a/changelogs/unreleased/54218-fix-mergeUrlParams.yml b/changelogs/unreleased/54218-fix-mergeUrlParams.yml deleted file mode 100644 index dae06b66e8e..00000000000 --- a/changelogs/unreleased/54218-fix-mergeUrlParams.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Fix mergeUrlParams with fragment URL" -merge_request: 54218 -author: Thomas Holder -type: fixed diff --git a/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml b/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml deleted file mode 100644 index 11f941ab9bb..00000000000 --- a/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Merge request pipeline tag, and adds tags to pipeline view -merge_request: 23364 -author: -type: added diff --git a/changelogs/unreleased/54391-tag.yml b/changelogs/unreleased/54391-tag.yml deleted file mode 100644 index be571c6b0c3..00000000000 --- a/changelogs/unreleased/54391-tag.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Correctly styles tags in sidebar for job page -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/54407-fix-limited-intersection-observers.yml b/changelogs/unreleased/54407-fix-limited-intersection-observers.yml deleted file mode 100644 index 2c2bedb170b..00000000000 --- a/changelogs/unreleased/54407-fix-limited-intersection-observers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Image Lazy Loader for some older browsers -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/54571-runner-tags.yml b/changelogs/unreleased/54571-runner-tags.yml deleted file mode 100644 index 1bb19d22e9c..00000000000 --- a/changelogs/unreleased/54571-runner-tags.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds margins between tags when a job is stuck -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml b/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml deleted file mode 100644 index fa905b47ca2..00000000000 --- a/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add new endpoint to download single artifact file for a ref -merge_request: 23538 -author: -type: added diff --git a/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml b/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml deleted file mode 100644 index 671d1590991..00000000000 --- a/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix Order By dropdown menu styling in tablet and mobile screens -merge_request: 23446 -author: -type: fixed diff --git a/changelogs/unreleased/54814-sidebar-styling-updates.yml b/changelogs/unreleased/54814-sidebar-styling-updates.yml new file mode 100644 index 00000000000..98e3836ee14 --- /dev/null +++ b/changelogs/unreleased/54814-sidebar-styling-updates.yml @@ -0,0 +1,5 @@ +--- +title: Fix label and header styles in the job details sidebar. +merge_request: 23816 +author: Nathan Friend +type: changed diff --git a/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml b/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml deleted file mode 100644 index ef8e93fca43..00000000000 --- a/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use read_repository scope on read-only files API -merge_request: 23534 -author: -type: fixed diff --git a/changelogs/unreleased/54857-fix-templates-path-traversal.yml b/changelogs/unreleased/54857-fix-templates-path-traversal.yml deleted file mode 100644 index 0da02432c60..00000000000 --- a/changelogs/unreleased/54857-fix-templates-path-traversal.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent a path traversal attack on global file templates -merge_request: -author: -type: security diff --git a/changelogs/unreleased/54953-fix-commit_email_hostname-accessor-in-fake_application_settings.yml b/changelogs/unreleased/54953-fix-commit_email_hostname-accessor-in-fake_application_settings.yml new file mode 100644 index 00000000000..623b3a7319c --- /dev/null +++ b/changelogs/unreleased/54953-fix-commit_email_hostname-accessor-in-fake_application_settings.yml @@ -0,0 +1,5 @@ +--- +title: Fix a 500 error that could occur until all migrations are done +merge_request: 23939 +author: +type: fixed diff --git a/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml b/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml deleted file mode 100644 index 107a93e5b12..00000000000 --- a/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix gitlab:web_hook tasks -merge_request: 23635 -author: -type: fixed diff --git a/changelogs/unreleased/55103-hide-group-cluster-features.yml b/changelogs/unreleased/55103-hide-group-cluster-features.yml new file mode 100644 index 00000000000..fbe780d6f01 --- /dev/null +++ b/changelogs/unreleased/55103-hide-group-cluster-features.yml @@ -0,0 +1,5 @@ +--- +title: Hide cluster features that don't work yet with Group Clusters +merge_request: 23935 +author: +type: fixed diff --git a/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml deleted file mode 100644 index 994859b1d1d..00000000000 --- a/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix a frozen string error in app/mailers/notify.rb -merge_request: 23683 -author: -type: fixed diff --git a/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml deleted file mode 100644 index a98e70465b2..00000000000 --- a/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix a frozen string error in lib/gitlab/utils.rb -merge_request: 23690 -author: -type: fixed diff --git a/changelogs/unreleased/55138-fix-mr-discussions-count.yml b/changelogs/unreleased/55138-fix-mr-discussions-count.yml deleted file mode 100644 index 667e9b971d8..00000000000 --- a/changelogs/unreleased/55138-fix-mr-discussions-count.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix MR resolved discussion counts being too low -merge_request: 23710 -author: -type: fixed diff --git a/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml b/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml deleted file mode 100644 index 685a8309c72..00000000000 --- a/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix a potential frozen string error in app/mailers/notify.rb -merge_request: 23728 -author: -type: fixed diff --git a/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml b/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml new file mode 100644 index 00000000000..c6ff52b0fa1 --- /dev/null +++ b/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml @@ -0,0 +1,5 @@ +--- +title: Split bio into individual line in extended user tooltips +merge_request: 23940 +author: +type: other diff --git a/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml b/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml deleted file mode 100644 index d2ff095ce55..00000000000 --- a/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix due date test -merge_request: 23845 -author: -type: other diff --git a/changelogs/unreleased/_acet-fix-flash-styling.yml b/changelogs/unreleased/_acet-fix-flash-styling.yml deleted file mode 100644 index 57354c04899..00000000000 --- a/changelogs/unreleased/_acet-fix-flash-styling.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix flash notice styling for fluid layout -merge_request: 23382 -author: -type: fixed diff --git a/changelogs/unreleased/ab-approximate-counts.yml b/changelogs/unreleased/ab-approximate-counts.yml deleted file mode 100644 index 8a67239d031..00000000000 --- a/changelogs/unreleased/ab-approximate-counts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Approximate counting strategy with TABLESAMPLE. -merge_request: 22650 -author: -type: performance diff --git a/changelogs/unreleased/added-glob-for-ci-changes-detection.yml b/changelogs/unreleased/added-glob-for-ci-changes-detection.yml deleted file mode 100644 index 887c6ef0346..00000000000 --- a/changelogs/unreleased/added-glob-for-ci-changes-detection.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added glob for CI changes detection -merge_request: 23128 -author: Kirill Zaitsev -type: added diff --git a/changelogs/unreleased/an-gitaly-version-0-133-0.yml b/changelogs/unreleased/an-gitaly-version-0-133-0.yml deleted file mode 100644 index 4f3943ceacb..00000000000 --- a/changelogs/unreleased/an-gitaly-version-0-133-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Updated Gitaly to v0.133.0 -merge_request: 23148 -author: -type: other diff --git a/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml b/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml deleted file mode 100644 index d15c5654d99..00000000000 --- a/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Relocate JSONWebToken::HMACToken from EE -merge_request: 22906 -author: -type: changed diff --git a/changelogs/unreleased/auto_devops_kubernetes_active.yml b/changelogs/unreleased/auto_devops_kubernetes_active.yml deleted file mode 100644 index 310d37128c9..00000000000 --- a/changelogs/unreleased/auto_devops_kubernetes_active.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Switch kubernetes:active with checking in Auto-DevOps.gitlab-ci.yml -merge_request: 22929 -author: -type: fixed diff --git a/changelogs/unreleased/blackst0ne-add-discord-service.yml b/changelogs/unreleased/blackst0ne-add-discord-service.yml deleted file mode 100644 index 85dedf6d81f..00000000000 --- a/changelogs/unreleased/blackst0ne-add-discord-service.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add Discord integration -merge_request: 22684 -author: "@blackst0ne" -type: added diff --git a/changelogs/unreleased/bump_gpgme_gem.yml b/changelogs/unreleased/bump_gpgme_gem.yml deleted file mode 100644 index 4c0067cb824..00000000000 --- a/changelogs/unreleased/bump_gpgme_gem.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump gpgme gem version from 2.0.13 to 2.0.18 -merge_request: -author: asaparov -type: other diff --git a/changelogs/unreleased/bvl-use-shell-writeref.yml b/changelogs/unreleased/bvl-use-shell-writeref.yml deleted file mode 100644 index 682d428e8c5..00000000000 --- a/changelogs/unreleased/bvl-use-shell-writeref.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid creating invalid refs using rugged, shelling out for writing refs -merge_request: 23286 -author: -type: fixed diff --git a/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml b/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml deleted file mode 100644 index b5fd99c304f..00000000000 --- a/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix API::Namespaces routing to accept namepaces with dots -merge_request: 22912 -author: -type: fixed diff --git a/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml b/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml deleted file mode 100644 index eb5d2e3244c..00000000000 --- a/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Respect confirmed flag on secondary emails -merge_request: 23181 -author: -type: fixed diff --git a/changelogs/unreleased/cert-manager-email.yml b/changelogs/unreleased/cert-manager-email.yml deleted file mode 100644 index 530608d9660..00000000000 --- a/changelogs/unreleased/cert-manager-email.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Ability to override email for cert-manager -merge_request: 23503 -author: Amit Rathi -type: added diff --git a/changelogs/unreleased/certmanager-temp.yml b/changelogs/unreleased/certmanager-temp.yml deleted file mode 100644 index 3f908d01c9f..00000000000 --- a/changelogs/unreleased/certmanager-temp.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "#40635: Adds support for cert-manager" -merge_request: 23036 -author: Amit Rathi -type: added diff --git a/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml b/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml deleted file mode 100644 index 31c131045b9..00000000000 --- a/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Validate chunk size when persist -merge_request: 23341 -author: -type: fixed diff --git a/changelogs/unreleased/commit-badge-style-fix.yml b/changelogs/unreleased/commit-badge-style-fix.yml deleted file mode 100644 index d7b37717853..00000000000 --- a/changelogs/unreleased/commit-badge-style-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed styling of image comment badges on commits -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/define-default-value-for-only-except-keys.yml b/changelogs/unreleased/define-default-value-for-only-except-keys.yml deleted file mode 100644 index ed0e982f0fc..00000000000 --- a/changelogs/unreleased/define-default-value-for-only-except-keys.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Define the default value for only/except policies -merge_request: 23765 -author: -type: changed diff --git a/changelogs/unreleased/depracated-migration-inheritance.yml b/changelogs/unreleased/depracated-migration-inheritance.yml new file mode 100644 index 00000000000..1ea9b2df59c --- /dev/null +++ b/changelogs/unreleased/depracated-migration-inheritance.yml @@ -0,0 +1,5 @@ +--- +title: ActiveRecord::Migration -> ActiveRecord::Migration[5.0] +merge_request: 23910 +author: Jasper Maes +type: other diff --git a/changelogs/unreleased/deprecated-instance-find.yml b/changelogs/unreleased/deprecated-instance-find.yml deleted file mode 100644 index d2ba821e124..00000000000 --- a/changelogs/unreleased/deprecated-instance-find.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Fix deprecation: You are passing an instance of ActiveRecord::Base to' -merge_request: 23369 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/diff-expand-commit-file.yml b/changelogs/unreleased/diff-expand-commit-file.yml deleted file mode 100644 index 8ca784d75c1..00000000000 --- a/changelogs/unreleased/diff-expand-commit-file.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed diff files expanding not loading commit content -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/diff-fix-expanding.yml b/changelogs/unreleased/diff-fix-expanding.yml deleted file mode 100644 index 8ba7f87addc..00000000000 --- a/changelogs/unreleased/diff-fix-expanding.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed multiple diff line discussions not expanding -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/discussion-perf-improvement.yml b/changelogs/unreleased/discussion-perf-improvement.yml deleted file mode 100644 index defff8a55f5..00000000000 --- a/changelogs/unreleased/discussion-perf-improvement.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve initial discussion rendering performance -merge_request: 22607 -author: -type: changed diff --git a/changelogs/unreleased/dm-batch-loader-key.yml b/changelogs/unreleased/dm-batch-loader-key.yml deleted file mode 100644 index 047fdbc4b3f..00000000000 --- a/changelogs/unreleased/dm-batch-loader-key.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Batch load only data from same repository when lazy object is accessed -merge_request: 23309 -author: -type: performance diff --git a/changelogs/unreleased/dm-note-email-image-diff-discussion.yml b/changelogs/unreleased/dm-note-email-image-diff-discussion.yml new file mode 100644 index 00000000000..6532052e132 --- /dev/null +++ b/changelogs/unreleased/dm-note-email-image-diff-discussion.yml @@ -0,0 +1,5 @@ +--- +title: Fix notification email for image diff notes +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml b/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml deleted file mode 100644 index fb0c508400c..00000000000 --- a/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove old webhook logs after 90 days, as documented, instead of after 2 -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/docs-minor-aws-fixes.yml b/changelogs/unreleased/docs-minor-aws-fixes.yml deleted file mode 100644 index 64fa6b12afe..00000000000 --- a/changelogs/unreleased/docs-minor-aws-fixes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixes to AWS documentation spelling and grammar -merge_request: 23198 -author: Brendan O'Leary -type: other diff --git a/changelogs/unreleased/document-raw-snippet-api.yml b/changelogs/unreleased/document-raw-snippet-api.yml deleted file mode 100644 index 3b8818cea5c..00000000000 --- a/changelogs/unreleased/document-raw-snippet-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix lack of documentation on how to fetch a snippet's content using API -merge_request: 23448 -author: Colin Leroy -type: other diff --git a/changelogs/unreleased/drop-default-value-status-deployments.yml b/changelogs/unreleased/drop-default-value-status-deployments.yml deleted file mode 100644 index fdb826a0507..00000000000 --- a/changelogs/unreleased/drop-default-value-status-deployments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Drop default value on status column in deployments table -merge_request: 22971 -author: -type: other diff --git a/changelogs/unreleased/drop-gcp-cluster-table.yml b/changelogs/unreleased/drop-gcp-cluster-table.yml deleted file mode 100644 index 15964ec2eaf..00000000000 --- a/changelogs/unreleased/drop-gcp-cluster-table.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Drop gcp_clusters table -merge_request: 22713 -author: -type: other diff --git a/changelogs/unreleased/expose-mr-pipeline-variables.yml b/changelogs/unreleased/expose-mr-pipeline-variables.yml deleted file mode 100644 index b77b9a69d5c..00000000000 --- a/changelogs/unreleased/expose-mr-pipeline-variables.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Expose merge request pipeline variables -merge_request: 23398 -author: -type: changed diff --git a/changelogs/unreleased/feature-option-to-make-variables-protected.yml b/changelogs/unreleased/feature-option-to-make-variables-protected.yml new file mode 100644 index 00000000000..c99c0481c35 --- /dev/null +++ b/changelogs/unreleased/feature-option-to-make-variables-protected.yml @@ -0,0 +1,5 @@ +--- +title: Add option to make ci variables protected by default +merge_request: 22744 +author: Alexis Reigel +type: added diff --git a/changelogs/unreleased/fix-55448.yml b/changelogs/unreleased/fix-55448.yml new file mode 100644 index 00000000000..e0bdbb6eda4 --- /dev/null +++ b/changelogs/unreleased/fix-55448.yml @@ -0,0 +1,5 @@ +--- +title: Remove deprecated xhr from specs +merge_request: 23949 +author: Jasper Maes +type: other diff --git a/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml b/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml deleted file mode 100644 index 04fc88bc3d3..00000000000 --- a/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Encrypt CI/CD builds authentication tokens -merge_request: 23436 -author: -type: security diff --git a/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml b/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml deleted file mode 100644 index 4ce4f96c1dd..00000000000 --- a/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Encrypt runners tokens -merge_request: 23412 -author: -type: security diff --git a/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml b/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml deleted file mode 100644 index 52b431edf2c..00000000000 --- a/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve help and validation sections of maximum build timeout inputs -merge_request: 23586 -author: -type: fixed diff --git a/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml b/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml deleted file mode 100644 index ab926fbd43b..00000000000 --- a/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix unrelated deployment status in MR widget -merge_request: 23175 -author: -type: fixed diff --git a/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml b/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml deleted file mode 100644 index 20005ba355e..00000000000 --- a/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix multiple commits shade overlapping vertical discussion line -merge_request: 23515 -author: -type: fixed diff --git a/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml b/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml deleted file mode 100644 index 0f01552ff7e..00000000000 --- a/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade minimum required Git version to 2.18.0 -merge_request: 22803 -author: -type: other diff --git a/changelogs/unreleased/fj-clean-content-headers.yml b/changelogs/unreleased/fj-clean-content-headers.yml deleted file mode 100644 index 59e25ca6578..00000000000 --- a/changelogs/unreleased/fj-clean-content-headers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added feature flag to signal content headers detection by Workhorse -merge_request: 22667 -author: -type: added diff --git a/changelogs/unreleased/fj-force-content-disposition.yml b/changelogs/unreleased/fj-force-content-disposition.yml deleted file mode 100644 index d84555a489f..00000000000 --- a/changelogs/unreleased/fj-force-content-disposition.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Force content disposition attachment to several endpoints -merge_request: 23223 -author: -type: other diff --git a/changelogs/unreleased/force-reload-arguments-1.yml b/changelogs/unreleased/force-reload-arguments-1.yml deleted file mode 100644 index 29f34b8bdbe..00000000000 --- a/changelogs/unreleased/force-reload-arguments-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Passing an argument to force an association to reload is now deprecated -merge_request: 23334 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml deleted file mode 100644 index e718d716647..00000000000 --- a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable even more frozen string for lib/gitlab -merge_request: -author: gfyoung -type: performance diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml deleted file mode 100644 index e718d716647..00000000000 --- a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable even more frozen string for lib/gitlab -merge_request: -author: gfyoung -type: performance diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml deleted file mode 100644 index cfbc4ced635..00000000000 --- a/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable even more frozen string in lib/gitlab/**/*.rb -merge_request: -author: gfyoung -type: performance diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-more.yml deleted file mode 100644 index cfbc4ced635..00000000000 --- a/changelogs/unreleased/frozen-string-lib-gitlab-more.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable even more frozen string in lib/gitlab/**/*.rb -merge_request: -author: gfyoung -type: performance diff --git a/changelogs/unreleased/frozen-string-lib-rubocop.yml b/changelogs/unreleased/frozen-string-lib-rubocop.yml deleted file mode 100644 index 9fe342e251b..00000000000 --- a/changelogs/unreleased/frozen-string-lib-rubocop.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable Rubocop on lib/gitlab -merge_request: -author: gfyoung -type: other diff --git a/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml b/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml deleted file mode 100644 index 606314b5780..00000000000 --- a/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add top padding for nested environment items loading icon -merge_request: 23580 -author: George Tsiolis -type: fixed diff --git a/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml b/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml deleted file mode 100644 index 481ce656dc7..00000000000 --- a/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Align issue status label and confidential icon. -merge_request: 23046 -author: George Tsiolis -type: fixed diff --git a/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml b/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml deleted file mode 100644 index 233cc43117d..00000000000 --- a/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change breadcrumb title for contribution charts -merge_request: 23071 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/gt-change-container-width-for-project-import.yml b/changelogs/unreleased/gt-change-container-width-for-project-import.yml deleted file mode 100644 index ec2beb15912..00000000000 --- a/changelogs/unreleased/gt-change-container-width-for-project-import.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change container width for project import -merge_request: 23318 -author: George Tsiolis -type: fixed diff --git a/changelogs/unreleased/gt-externalize-app-views-invites.yml b/changelogs/unreleased/gt-externalize-app-views-invites.yml deleted file mode 100644 index b5a22177f9b..00000000000 --- a/changelogs/unreleased/gt-externalize-app-views-invites.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Externalize strings from `/app/views/invites` -merge_request: 23205 -author: Tao Wang -type: other diff --git a/changelogs/unreleased/gt-externalize-app-views-project-runners.yml b/changelogs/unreleased/gt-externalize-app-views-project-runners.yml deleted file mode 100644 index d7d591e2175..00000000000 --- a/changelogs/unreleased/gt-externalize-app-views-project-runners.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Externalize strings from `/app/views/project/runners` -merge_request: 23208 -author: Tao Wang -type: other diff --git a/changelogs/unreleased/gt-externalize-app-views-snippets.yml b/changelogs/unreleased/gt-externalize-app-views-snippets.yml deleted file mode 100644 index 633aa9f2534..00000000000 --- a/changelogs/unreleased/gt-externalize-app-views-snippets.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Externalize strings from `/app/views/snippets` -merge_request: 23351 -author: Tao Wang -type: other diff --git a/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml b/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml deleted file mode 100644 index 60603905a2d..00000000000 --- a/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix typo in notebook props -merge_request: 23103 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/gt-fix-typos-in-lib.yml b/changelogs/unreleased/gt-fix-typos-in-lib.yml deleted file mode 100644 index 32ccd03b063..00000000000 --- a/changelogs/unreleased/gt-fix-typos-in-lib.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix typos in lib -merge_request: 23106 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml b/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml deleted file mode 100644 index dc41de61046..00000000000 --- a/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove monospace extend -merge_request: 23089 -author: George Tsiolis -type: performance diff --git a/changelogs/unreleased/gt-remove-unused-project-method.yml b/changelogs/unreleased/gt-remove-unused-project-method.yml deleted file mode 100644 index 2d60c2fe423..00000000000 --- a/changelogs/unreleased/gt-remove-unused-project-method.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove unused project method -merge_request: 54103 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/gt-rename-diffs-store-variable.yml b/changelogs/unreleased/gt-rename-diffs-store-variable.yml deleted file mode 100644 index 0aed49f3d60..00000000000 --- a/changelogs/unreleased/gt-rename-diffs-store-variable.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rename diffs store variable -merge_request: 23123 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml b/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml deleted file mode 100644 index eed31950a76..00000000000 --- a/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show primary button when all labels are prioritized -merge_request: 23648 -author: George Tsiolis -type: other diff --git a/changelogs/unreleased/gt-update-env-metrics-empty-state.yml b/changelogs/unreleased/gt-update-env-metrics-empty-state.yml deleted file mode 100644 index a05dc07e65c..00000000000 --- a/changelogs/unreleased/gt-update-env-metrics-empty-state.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update environments metrics empty state -merge_request: 23074 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/gt-use-gl-tooltip-directive.yml b/changelogs/unreleased/gt-use-gl-tooltip-directive.yml deleted file mode 100644 index 91fdb73e3c6..00000000000 --- a/changelogs/unreleased/gt-use-gl-tooltip-directive.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Replace tooltip directive with gl-tooltip diretive in badges, cycle analytics, and diffs -merge_request: 22770 -author: George Tsiolis -type: performance diff --git a/changelogs/unreleased/ide-open-all-mr-files.yml b/changelogs/unreleased/ide-open-all-mr-files.yml deleted file mode 100644 index 6a5ea8908fc..00000000000 --- a/changelogs/unreleased/ide-open-all-mr-files.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Open first 10 merge request files in IDE -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml b/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml deleted file mode 100644 index 90f47aa12db..00000000000 --- a/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove auto deactivation when failed to create a pipeline via pipeline schedules -merge_request: 22243 -author: -type: changed diff --git a/changelogs/unreleased/improve_auto_devops_migration_debug.yml b/changelogs/unreleased/improve_auto_devops_migration_debug.yml deleted file mode 100644 index 96a78808361..00000000000 --- a/changelogs/unreleased/improve_auto_devops_migration_debug.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Auto DevOps: Add echo for each branch of the deploy() function where we run - helm upgrade' -merge_request: 23499 -author: -type: changed diff --git a/changelogs/unreleased/include-new-link-in-breadcrumb.yml b/changelogs/unreleased/include-new-link-in-breadcrumb.yml deleted file mode 100644 index 68c808d66d7..00000000000 --- a/changelogs/unreleased/include-new-link-in-breadcrumb.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Include new link in breadcrumb for issues, merge requests, milestones, and labels -merge_request: 18515 -author: George Tsiolis -type: changed diff --git a/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml b/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml deleted file mode 100644 index d21254b16d0..00000000000 --- a/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add empty state for graphs with no values -merge_request: 22630 -author: -type: fixed diff --git a/changelogs/unreleased/jupyter-tls.yml b/changelogs/unreleased/jupyter-tls.yml deleted file mode 100644 index 4111edd34ff..00000000000 --- a/changelogs/unreleased/jupyter-tls.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "#52753: HTTPS for JupyterHub installation" -merge_request: 23479 -author: Amit Rathi -type: added diff --git a/changelogs/unreleased/kcj-add-philosophy.yml b/changelogs/unreleased/kcj-add-philosophy.yml deleted file mode 100644 index d164ce165ea..00000000000 --- a/changelogs/unreleased/kcj-add-philosophy.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds a PHILOSOPHY.md which references GitLab Product Handbook -merge_request: 23200 -author: -type: other diff --git a/changelogs/unreleased/kubernetes-http-response-code.yml b/changelogs/unreleased/kubernetes-http-response-code.yml deleted file mode 100644 index 551fe2edc3c..00000000000 --- a/changelogs/unreleased/kubernetes-http-response-code.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show HTTP response code for Kubernetes errors -merge_request: 22964 -author: -type: other diff --git a/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml b/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml deleted file mode 100644 index c8e959176d0..00000000000 --- a/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fallback to admin KUBE_TOKEN for project clusters only -merge_request: 23527 -author: -type: other diff --git a/changelogs/unreleased/lock-trace-writes.yml b/changelogs/unreleased/lock-trace-writes.yml deleted file mode 100644 index 9c5239081b9..00000000000 --- a/changelogs/unreleased/lock-trace-writes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Lock writes to trace stream -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-deadlock-chunked-io.yml b/changelogs/unreleased/markdown-toolbar-btn-fix.yml index def7a59e86e..eefb4d19f86 100644 --- a/changelogs/unreleased/fix-deadlock-chunked-io.yml +++ b/changelogs/unreleased/markdown-toolbar-btn-fix.yml @@ -1,5 +1,5 @@ --- -title: Fix deadlock on ChunkedIO +title: Fixed markdown toolbar buttons merge_request: author: type: fixed diff --git a/changelogs/unreleased/mg-fix-knative-application-row.yml b/changelogs/unreleased/mg-fix-knative-application-row.yml deleted file mode 100644 index 95142d380a4..00000000000 --- a/changelogs/unreleased/mg-fix-knative-application-row.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Hide Knative from group cluster applications until supported -merge_request: 23577 -author: -type: fixed diff --git a/changelogs/unreleased/mk-avoid-read-only-error.yml b/changelogs/unreleased/mk-avoid-read-only-error.yml new file mode 100644 index 00000000000..8641f5db9f0 --- /dev/null +++ b/changelogs/unreleased/mk-avoid-read-only-error.yml @@ -0,0 +1,5 @@ +--- +title: Prevent admins from attempting hashed storage migration on read only DB +merge_request: 23597 +author: +type: fixed diff --git a/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml b/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml deleted file mode 100644 index 0269e7b6196..00000000000 --- a/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix error when searching for group issues with priority or popularity sort -merge_request: 23445 -author: -type: fixed diff --git a/changelogs/unreleased/mr-file-tree-commit.yml b/changelogs/unreleased/mr-file-tree-commit.yml deleted file mode 100644 index e0d47e6e61f..00000000000 --- a/changelogs/unreleased/mr-file-tree-commit.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show tree collapse button for merge request commit diffs -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/mr-origin-23218.yml b/changelogs/unreleased/mr-origin-23218.yml deleted file mode 100644 index 49867f04343..00000000000 --- a/changelogs/unreleased/mr-origin-23218.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix typo for scheduled pipeline -merge_request: 23218 -author: Davy Defaud -type: other diff --git a/changelogs/unreleased/mr-pipelines-2.yml b/changelogs/unreleased/mr-pipelines-2.yml deleted file mode 100644 index 683c626c3ce..00000000000 --- a/changelogs/unreleased/mr-pipelines-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Merge request pipelines -merge_request: 23217 -author: -type: added diff --git a/changelogs/unreleased/mr-sticky-headers.yml b/changelogs/unreleased/mr-sticky-headers.yml deleted file mode 100644 index c20829bc2d7..00000000000 --- a/changelogs/unreleased/mr-sticky-headers.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make diff file headers sticky -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/mr-tree-filter-path-name.yml b/changelogs/unreleased/mr-tree-filter-path-name.yml deleted file mode 100644 index 152f8a67337..00000000000 --- a/changelogs/unreleased/mr-tree-filter-path-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Changed merge request filtering to be by path instead of name -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/multiple-diff-line-discussions-fix.yml b/changelogs/unreleased/multiple-diff-line-discussions-fix.yml deleted file mode 100644 index 870a8ab3815..00000000000 --- a/changelogs/unreleased/multiple-diff-line-discussions-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed duplicate discussions getting added to diff lines -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/non-webkit-scrollbar-fixing.yml b/changelogs/unreleased/non-webkit-scrollbar-fixing.yml deleted file mode 100644 index 526a9f25486..00000000000 --- a/changelogs/unreleased/non-webkit-scrollbar-fixing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix horizontal scrollbar overlapping on horizontal scrolling-tabs -merge_request: 23167 -author: Harry Kiselev -type: other diff --git a/changelogs/unreleased/optimise-job-request.yml b/changelogs/unreleased/optimise-job-request.yml deleted file mode 100644 index e1265841b48..00000000000 --- a/changelogs/unreleased/optimise-job-request.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use cached size when passing artifacts to Runner -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/order-of-notification-settings.yml b/changelogs/unreleased/order-of-notification-settings.yml deleted file mode 100644 index 0f0243bcb40..00000000000 --- a/changelogs/unreleased/order-of-notification-settings.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: reorder notification settings by noisy-ness -merge_request: -author: C.J. Jameson -type: changed diff --git a/changelogs/unreleased/osw-fallback-on-blank-refs.yml b/changelogs/unreleased/osw-fallback-on-blank-refs.yml deleted file mode 100644 index 039179f5829..00000000000 --- a/changelogs/unreleased/osw-fallback-on-blank-refs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid Gitaly RPC errors when fetching diff stats -merge_request: 22995 -author: -type: fixed diff --git a/changelogs/unreleased/osw-fix-grouping-by-file-path.yml b/changelogs/unreleased/osw-fix-grouping-by-file-path.yml deleted file mode 100644 index dff3116e7c6..00000000000 --- a/changelogs/unreleased/osw-fix-grouping-by-file-path.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid 500's when serializing legacy diff notes -merge_request: 23544 -author: -type: fixed diff --git a/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml b/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml deleted file mode 100644 index 58d9a19d038..00000000000 --- a/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove unused data from discussions endpoint -merge_request: 23570 -author: -type: performance diff --git a/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml b/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml deleted file mode 100644 index 09a10a86adc..00000000000 --- a/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Populate MR metrics with events table information (migration) -merge_request: 23564 -author: -type: performance diff --git a/changelogs/unreleased/profile-fixing.yml b/changelogs/unreleased/profile-fixing.yml deleted file mode 100644 index 7e255d997d8..00000000000 --- a/changelogs/unreleased/profile-fixing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix bottom paddings of profile header and some markup updates of profile -merge_request: 23168 -author: Harry Kiselev -type: other diff --git a/changelogs/unreleased/project_identicon_fix.yml b/changelogs/unreleased/project_identicon_fix.yml deleted file mode 100644 index de4876fc4a5..00000000000 --- a/changelogs/unreleased/project_identicon_fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix project identicon aligning Harry Kiselev -merge_request: 23166 -author: Harry Kiselev -type: other diff --git a/changelogs/unreleased/rails5-active-record-class-value.yml b/changelogs/unreleased/rails5-active-record-class-value.yml deleted file mode 100644 index 9f9fdf10cd1..00000000000 --- a/changelogs/unreleased/rails5-active-record-class-value.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Rails5: Passing a class as a value in an Active Record query is deprecated' -merge_request: 23164 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/rails5-deprecation-render-nothing.yml b/changelogs/unreleased/rails5-deprecation-render-nothing.yml deleted file mode 100644 index 32e2d5800c7..00000000000 --- a/changelogs/unreleased/rails5-deprecation-render-nothing.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: render :nothing option is deprecated, Use head method to respond with empty - response body. -merge_request: 23311 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/rails5-env-deprecated.yml b/changelogs/unreleased/rails5-env-deprecated.yml deleted file mode 100644 index 2f8573e2ff6..00000000000 --- a/changelogs/unreleased/rails5-env-deprecated.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Rails5: env is deprecated and will be removed from Rails 5.1' -merge_request: 22626 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/remove-blob-search-limit.yml b/changelogs/unreleased/remove-blob-search-limit.yml deleted file mode 100644 index 5bad3a83dbb..00000000000 --- a/changelogs/unreleased/remove-blob-search-limit.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove limit of 100 when searching repository code. -merge_request: 8671 -author: -type: fixed diff --git a/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml b/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml deleted file mode 100644 index 2348bfab7d9..00000000000 --- a/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Return real deployment status to frontend -merge_request: 23270 -author: -type: fixed diff --git a/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml b/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml deleted file mode 100644 index 3a8b3a0df5d..00000000000 --- a/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove duplicate primary button in dashboard snippets on small viewports -merge_request: 22902 -author: George Tsiolis -type: fixed diff --git a/changelogs/unreleased/render-text-deprecated.yml b/changelogs/unreleased/render-text-deprecated.yml deleted file mode 100644 index 7dbbd13bcef..00000000000 --- a/changelogs/unreleased/render-text-deprecated.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Fix deprecation: render :text is deprecated because it does not actually render - a text/plain response' -merge_request: 23425 -author: Jasper Maes -type: other diff --git a/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml b/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml deleted file mode 100644 index 607f2709f90..00000000000 --- a/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Updates service to update Kubernetes project namespaces and restricted service - account if present -merge_request: 23525 -author: -type: changed diff --git a/changelogs/unreleased/revert-1cccfca1.yml b/changelogs/unreleased/revert-1cccfca1.yml deleted file mode 100644 index c1efdaac138..00000000000 --- a/changelogs/unreleased/revert-1cccfca1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Restore kubernetes:active in Auto-DevOps.gitlab-ci.yml (reverts 22929) -merge_request: 23826 -author: -type: fixed diff --git a/changelogs/unreleased/rs-cherry-pick-api.yml b/changelogs/unreleased/rs-cherry-pick-api.yml deleted file mode 100644 index ce844dfc939..00000000000 --- a/changelogs/unreleased/rs-cherry-pick-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve possible cherry pick API race condition -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/security-182-update-workhorse.yml b/changelogs/unreleased/security-182-update-workhorse.yml deleted file mode 100644 index 76850901b68..00000000000 --- a/changelogs/unreleased/security-182-update-workhorse.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Redact sensitive information on gitlab-workhorse log -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-2717-xss-username-autocomplete.yml b/changelogs/unreleased/security-2717-xss-username-autocomplete.yml deleted file mode 100644 index d9b1015eeb4..00000000000 --- a/changelogs/unreleased/security-2717-xss-username-autocomplete.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Escape user fullname while rendering autocomplete template to prevent XSS -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-2736-prometheus-ssrf.yml b/changelogs/unreleased/security-2736-prometheus-ssrf.yml deleted file mode 100644 index 9d0dda8a75f..00000000000 --- a/changelogs/unreleased/security-2736-prometheus-ssrf.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Do not follow redirects in Prometheus service when making http requests to the configured api url -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-2754-fix-lfs-import.yml b/changelogs/unreleased/security-2754-fix-lfs-import.yml deleted file mode 100644 index e8e74c9c3f6..00000000000 --- a/changelogs/unreleased/security-2754-fix-lfs-import.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Validate LFS hrefs before downloading them -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml b/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml deleted file mode 100644 index 0361fb0c041..00000000000 --- a/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't expose confidential information in commit message list -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-email-change-notification.yml b/changelogs/unreleased/security-email-change-notification.yml deleted file mode 100644 index 45075ff20bb..00000000000 --- a/changelogs/unreleased/security-email-change-notification.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Provide email notification when a user changes their email address -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-fix-pat-web-access.yml b/changelogs/unreleased/security-fix-pat-web-access.yml deleted file mode 100644 index 62ffb908fe5..00000000000 --- a/changelogs/unreleased/security-fix-pat-web-access.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Restrict Personal Access Tokens to API scope on web requests -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-fix-uri-xss-applications.yml b/changelogs/unreleased/security-fix-uri-xss-applications.yml deleted file mode 100644 index 0eaa1b1c4a3..00000000000 --- a/changelogs/unreleased/security-fix-uri-xss-applications.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Resolve reflected XSS in Ouath authorize window -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml b/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml deleted file mode 100644 index 32c85a2a7da..00000000000 --- a/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix SSRF in project integrations -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-fj-crlf-injection.yml b/changelogs/unreleased/security-fj-crlf-injection.yml deleted file mode 100644 index 861167b8a6e..00000000000 --- a/changelogs/unreleased/security-fj-crlf-injection.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix CRLF vulnerability in Project hooks -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-guest-comments.yml b/changelogs/unreleased/security-guest-comments.yml deleted file mode 100644 index 2c99512433b..00000000000 --- a/changelogs/unreleased/security-guest-comments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed ability to comment on locked/confidential issues. -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-guest-comments_2.yml b/changelogs/unreleased/security-guest-comments_2.yml deleted file mode 100644 index be6f2d6a490..00000000000 --- a/changelogs/unreleased/security-guest-comments_2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed ability of guest users to edit/delete comments on locked or confidential issues. -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-issue_51301.yml b/changelogs/unreleased/security-issue_51301.yml deleted file mode 100644 index cf8ebb54b1c..00000000000 --- a/changelogs/unreleased/security-issue_51301.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix milestone promotion authorization check -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-mermaid-xss.yml b/changelogs/unreleased/security-mermaid-xss.yml deleted file mode 100644 index bcf93ef37ff..00000000000 --- a/changelogs/unreleased/security-mermaid-xss.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Configure mermaid to not render HTML content in diagrams -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-pages-toctou-race.yml b/changelogs/unreleased/security-pages-toctou-race.yml deleted file mode 100644 index 1c055f6087f..00000000000 --- a/changelogs/unreleased/security-pages-toctou-race.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix a possible symlink time of check to time of use race condition in GitLab - Pages -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-private-group.yml b/changelogs/unreleased/security-private-group.yml deleted file mode 100644 index dbb7794dfed..00000000000 --- a/changelogs/unreleased/security-private-group.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Removed ability to see private group names when the group id is entered in - the url. -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-stored-xss-for-environments.yml b/changelogs/unreleased/security-stored-xss-for-environments.yml deleted file mode 100644 index 5d78ca00942..00000000000 --- a/changelogs/unreleased/security-stored-xss-for-environments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix stored XSS for Environments -merge_request: -author: -type: security diff --git a/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml b/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml deleted file mode 100644 index 3bd8123a346..00000000000 --- a/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix possible XSS attack in Markdown urls with spaces -merge_request: 2599 -author: -type: security diff --git a/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml b/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml deleted file mode 100644 index 6eac2a0146c..00000000000 --- a/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make KUBECONFIG nil if KUBE_TOKEN is nil -merge_request: 23414 -author: -type: fixed diff --git a/changelogs/unreleased/sh-53180-append-path.yml b/changelogs/unreleased/sh-53180-append-path.yml deleted file mode 100644 index 64fae5522d8..00000000000 --- a/changelogs/unreleased/sh-53180-append-path.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make sure there's only one slash as path separator -merge_request: 22954 -author: -type: other diff --git a/changelogs/unreleased/sh-bump-gems-security.yml b/changelogs/unreleased/sh-bump-gems-security.yml deleted file mode 100644 index 06489f6f979..00000000000 --- a/changelogs/unreleased/sh-bump-gems-security.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Bump nokogiri, loofah, and rack gems for security updates -merge_request: 23204 -author: -type: security diff --git a/changelogs/unreleased/sh-bump-ruby-2-5-3.yml b/changelogs/unreleased/sh-bump-ruby-2-5-3.yml deleted file mode 100644 index 13cadc73e9c..00000000000 --- a/changelogs/unreleased/sh-bump-ruby-2-5-3.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade to Ruby 2.5.3 -merge_request: 2806 -author: -type: performance diff --git a/changelogs/unreleased/sh-cache-avatar-paths.yml b/changelogs/unreleased/sh-cache-avatar-paths.yml new file mode 100644 index 00000000000..b59a4db413d --- /dev/null +++ b/changelogs/unreleased/sh-cache-avatar-paths.yml @@ -0,0 +1,5 @@ +--- +title: Cache avatar URLs and paths within a request +merge_request: 23950 +author: +type: performance diff --git a/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml b/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml deleted file mode 100644 index e42906e88f2..00000000000 --- a/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disable password autocomplete in mirror form fill -merge_request: 23402 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-http-clone-panel.yml b/changelogs/unreleased/sh-fix-http-clone-panel.yml new file mode 100644 index 00000000000..ab220bd5076 --- /dev/null +++ b/changelogs/unreleased/sh-fix-http-clone-panel.yml @@ -0,0 +1,5 @@ +--- +title: Fix missing Git clone button when protocol restriction setting enabled +merge_request: 24015 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-38317.yml b/changelogs/unreleased/sh-fix-issue-38317.yml deleted file mode 100644 index 13fcb5b8f96..00000000000 --- a/changelogs/unreleased/sh-fix-issue-38317.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove needless auto-capitalization on Wiki page titles -merge_request: 23288 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-51220.yml b/changelogs/unreleased/sh-fix-issue-51220.yml deleted file mode 100644 index 048f58611cb..00000000000 --- a/changelogs/unreleased/sh-fix-issue-51220.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Handle force_remove_source_branch when creating merge request -merge_request: 23281 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-issue-53783-ce.yml b/changelogs/unreleased/sh-fix-issue-53783-ce.yml deleted file mode 100644 index 10be1d81768..00000000000 --- a/changelogs/unreleased/sh-fix-issue-53783-ce.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix enabling project deploy key for admins -merge_request: 23043 -author: -type: fixed diff --git a/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml b/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml deleted file mode 100644 index 627de25650d..00000000000 --- a/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix "protected branches only" checkbox not set properly at init -merge_request: 23409 -author: -type: fixed diff --git a/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml b/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml deleted file mode 100644 index 185e2547e16..00000000000 --- a/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Gracefully handle unknown/invalid GPG keys -merge_request: 23492 -author: -type: fixed diff --git a/changelogs/unreleased/sh-handle-string-null-bytes.yml b/changelogs/unreleased/sh-handle-string-null-bytes.yml deleted file mode 100644 index edc045274e3..00000000000 --- a/changelogs/unreleased/sh-handle-string-null-bytes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Gracefully handle references with null bytes -merge_request: 23365 -author: -type: fixed diff --git a/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml b/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml deleted file mode 100644 index c010bd1f540..00000000000 --- a/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Only allow strings in URL::Sanitizer.valid? -merge_request: 23675 -author: -type: fixed diff --git a/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml b/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml deleted file mode 100644 index e8bee64f780..00000000000 --- a/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid caching BroadcastMessage as an ActiveRecord object -merge_request: 23662 -author: -type: fixed diff --git a/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml b/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml deleted file mode 100644 index 3ec15908fc7..00000000000 --- a/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove display of local Sidekiq process in /admin/sidekiq -merge_request: 23118 -author: -type: fixed diff --git a/changelogs/unreleased/sh-truncate-with-periods.yml b/changelogs/unreleased/sh-truncate-with-periods.yml deleted file mode 100644 index b1c6b4f9cbd..00000000000 --- a/changelogs/unreleased/sh-truncate-with-periods.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Truncate merge request titles with periods instead of ellipsis -merge_request: 23558 -author: -type: changed diff --git a/changelogs/unreleased/sh-use-nakayoshi-fork.yml b/changelogs/unreleased/sh-use-nakayoshi-fork.yml deleted file mode 100644 index 5977d9b0974..00000000000 --- a/changelogs/unreleased/sh-use-nakayoshi-fork.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve memory performance by reducing dirty pages after fork() -merge_request: 23169 -author: -type: performance diff --git a/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml b/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml deleted file mode 100644 index 6a82e32c416..00000000000 --- a/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use Nokogiri as the ActiveSupport XML backend -merge_request: 23136 -author: -type: performance diff --git a/changelogs/unreleased/spec-positional-arguments.yml b/changelogs/unreleased/spec-positional-arguments.yml new file mode 100644 index 00000000000..9dc114e5595 --- /dev/null +++ b/changelogs/unreleased/spec-positional-arguments.yml @@ -0,0 +1,5 @@ +--- +title: 'Fix deprecation: Using positional arguments in integration tests' +merge_request: 24009 +author: Jasper Maes +type: other diff --git a/changelogs/unreleased/specs-positional-arguments.yml b/changelogs/unreleased/specs-positional-arguments.yml new file mode 100644 index 00000000000..38b831bd72c --- /dev/null +++ b/changelogs/unreleased/specs-positional-arguments.yml @@ -0,0 +1,5 @@ +--- +title: convert specs in javascripts/ and support/ to new syntax +merge_request: 23947 +author: Jasper Maes +type: other diff --git a/changelogs/unreleased/speed-up-relative-positioning.yml b/changelogs/unreleased/speed-up-relative-positioning.yml deleted file mode 100644 index 3bd865fb5de..00000000000 --- a/changelogs/unreleased/speed-up-relative-positioning.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Speed up issue board lists in groups with many projects -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/store-correlation-logs.yml b/changelogs/unreleased/store-correlation-logs.yml deleted file mode 100644 index d5f6c789a17..00000000000 --- a/changelogs/unreleased/store-correlation-logs.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Log and pass correlation-id between Unicorn, Sidekiq and Gitaly -merge_request: -author: -type: added diff --git a/changelogs/unreleased/suggest-change-to-diff-line.yml b/changelogs/unreleased/suggest-change-to-diff-line.yml deleted file mode 100644 index cb949f14e8c..00000000000 --- a/changelogs/unreleased/suggest-change-to-diff-line.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add ability to render suggestions -merge_request: 23147 -author: -type: added diff --git a/changelogs/unreleased/support-gitaly-tls.yml b/changelogs/unreleased/support-gitaly-tls.yml new file mode 100644 index 00000000000..2a15500d6da --- /dev/null +++ b/changelogs/unreleased/support-gitaly-tls.yml @@ -0,0 +1,5 @@ +--- +title: Support tls communication in gitaly +merge_request: 22602 +author: +type: added diff --git a/changelogs/unreleased/switch-rails.yml b/changelogs/unreleased/switch-rails.yml deleted file mode 100644 index 4edf709dbd4..00000000000 --- a/changelogs/unreleased/switch-rails.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Switch to Rails 5 -merge_request: 21492 -author: -type: other diff --git a/changelogs/unreleased/tc-backfill-full-path-config.yml b/changelogs/unreleased/tc-backfill-full-path-config.yml deleted file mode 100644 index 4f06284d0e3..00000000000 --- a/changelogs/unreleased/tc-backfill-full-path-config.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Migration to write fullpath in all repository configs -merge_request: 22322 -author: -type: other diff --git a/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml b/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml deleted file mode 100644 index 90a5c8c4e2c..00000000000 --- a/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fill project_repositories for hashed storage projects -merge_request: 23482 -author: -type: added diff --git a/changelogs/unreleased/tc-repo-full-path-in-db.yml b/changelogs/unreleased/tc-repo-full-path-in-db.yml deleted file mode 100644 index ead8feabeb9..00000000000 --- a/changelogs/unreleased/tc-repo-full-path-in-db.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add model and relation to store repo full path in database -merge_request: 23143 -author: -type: added diff --git a/changelogs/unreleased/triggermesh-phase2-external-ip.yml b/changelogs/unreleased/triggermesh-phase2-external-ip.yml deleted file mode 100644 index 582c8f6df2e..00000000000 --- a/changelogs/unreleased/triggermesh-phase2-external-ip.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add an external IP address to the knative cluster application page -merge_request: -author: Chris Baumbauer -type: fixed diff --git a/changelogs/unreleased/triggermesh-phase2-knative-description.yml b/changelogs/unreleased/triggermesh-phase2-knative-description.yml deleted file mode 100644 index c6cee1984d5..00000000000 --- a/changelogs/unreleased/triggermesh-phase2-knative-description.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Modify the wording for the knative cluster application to match upstream -merge_request: 23289 -author: Chris Baumbauer -type: fixed diff --git a/changelogs/unreleased/triggermesh-phase2-serverless-list.yml b/changelogs/unreleased/triggermesh-phase2-serverless-list.yml deleted file mode 100644 index 22e1a35dd90..00000000000 --- a/changelogs/unreleased/triggermesh-phase2-serverless-list.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Introduce Knative and Serverless Components -merge_request: 23174 -author: Chris Baumbauer -type: added diff --git a/changelogs/unreleased/triggermesh-phase2-serverless.yml b/changelogs/unreleased/triggermesh-phase2-serverless.yml deleted file mode 100644 index bee2b5e1e2c..00000000000 --- a/changelogs/unreleased/triggermesh-phase2-serverless.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add knative client to kubeclient library -merge_request: 22968 -author: cab105 -type: added diff --git a/changelogs/unreleased/unicorn-monkey-patch.yml b/changelogs/unreleased/unicorn-monkey-patch.yml deleted file mode 100644 index 6b0e00ca291..00000000000 --- a/changelogs/unreleased/unicorn-monkey-patch.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add monkey patch to unicorn to fix eof? problem -merge_request: 23385 -author: -type: fixed diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml deleted file mode 100644 index dffcdb0bb5a..00000000000 --- a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update used version of Runner Helm Chart to 0.1.39 -merge_request: 23633 -author: -type: other diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml deleted file mode 100644 index 9051e4f79c8..00000000000 --- a/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update used version of Runner Helm Chart to 0.1.38 -merge_request: 23304 -author: -type: other diff --git a/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml b/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml deleted file mode 100644 index 1389693b9a9..00000000000 --- a/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade workhorse to 7.6.0 -merge_request: 23694 -author: -type: other diff --git a/changelogs/unreleased/upgrade_kubeclient_400.yml b/changelogs/unreleased/upgrade_kubeclient_400.yml deleted file mode 100644 index edb38710e6a..00000000000 --- a/changelogs/unreleased/upgrade_kubeclient_400.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade kubeclient to 4.0.0 -merge_request: 23261 -author: Praveen Arimbrathodiyil @pravi -type: other diff --git a/changelogs/unreleased/usage-count.yml b/changelogs/unreleased/usage-count.yml deleted file mode 100644 index efff2615ce4..00000000000 --- a/changelogs/unreleased/usage-count.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use approximate count for big tables for usage statistics. -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/validate-foreign-keys-being-indexed.yml b/changelogs/unreleased/validate-foreign-keys-being-indexed.yml deleted file mode 100644 index 6608a93c08f..00000000000 --- a/changelogs/unreleased/validate-foreign-keys-being-indexed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Validate foreign keys being created and indexed for column with _id -merge_request: 22808 -author: -type: performance diff --git a/changelogs/unreleased/winh-collapse-discussions.yml b/changelogs/unreleased/winh-collapse-discussions.yml deleted file mode 100644 index 19d04506318..00000000000 --- a/changelogs/unreleased/winh-collapse-discussions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix collapsing discussion replies -merge_request: 23462 -author: -type: fixed diff --git a/changelogs/unreleased/winh-divider-margin.yml b/changelogs/unreleased/winh-divider-margin.yml deleted file mode 100644 index db84090c15c..00000000000 --- a/changelogs/unreleased/winh-divider-margin.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adjust divider margin to comply with design specs -merge_request: 23548 -author: -type: changed diff --git a/changelogs/unreleased/winh-dropdown-divider-color.yml b/changelogs/unreleased/winh-dropdown-divider-color.yml deleted file mode 100644 index 6b6ecd831b8..00000000000 --- a/changelogs/unreleased/winh-dropdown-divider-color.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change dropdown divider color to gray-200 (#dfdfdf) -merge_request: 23592 -author: -type: changed diff --git a/changelogs/unreleased/winh-dropdown-item-padding.yml b/changelogs/unreleased/winh-dropdown-item-padding.yml deleted file mode 100644 index 9f18abba9d1..00000000000 --- a/changelogs/unreleased/winh-dropdown-item-padding.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adjust dropdown item and header padding to comply with design specs -merge_request: 23552 -author: -type: changed diff --git a/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml b/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml deleted file mode 100644 index 18f7da56edb..00000000000 --- a/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove close icon from projects dropdown in issue boards -merge_request: 23567 -author: -type: changed diff --git a/changelogs/unreleased/winh-markdown-preview-lists.yml b/changelogs/unreleased/winh-markdown-preview-lists.yml deleted file mode 100644 index 6e47726283d..00000000000 --- a/changelogs/unreleased/winh-markdown-preview-lists.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove unnecessary div from MarkdownField to apply list styles correctly -merge_request: 23733 -author: -type: fixed diff --git a/changelogs/unreleased/winh-merge-request-commit-context.yml b/changelogs/unreleased/winh-merge-request-commit-context.yml new file mode 100644 index 00000000000..9e12a926af4 --- /dev/null +++ b/changelogs/unreleased/winh-merge-request-commit-context.yml @@ -0,0 +1,5 @@ +--- +title: Display commit ID for discussions made on merge request commits +merge_request: 23837 +author: +type: fixed diff --git a/changelogs/unreleased/winh-merge-request-commit-discussion.yml b/changelogs/unreleased/winh-merge-request-commit-discussion.yml deleted file mode 100644 index b0c6264369b..00000000000 --- a/changelogs/unreleased/winh-merge-request-commit-discussion.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Display commit ID for commit diff discussion on merge request -merge_request: 23370 -author: -type: fixed diff --git a/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml b/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml deleted file mode 100644 index 2ce16a2b6b7..00000000000 --- a/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Pass commit when posting diff discussions -merge_request: 23371 -author: -type: fixed diff --git a/changelogs/unreleased/winh-milestone-select.yml b/changelogs/unreleased/winh-milestone-select.yml deleted file mode 100644 index 8464fc6c541..00000000000 --- a/changelogs/unreleased/winh-milestone-select.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix milestone select in issue sidebar of issue boards -merge_request: 23625 -author: -type: fixed diff --git a/changelogs/unreleased/winh-resolved-discussions-reply-field.yml b/changelogs/unreleased/winh-resolved-discussions-reply-field.yml deleted file mode 100644 index 01cf35ae8a7..00000000000 --- a/changelogs/unreleased/winh-resolved-discussions-reply-field.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Display reply field if resolved discussion has no replies -merge_request: 23801 -author: -type: fixed diff --git a/changelogs/unreleased/winh-upgrade-gitlab-ui.yml b/changelogs/unreleased/winh-upgrade-gitlab-ui.yml new file mode 100644 index 00000000000..b312a329f5d --- /dev/null +++ b/changelogs/unreleased/winh-upgrade-gitlab-ui.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade @gitlab/ui to 1.16.2 +merge_request: 23946 +author: +type: other diff --git a/changelogs/unreleased/workhorse-7-3-0.yml b/changelogs/unreleased/workhorse-7-3-0.yml deleted file mode 100644 index 6708b8a3cbb..00000000000 --- a/changelogs/unreleased/workhorse-7-3-0.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade GitLab Workhorse to v7.3.0 -merge_request: 23489 -author: -type: other diff --git a/changelogs/unreleased/zj-improve-gitaly-pb.yml b/changelogs/unreleased/zj-improve-gitaly-pb.yml deleted file mode 100644 index 506a0303d8a..00000000000 --- a/changelogs/unreleased/zj-improve-gitaly-pb.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Show what RPC is called in the performance bar -merge_request: 23140 -author: -type: other diff --git a/changelogs/unreleased/zj-pool-repository-creation.yml b/changelogs/unreleased/zj-pool-repository-creation.yml deleted file mode 100644 index a24b96e4924..00000000000 --- a/changelogs/unreleased/zj-pool-repository-creation.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow public forks to be deduplicated -merge_request: 23508 -author: -type: added diff --git a/changelogs/unreleased/zj-remove-broken-storage.yml b/changelogs/unreleased/zj-remove-broken-storage.yml deleted file mode 100644 index 9df87b40e09..00000000000 --- a/changelogs/unreleased/zj-remove-broken-storage.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove obsolete gitlab_shell rake tasks -merge_request: 22417 -author: -type: removed diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 1c16b999e55..7fe85f0e0d7 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -612,7 +612,7 @@ production: &base storages: # You must have at least a `default` storage path. default: path: /home/git/repositories/ - gitaly_address: unix:/home/git/gitlab/tmp/sockets/private/gitaly.socket # TCP connections are supported too (e.g. tcp://host:port) + gitaly_address: unix:/home/git/gitlab/tmp/sockets/private/gitaly.socket # TCP connections are supported too (e.g. tcp://host:port). TLS connections are also supported using the system certificate pool (eg: tls://host:port). # gitaly_token: 'special token' # Optional: override global gitaly.token for this storage. ## Backup settings diff --git a/config/initializers/8_metrics.rb b/config/initializers/zz_metrics.rb index 468f80939d7..462e8c811a6 100644 --- a/config/initializers/8_metrics.rb +++ b/config/initializers/zz_metrics.rb @@ -1,3 +1,6 @@ +# This file was prefixed with zz_ because we want to load it the last! +# See: https://gitlab.com/gitlab-org/gitlab-ce/issues/55611 + # Autoload all classes that we want to instrument, and instrument the methods we # need. This takes the Gitlab::Metrics::Instrumentation module as an argument so # that we can stub it for testing, as it is only called when metrics are diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile index be7b301866d..52af837c261 100644 --- a/danger/documentation/Dangerfile +++ b/danger/documentation/Dangerfile @@ -32,7 +32,7 @@ to be reviewed. | Tech writer | Stage(s) | | ------------ | ------------------------------------------------------------ | | `@marcia` | ~Create ~Release + ~"development guidelines" | -| `@axil` | ~Distribution ~Gitaly ~Gitter ~Monitoring ~Packaging ~Secure | +| `@axil` | ~Distribution ~Gitaly ~Gitter ~Monitoring ~Package ~Secure | | `@eread` | ~Manage ~Configure ~Geo ~Verify | | `@mikelewis` | ~Plan | diff --git a/db/fixtures/development/24_forks.rb b/db/fixtures/development/24_forks.rb index 61e39c871e6..5eb5956ec74 100644 --- a/db/fixtures/development/24_forks.rb +++ b/db/fixtures/development/24_forks.rb @@ -4,6 +4,12 @@ Sidekiq::Testing.inline! do Gitlab::Seeder.quiet do User.all.sample(10).each do |user| source_project = Project.public_only.sample + + ## + # 04_project.rb might not have created a public project because + # we use randomized approach (e.g. `Array#sample`). + return unless source_project + fork_project = Projects::ForkService.new(source_project, user, namespace: user.namespace).execute if fork_project.valid? diff --git a/db/migrate/20181006004100_import_common_metrics_nginx_vts.rb b/db/migrate/20181006004100_import_common_metrics_nginx_vts.rb index 98fafed7912..5cd312837df 100644 --- a/db/migrate/20181006004100_import_common_metrics_nginx_vts.rb +++ b/db/migrate/20181006004100_import_common_metrics_nginx_vts.rb @@ -1,4 +1,4 @@ -class ImportCommonMetricsNginxVts < ActiveRecord::Migration +class ImportCommonMetricsNginxVts < ActiveRecord::Migration[5.0] include Gitlab::Database::MigrationHelpers require Rails.root.join('db/importers/common_metrics_importer.rb') diff --git a/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb b/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb new file mode 100644 index 00000000000..85ee34afe1e --- /dev/null +++ b/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddProtectedCiVariablesToApplicationSettings < ActiveRecord::Migration[5.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default(:application_settings, :protected_ci_variables, :boolean, default: false, allow_null: false) + end + + def down + remove_column(:application_settings, :protected_ci_variables) + end +end diff --git a/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb b/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb new file mode 100644 index 00000000000..c37f8c039c0 --- /dev/null +++ b/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class MigrateClusterConfigureWorkerSidekiqQueue < ActiveRecord::Migration[5.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + sidekiq_queue_migrate 'gcp_cluster:cluster_platform_configure', to: 'gcp_cluster:cluster_configure' + end + + def down + sidekiq_queue_migrate 'gcp_cluster:cluster_configure', to: 'gcp_cluster:cluster_platform_configure' + end +end diff --git a/db/schema.rb b/db/schema.rb index 604ed1cd6b0..0af185409a9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20181218192239) do +ActiveRecord::Schema.define(version: 20181219145520) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -166,6 +166,7 @@ ActiveRecord::Schema.define(version: 20181218192239) do t.integer "diff_max_patch_bytes", default: 102400, null: false t.integer "archive_builds_in_seconds" t.string "commit_email_hostname" + t.boolean "protected_ci_variables", default: false, null: false t.string "runners_registration_token_encrypted" t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree end diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md index dc6a71e2ebd..cf37eaa0b61 100644 --- a/doc/administration/gitaly/index.md +++ b/doc/administration/gitaly/index.md @@ -1,6 +1,6 @@ # Gitaly -[Gitaly](https://gitlab.com/gitlab-org/gitaly) is the service that +[Gitaly](https://gitlab.com/gitlab-org/gitaly) is the service that provides high-level RPC access to Git repositories. Without it, no other components can read or write Git data. @@ -23,7 +23,7 @@ gitaly['prometheus_listen_addr'] = 'localhost:9236' ``` To change a Gitaly setting in installations from source you can edit -`/home/git/gitaly/config.toml`. Changes will be applied when you run +`/home/git/gitaly/config.toml`. Changes will be applied when you run `service gitlab restart`. ```toml @@ -91,13 +91,13 @@ documentation on configuring Gitaly authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configuration/README.md#authentication) . -Gitaly must trigger some callbacks to GitLab via GitLab Shell. As a result, +Gitaly must trigger some callbacks to GitLab via GitLab Shell. As a result, the GitLab Shell secret must be the same between the other GitLab servers and the Gitaly server. The easiest way to accomplish this is to copy `/etc/gitlab/gitlab-secrets.json` from an existing GitLab server to the Gitaly server. Without this shared secret, -Git operations in GitLab will result in an API error. +Git operations in GitLab will result in an API error. -> **NOTE:** In most or all cases the storage paths below end in `/repositories` which is +> **NOTE:** In most or all cases the storage paths below end in `/repositories` which is different than `path` in `git_data_dirs` of Omnibus installations. Check the directory layout on your Gitaly server to be sure. @@ -133,6 +133,11 @@ gitaly['storage'] = [ { 'name' => 'default', 'path' => '/mnt/gitlab/default/repositories' }, { 'name' => 'storage1', 'path' => '/mnt/gitlab/storage1/repositories' }, ] + +# To use tls for gitaly you need to add +gitaly['tls_listen_addr'] = "0.0.0.0:9999" +gitaly['certificate_path'] = "path/to/cert.pem" +gitaly['key_path'] = "path/to/key.pem" ``` Source installations: @@ -140,6 +145,11 @@ Source installations: ```toml # /home/git/gitaly/config.toml listen_addr = '0.0.0.0:8075' +tls_listen_addr = '0.0.0.0:9999' + +[tls] +certificate_path = /path/to/cert.pem +key_path = /path/to/key.pem [auth] token = 'abc123secret' @@ -205,6 +215,70 @@ Gitaly logs on your Gitaly server (`sudo gitlab-ctl tail gitaly` or coming in. One sure way to trigger a Gitaly request is to clone a repository from your GitLab server over HTTP. +## TLS support + +Gitaly supports TLS credentials for GRPC authentication. To be able to communicate +with a gitaly instance that listens for secure connections you will need to use `tls://` url +scheme in the `gitaly_address` of the corresponding storage entry in the gitlab configuration. + +The admin needs to bring their own certificate as we do not provide that automatically. +The certificate to be used needs to be installed on all gitaly nodes and on all client nodes that communicate with it following procedures described in [GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates) + +### Example TLS configuration + +### Omnibus installations: + +#### On client nodes: + +```ruby +# /etc/gitlab/gitlab.rb +git_data_dirs({ + 'default' => { 'path' => '/mnt/gitlab/default', 'gitaly_address' => 'tls://gitaly.internal:9999' }, + 'storage1' => { 'path' => '/mnt/gitlab/storage1', 'gitaly_address' => 'tls://gitaly.internal:9999' }, +}) + +gitlab_rails['gitaly_token'] = 'abc123secret' +``` + +#### On gitaly server nodes: + +```ruby +gitaly['tls_listen_addr'] = "0.0.0.0:9999" +gitaly['certificate_path'] = "path/to/cert.pem" +gitaly['key_path'] = "path/to/key.pem" +``` + +### Source installations: + +#### On client nodes: + +```yaml +# /home/git/gitlab/config/gitlab.yml +gitlab: + repositories: + storages: + default: + path: /mnt/gitlab/default/repositories + gitaly_address: tls://gitaly.internal:9999 + storage1: + path: /mnt/gitlab/storage1/repositories + gitaly_address: tls://gitaly.internal:9999 + + gitaly: + token: 'abc123secret' +``` + +#### On gitaly server nodes: + +```toml +# /home/git/gitaly/config.toml +tls_listen_addr = '0.0.0.0:9999' + +[tls] +certificate_path = '/path/to/cert.pem' +key_path = '/path/to/key.pem' +``` + ## Disabling or enabling the Gitaly service in a cluster environment If you are running Gitaly [as a remote diff --git a/doc/administration/index.md b/doc/administration/index.md index 6083806af6c..89132cd95f0 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -95,6 +95,7 @@ created in snippets, wikis, and repos. - [Postfix for incoming email](reply_by_email_postfix_setup.md): Set up a basic Postfix mail server with IMAP authentication on Ubuntu for incoming emails. +- [Abuse reports](../user/admin_area/abuse_reports.md): View and resolve abuse reports from your users. [reply by email]: reply_by_email.md [issues by email]: ../user/project/issues/create_new_issue.md#new-issue-via-email diff --git a/doc/api/jobs.md b/doc/api/jobs.md index 589c48ee08d..d2dd9c676e3 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -8,12 +8,12 @@ Get a list of jobs in a project. GET /projects/:id/jobs ``` -| Attribute | Type | Required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `scope` | string **or** array of strings | no | The scope of jobs to show, one or array of: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, `manual`; showing all jobs if none provided | +| Attribute | Type | Required | Description | +|-----------|--------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. | -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running' ``` @@ -140,13 +140,13 @@ Get a list of jobs for a pipeline. GET /projects/:id/pipelines/:pipeline_id/jobs ``` -| Attribute | Type | Required | Description | -|---------------|--------------------------------|----------|----------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `pipeline_id` | integer | yes | The ID of a pipeline | -| `scope` | string **or** array of strings | no | The scope of jobs to show, one or array of: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, `manual`; showing all jobs if none provided | +| Attribute | Type | Required | Description | +|---------------|--------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `pipeline_id` | integer | yes | The ID of a pipeline. | +| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. | -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" 'https://gitlab.example.com/api/v4/projects/1/pipelines/6/jobs?scope[]=pending&scope[]=running' ``` @@ -273,12 +273,12 @@ Get a single job of a project GET /projects/:id/jobs/:job_id ``` -| Attribute | Type | Required | Description | -|------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8" ``` @@ -348,18 +348,18 @@ Get job artifacts of a project. GET /projects/:id/jobs/:job_id/artifacts ``` -| Attribute | Type | Required | Description | -|------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | Example requests: -``` +```sh curl --location --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8/artifacts" ``` -Response: +Possible response status codes: | Status | Description | |-----------|---------------------------------| @@ -383,19 +383,19 @@ GET /projects/:id/jobs/artifacts/:ref_name/download?job=name Parameters -| Attribute | Type | Required | Description | -|-------------|---------|----------|-------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `ref_name` | string | yes | The ref from a repository (can only be branch or tag name, not HEAD or SHA) | -| `job` | string | yes | The name of the job | +| Attribute | Type | Required | Description | +|------------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `ref_name` | string | yes | Branch or tag name in repository. HEAD or SHA references are not supported. | +| `job` | string | yes | The name of the job. | Example requests: -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/master/download?job=test" ``` -Example response: +Possible response status codes: | Status | Description | |-----------|---------------------------------| @@ -408,9 +408,9 @@ Example response: > Introduced in GitLab 10.0 -Download a single artifact file from within the job's artifacts archive. - -Only a single file is going to be extracted from the archive and streamed to a client. +Download a single artifact file from a job with a specified ID from within +the job's artifacts archive. The file is extracted from the archive and +streamed to the client. ``` GET /projects/:id/jobs/:job_id/artifacts/*artifact_path @@ -418,19 +418,19 @@ GET /projects/:id/jobs/:job_id/artifacts/*artifact_path Parameters -| Attribute | Type | Required | Description | -|-----------------|---------|----------|-------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id ` | integer | yes | The unique job identifier | -| `artifact_path` | string | yes | Path to a file inside the artifacts archive | +| Attribute | Type | Required | Description | +|-----------------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id ` | integer | yes | The unique job identifier. | +| `artifact_path` | string | yes | Path to a file inside the artifacts archive. | Example request: -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/5/artifacts/some/release/file.pdf" ``` -Example response: +Possible response status codes: | Status | Description | |-----------|--------------------------------------| @@ -481,16 +481,16 @@ Get a trace of a specific job of a project GET /projects/:id/jobs/:job_id/trace ``` -| Attribute | Type | Required | Description | -|------------|---------|----------|---------------------| -| id | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| job_id | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| id | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| job_id | integer | yes | The ID of a job. | -``` +```sh curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/8/trace" ``` -Response: +Possible response status codes: | Status | Description | |-----------|-----------------------------------| @@ -505,12 +505,12 @@ Cancel a single job of a project POST /projects/:id/jobs/:job_id/cancel ``` -| Attribute | Type | Required | Description | -|------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | -``` +```sh curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/cancel" ``` @@ -553,12 +553,12 @@ Retry a single job of a project POST /projects/:id/jobs/:job_id/retry ``` -| Attribute | Type | Required | Description | -|------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | -``` +```sh curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/retry" ``` @@ -603,14 +603,14 @@ POST /projects/:id/jobs/:job_id/erase Parameters -| Attribute | Type | Required | Description | -|-------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | Example of request -``` +```sh curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/erase" ``` @@ -656,14 +656,14 @@ POST /projects/:id/jobs/:job_id/artifacts/keep Parameters -| Attribute | Type | Required | Description | -|-------------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | Example request: -``` +```sh curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/artifacts/keep" ``` @@ -707,12 +707,12 @@ Triggers a manual action to start a job. POST /projects/:id/jobs/:job_id/play ``` -| Attribute | Type | Required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `job_id` | integer | yes | The ID of a job | +| Attribute | Type | Required | Description | +|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. | +| `job_id` | integer | yes | The ID of a job. | -``` +```sh curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/1/play" ``` diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md index cae051daa56..1e2be2e8475 100644 --- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md +++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md @@ -254,7 +254,7 @@ To ensure our changes don't break the build and all tests still pass, we utilize Continuous Integration (CI) to run these checks automatically for every push. Read through this article to understand [Continuous Integration, Continuous Delivery, and Continuous Deployment](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/), and how these methods are leveraged by GitLab. -From the [last tutorial](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) we already have a `gitlab-ci.yml` file set up for building our app from +From the [last tutorial](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) we already have a `.gitlab-ci.yml` file set up for building our app from every push. We need to set up a new CI job for testing, which GitLab CI/CD will run after the build job using our generated artifacts from gulp. Please read through the [documentation on CI/CD configuration](../../../ci/yaml/README.md) file to explore its contents and adjust it to your needs. diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md index 706e83abf44..bf1e61442d4 100644 --- a/doc/ci/merge_request_pipelines/index.md +++ b/doc/ci/merge_request_pipelines/index.md @@ -1,11 +1,12 @@ # Pipelines for merge requests -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/15310) in GitLab 11.6 +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/15310) in GitLab 11.6. -Usually, when a developer creates a new merge request, a pipeline runs on the +Usually, when you create a new merge request, a pipeline runs on the new change and checks if it's qualified to be merged into a target branch. This pipeline should contain only necessary jobs for checking the new changes. -For example, unit tests, lint checks, and Review Apps are often used in this cycle. +For example, unit tests, lint checks, and [Review Apps](../review_apps/index.md) +are often used in this cycle. With pipelines for merge requests, you can design a specific pipeline structure for merge requests. All you need to do is just adding `only: [merge_requests]` to @@ -14,10 +15,10 @@ Every time, when developers create or update merge requests, a pipeline runs on their new commits at every push to GitLab. NOTE: **Note**: -If you use both this feature and the [Merge When Pipeline Succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md) -feature, pipelines for merge requests take precendence over the other regular pipelines. +If you use both this feature and [Merge When Pipeline Succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md), +pipelines for merge requests take precedence over the other regular pipelines. -For example, consider a GitLab CI/CD configuration in .gitlab-ci.yml as follows: +For example, consider the following [`.gitlab-ci.yml`](../yaml/README.md): ```yaml build: @@ -39,20 +40,18 @@ deploy: script: ./deploy ``` -After a developer updated code in a merge request with whatever methods (e.g. `git push`), -GitLab detects that the code is updated and create a new pipeline for the merge request. +After the merge request is updated with new commits, GitLab detects that changes +have occurred and creates a new pipeline for the merge request. The pipeline fetches the latest code from the source branch and run tests against it. -In this example, the pipeline contains only `build` and `test` jobs. -Since `deploy` job does not have the `only: [merge_requests]` rule, +In the above example, the pipeline contains only `build` and `test` jobs. +Since the `deploy` job doesn't have the `only: [merge_requests]` rule, deployment jobs will not happen in the merge request. -Consider this pipeline list viewed from the **Pipelines** tab in a merge request: +Pipelines tagged as **merge request** indicate that they were triggered +when a merge request was created or updated. ![Merge request page](img/merge_request.png) -Note that pipelines tagged as **merge request** indicate that they were triggered -when a merge request was created or updated. - The same tag is shown on the pipeline's details: ![Pipeline's details](img/pipeline_detail.png) @@ -66,7 +65,7 @@ flow, external contributors follow the following steps: 1. Create a merge request from the forked project that targets the `master` branch in the parent project. 1. A pipeline runs on the merge request. -1. A mainatiner from the parent project checks the pipeline result, and merge +1. A maintainer from the parent project checks the pipeline result, and merge into a target branch if the latest pipeline has passed. Currently, those pipelines are created in a **forked** project, not in the @@ -77,7 +76,7 @@ by tweaking their GitLab Runner in the forked project. There are multiple reasons about why GitLab doesn't allow those pipelines to be created in the parent project, but one of the biggest reasons is security concern. External users could steal secret variables from the parent project by modifying -.gitlab-ci.yml, which could be some sort of credentials. This should not happen. +`.gitlab-ci.yml`, which could be some sort of credentials. This should not happen. We're discussing a secure solution of running pipelines for merge requests that submitted from forked projects, diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 4df5d8fb54a..440254e58bd 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -584,15 +584,17 @@ osx job: ## `allow_failure` -`allow_failure` is used when you want to allow a job to fail without impacting -the rest of the CI suite. Failed jobs don't contribute to the commit status. +`allow_failure` allows a job to fail without impacting the rest of the CI +suite. The default value is `false`, except for [manual](#whenmanual) jobs. -When enabled and the job fails, the pipeline will be successful/green for all -intents and purposes, but a "CI build passed with warnings" message will be -displayed on the merge request or commit or job page. This is to be used by -jobs that are allowed to fail, but where failure indicates some other (manual) -steps should be taken elsewhere. +When enabled and the job fails, the job will show an orange warning in the UI. +However, the logical flow of the pipeline will consider the job a +success/passed, and is not blocked. + +Assuming all other jobs are successful, the job's stage and its pipeline will +show the same orange warning. However, the associated commit will be marked +"passed", without warnings. In the example below, `job1` and `job2` will run in parallel, but if `job1` fails, it will not stop the next stage from running, since it's marked with @@ -624,7 +626,8 @@ failure. `when` can be set to one of the following values: 1. `on_success` - execute job only when all jobs from prior stages - succeed. This is the default. + succeed (or are considered succeeding because they are marked + `allow_failure`). This is the default. 1. `on_failure` - execute job only when at least one job from prior stages fails. 1. `always` - execute job regardless of the status of jobs from prior stages. diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md index 5b32b5cd46f..6bcee74a3dd 100644 --- a/doc/development/contributing/merge_request_workflow.md +++ b/doc/development/contributing/merge_request_workflow.md @@ -179,7 +179,6 @@ merge request: 1. Note the addition in the release blog post (create one if it doesn't exist yet) https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/ 1. Upgrade guide, for example https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/7.5-to-7.6.md -1. Upgrader https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md#2-run-gitlab-upgrade-tool 1. Installation guide https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies 1. GitLab Development Kit https://gitlab.com/gitlab-org/gitlab-development-kit 1. Test suite https://gitlab.com/gitlab-org/gitlab-ce/blob/master/scripts/prepare_build.sh diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md index bef166f2aec..a36dc6424a7 100644 --- a/doc/development/instrumentation.md +++ b/doc/development/instrumentation.md @@ -35,7 +35,7 @@ Using this method is in general preferred over directly calling the various instrumentation methods. Method instrumentation should be added in the initializer -`config/initializers/8_metrics.rb`. +`config/initializers/zz_metrics.rb`. ### Examples diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md index 74e2598f860..26ced45de7b 100644 --- a/doc/install/kubernetes/gitlab_chart.md +++ b/doc/install/kubernetes/gitlab_chart.md @@ -47,8 +47,9 @@ In order to deploy GitLab on Kubernetes, the following are required: 1. `helm` and `kubectl` [installed on your computer](preparation/tools_installation.md). 1. A Kubernetes cluster, version 1.8 or higher. 6vCPU and 16GB of RAM is recommended. - - [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster) - [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) + - [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster) + - [IBM IKS](https://console.bluemix.net/docs/tutorials/scalable-webapp-kubernetes.html#create_kube_cluster) - [Microsoft AKS](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal) 1. A [wildcard DNS entry and external IP address](preparation/networking.md) 1. [Authenticate and connect](preparation/connect.md) to the cluster diff --git a/doc/ssh/README.md b/doc/ssh/README.md index d9ae3c08172..e570627bfc1 100644 --- a/doc/ssh/README.md +++ b/doc/ssh/README.md @@ -185,7 +185,26 @@ your terminal (replacing `gitlab.com` with your GitLab's instance domain): ssh -T git@gitlab.com ``` -You should receive a _Welcome to GitLab, `@username`!_ message. +The first time you connect to GitLab via SSH, you will be asked to verify the +authenticity of the GitLab host you are connecting to. +For example, when connecting to GitLab.com, answer `yes` to add GitLab.com to +the list of trusted hosts: + +``` +The authenticity of host 'gitlab.com (35.231.145.151)' can't be established. +ECDSA key fingerprint is SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw. +Are you sure you want to continue connecting (yes/no)? yes +Warning: Permanently added 'gitlab.com' (ECDSA) to the list of known hosts. +``` + +NOTE: **Note:** +For GitLab.com, consult the +[SSH host keys fingerprints](../user/gitlab_com/index.md#ssh-host-keys-fingerprints), +to make sure you're connecting to the correct server. + +Once added to the list of known hosts, you won't be asked to validate the +authenticity of GitLab's host again. Run the above command once more, and +you should only receive a _Welcome to GitLab, `@username`!_ message. If the welcome message doesn't appear, run SSH's verbose mode by replacing `-T` with `-vvvT` to understand where the error is. diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md deleted file mode 100644 index 746d6bf93e7..00000000000 --- a/doc/update/upgrader.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -comments: false ---- - -# GitLab Upgrader (deprecated) - -*DEPRECATED* We recommend to [switch to the Omnibus package and repository server](https://about.gitlab.com/update/) instead of using this script. - -Although deprecated, if someone wants to make this script into a gem or otherwise improve it merge requests are welcome. - -*Make sure you view this [upgrade guide from the 'master' branch](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md) for the most up to date instructions.* - -GitLab Upgrader - a ruby script that allows you easily upgrade GitLab to latest minor version. - -For example it can update your application from 6.4 to latest GitLab 6 version (like 6.6.1). - -You still need to create a backup and manually restart GitLab after running the script but all other operations are done by this upgrade script. - -If you have local changes to your GitLab repository the script will stash them and you need to use `git stash pop` after running the script. - -**GitLab Upgrader is available only for GitLab version 6.4.2 or higher.** - -**This script does NOT update gitlab-shell, it needs manual update. See step 5 below.** - -## 0. Backup - - cd /home/git/gitlab - sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production - -## 1. Stop server - - sudo service gitlab stop - -## 2. Run GitLab upgrade tool - -Please replace X.X.X with the [latest GitLab release](https://packages.gitlab.com/gitlab/gitlab-ce). - -GitLab 7.9 adds `nodejs` as a dependency. GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX). GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies) - - cd /home/git/gitlab - sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' - - # to perform a non-interactive install (no user input required) you can add -y - # sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y - -## 3. Start application - - sudo service gitlab start - sudo service nginx restart - -## 4. Check application status - -Check if GitLab and its dependencies are configured correctly: - - sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production - -If all items are green, then congratulations upgrade is complete! - -## 5. Upgrade GitLab Shell - -GitLab Shell might be outdated, running the commands below ensures you're using a compatible version: - -``` -cd /home/git/gitlab-shell -sudo -u git -H git fetch -sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi' -``` - -## One line upgrade command - -You've read through the entire guide and probably already did all the steps one by one. - -Below is a one line command with step 1 to 5 for the next time you upgrade. - -Please replace X.X.X with the [latest GitLab release](https://packages.gitlab.com/gitlab/gitlab-ce). - -```bash -cd /home/git/gitlab; \ - sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \ - sudo service gitlab stop; \ - sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y; \ - cd /home/git/gitlab-shell; \ - sudo -u git -H git fetch; \ - sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \ - sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi'; \ - cd /home/git/gitlab; \ - sudo service gitlab start; \ - sudo service nginx restart; \ - sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production -```
\ No newline at end of file diff --git a/doc/user/abuse_reports.md b/doc/user/abuse_reports.md new file mode 100644 index 00000000000..1f4f598b121 --- /dev/null +++ b/doc/user/abuse_reports.md @@ -0,0 +1,53 @@ +# Abuse reports + +Report abuse from users to GitLab administrators. + +You can report a user through their: + +- [Profile](#reporting-abuse-through-a-users-profile) +- [Comments](#reporting-abuse-through-a-users-comment) +- [Issues and Merge requests](#reporting-abuse-through-a-users-issue-or-merge-request) + +## Reporting abuse through a user's profile + +To report abuse from a user's profile page: + +1. Click on the exclamation point report abuse button at the top right of the user's profile. +1. Complete an abuse report. +1. Click the **Send report** button. + +## Reporting abuse through a user's comment + +To report abuse from a user's comment: + +1. Click on the vertical ellipsis (⋮) more actions button to open the dropdown. +1. Select **Report as abuse**. +1. Complete an abuse report. +1. Click the **Send report** button. + + +NOTE: **Note:** +A URL to the reported user's comment will be +pre-filled in the abuse report's **Message** field. + +## Reporting abuse through a user's issue or merge request + +The **Report abuse** button is displayed at the top right of the issue or merge request: + +- When **Report abuse** is selected from the menu that appears when the **Close issue** or **Close merge request** button is clicked, for users that have permission to close the issue or merge request. +- When viewing the issue or merge request, for users that don't have permission to close the issue or merge request. + +With the **Report abuse** button displayed, to submit an abuse report: + +1. Click the **Report abuse** button. +1. Submit an abuse report. +1. Click the **Send report** button. + +NOTE: **Note:** +A URL to the reported user's issue or merge request will be pre-filled +in the abuse report's **Message** field. + +## Managing abuse reports + +Admins are able to view and resolve abuse reports. +For more information, see [abuse reports administration documentation](admin_area/abuse_reports.md). diff --git a/doc/user/admin_area/abuse_reports.md b/doc/user/admin_area/abuse_reports.md new file mode 100644 index 00000000000..01c2d9607f5 --- /dev/null +++ b/doc/user/admin_area/abuse_reports.md @@ -0,0 +1,31 @@ +# Abuse reports + +View and resolve abuse reports from GitLab users. + +Admins can view abuse reports in the admin area and are able to +resolve the reports by removing the reported user, blocking the reported user, or removing the report. + +## Reporting abuse + +To find out more about reporting abuse, see [abuse reports user documentation](../abuse_reports.md). + +## Resolving abuse reports + +To access abuse reports, go to **Admin area > Abuse Reports**. + +There are 3 ways to resolve an abuse report, with a button for each method: + +- Remove user & report: [Deletes the reported user](../profile/account/delete_account.md) from the instance and removes the abuse report from the list. +- Block user: Blocks the reported user from the instance and does not remove the abuse report from the list. +- Remove report: Removes the abuse report from the list and does not restrict the access for the reported user. + +![abuse-reports-page-image](img/abuse_reports_page.png) + +## Blocked users + +Blocking a user will not remove the abuse report from the list. + +Instead, the block button will be disabled and explain that the user is "Already blocked". +You are still able to remove the user and/or report if necessary. + +![abuse-report-blocked-user-image](img/abuse_report_blocked_user.png) diff --git a/doc/user/admin_area/img/abuse_report_blocked_user.png b/doc/user/admin_area/img/abuse_report_blocked_user.png Binary files differnew file mode 100644 index 00000000000..0cb4c7bb8ac --- /dev/null +++ b/doc/user/admin_area/img/abuse_report_blocked_user.png diff --git a/doc/user/admin_area/img/abuse_reports_page.png b/doc/user/admin_area/img/abuse_reports_page.png Binary files differnew file mode 100644 index 00000000000..81dbe976cda --- /dev/null +++ b/doc/user/admin_area/img/abuse_reports_page.png diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md index 8e03d116b81..9f9b2da23e1 100644 --- a/doc/user/group/clusters/index.md +++ b/doc/user/group/clusters/index.md @@ -1,9 +1,7 @@ # Group-level Kubernetes clusters > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758) in GitLab 11.6. - -CAUTION: **Warning:** -Group Cluster integration is currently in **Beta**. +> Group Cluster integration is currently in [Beta](https://about.gitlab.com/handbook/product/#alpha-beta-ga). ## Overview diff --git a/doc/user/index.md b/doc/user/index.md index 08995032cb1..fc68404d0c2 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -113,6 +113,7 @@ methods available in GitLab. user type (guest, reporter, developer, maintainer, owner). - [Feature highlight](feature_highlight.md): Learn more about the little blue dots around the app that explain certain features +- [Abuse reports](abuse_reports.md): Report abuse from users to GitLab administrators ## Groups diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md index 49f0ce2cd79..b497cc414af 100644 --- a/doc/user/profile/account/delete_account.md +++ b/doc/user/profile/account/delete_account.md @@ -25,7 +25,7 @@ Here's a list of things that will not be deleted: Instead of being deleted, these records will be moved to a system-wide "Ghost User", whose sole purpose is to act as a container for such records. -When a user is deleted from an abuse report or spam log, these associated +When a user is deleted from an [abuse report](../../admin_area/abuse_reports.md) or spam log, these associated records are not ghosted and will be removed, along with any groups the user is a sole owner of. Administrators can also request this behaviour when deleting users from the [API](../../../api/users.md#user-deletion) or the @@ -35,4 +35,3 @@ admin area. [ce-10273]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10273 [ce-10467]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10467 [ce-11853]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11853 - diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index db48388e90d..6bdafc60949 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -254,15 +254,19 @@ install it manually. GitLab provides a one-click install for various applications which can be added directly to your configured cluster. Those applications are needed for [Review Apps](../../../ci/review_apps/index.md) and -[deployments](../../../ci/environments.md). +[deployments](../../../ci/environments.md). You can install them after you +[create a cluster](#adding-and-creating-a-new-gke-cluster-via-gitlab). + +To see a list of available applications to install: + +1. Navigate to your project's **Operations > Kubernetes**. +1. Select your cluster. + +Install Helm Tiller first because it's used to install other applications. NOTE: **Note:** -With the exception of Knative, the applications will be installed in a dedicated namespace called -`gitlab-managed-apps`. In case you have added an existing Kubernetes cluster -with Tiller already installed, you should be careful as GitLab cannot -detect it. In this event, installing Tiller via the applications will -result in the cluster having it twice. This can lead to confusion during -deployments. +As of GitLab 11.6, Helm Tiller will be upgraded to the latest version supported +by GitLab before installing any of the applications. | Application | GitLab version | Description | Helm Chart | | ----------- | :------------: | ----------- | --------------- | @@ -274,9 +278,14 @@ deployments. | [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) that installs additional useful packages on top of the base Jupyter. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found in [our Nurtch documentation](runbooks/index.md#nurtch-executable-runbooks). **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) | | [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#role-based-access-control-rbac). | [knative/knative](https://storage.googleapis.com/triggermesh-charts) -NOTE: **Note:** -As of GitLab 11.6 Helm Tiller will be upgraded to the latest version supported -by GitLab before installing any of the above applications. +With the exception of Knative, the applications will be installed in a dedicated +namespace called `gitlab-managed-apps`. + +CAUTION: **Caution:** +If you have an existing Kubernetes cluster with Tiller already installed, +you should be careful as GitLab cannot detect it. In this case, installing +Tiller via the applications will result in the cluster having it twice, which +can lead to confusion during deployments. ## Getting the external IP address diff --git a/doc/user/project/clusters/serverless/img/function-execution.png b/doc/user/project/clusters/serverless/img/function-execution.png Binary files differnew file mode 100644 index 00000000000..93b0b6d802d --- /dev/null +++ b/doc/user/project/clusters/serverless/img/function-execution.png diff --git a/doc/user/project/clusters/serverless/img/serverless-page.png b/doc/user/project/clusters/serverless/img/serverless-page.png Binary files differindex 5d808fc2d4f..960d6e736d6 100644 --- a/doc/user/project/clusters/serverless/img/serverless-page.png +++ b/doc/user/project/clusters/serverless/img/serverless-page.png diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md index c1f2e844362..a423212a879 100644 --- a/doc/user/project/clusters/serverless/index.md +++ b/doc/user/project/clusters/serverless/index.md @@ -1,9 +1,7 @@ # Serverless > Introduced in GitLab 11.5. - -CAUTION: **Caution:** -Serverless is currently in [alpha](https://about.gitlab.com/handbook/product/#alpha). +> Serverless is currently in [alpha](https://about.gitlab.com/handbook/product/#alpha). Run serverless workloads on Kubernetes using [Knative](https://cloud.google.com/knative/). @@ -31,13 +29,13 @@ To run Knative on Gitlab, you will need: external IP address for all the applications served by Knative. You will be prompted to enter a wildcard domain where your applications will be served. Configure your DNS server to use the external IP address for that domain. -1. **`gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko) +1. **`.gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko) to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm) to simplify the deployment of knative services and functions. -1. **`serverless.yml`** (for [functions only](#deploying-functions)): When using serverless to deploy functions, the `serverless.yml` file +1. **`serverless.yaml`** (for [functions only](#deploying-functions)): When using serverless to deploy functions, the `serverless.yaml` file will contain the information for all the functions being hosted in the repository as well as a reference to the runtime being used. -1. **`Dockerfile`:** Knative requires a `Dockerfile` in order to build your application. It should be included +1. **`Dockerfile`** (for [applications only](#deploying-serverless-applications): Knative requires a `Dockerfile` in order to build your application. It should be included at the root of your project's repo and expose port `8080`. ## Installing Knative via GitLab's Kubernetes integration @@ -75,13 +73,18 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22. > Introduced in GitLab 11.6. -Using functions is useful for initiating, responding, or triggering independent +Using functions is useful for dealing with independent events without needing to maintain a complex unified infrastructure. This allows you to focus on a single task that can be executed/scaled automatically and independently. -In order to deploy functions to your Knative instance, the following templates must be present: +Currently the following [runtimes](https://gitlab.com/triggermesh/runtimes) are offered: + +- node.js +- kaniko + +In order to deploy functions to your Knative instance, the following files must be present: -1. `gitlab-ci.yml`: This template allows to define the stage, environment, and +1. `.gitlab-ci.yml`: This template allows to define the stage, environment, and image to be used for your functions. It must be included at the root of your repository: ```yaml @@ -91,17 +94,22 @@ In order to deploy functions to your Knative instance, the following templates m functions: stage: deploy environment: test - image: gcr.io/triggermesh/tm:v0.0.6 + image: gcr.io/triggermesh/tm:v0.0.7 script: - tm -n "$KUBE_NAMESPACE" set registry-auth gitlab-registry --registry "$CI_REGISTRY" --username "$CI_REGISTRY_USER" --password "$CI_JOB_TOKEN" - tm -n "$KUBE_NAMESPACE" --registry-host "$CI_REGISTRY_IMAGE" deploy --wait ``` -2. `serverless.yml`: This template contains the metadata for your functions, - such as name, runtime, and environment. It must be included at the root of your repository: + The `gitlab-ci.yml` template creates a `Deploy` stage with a `functions` job that invokes the `tm` CLI with the required parameters. + +2. `serverless.yaml`: This file contains the metadata for your functions, + such as name, runtime, and environment. It must be included at the root of your repository. The following is a sample `echo` function which shows the required structure for the file. + + NOTE: **Note:** + The file extension for the `serverless.yaml` file must be specified as `.yaml` in order to the file to be parsed properly. Specifying the extension as `.yml` will not work. ```yaml - service: knative-test + service: my-functions description: "Deploying functions from GitLab using Knative" provider: @@ -111,27 +119,51 @@ In order to deploy functions to your Knative instance, the following templates m FOO: BAR functions: - container: - handler: simple - description: "knative canonical sample" - runtime: https://gitlab.com/triggermesh/runtimes/raw/master/kaniko.yaml + echo: + handler: echo + runtime: https://gitlab.com/triggermesh/runtimes/raw/master/nodejs.yaml + description: "echo function using node.js runtime" buildargs: - - DIRECTORY=simple - environment: - SIMPLE_MSG: Hello - - nodejs: - handler: nodejs - runtime: https://gitlab.com/triggermesh/runtimes/raw/master/nodejs.yaml - description: "nodejs fragment" - buildargs: - - DIRECTORY=nodejs + - DIRECTORY=echo environment: - FUNCTION: nodejs + FUNCTION: echo ``` -After the templates have been created, each function must be defined as a single -file in your repository. Committing a function to your project will result in a + +The `serverless.yaml` file contains three sections with distinct parameters: + +### `service` + +| Parameter | Description | +|-----------|-------------| +| `service` | Name for the Knative service which will serve the function. | +| `description` | A short description of the `service`. | + + +### `provider` + +| Parameter | Description | +|-----------|-------------| +| `name` | Indicates which provider is used to execute the `serverless.yaml` file. In this case, the TriggerMesh `tm` CLI. | +| `registry-secret` | Indicates which registry will be used to store docker images. The sample function is using the GitLab Registry (`gitlab-registry`). A different registry host may be specified using `registry` key in the `provider` object. If changing the default, update the permission and the secret value on the `gitlab-ci.yml` file | +| `environment` | Includes the environment variables to be passed as part of function execution for **all** functions in the file, where `FOO` is the variable name and `BAR` are he variable contents. You may replace this with you own variables. | + +### `functions` + +In the `serverless.yaml` example above, the function name is `echo` and the subsequent lines contain the function attributes. + + +| Parameter | Description | +|-----------|-------------| +| `handler` | The function's file name. In the example above, both the function name and the handler are the same. | +| `runtime` | The runtime to be used to execute the function. | +| `description` | A short description of the function. | +| `buildargs` | Pointer to the function file in the repo. In the sample the function is located in the `echo` directory. | +| `environment` | Sets an environment variable for the specific function only. | + +After the `gitlab-ci.yml` template has been added and the `serverless.yaml` file has been +created, each function must be defined as a single file in your repository. Committing a +function to your project will result in a CI pipeline being executed which will deploy each function as a Knative service. Once the deploy stage has finished, additional details for the function will appear under **Operations > Serverless**. @@ -149,6 +181,10 @@ The function details can be retrieved directly from Knative on the cluster: kubectl -n "$KUBE_NAMESPACE" get services.serving.knative.dev ``` +The sample function can now be triggered from any HTTP client using a simple `POST` call. + +![function exection](img/function-execution.png) + Currently, the Serverless page presents all functions available in all clusters registered for the project with Knative installed. ## Deploying Serverless applications @@ -190,17 +226,12 @@ deploy: ## Deploy the application with Knative -With all the pieces in place, you can create a new CI pipeline to deploy the Knative application. Navigate to -**CI/CD > Pipelines** and click the **Run Pipeline** button at the upper-right part of the screen. Then, on the -Pipelines page, click **Create pipeline**. +With all the pieces in place, the next time a CI pipeline runs, the Knative application will be deployed. Navigate to +**CI/CD > Pipelines** and click the most recent pipeline. ## Obtain the URL for the Knative deployment -There are two ways to obtain the URL for the Knative deployment. - -### Using the CI/CD deployment job output - -Once all the stages of the pipeline finish, click the **deploy** stage. +Use the CI/CD deployment job output to obtain the deployment URL. Once all the stages of the pipeline finish, click the **deploy** stage. ![deploy stage](img/deploy-stage.png) diff --git a/doc/user/project/img/releases.png b/doc/user/project/img/releases.png Binary files differnew file mode 100644 index 00000000000..aec1db89a75 --- /dev/null +++ b/doc/user/project/img/releases.png diff --git a/doc/user/project/releases.md b/doc/user/project/releases.md new file mode 100644 index 00000000000..8dad4240c91 --- /dev/null +++ b/doc/user/project/releases.md @@ -0,0 +1,12 @@ +# Releases + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41766) in GitLab 11.7. + +Releases mark specific points in a project's development history, communicate +information about the type of change, and deliver on prepared, often compiled, +versions of the software to be reused elsewhere. Currently, releases can only be +created through the API. + +Navigate to **Project > Releases** in order to see the list of releases of a project. + +![Releases list](img/releases.png) diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index 1710bba2fd0..fac5975a0dc 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -29,7 +29,7 @@ You can either use the user interface (UI), or connect your local computer with GitLab [through the command line](../../../gitlab-basics/command-line-commands.md#start-working-on-your-project). To configure [GitLab CI/CD](../../../ci/README.md) to build, test, and deploy -you code, add a file called [.`gitlab-ci.yml`](../../../ci/quick_start/README.md) +you code, add a file called [`.gitlab-ci.yml`](../../../ci/quick_start/README.md) to your repository's root. **From the user interface:** diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b83a5c14190..22403664c21 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -323,7 +323,7 @@ module API expose :request_access_enabled expose :full_name, :full_path - if ::Group.supports_nested_groups? + if ::Group.supports_nested_objects? expose :parent_id end diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 626a2008dee..64958ff982a 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -113,7 +113,7 @@ module API requires :name, type: String, desc: 'The name of the group' requires :path, type: String, desc: 'The path of the group' - if ::Group.supports_nested_groups? + if ::Group.supports_nested_objects? optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group' end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index a7d67a6300e..c3eca713712 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -163,9 +163,11 @@ module API end def find_branch!(branch_name) - user_project.repository.find_branch(branch_name) || not_found!('Branch') - rescue Gitlab::Git::CommandError - render_api_error!('The branch refname is invalid', 400) + if Gitlab::GitRefValidator.validate(branch_name) + user_project.repository.find_branch(branch_name) || not_found!('Branch') + else + render_api_error!('The branch refname is invalid', 400) + end end def find_project_label(id) diff --git a/lib/gitlab/fake_application_settings.rb b/lib/gitlab/fake_application_settings.rb index db1aeeea8d3..bd806269bf0 100644 --- a/lib/gitlab/fake_application_settings.rb +++ b/lib/gitlab/fake_application_settings.rb @@ -37,5 +37,9 @@ module Gitlab def pick_repository_storage repository_storages.sample end + + def commit_email_hostname + super.presence || ApplicationSetting.default_commit_email_hostname + end end end diff --git a/lib/gitlab/git/object_pool.rb b/lib/gitlab/git/object_pool.rb index ba9b40b7df4..1c6242b444a 100644 --- a/lib/gitlab/git/object_pool.rb +++ b/lib/gitlab/git/object_pool.rb @@ -8,7 +8,7 @@ module Gitlab GL_REPOSITORY = "" delegate :exists?, :size, to: :repository - delegate :delete, to: :object_pool_service + delegate :unlink_repository, :delete, to: :object_pool_service attr_reader :storage, :relative_path, :source_repository diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index 11021ee06b3..8bf8a3b53cd 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -26,6 +26,7 @@ module Gitlab end end + PEM_REGEX = /\-+BEGIN CERTIFICATE\-+.+?\-+END CERTIFICATE\-+/m SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION' MAXIMUM_GITALY_CALLS = 35 CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze @@ -50,11 +51,42 @@ module Gitlab @stubs[storage][name] ||= begin klass = stub_class(name) addr = stub_address(storage) - klass.new(addr, :this_channel_is_insecure) + creds = stub_creds(storage) + klass.new(addr, creds) end end end + def self.stub_cert_paths + cert_paths = Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*"] + cert_paths << OpenSSL::X509::DEFAULT_CERT_FILE if File.exist? OpenSSL::X509::DEFAULT_CERT_FILE + cert_paths + end + + def self.stub_certs + return @certs if @certs + + @certs = stub_cert_paths.flat_map do |cert_file| + File.read(cert_file).scan(PEM_REGEX).map do |cert| + begin + OpenSSL::X509::Certificate.new(cert).to_pem + rescue OpenSSL::OpenSSLError => e + Rails.logger.error "Could not load certificate #{cert_file} #{e}" + Gitlab::Sentry.track_exception(e, extra: { cert_file: cert_file }) + nil + end + end.compact + end.uniq.join("\n") + end + + def self.stub_creds(storage) + if URI(address(storage)).scheme == 'tls' + GRPC::Core::ChannelCredentials.new stub_certs + else + :this_channel_is_insecure + end + end + def self.stub_class(name) if name == :health_check Grpc::Health::V1::Health::Stub @@ -64,9 +96,7 @@ module Gitlab end def self.stub_address(storage) - addr = address(storage) - addr = addr.sub(%r{^tcp://}, '') if URI(addr).scheme == 'tcp' - addr + address(storage).sub(%r{^tcp://|^tls://}, '') end def self.clear_stubs! @@ -88,8 +118,8 @@ module Gitlab raise "storage #{storage.inspect} is missing a gitaly_address" end - unless URI(address).scheme.in?(%w(tcp unix)) - raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix'" + unless URI(address).scheme.in?(%w(tcp unix tls)) + raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix' or 'tls'" end address diff --git a/lib/gitlab/gitaly_client/object_pool_service.rb b/lib/gitlab/gitaly_client/object_pool_service.rb index 272ce73ad64..6e7ede5fd18 100644 --- a/lib/gitlab/gitaly_client/object_pool_service.rb +++ b/lib/gitlab/gitaly_client/object_pool_service.rb @@ -35,7 +35,10 @@ module Gitlab end def unlink_repository(repository) - request = Gitaly::UnlinkRepositoryFromObjectPoolRequest.new(repository: repository.gitaly_repository) + request = Gitaly::UnlinkRepositoryFromObjectPoolRequest.new( + object_pool: object_pool, + repository: repository.gitaly_repository + ) GitalyClient.call(storage, :object_pool_service, :unlink_repository_from_object_pool, request, timeout: GitalyClient.fast_timeout) diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb index c9e2a6a78d9..bdecff0931c 100644 --- a/lib/gitlab/import_export/command_line_util.rb +++ b/lib/gitlab/import_export/command_line_util.rb @@ -3,7 +3,8 @@ module Gitlab module ImportExport module CommandLineUtil - DEFAULT_MODE = 0700 + UNTAR_MASK = 'u+rwX,go+rX,go-w' + DEFAULT_DIR_MODE = 0700 def tar_czf(archive:, dir:) tar_with_options(archive: archive, dir: dir, options: 'czf') @@ -14,8 +15,8 @@ module Gitlab end def mkdir_p(path) - FileUtils.mkdir_p(path, mode: DEFAULT_MODE) - FileUtils.chmod(DEFAULT_MODE, path) + FileUtils.mkdir_p(path, mode: DEFAULT_DIR_MODE) + FileUtils.chmod(DEFAULT_DIR_MODE, path) end private @@ -41,6 +42,7 @@ module Gitlab def untar_with_options(archive:, dir:, options:) execute(%W(tar -#{options} #{archive} -C #{dir})) + execute(%W(chmod -R #{UNTAR_MASK} #{dir})) end def execute(cmd) diff --git a/lib/gitlab/json_cache.rb b/lib/gitlab/json_cache.rb new file mode 100644 index 00000000000..1adf83739ad --- /dev/null +++ b/lib/gitlab/json_cache.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Gitlab + class JsonCache + attr_reader :backend, :cache_key_with_version, :namespace + + def initialize(options = {}) + @backend = options.fetch(:backend, Rails.cache) + @namespace = options.fetch(:namespace, nil) + @cache_key_with_version = options.fetch(:cache_key_with_version, true) + end + + def active? + if backend.respond_to?(:active?) + backend.active? + else + true + end + end + + def cache_key(key) + expanded_cache_key = [namespace, key].compact + + if cache_key_with_version + expanded_cache_key << Rails.version + end + + expanded_cache_key.join(':') + end + + def expire(key) + backend.delete(cache_key(key)) + end + + def read(key, klass = nil) + value = backend.read(cache_key(key)) + value = parse_value(value, klass) if value + value + end + + def write(key, value, options = nil) + backend.write(cache_key(key), value.to_json, options) + end + + def fetch(key, options = {}, &block) + klass = options.delete(:as) + value = read(key, klass) + + return value unless value.nil? + + value = yield + + write(key, value, options) + + value + end + + private + + def parse_value(raw, klass) + value = ActiveSupport::JSON.decode(raw) + + case value + when Hash then parse_entry(value, klass) + when Array then parse_entries(value, klass) + else + value + end + rescue ActiveSupport::JSON.parse_error + nil + end + + def parse_entry(raw, klass) + klass.new(raw) if valid_entry?(raw, klass) + end + + def valid_entry?(raw, klass) + return false unless klass && raw.is_a?(Hash) + + (raw.keys - klass.attribute_names).empty? + end + + def parse_entries(values, klass) + values.map { |value| parse_entry(value, klass) }.compact + end + end +end diff --git a/lib/gitlab/group_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index 97cbdc6cb39..f2772c733c7 100644 --- a/lib/gitlab/group_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -1,16 +1,16 @@ # frozen_string_literal: true module Gitlab - # Retrieving of parent or child groups based on a base ActiveRecord relation. + # Retrieving of parent or child objects based on a base ActiveRecord relation. # # This class uses recursive CTEs and as a result will only work on PostgreSQL. - class GroupHierarchy + class ObjectHierarchy attr_reader :ancestors_base, :descendants_base, :model # ancestors_base - An instance of ActiveRecord::Relation for which to - # get parent groups. + # get parent objects. # descendants_base - An instance of ActiveRecord::Relation for which to - # get child groups. If omitted, ancestors_base is used. + # get child objects. If omitted, ancestors_base is used. def initialize(ancestors_base, descendants_base = ancestors_base) raise ArgumentError.new("Model of ancestors_base does not match model of descendants_base") if ancestors_base.model != descendants_base.model @@ -39,7 +39,7 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord - # Returns a relation that includes the ancestors_base set of groups + # Returns a relation that includes the ancestors_base set of objects # and all their ancestors (recursively). # # Passing an `upto` will stop the recursion once the specified parent_id is @@ -47,13 +47,13 @@ module Gitlab # included. # # Passing a `hierarchy_order` with either `:asc` or `:desc` will cause the - # recursive query order from most nested group to root or from the root - # ancestor to most nested group respectively. This uses a `depth` column + # recursive query order from most nested object to root or from the root + # ancestor to most nested object respectively. This uses a `depth` column # where `1` is defined as the depth for the base and increment as we go up # each parent. # rubocop: disable CodeReuse/ActiveRecord def base_and_ancestors(upto: nil, hierarchy_order: nil) - return ancestors_base unless Group.supports_nested_groups? + return ancestors_base unless hierarchy_supported? recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all) recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order @@ -62,16 +62,16 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord - # Returns a relation that includes the descendants_base set of groups + # Returns a relation that includes the descendants_base set of objects # and all their descendants (recursively). def base_and_descendants - return descendants_base unless Group.supports_nested_groups? + return descendants_base unless hierarchy_supported? read_only(base_and_descendants_cte.apply_to(model.all)) end - # Returns a relation that includes the base groups, their ancestors, - # and the descendants of the base groups. + # Returns a relation that includes the base objects, their ancestors, + # and the descendants of the base objects. # # The resulting query will roughly look like the following: # @@ -91,16 +91,16 @@ module Gitlab # Using this approach allows us to further add criteria to the relation with # Rails thinking it's selecting data the usual way. # - # If nested groups are not supported, ancestors_base is returned. + # If nested objects are not supported, ancestors_base is returned. # rubocop: disable CodeReuse/ActiveRecord - def all_groups - return ancestors_base unless Group.supports_nested_groups? + def all_objects + return ancestors_base unless hierarchy_supported? ancestors = base_and_ancestors_cte descendants = base_and_descendants_cte - ancestors_table = ancestors.alias_to(groups_table) - descendants_table = descendants.alias_to(groups_table) + ancestors_table = ancestors.alias_to(objects_table) + descendants_table = descendants.alias_to(objects_table) relation = model .unscoped @@ -117,23 +117,27 @@ module Gitlab private + def hierarchy_supported? + Gitlab::Database.postgresql? + end + # rubocop: disable CodeReuse/ActiveRecord def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil) cte = SQL::RecursiveCTE.new(:base_and_ancestors) depth_column = :depth base_query = ancestors_base.except(:order) - base_query = base_query.select("1 as #{depth_column}", groups_table[Arel.star]) if hierarchy_order + base_query = base_query.select("1 as #{depth_column}", objects_table[Arel.star]) if hierarchy_order cte << base_query # Recursively get all the ancestors of the base set. parent_query = model - .from([groups_table, cte.table]) - .where(groups_table[:id].eq(cte.table[:parent_id])) + .from([objects_table, cte.table]) + .where(objects_table[:id].eq(cte.table[:parent_id])) .except(:order) - parent_query = parent_query.select(cte.table[depth_column] + 1, groups_table[Arel.star]) if hierarchy_order + parent_query = parent_query.select(cte.table[depth_column] + 1, objects_table[Arel.star]) if hierarchy_order parent_query = parent_query.where(cte.table[:parent_id].not_eq(stop_id)) if stop_id cte << parent_query @@ -149,15 +153,15 @@ module Gitlab # Recursively get all the descendants of the base set. cte << model - .from([groups_table, cte.table]) - .where(groups_table[:parent_id].eq(cte.table[:id])) + .from([objects_table, cte.table]) + .where(objects_table[:parent_id].eq(cte.table[:id])) .except(:order) cte end # rubocop: enable CodeReuse/ActiveRecord - def groups_table + def objects_table model.arel_table end diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb deleted file mode 100644 index ccab0e4dd73..00000000000 --- a/lib/gitlab/upgrader.rb +++ /dev/null @@ -1,111 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - class Upgrader - def execute - puts "GitLab #{current_version.major} upgrade tool" - puts "Your version is #{current_version}" - puts "Latest available version for GitLab #{current_version.major} is #{latest_version}" - - if latest_version? - puts "You are using the latest GitLab version" - else - puts "Newer GitLab version is available" - - answer = if ARGV.first == "-y" - "yes" - else - prompt("Do you want to upgrade (yes/no)? ", %w{yes no}) - end - - if answer == "yes" - upgrade - else - exit 0 - end - end - end - - def latest_version? - current_version >= latest_version - end - - def current_version - @current_version ||= Gitlab::VersionInfo.parse(current_version_raw) - end - - def latest_version - @latest_version ||= Gitlab::VersionInfo.parse(latest_version_raw) - end - - def current_version_raw - File.read(File.join(gitlab_path, "VERSION")).strip - end - - def latest_version_raw - git_tags = fetch_git_tags - git_tags = git_tags.select { |version| version =~ /v\d+\.\d+\.\d+\Z/ } - git_versions = git_tags.map { |tag| Gitlab::VersionInfo.parse(tag.match(/v\d+\.\d+\.\d+/).to_s) } - "v#{git_versions.sort.last}" - end - - def fetch_git_tags - remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git)) - remote_tags.split("\n").grep(%r{tags/v#{current_version.major}}) - end - - def update_commands - { - "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash), - "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch), - "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}), - "Install gems" => %w(bundle), - "Migrate DB" => %w(bundle exec rake db:migrate), - "Recompile assets" => %w(bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile), - "Clear cache" => %w(bundle exec rake cache:clear) - } - end - - def env - { - 'RAILS_ENV' => 'production', - 'NODE_ENV' => 'production' - } - end - - def upgrade - update_commands.each do |title, cmd| - puts title - puts " -> #{cmd.join(' ')}" - - if system(env, *cmd) - puts " -> OK" - else - puts " -> FAILED" - puts "Failed to upgrade. Try to repeat task or proceed with upgrade manually " - exit 1 - end - end - - puts "Done" - end - - def gitlab_path - File.expand_path(File.join(File.dirname(__FILE__), '../..')) - end - - # Prompt the user to input something - # - # message - the message to display before input - # choices - array of strings of acceptable answers or nil for any answer - # - # Returns the user's answer - def prompt(message, choices = nil) - begin - print(message) - answer = STDIN.gets.chomp - end while !choices.include?(answer) - answer - end - end -end diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb index c412961ea3f..c87e97d0213 100644 --- a/lib/gitlab/utils/override.rb +++ b/lib/gitlab/utils/override.rb @@ -4,16 +4,11 @@ module Gitlab module Utils module Override class Extension - def self.verify_class!(klass, method_name) - instance_method_defined?(klass, method_name) || - raise( - NotImplementedError.new( - "#{klass}\##{method_name} doesn't exist!")) - end - - def self.instance_method_defined?(klass, name, include_super: true) - klass.instance_methods(include_super).include?(name) || - klass.private_instance_methods(include_super).include?(name) + def self.verify_class!(klass, method_name, arity) + extension = new(klass) + parents = extension.parents_for(klass) + extension.verify_method!( + klass: klass, parents: parents, method_name: method_name, sub_method_arity: arity) end attr_reader :subject @@ -22,35 +17,77 @@ module Gitlab @subject = subject end - def add_method_name(method_name) - method_names << method_name - end - - def add_class(klass) - classes << klass + def parents_for(klass) + index = klass.ancestors.index(subject) + klass.ancestors.drop(index + 1) end def verify! classes.each do |klass| - index = klass.ancestors.index(subject) - parents = klass.ancestors.drop(index + 1) - - method_names.each do |method_name| - parents.any? do |parent| - self.class.instance_method_defined?( - parent, method_name, include_super: false) - end || - raise( - NotImplementedError.new( - "#{klass}\##{method_name} doesn't exist!")) + parents = parents_for(klass) + + method_names.each_pair do |method_name, arity| + verify_method!( + klass: klass, + parents: parents, + method_name: method_name, + sub_method_arity: arity) end end end + def verify_method!(klass:, parents:, method_name:, sub_method_arity:) + overridden_parent = parents.find do |parent| + instance_method_defined?(parent, method_name) + end + + raise NotImplementedError.new("#{klass}\##{method_name} doesn't exist!") unless overridden_parent + + super_method_arity = find_direct_method(overridden_parent, method_name).arity + + unless arity_compatible?(sub_method_arity, super_method_arity) + raise NotImplementedError.new("#{subject}\##{method_name} has arity of #{sub_method_arity}, but #{overridden_parent}\##{method_name} has arity of #{super_method_arity}") + end + end + + def add_method_name(method_name, arity = nil) + method_names[method_name] = arity + end + + def add_class(klass) + classes << klass + end + + def verify_override?(method_name) + method_names.has_key?(method_name) + end + private + def instance_method_defined?(klass, name) + klass.instance_methods(false).include?(name) || + klass.private_instance_methods(false).include?(name) + end + + def find_direct_method(klass, name) + method = klass.instance_method(name) + method = method.super_method until method && klass == method.owner + method + end + + def arity_compatible?(sub_method_arity, super_method_arity) + if sub_method_arity >= 0 && super_method_arity >= 0 + # Regular arguments + sub_method_arity == super_method_arity + else + # It's too complex to check this case, just allow sub-method having negative arity + # But we don't allow sub_method_arity > 0 yet super_method_arity < 0 + sub_method_arity < 0 + end + end + def method_names - @method_names ||= [] + @method_names ||= {} end def classes @@ -80,11 +117,21 @@ module Gitlab def override(method_name) return unless ENV['STATIC_VERIFICATION'] + Override.extensions[self] ||= Extension.new(self) + Override.extensions[self].add_method_name(method_name) + end + + def method_added(method_name) + super + + return unless ENV['STATIC_VERIFICATION'] + return unless Override.extensions[self]&.verify_override?(method_name) + + method_arity = instance_method(method_name).arity if is_a?(Class) - Extension.verify_class!(self, method_name) + Extension.verify_class!(self, method_name, method_arity) else # We delay the check for modules - Override.extensions[self] ||= Extension.new(self) - Override.extensions[self].add_method_name(method_name) + Override.extensions[self].add_method_name(method_name, method_arity) end end diff --git a/lib/tasks/gitlab/storage.rake b/lib/tasks/gitlab/storage.rake index f539b1df955..09dc3aa9882 100644 --- a/lib/tasks/gitlab/storage.rake +++ b/lib/tasks/gitlab/storage.rake @@ -2,6 +2,12 @@ namespace :gitlab do namespace :storage do desc 'GitLab | Storage | Migrate existing projects to Hashed Storage' task migrate_to_hashed: :environment do + if Gitlab::Database.read_only? + warn 'This task requires database write access. Exiting.' + + next + end + storage_migrator = Gitlab::HashedStorage::Migrator.new helper = Gitlab::HashedStorage::RakeHelper @@ -9,7 +15,7 @@ namespace :gitlab do project = Project.with_unmigrated_storage.find_by(id: helper.range_from) unless project - puts "There are no projects requiring storage migration with ID=#{helper.range_from}" + warn "There are no projects requiring storage migration with ID=#{helper.range_from}" next end @@ -23,7 +29,7 @@ namespace :gitlab do legacy_projects_count = Project.with_unmigrated_storage.count if legacy_projects_count == 0 - puts 'There are no projects requiring storage migration. Nothing to do!' + warn 'There are no projects requiring storage migration. Nothing to do!' next end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 61fb56d2fa2..b27efe04966 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -97,9 +97,6 @@ msgstr[1] "" msgid "%{actionText} & %{openOrClose} %{noteable}" msgstr "" -msgid "%{bio} at %{organization}" -msgstr "" - msgid "%{commit_author_link} authored %{commit_timeago}" msgstr "" @@ -438,9 +435,15 @@ msgstr "" msgid "AdminProjects|Delete project" msgstr "" +msgid "AdminSettings|Environment variables are protected by default" +msgstr "" + msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages." msgstr "" +msgid "AdminSettings|When creating a new environment variable it will be protected by default." +msgstr "" + msgid "AdminUsers|Block user" msgstr "" @@ -525,6 +528,9 @@ msgstr "" msgid "An error has occurred" msgstr "" +msgid "An error occured while fetching the releases. Please try again." +msgstr "" + msgid "An error occurred creating the new branch." msgstr "" @@ -2743,6 +2749,15 @@ msgstr "" msgid "Enter the merge request title" msgstr "" +msgid "Environment variables" +msgstr "" + +msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want." +msgstr "" + +msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default" +msgstr "" + msgid "Environments" msgstr "" @@ -3172,6 +3187,9 @@ msgstr "" msgid "Geo" msgstr "" +msgid "Getting started with releases" +msgstr "" + msgid "Git" msgstr "" @@ -3756,7 +3774,7 @@ msgstr "" msgid "Job|The artifacts were removed" msgstr "" -msgid "Job|The artifacts will be removed in" +msgid "Job|The artifacts will be removed" msgstr "" msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it." @@ -4090,9 +4108,6 @@ msgstr "" msgid "Merge Request" msgstr "" -msgid "Merge Request:" -msgstr "" - msgid "Merge Requests" msgstr "" @@ -4132,6 +4147,9 @@ msgstr "" msgid "MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}" msgstr "" +msgid "MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}" +msgstr "" + msgid "MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}" msgstr "" @@ -4628,6 +4646,9 @@ msgstr "" msgid "Open" msgstr "" +msgid "Open Documentation" +msgstr "" + msgid "Open in Xcode" msgstr "" @@ -5527,6 +5548,9 @@ msgstr "" msgid "Releases" msgstr "" +msgid "Releases mark specific points in a project's development history, communicate information about the type of change, and deliver on prepared, often compiled, versions of the software to be reused elsewhere. Currently, releases can only be created through the API." +msgstr "" + msgid "Remind later" msgstr "" @@ -7137,10 +7161,13 @@ msgstr "" msgid "Trending" msgstr "" -msgid "Trigger" +msgid "Trigger this manual action" msgstr "" -msgid "Trigger this manual action" +msgid "Trigger token:" +msgstr "" + +msgid "Trigger variables:" msgstr "" msgid "Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will impersonate their associated user including their access to projects and their project permissions." @@ -7338,15 +7365,6 @@ msgstr "" msgid "Users requesting access to" msgstr "" -msgid "Variables" -msgstr "" - -msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want." -msgstr "" - -msgid "Variables:" -msgstr "" - msgid "Various container registry settings." msgstr "" @@ -7876,6 +7894,9 @@ msgstr "" msgid "importing" msgstr "" +msgid "in" +msgstr "" + msgid "issue boards" msgstr "" diff --git a/package.json b/package.json index 8ee31b8e57b..1dc9797c59b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@babel/preset-env": "^7.1.0", "@gitlab/csslab": "^1.8.0", "@gitlab/svgs": "^1.43.0", - "@gitlab/ui": "^1.15.0", + "@gitlab/ui": "^1.18.0", "apollo-boost": "^0.1.20", "apollo-client": "^2.4.5", "autosize": "^4.0.0", diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 88ade66f47d..615d17bbcfe 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -108,8 +108,12 @@ module QA element.select value.to_s.capitalize end - def has_element?(name) - has_css?(element_selector_css(name)) + def has_element?(name, wait: Capybara.default_max_wait_time) + has_css?(element_selector_css(name), wait: wait) + end + + def has_no_text?(text) + page.has_no_text? text end def within_element(name) diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 97ffe0e5716..cb83ace20b6 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -35,13 +35,21 @@ module QA element :saml_login_button end + view 'app/views/layouts/devise.html.haml' do + element :login_page + end + def initialize # The login page is usually the entry point for all the scenarios so # we need to wait for the instance to start. That said, in some cases # we are already logged-in so we check both cases here. + # Check if we're already logged in first. If we don't then we have to + # wait 10 seconds for the check for the login page to fail every time + # we use this class when we're already logged in (E.g., whenever we + # create a personal access token to use for API access). wait(max: 500) do - has_css?('.login-page') || - Page::Main::Menu.act { has_personal_area?(wait: 0) } + Page::Main::Menu.act { has_personal_area?(wait: 0) } || + has_element?(:login_page) end end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index cc2724618e9..6804cc8fb20 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -63,15 +63,11 @@ module QA end def has_personal_area?(wait: Capybara.default_max_wait_time) - using_wait_time(wait) do - page.has_selector?(element_selector_css(:user_avatar)) - end + has_element?(:user_avatar, wait: wait) end def has_admin_area_link?(wait: Capybara.default_max_wait_time) - using_wait_time(wait) do - page.has_selector?(element_selector_css(:admin_area_link)) - end + has_element?(:admin_area_link, wait: wait) end private diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 43bc16d8c9a..df3b794b14b 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -77,7 +77,7 @@ module QA super end - def has_element?(name) + def has_element?(name, wait: Capybara.default_max_wait_time) found = super log("has_element? :#{name} returned #{found}") @@ -85,6 +85,14 @@ module QA found end + def has_no_text?(text) + found = super + + log(%Q{has_no_text?('#{text}') returned #{found}}) + + found + end + def within_element(name) log("within element :#{name}") diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb index 9d56353062b..a54ff424f53 100644 --- a/qa/spec/page/logging_spec.rb +++ b/qa/spec/page/logging_spec.rb @@ -65,6 +65,13 @@ describe QA::Support::Page::Logging do .to output(/has_element\? :element returned true/).to_stdout_from_any_process end + it 'logs has_no_text?' do + allow(page).to receive(:has_no_text?).with('foo').and_return(true) + + expect { subject.has_no_text? 'foo' } + .to output(/has_no_text\?\('foo'\) returned true/).to_stdout_from_any_process + end + it 'logs within_element' do expect { subject.within_element(:element) } .to output(/within element :element/).to_stdout_from_any_process diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 00a00306ff9..ed38dadfd6b 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -78,9 +78,11 @@ describe Groups::GroupMembersController do Gitlab::Access.options.each do |label, value| it "can change the access level to #{label}" do - xhr :put, :update, group_member: { access_level: value }, - group_id: group, - id: requester + put :update, params: { + group_member: { access_level: value }, + group_id: group, + id: requester + }, xhr: true expect(requester.reload.human_access).to eq(label) end @@ -130,7 +132,7 @@ describe Groups::GroupMembersController do end it '[JS] removes user from members' do - xhr :delete, :destroy, group_id: group, id: member + delete :destroy, params: { group_id: group, id: member }, xhr: true expect(response).to be_success expect(group.members).not_to include member diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index ea266384446..d94c18ddc02 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -311,7 +311,7 @@ describe Projects::ClustersController do describe 'security' do before do - allow(ClusterPlatformConfigureWorker).to receive(:perform_async) + allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end @@ -409,7 +409,7 @@ describe Projects::ClustersController do end before do - allow(ClusterPlatformConfigureWorker).to receive(:perform_async) + allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index a927d4329ef..e54cf3e8181 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -16,7 +16,7 @@ describe Projects::DeployKeysController do end context 'when html requested' do - it 'redirects to blob' do + it 'redirects to project settings with the correct anchor' do get :index, params: params expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-deploy-keys-settings')) @@ -60,6 +60,40 @@ describe Projects::DeployKeysController do end end + describe 'POST create' do + def create_params(title = 'my-key') + { + namespace_id: project.namespace.path, + project_id: project.path, + deploy_key: { + title: title, + key: attributes_for(:deploy_key)[:key], + deploy_keys_projects_attributes: { '0' => { can_push: '1' } } + } + } + end + + it 'creates a new deploy key for the project' do + expect { post :create, params: create_params }.to change(project.deploy_keys, :count).by(1) + + expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-deploy-keys-settings')) + end + + it 'redirects to project settings with the correct anchor' do + post :create, params: create_params + + expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-deploy-keys-settings')) + end + + context 'when the deploy key is invalid' do + it 'shows an alert with the validations errors' do + post :create, params: create_params(nil) + + expect(flash[:alert]).to eq("Title can't be blank, Deploy keys projects deploy key title can't be blank") + end + end + end + describe '/enable/:id' do let(:deploy_key) { create(:deploy_key) } let(:project2) { create(:project) } diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index f9193513a6a..a239ac16c0d 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -206,12 +206,12 @@ describe Projects::IssuesController do describe 'Redirect after sign in' do context 'with an AJAX request' do it 'does not store the visited URL' do - xhr :get, - :show, + get :show, params: { format: :json, namespace_id: project.namespace, project_id: project, id: issue.iid + }, xhr: true expect(session['user_return_to']).to be_blank end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 962dfb91c9f..759a4b8bdce 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -30,19 +30,6 @@ describe Projects::MergeRequestsController do end end - shared_examples "loads labels" do |action| - it "loads labels into the @labels variable" do - get action, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: merge_request.iid - }, - format: 'html' - expect(assigns(:labels)).not_to be_nil - end - end - describe "GET show" do def go(extra_params = {}) params = { @@ -54,8 +41,6 @@ describe Projects::MergeRequestsController do get :show, params: params.merge(extra_params) end - it_behaves_like "loads labels", :show - describe 'as html' do context 'when diff files were cleaned' do render_views @@ -333,7 +318,7 @@ describe Projects::MergeRequestsController do before do project.add_reporter(user) - xhr :post, :merge, params: base_params + post :merge, params: base_params, xhr: true end it 'returns 404' do @@ -681,13 +666,14 @@ describe Projects::MergeRequestsController do merge_request.title = merge_request.wip_title merge_request.save - xhr :post, :remove_wip, - format: :json, + post :remove_wip, params: { + format: :json, namespace_id: merge_request.project.namespace.to_param, project_id: merge_request.project, id: merge_request.iid - } + }, + xhr: true end it 'removes the wip status' do @@ -701,13 +687,14 @@ describe Projects::MergeRequestsController do describe 'POST cancel_merge_when_pipeline_succeeds' do subject do - xhr :post, :cancel_merge_when_pipeline_succeeds, - format: :json, + post :cancel_merge_when_pipeline_succeeds, params: { + format: :json, namespace_id: merge_request.project.namespace.to_param, project_id: merge_request.project, id: merge_request.iid - } + }, + xhr: true end it 'calls MergeRequests::MergeWhenPipelineSucceedsService' do diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 009f85903b5..3cc3fe69fba 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -82,10 +82,12 @@ describe Projects::ProjectMembersController do Gitlab::Access.options.each do |label, value| it "can change the access level to #{label}" do - xhr :put, :update, project_member: { access_level: value }, - namespace_id: project.namespace, - project_id: project, - id: requester + put :update, params: { + project_member: { access_level: value }, + namespace_id: project.namespace, + project_id: project, + id: requester + }, xhr: true expect(requester.reload.human_access).to eq(label) end @@ -148,9 +150,11 @@ describe Projects::ProjectMembersController do end it '[JS] removes user from members' do - xhr :delete, :destroy, namespace_id: project.namespace, - project_id: project, - id: member + delete :destroy, params: { + namespace_id: project.namespace, + project_id: project, + id: member + }, xhr: true expect(response).to be_success expect(project.members).not_to include member diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index ea299e1e8c5..62f2af947e4 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -22,13 +22,13 @@ describe Projects::RefsController do end def xhr_get(format = :html) - xhr :get, - :logs_tree, - namespace_id: project.namespace.to_param, - project_id: project, - id: 'master', - path: 'foo/bar/baz.html', - format: format + get :logs_tree, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: 'master', + path: 'foo/bar/baz.html', + format: format + }, xhr: true end it 'never throws MissingTemplate' do diff --git a/spec/controllers/projects/tags/releases_controller_spec.rb b/spec/controllers/projects/tags/releases_controller_spec.rb index 6bf4ac65a45..29f206c574b 100644 --- a/spec/controllers/projects/tags/releases_controller_spec.rb +++ b/spec/controllers/projects/tags/releases_controller_spec.rb @@ -18,7 +18,7 @@ describe Projects::Tags::ReleasesController do tag_id = release.tag project.releases.destroy_all # rubocop: disable DestroyAll - get :edit, namespace_id: project.namespace, project_id: project, tag_id: tag_id + get :edit, params: { namespace_id: project.namespace, project_id: project, tag_id: tag_id } release = assigns(:release) expect(release).not_to be_nil @@ -26,7 +26,7 @@ describe Projects::Tags::ReleasesController do end it 'retrieves an existing release' do - get :edit, namespace_id: project.namespace, project_id: project, tag_id: release.tag + get :edit, params: { namespace_id: project.namespace, project_id: project, tag_id: release.tag } release = assigns(:release) expect(release).not_to be_nil @@ -48,10 +48,11 @@ describe Projects::Tags::ReleasesController do end def update_release(description) - put :update, + put :update, params: { namespace_id: project.namespace.to_param, project_id: project, tag_id: release.tag, release: { description: description } + } end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 2d1f48bf249..c51f2f958f9 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -64,6 +64,21 @@ FactoryBot.define do resolved_at { Time.now } resolved_by { create(:user) } end + + factory :image_diff_note_on_merge_request do + position do + Gitlab::Diff::Position.new( + old_path: "files/images/any_image.png", + new_path: "files/images/any_image.png", + width: 10, + height: 10, + x: 1, + y: 1, + diff_refs: diff_refs, + position_type: "image" + ) + end + end end factory :diff_note_on_commit, traits: [:on_commit], class: DiffNote do diff --git a/spec/factories/pool_repositories.rb b/spec/factories/pool_repositories.rb index 265a4643f46..36e54cf44b4 100644 --- a/spec/factories/pool_repositories.rb +++ b/spec/factories/pool_repositories.rb @@ -15,6 +15,10 @@ FactoryBot.define do state :failed end + trait :obsolete do + state :obsolete + end + trait :ready do state :ready diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index 91c22e7ad82..f066b088800 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -1,7 +1,8 @@ require 'rails_helper' -describe 'Admin disables Git access protocol' do +describe 'Admin disables Git access protocol', :js do include StubENV + include MobileHelpers let(:project) { create(:project, :empty_repo) } let(:admin) { create(:admin) } @@ -20,7 +21,24 @@ describe 'Admin disables Git access protocol' do visit_project expect(page).to have_content("git clone #{project.ssh_url_to_repo}") - expect(page).not_to have_selector('#clone-dropdown') + + find('.clone-dropdown-btn').click + + within('.git-clone-holder') do + expect(page).to have_content('Clone with SSH') + expect(page).not_to have_content('Clone with HTTP') + end + end + + context 'mobile component' do + it 'shows only the SSH clone information' do + resize_screen_xs + visit_project + find('.dropdown-toggle').click + + expect(page).to have_content('Copy SSH clone URL') + expect(page).not_to have_content('Copy HTTP clone URL') + end end end @@ -31,9 +49,25 @@ describe 'Admin disables Git access protocol' do it 'shows only HTTP url' do visit_project + find('.clone-dropdown-btn').click expect(page).to have_content("git clone #{project.http_url_to_repo}") - expect(page).not_to have_selector('#clone-dropdown') + + within('.git-clone-holder') do + expect(page).to have_content('Clone with HTTP') + expect(page).not_to have_content('Clone with SSH') + end + end + + context 'mobile component' do + it 'shows only the HTTP clone information' do + resize_screen_xs + visit_project + find('.dropdown-toggle').click + + expect(page).to have_content('Copy HTTP clone URL') + expect(page).not_to have_content('Copy SSH clone URL') + end end end @@ -46,7 +80,24 @@ describe 'Admin disables Git access protocol' do visit_project expect(page).to have_content("git clone #{project.ssh_url_to_repo}") - expect(page).to have_selector('#clone-dropdown') + + find('.clone-dropdown-btn').click + + within('.git-clone-holder') do + expect(page).to have_content('Clone with SSH') + expect(page).to have_content('Clone with HTTP') + end + end + + context 'mobile component' do + it 'shows both SSH and HTTP clone information' do + resize_screen_xs + visit_project + find('.dropdown-toggle').click + + expect(page).to have_content('Copy HTTP clone URL') + expect(page).to have_content('Copy SSH clone URL') + end end end diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index 4e6f73ef58a..9671a4d8c49 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -65,7 +65,7 @@ describe 'Group show page' do context 'when subgroups are supported', :js, :nested_groups do before do - allow(Group).to receive(:supports_nested_groups?) { true } + allow(Group).to receive(:supports_nested_objects?) { true } visit path end @@ -76,7 +76,7 @@ describe 'Group show page' do context 'when subgroups are not supported' do before do - allow(Group).to receive(:supports_nested_groups?) { false } + allow(Group).to receive(:supports_nested_objects?) { false } visit path end diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index 830d56035aa..e60486f6dcb 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -14,7 +14,7 @@ describe "User creates issue" do visit(new_project_issue_path(project)) end - it "creates issue" do + it "creates issue", :js do page.within(".issue-form") do expect(page).to have_no_content("Assign to") .and have_no_content("Labels") @@ -27,11 +27,15 @@ describe "User creates issue" do issue_title = "500 error on profile" fill_in("Title", with: issue_title) + first('.js-md').click + first('.qa-issuable-form-description').native.send_keys('Description') + click_button("Submit issue") expect(page).to have_content(issue_title) .and have_content(user.name) .and have_content(project.name) + expect(page).to have_selector('strong', text: 'Description') end end diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 3d17eb3a73a..06e30571336 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js do context 'when user changes cluster parameters' do before do - allow(ClusterPlatformConfigureWorker).to receive(:perform_async) + allow(ClusterConfigureWorker).to receive(:perform_async) fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' page.within('#js-cluster-details') { click_button 'Save changes' } end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 651c02c7ecc..60f37f4b74a 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -351,8 +351,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do context 'when user is a maintainer' do shared_examples 'no reveal button variables behavior' do it 'renders a hidden value with no reveal values button', :js do - expect(page).to have_content('Token') - expect(page).to have_content('Variables') + expect(page).to have_content('Trigger token') + expect(page).to have_content('Trigger variables') expect(page).not_to have_css('.js-reveal-variables') @@ -389,8 +389,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do shared_examples 'reveal button variables behavior' do it 'renders a hidden value with a reveal values button', :js do - expect(page).to have_content('Token') - expect(page).to have_content('Variables') + expect(page).to have_content('Trigger token') + expect(page).to have_content('Trigger variables') expect(page).to have_css('.js-reveal-variables') diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb index 34ed771340f..873de85708a 100644 --- a/spec/features/users/overview_spec.rb +++ b/spec/features/users/overview_spec.rb @@ -119,6 +119,12 @@ describe 'Overview tab on a user profile', :js do it 'shows a link to the project list' do expect(find('#js-overview .projects-block')).to have_selector('.js-view-all', visible: true) end + + it 'shows projects in "compact mode"' do + page.within('#js-overview .projects-block') do + expect(find('.js-projects-list-holder')).to have_selector('.compact') + end + end end describe 'user has more than ten personal projects' do diff --git a/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json b/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json new file mode 100644 index 00000000000..b77e60ece12 --- /dev/null +++ b/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json @@ -0,0 +1,8 @@ +{ + "type": ["object", "null"], + "properties" : { + "id": { "type": "integer" }, + "delete_path": { "type": "string" } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/entities/issue_sidebar.json b/spec/fixtures/api/schemas/entities/issue_sidebar.json index 682e345d5f5..93adb493d1b 100644 --- a/spec/fixtures/api/schemas/entities/issue_sidebar.json +++ b/spec/fixtures/api/schemas/entities/issue_sidebar.json @@ -2,20 +2,46 @@ "type": "object", "properties" : { "id": { "type": "integer" }, - "iid": { "type": "integer" }, - "subscribed": { "type": "boolean" }, - "time_estimate": { "type": "integer" }, - "total_time_spent": { "type": "integer" }, - "human_time_estimate": { "type": ["integer", "null"] }, - "human_total_time_spent": { "type": ["integer", "null"] }, - "participants": { - "type": "array", - "items": { "$ref": "../public_api/v4/user/basic.json" } + "type": { "type": "string" }, + "author_id": { "type": "integer" }, + "project_id": { "type": "integer" }, + "discussion_locked": { "type": ["boolean", "null"] }, + "due_date": { "type": "date" }, + "confidential": { "type": "boolean" }, + "reference": { "type": "string" }, + "current_user": { + "allOf": [ + { "$ref": "../public_api/v4/user/basic.json" }, + { "type": "object", + "properties" : { + "todo": { "$ref": "issuable_sidebar_todo.json" }, + "can_edit": { "type": "boolean" }, + "can_move": { "type": "boolean" }, + "can_admin_label": { "type": "boolean" } + } + } + ] + }, + "milestone": { + "oneOf": [ + { "type": "null" }, + { "$ref": "../public_api/v4/milestone.json" } + ] }, - "assignees": { + "labels": { "type": "array", - "items": { "$ref": "../public_api/v4/user/basic.json" } - } - }, - "additionalProperties": false + "items": { "$ref": "label.json" } + }, + "issuable_json_path": { "type": "string" }, + "namespace_path": { "type": "string" }, + "project_path": { "type": "string" }, + "project_full_path": { "type": "string" }, + "project_issuables_path": { "type": "string" }, + "create_todo_path": { "type": "string" }, + "project_milestones_path": { "type": "string" }, + "project_labels_path": { "type": "string" }, + "toggle_subscription_path": { "type": "string" }, + "move_issue_path": { "type": "string" }, + "projects_autocomplete_path": { "type": "string" } + } } diff --git a/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json b/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json new file mode 100644 index 00000000000..11be903b083 --- /dev/null +++ b/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties" : { + "subscribed": { "type": "boolean" }, + "time_estimate": { "type": "integer" }, + "total_time_spent": { "type": "integer" }, + "human_time_estimate": { "type": ["integer", "null"] }, + "human_total_time_spent": { "type": ["integer", "null"] }, + "participants": { + "type": "array", + "items": { "$ref": "../public_api/v4/user/basic.json" } + }, + "assignees": { + "type": "array", + "items": { "$ref": "../public_api/v4/user/basic.json" } + } + } +} diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json index cf257ac00de..4c04c838cb8 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_basic.json +++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json @@ -4,15 +4,9 @@ "state": { "type": "string" }, "merge_status": { "type": "string" }, "source_branch_exists": { "type": "boolean" }, - "time_estimate": { "type": "integer" }, - "total_time_spent": { "type": "integer" }, - "human_time_estimate": { "type": ["string", "null"] }, - "human_total_time_spent": { "type": ["string", "null"] }, "merge_error": { "type": ["string", "null"] }, "rebase_in_progress": { "type": "boolean" }, "assignee_id": { "type": ["integer", "null"] }, - "subscribed": { "type": ["boolean", "null"] }, - "participants": { "type": "array" }, "allow_collaboration": { "type": "boolean"}, "allow_maintainer_to_push": { "type": "boolean"}, "assignee": { diff --git a/spec/fixtures/api/schemas/entities/merge_request_sidebar.json b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json new file mode 100644 index 00000000000..7e9e048a9fd --- /dev/null +++ b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json @@ -0,0 +1,56 @@ +{ + "type": "object", + "properties" : { + "id": { "type": "integer" }, + "type": { "type": "string" }, + "author_id": { "type": "integer" }, + "project_id": { "type": "integer" }, + "discussion_locked": { "type": ["boolean", "null"] }, + "reference": { "type": "string" }, + "current_user": { + "allOf": [ + { "$ref": "../public_api/v4/user/basic.json" }, + { "type": "object", + "properties" : { + "todo": { "$ref": "issuable_sidebar_todo.json" }, + "can_edit": { "type": "boolean" }, + "can_move": { "type": "boolean" }, + "can_admin_label": { "type": "boolean" } + } + } + ] + }, + "milestone": { + "oneOf": [ + { "type": "null" }, + { "$ref": "../public_api/v4/milestones.json" } + ] + }, + "labels": { + "type": "array", + "items": { "$ref": "label.json" } + }, + "assignee": { + "allOf": [ + { "$ref": "../public_api/v4/user/basic.json" }, + { "type": "object", + "properties" : { + "can_merge": { "type": "boolean" } + } + } + ] + }, + "issuable_json_path": { "type": "string" }, + "namespace_path": { "type": "string" }, + "project_path": { "type": "string" }, + "project_full_path": { "type": "string" }, + "project_issuables_path": { "type": "string" }, + "create_todo_path": { "type": "string" }, + "project_milestones_path": { "type": "string" }, + "project_labels_path": { "type": "string" }, + "toggle_subscription_path": { "type": "string" }, + "move_issue_path": { "type": "string" }, + "projects_autocomplete_path": { "type": "string" } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json b/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json new file mode 100644 index 00000000000..682e345d5f5 --- /dev/null +++ b/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "properties" : { + "id": { "type": "integer" }, + "iid": { "type": "integer" }, + "subscribed": { "type": "boolean" }, + "time_estimate": { "type": "integer" }, + "total_time_spent": { "type": "integer" }, + "human_time_estimate": { "type": ["integer", "null"] }, + "human_total_time_spent": { "type": ["integer", "null"] }, + "participants": { + "type": "array", + "items": { "$ref": "../public_api/v4/user/basic.json" } + }, + "assignees": { + "type": "array", + "items": { "$ref": "../public_api/v4/user/basic.json" } + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/milestone.json b/spec/fixtures/api/schemas/public_api/v4/milestone.json new file mode 100644 index 00000000000..6ca2e88ae91 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/milestone.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "properties" : { + "id": { "type": "integer" }, + "iid": { "type": "integer" }, + "project_id": { "type": ["integer", "null"] }, + "group_id": { "type": ["integer", "null"] }, + "title": { "type": "string" }, + "description": { "type": ["string", "null"] }, + "state": { "type": "string" }, + "created_at": { "type": "date" }, + "updated_at": { "type": "date" }, + "start_date": { "type": "date" }, + "due_date": { "type": "date" }, + "web_url": { "type": "string" } + }, + "required": [ + "id", "iid", "title", "description", "state", + "state", "created_at", "updated_at", "start_date", "due_date" + ], + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/milestones.json b/spec/fixtures/api/schemas/public_api/v4/milestones.json index 448e97d6c85..dcbc1910bfe 100644 --- a/spec/fixtures/api/schemas/public_api/v4/milestones.json +++ b/spec/fixtures/api/schemas/public_api/v4/milestones.json @@ -1,25 +1,6 @@ { "type": "array", "items": { - "type": "object", - "properties" : { - "id": { "type": "integer" }, - "iid": { "type": "integer" }, - "project_id": { "type": ["integer", "null"] }, - "group_id": { "type": ["integer", "null"] }, - "title": { "type": "string" }, - "description": { "type": ["string", "null"] }, - "state": { "type": "string" }, - "created_at": { "type": "date" }, - "updated_at": { "type": "date" }, - "start_date": { "type": "date" }, - "due_date": { "type": "date" }, - "web_url": { "type": "string" } - }, - "required": [ - "id", "iid", "title", "description", "state", - "state", "created_at", "updated_at", "start_date", "due_date" - ], - "additionalProperties": false + "$ref": "./milestone.json" } } diff --git a/spec/fixtures/symlink_export.tar.gz b/spec/fixtures/symlink_export.tar.gz Binary files differnew file mode 100644 index 00000000000..f295f69c56c --- /dev/null +++ b/spec/fixtures/symlink_export.tar.gz diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 4af98bc3678..81231cca085 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -43,16 +43,19 @@ describe IssuablesHelper do end describe '#issuable_labels_tooltip' do + let(:label_entity) { LabelEntity.represent(label).as_json } + let(:label2_entity) { LabelEntity.represent(label2).as_json } + it 'returns label text with no labels' do expect(issuable_labels_tooltip([])).to eq("Labels") end it 'returns label text with labels within max limit' do - expect(issuable_labels_tooltip([label])).to eq(label.title) + expect(issuable_labels_tooltip([label_entity])).to eq(label[:title]) end it 'returns label text with labels exceeding max limit' do - expect(issuable_labels_tooltip([label, label2], limit: 1)).to eq("#{label.title}, and 1 more") + expect(issuable_labels_tooltip([label_entity, label2_entity], limit: 1)).to eq("#{label[:title]}, and 1 more") end end @@ -197,33 +200,4 @@ describe IssuablesHelper do expect(helper.issuable_initial_data(issue)).to eq(expected_data) end end - - describe '#selected_labels' do - context 'if label_name param is a string' do - it 'returns a new label with title' do - allow(helper).to receive(:params) - .and_return(ActionController::Parameters.new(label_name: 'test label')) - - labels = helper.selected_labels - - expect(labels).to be_an(Array) - expect(labels.size).to eq(1) - expect(labels.first.title).to eq('test label') - end - end - - context 'if label_name param is an array' do - it 'returns a new label with title for each element' do - allow(helper).to receive(:params) - .and_return(ActionController::Parameters.new(label_name: ['test label 1', 'test label 2'])) - - labels = helper.selected_labels - - expect(labels).to be_an(Array) - expect(labels.size).to eq(2) - expect(labels.first.title).to eq('test label 1') - expect(labels.second.title).to eq('test label 2') - end - end - end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 486416c3370..edd680ee1d1 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -519,4 +519,114 @@ describe ProjectsHelper do expect(helper.legacy_render_context({})).to be_empty end end + + describe '#explore_projects_tab?' do + subject { helper.explore_projects_tab? } + + it 'returns true when on the "All" tab under "Explore projects"' do + allow(@request).to receive(:path) { explore_projects_path } + + expect(subject).to be_truthy + end + + it 'returns true when on the "Trending" tab under "Explore projects"' do + allow(@request).to receive(:path) { trending_explore_projects_path } + + expect(subject).to be_truthy + end + + it 'returns true when on the "Starred" tab under "Explore projects"' do + allow(@request).to receive(:path) { starred_explore_projects_path } + + expect(subject).to be_truthy + end + + it 'returns false when on the "Your projects" tab' do + allow(@request).to receive(:path) { dashboard_projects_path } + + expect(subject).to be_falsey + end + end + + describe '#show_merge_request_count' do + context 'when the feature flag is enabled' do + before do + stub_feature_flags(project_list_show_mr_count: true) + end + + it 'returns true if compact mode is disabled' do + expect(helper.show_merge_request_count?).to be_truthy + end + + it 'returns false if compact mode is enabled' do + expect(helper.show_merge_request_count?(compact_mode: true)).to be_falsey + end + end + + context 'when the feature flag is disabled' do + before do + stub_feature_flags(project_list_show_mr_count: false) + end + + it 'always returns false' do + expect(helper.show_merge_request_count?(disabled: false)).to be_falsy + expect(helper.show_merge_request_count?(disabled: true)).to be_falsy + end + end + + context 'disabled flag' do + before do + stub_feature_flags(project_list_show_mr_count: true) + end + + it 'returns false if disabled flag is true' do + expect(helper.show_merge_request_count?(disabled: true)).to be_falsey + end + + it 'returns true if disabled flag is false' do + expect(helper.show_merge_request_count?).to be_truthy + end + end + end + + describe '#show_issue_count?' do + context 'when the feature flag is enabled' do + before do + stub_feature_flags(project_list_show_issue_count: true) + end + + it 'returns true if compact mode is disabled' do + expect(helper.show_issue_count?).to be_truthy + end + + it 'returns false if compact mode is enabled' do + expect(helper.show_issue_count?(compact_mode: true)).to be_falsey + end + end + + context 'when the feature flag is disabled' do + before do + stub_feature_flags(project_list_show_issue_count: false) + end + + it 'always returns false' do + expect(helper.show_issue_count?(disabled: false)).to be_falsy + expect(helper.show_issue_count?(disabled: true)).to be_falsy + end + end + + context 'disabled flag' do + before do + stub_feature_flags(project_list_show_issue_count: true) + end + + it 'returns false if disabled flag is true' do + expect(helper.show_issue_count?(disabled: true)).to be_falsey + end + + it 'returns true if disabled flag is false' do + expect(helper.show_issue_count?).to be_truthy + end + end + end end diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/zz_metrics_spec.rb index 80c77057065..3eaccfe8d8b 100644 --- a/spec/initializers/8_metrics_spec.rb +++ b/spec/initializers/zz_metrics_spec.rb @@ -16,7 +16,7 @@ describe 'instrument_classes' do end it 'can autoload and instrument all files' do - require_relative '../../config/initializers/8_metrics' + require_relative '../../config/initializers/zz_metrics' expect { instrument_classes(config) }.not_to raise_error end end diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js index 30b15011def..bef59b86d0c 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -118,6 +118,8 @@ describe('VariableList', () => { loadFixtures('projects/ci_cd_settings.html.raw'); $wrapper = $('.js-ci-variable-list-section'); + $wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false'); + variableList = new VariableList({ container: $wrapper, formField: 'variables', diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js index f096638e3d6..4268634d302 100644 --- a/spec/javascripts/diffs/store/utils_spec.js +++ b/spec/javascripts/diffs/store/utils_spec.js @@ -294,10 +294,14 @@ describe('DiffsStoreUtils', () => { }); describe('prepareDiffData', () => { - it('sets the renderIt and collapsed attribute on files', () => { - const preparedDiff = { diff_files: [getDiffFileMock()] }; + let preparedDiff; + + beforeEach(() => { + preparedDiff = { diff_files: [getDiffFileMock()] }; utils.prepareDiffData(preparedDiff); + }); + it('sets the renderIt and collapsed attribute on files', () => { const firstParallelDiffLine = preparedDiff.diff_files[0].parallel_diff_lines[2]; expect(firstParallelDiffLine.left.discussions.length).toBe(0); @@ -323,6 +327,18 @@ describe('DiffsStoreUtils', () => { expect(preparedDiff.diff_files[0].renderIt).toBeTruthy(); expect(preparedDiff.diff_files[0].collapsed).toBeFalsy(); }); + + it('adds line_code to all lines', () => { + expect( + preparedDiff.diff_files[0].parallel_diff_lines.filter(line => !line.line_code), + ).toHaveLength(0); + }); + + it('uses right line code if left has none', () => { + const firstLine = preparedDiff.diff_files[0].parallel_diff_lines[0]; + + expect(firstLine.line_code).toEqual(firstLine.right.line_code); + }); }); describe('isDiscussionApplicableToLine', () => { diff --git a/spec/javascripts/environments/environment_terminal_button_spec.js b/spec/javascripts/environments/environment_terminal_button_spec.js index f1576b19d1b..56e18db59c5 100644 --- a/spec/javascripts/environments/environment_terminal_button_spec.js +++ b/spec/javascripts/environments/environment_terminal_button_spec.js @@ -2,30 +2,46 @@ import Vue from 'vue'; import terminalComp from '~/environments/components/environment_terminal_button.vue'; describe('Stop Component', () => { - let TerminalComponent; let component; const terminalPath = '/path'; - beforeEach(() => { - TerminalComponent = Vue.extend(terminalComp); - + const mountWithProps = props => { + const TerminalComponent = Vue.extend(terminalComp); component = new TerminalComponent({ - propsData: { - terminalPath, - }, + propsData: props, }).$mount(); - }); + }; + + describe('enabled', () => { + beforeEach(() => { + mountWithProps({ terminalPath }); + }); + + describe('computed', () => { + it('title', () => { + expect(component.title).toEqual('Terminal'); + }); + }); - describe('computed', () => { - it('title', () => { - expect(component.title).toEqual('Terminal'); + it('should render a link to open a web terminal with the provided path', () => { + expect(component.$el.tagName).toEqual('A'); + expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal'); + expect(component.$el.getAttribute('aria-label')).toEqual('Terminal'); + expect(component.$el.getAttribute('href')).toEqual(terminalPath); + }); + + it('should render a non-disabled button', () => { + expect(component.$el.classList).not.toContain('disabled'); }); }); - it('should render a link to open a web terminal with the provided path', () => { - expect(component.$el.tagName).toEqual('A'); - expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal'); - expect(component.$el.getAttribute('aria-label')).toEqual('Terminal'); - expect(component.$el.getAttribute('href')).toEqual(terminalPath); + describe('disabled', () => { + beforeEach(() => { + mountWithProps({ terminalPath, disabled: true }); + }); + + it('should render a disabled button', () => { + expect(component.$el.classList).toContain('disabled'); + }); }); }); diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb index 81e8a51a902..1b2a3b484bb 100644 --- a/spec/javascripts/fixtures/blob.rb +++ b/spec/javascripts/fixtures/blob.rb @@ -22,10 +22,11 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do end it 'blob/show.html.raw' do |example| - get(:show, - namespace_id: project.namespace, - project_id: project, - id: 'add-ipython-files/files/ipython/basic.ipynb') + get(:show, params: { + namespace_id: project.namespace, + project_id: project, + id: 'add-ipython-files/files/ipython/basic.ipynb' + }) expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb index 494c9cabdcc..1d675e008ba 100644 --- a/spec/javascripts/fixtures/boards.rb +++ b/spec/javascripts/fixtures/boards.rb @@ -18,9 +18,10 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller end it 'boards/show.html.raw' do |example| - get(:index, - namespace_id: project.namespace, - project_id: project) + get(:index, params: { + namespace_id: project.namespace, + project_id: project + }) expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index 4fc072d2585..3cc713ef90f 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -22,9 +22,10 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle end it 'branches/new_branch.html.raw' do |example| - get :new, + get :new, params: { namespace_id: project.namespace.to_param, project_id: project + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb index 8e74c4f859c..69dbe54ffc2 100644 --- a/spec/javascripts/fixtures/clusters.rb +++ b/spec/javascripts/fixtures/clusters.rb @@ -23,10 +23,11 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle end it 'clusters/show_cluster.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project, id: cluster + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb index 24ab8159a18..f0e4bb50c67 100644 --- a/spec/javascripts/fixtures/commit.rb +++ b/spec/javascripts/fixtures/commit.rb @@ -25,7 +25,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller id: commit.id } - get :show, params + get :show, params: params expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/deploy_keys.rb b/spec/javascripts/fixtures/deploy_keys.rb index 24699c3043a..efbda955972 100644 --- a/spec/javascripts/fixtures/deploy_keys.rb +++ b/spec/javascripts/fixtures/deploy_keys.rb @@ -33,10 +33,10 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control create(:deploy_keys_project, project: project3, deploy_key: project_key) create(:deploy_keys_project, project: project4, deploy_key: project_key) - get :index, + get :index, params: { namespace_id: project.namespace.to_param, - project_id: project, - format: :json + project_id: project + }, format: :json expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb index b42f442557c..f8d55fc97c3 100644 --- a/spec/javascripts/fixtures/groups.rb +++ b/spec/javascripts/fixtures/groups.rb @@ -19,8 +19,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do describe GroupsController, '(JavaScript fixtures)', type: :controller do it 'groups/edit.html.raw' do |example| - get :edit, - id: group + get :edit, params: { id: group } expect(response).to be_success store_frontend_fixture(response, example.description) @@ -29,8 +28,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do it 'groups/ci_cd_settings.html.raw' do |example| - get :show, - group_id: group + get :show, params: { group_id: group } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 0ee2f82dfd6..18fb1bebf8b 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -43,9 +43,10 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller it 'issues/issue_list.html.raw' do |example| create(:issue, project: project) - get :index, + get :index, params: { namespace_id: project.namespace.to_param, project_id: project + } expect(response).to be_success store_frontend_fixture(response, example.description) @@ -54,10 +55,11 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller private def render_issue(fixture_file_name, issue) - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project, id: issue.to_param + } expect(response).to be_success store_frontend_fixture(response, fixture_file_name) diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb index 82d7a5e394e..d6b5349594d 100644 --- a/spec/javascripts/fixtures/jobs.rb +++ b/spec/javascripts/fixtures/jobs.rb @@ -34,21 +34,22 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do end it 'builds/build-with-artifacts.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project, id: build_with_artifacts.to_param + } expect(response).to be_success store_frontend_fixture(response, example.description) end it 'jobs/delayed.json' do |example| - get :show, - namespace_id: project.namespace.to_param, - project_id: project, - id: delayed_job.to_param, - format: :json + get :show, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: delayed_job.to_param + }, format: :json expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/labels.rb b/spec/javascripts/fixtures/labels.rb index b730d557e21..9420194e675 100644 --- a/spec/javascripts/fixtures/labels.rb +++ b/spec/javascripts/fixtures/labels.rb @@ -31,9 +31,9 @@ describe 'Labels (JavaScript fixtures)' do end it 'labels/group_labels.json' do |example| - get :index, - group_id: group, - format: 'json' + get :index, params: { + group_id: group + }, format: 'json' expect(response).to be_success store_frontend_fixture(response, example.description) @@ -48,10 +48,10 @@ describe 'Labels (JavaScript fixtures)' do end it 'labels/project_labels.json' do |example| - get :index, + get :index, params: { namespace_id: group, - project_id: project, - format: 'json' + project_id: project + }, format: 'json' expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 7257d0c8556..26e81f06c0b 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -112,21 +112,21 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont private def render_discussions_json(merge_request, fixture_file_name) - get :discussions, + get :discussions, params: { namespace_id: project.namespace.to_param, project_id: project, - id: merge_request.to_param, - format: :json + id: merge_request.to_param + }, format: :json store_frontend_fixture(response, fixture_file_name) end def render_merge_request(fixture_file_name, merge_request) - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project, - id: merge_request.to_param, - format: :html + id: merge_request.to_param + }, format: :html expect(response).to be_success store_frontend_fixture(response, fixture_file_name) diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb index afe34b834b0..57462e74bb2 100644 --- a/spec/javascripts/fixtures/merge_requests_diffs.rb +++ b/spec/javascripts/fixtures/merge_requests_diffs.rb @@ -57,13 +57,13 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type private def render_merge_request(fixture_file_name, merge_request, view: 'inline', **extra_params) - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project, id: merge_request.to_param, - format: :json, view: view, **extra_params + }, format: :json expect(response).to be_success store_frontend_fixture(response, fixture_file_name) diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb index 56f27ea7df1..05d79ec8de9 100644 --- a/spec/javascripts/fixtures/pipeline_schedules.rb +++ b/spec/javascripts/fixtures/pipeline_schedules.rb @@ -22,20 +22,22 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : end it 'pipeline_schedules/edit.html.raw' do |example| - get :edit, + get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id + } expect(response).to be_success store_frontend_fixture(response, example.description) end it 'pipeline_schedules/edit_with_variables.html.raw' do |example| - get :edit, + get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule_populated.id + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/pipelines.rb b/spec/javascripts/fixtures/pipelines.rb index bb85da50f0f..42b552e81c0 100644 --- a/spec/javascripts/fixtures/pipelines.rb +++ b/spec/javascripts/fixtures/pipelines.rb @@ -24,10 +24,10 @@ describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controll end it 'pipelines/pipelines.json' do |example| - get :index, + get :index, params: { namespace_id: namespace, - project_id: project, - format: :json + project_id: project + }, format: :json expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index d98f7f55b20..9b48646f8f0 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -28,27 +28,30 @@ describe 'Projects (JavaScript fixtures)', type: :controller do describe ProjectsController, '(JavaScript fixtures)', type: :controller do it 'projects/dashboard.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project.namespace.to_param, id: project + } expect(response).to be_success store_frontend_fixture(response, example.description) end it 'projects/overview.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project_with_repo.namespace.to_param, id: project_with_repo + } expect(response).to be_success store_frontend_fixture(response, example.description) end it 'projects/edit.html.raw' do |example| - get :edit, + get :edit, params: { namespace_id: project.namespace.to_param, id: project + } expect(response).to be_success store_frontend_fixture(response, example.description) @@ -57,18 +60,20 @@ describe 'Projects (JavaScript fixtures)', type: :controller do describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do it 'projects/ci_cd_settings.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project.namespace.to_param, project_id: project + } expect(response).to be_success store_frontend_fixture(response, example.description) end it 'projects/ci_cd_settings_with_variables.html.raw' do |example| - get :show, + get :show, params: { namespace_id: project_variable_populated.namespace.to_param, project_id: project_variable_populated + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb index f95f8038ffb..746fbfd66dd 100644 --- a/spec/javascripts/fixtures/prometheus_service.rb +++ b/spec/javascripts/fixtures/prometheus_service.rb @@ -23,10 +23,11 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle end it 'services/prometheus/prometheus_service.html.raw' do |example| - get :edit, + get :edit, params: { namespace_id: namespace, project_id: project, id: service.to_param + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb index 9280ed5a7f1..6ccd74a07ff 100644 --- a/spec/javascripts/fixtures/services.rb +++ b/spec/javascripts/fixtures/services.rb @@ -23,10 +23,11 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle end it 'services/edit_service.html.raw' do |example| - get :edit, + get :edit, params: { namespace_id: namespace, project_id: project, id: service.to_param + } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb index 38fc963caf7..a14837e4d4a 100644 --- a/spec/javascripts/fixtures/snippet.rb +++ b/spec/javascripts/fixtures/snippet.rb @@ -24,7 +24,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do end it 'snippets/show.html.raw' do |example| - get(:show, id: snippet.to_param) + get(:show, params: { id: snippet.to_param }) expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index 426b854fe8b..b5f6620873b 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -42,12 +42,12 @@ describe 'Todos (JavaScript fixtures)' do end it 'todos/todos.json' do |example| - post :create, + post :create, params: { namespace_id: namespace, project_id: project, issuable_type: 'issue', - issuable_id: issue_2.id, - format: 'json' + issuable_id: issue_2.id + }, format: 'json' expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb index e3d7986f2cf..f0aa874bf75 100644 --- a/spec/javascripts/fixtures/u2f.rb +++ b/spec/javascripts/fixtures/u2f.rb @@ -21,7 +21,7 @@ context 'U2F' do it 'u2f/authenticate.html.raw' do |example| allow(controller).to receive(:find_user).and_return(user) - post :create, user: { login: user.username, password: user.password } + post :create, params: { user: { login: user.username, password: user.password } } expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/jobs/components/artifacts_block_spec.js b/spec/javascripts/jobs/components/artifacts_block_spec.js index 2fa7ff653fe..27d480ef2ea 100644 --- a/spec/javascripts/jobs/components/artifacts_block_spec.js +++ b/spec/javascripts/jobs/components/artifacts_block_spec.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import { getTimeago } from '~/lib/utils/datetime_utility'; import component from '~/jobs/components/artifacts_block.vue'; import mountComponent from '../../helpers/vue_mount_component_helper'; +import { trimText } from '../../helpers/vue_component_helper'; describe('Artifacts block', () => { const Component = Vue.extend(component); @@ -9,7 +10,7 @@ describe('Artifacts block', () => { const expireAt = '2018-08-14T09:38:49.157Z'; const timeago = getTimeago(); - const formatedDate = timeago.format(expireAt); + const formattedDate = timeago.format(expireAt); const expiredArtifact = { expire_at: expireAt, @@ -36,9 +37,8 @@ describe('Artifacts block', () => { expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull(); expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull(); - expect(vm.$el.textContent).toContain(formatedDate); - expect(vm.$el.querySelector('.js-artifacts-removed').textContent.trim()).toEqual( - 'The artifacts were removed', + expect(trimText(vm.$el.querySelector('.js-artifacts-removed').textContent)).toEqual( + `The artifacts were removed ${formattedDate}`, ); }); }); @@ -51,9 +51,8 @@ describe('Artifacts block', () => { expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull(); expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull(); - expect(vm.$el.textContent).toContain(formatedDate); - expect(vm.$el.querySelector('.js-artifacts-will-be-removed').textContent.trim()).toEqual( - 'The artifacts will be removed in', + expect(trimText(vm.$el.querySelector('.js-artifacts-will-be-removed').textContent)).toEqual( + `The artifacts will be removed ${formattedDate}`, ); }); }); diff --git a/spec/javascripts/jobs/components/sidebar_spec.js b/spec/javascripts/jobs/components/sidebar_spec.js index 424092d2d88..b0bc16d7c64 100644 --- a/spec/javascripts/jobs/components/sidebar_spec.js +++ b/spec/javascripts/jobs/components/sidebar_spec.js @@ -79,14 +79,6 @@ describe('Sidebar details block', () => { }); describe('information', () => { - it('should render merge request link', () => { - expect(trimText(vm.$el.querySelector('.js-job-mr').textContent)).toEqual('Merge Request: !2'); - - expect(vm.$el.querySelector('.js-job-mr a').getAttribute('href')).toEqual( - job.merge_request.path, - ); - }); - it('should render job duration', () => { expect(trimText(vm.$el.querySelector('.js-job-duration').textContent)).toEqual( 'Duration: 6 seconds', diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js index 106a4ac2546..3aff2dd0641 100644 --- a/spec/javascripts/notes/components/noteable_discussion_spec.js +++ b/spec/javascripts/notes/components/noteable_discussion_spec.js @@ -133,8 +133,10 @@ describe('noteable_discussion component', () => { }); }); - describe('commit discussion', () => { + describe('action text', () => { const commitId = 'razupaltuff'; + const truncatedCommitId = commitId.substr(0, 8); + let commitElement; beforeEach(() => { vm.$destroy(); @@ -143,7 +145,6 @@ describe('noteable_discussion component', () => { projectPath: 'something', }; - vm.$destroy(); vm = new Component({ propsData: { discussion: { @@ -159,17 +160,73 @@ describe('noteable_discussion component', () => { }, store, }).$mount(); + + commitElement = vm.$el.querySelector('.commit-sha'); + }); + + describe('for commit discussions', () => { + it('should display a monospace started a discussion on commit', () => { + expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`); + expect(commitElement).not.toBe(null); + expect(commitElement).toHaveText(truncatedCommitId); + }); }); - it('displays a monospace started a discussion on commit', () => { - const truncatedCommitId = commitId.substr(0, 8); + describe('for diff discussion with a commit id', () => { + it('should display started discussion on commit header', done => { + vm.discussion.for_commit = false; - expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`); + vm.$nextTick(() => { + expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`); + expect(commitElement).not.toBe(null); - const commitElement = vm.$el.querySelector('.commit-sha'); + done(); + }); + }); - expect(commitElement).not.toBe(null); - expect(commitElement).toHaveText(truncatedCommitId); + it('should display outdated change on commit header', done => { + vm.discussion.for_commit = false; + vm.discussion.active = false; + + vm.$nextTick(() => { + expect(vm.$el).toContainText( + `started a discussion on an outdated change in commit ${truncatedCommitId}`, + ); + + expect(commitElement).not.toBe(null); + + done(); + }); + }); + }); + + describe('for diff discussions without a commit id', () => { + it('should show started a discussion on the diff text', done => { + Object.assign(vm.discussion, { + for_commit: false, + commit_id: null, + }); + + vm.$nextTick(() => { + expect(vm.$el).toContainText('started a discussion on the diff'); + + done(); + }); + }); + + it('should show discussion on older version text', done => { + Object.assign(vm.discussion, { + for_commit: false, + commit_id: null, + active: false, + }); + + vm.$nextTick(() => { + expect(vm.$el).toContainText('started a discussion on an old version of the diff'); + + done(); + }); + }); }); }); }); diff --git a/spec/javascripts/releases/components/app_spec.js b/spec/javascripts/releases/components/app_spec.js new file mode 100644 index 00000000000..f30c7685e34 --- /dev/null +++ b/spec/javascripts/releases/components/app_spec.js @@ -0,0 +1,79 @@ +import Vue from 'vue'; +import app from '~/releases/components/app.vue'; +import createStore from '~/releases/store'; +import api from '~/api'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { resetStore } from '../store/helpers'; +import { releases } from '../mock_data'; + +describe('Releases App ', () => { + const Component = Vue.extend(app); + let store; + let vm; + + const props = { + projectId: 'gitlab-ce', + documentationLink: 'help/releases', + illustrationPath: 'illustration/path', + }; + + beforeEach(() => { + store = createStore(); + }); + + afterEach(() => { + resetStore(store); + vm.$destroy(); + }); + + describe('while loading', () => { + beforeEach(() => { + spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [] })); + vm = mountComponentWithStore(Component, { props, store }); + }); + + it('renders loading icon', done => { + expect(vm.$el.querySelector('.js-loading')).not.toBeNull(); + expect(vm.$el.querySelector('.js-empty-state')).toBeNull(); + expect(vm.$el.querySelector('.js-success-state')).toBeNull(); + + setTimeout(() => { + done(); + }, 0); + }); + }); + + describe('with successful request', () => { + beforeEach(() => { + spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: releases })); + vm = mountComponentWithStore(Component, { props, store }); + }); + + it('renders success state', done => { + setTimeout(() => { + expect(vm.$el.querySelector('.js-loading')).toBeNull(); + expect(vm.$el.querySelector('.js-empty-state')).toBeNull(); + expect(vm.$el.querySelector('.js-success-state')).not.toBeNull(); + + done(); + }, 0); + }); + }); + + describe('with empty request', () => { + beforeEach(() => { + spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: [] })); + vm = mountComponentWithStore(Component, { props, store }); + }); + + it('renders empty state', done => { + setTimeout(() => { + expect(vm.$el.querySelector('.js-loading')).toBeNull(); + expect(vm.$el.querySelector('.js-empty-state')).not.toBeNull(); + expect(vm.$el.querySelector('.js-success-state')).toBeNull(); + + done(); + }, 0); + }); + }); +}); diff --git a/spec/javascripts/releases/components/release_block_spec.js b/spec/javascripts/releases/components/release_block_spec.js index c0cd15b7507..29420216bc4 100644 --- a/spec/javascripts/releases/components/release_block_spec.js +++ b/spec/javascripts/releases/components/release_block_spec.js @@ -15,6 +15,16 @@ describe('Release block', () => { author_name: 'Release bot', author_email: 'release-bot@example.com', created_at: '2012-05-28T05:00:00-07:00', + author: { + avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png', + id: 482476, + name: 'John Doe', + path: '/johndoe', + state: 'active', + status_tooltip_html: null, + username: 'johndoe', + web_url: 'https://gitlab.com/johndoe', + }, commit: { id: '2695effb5807a22ff3d138d593fd856244e155e7', short_id: '2695effb', @@ -66,32 +76,10 @@ describe('Release block', () => { ], }, }; - - const props = { - name: release.name, - tag: release.tag_name, - commit: release.commit, - description: release.description_html, - author: { - avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png', - id: 482476, - name: 'John Doe', - path: '/johndoe', - state: 'active', - status_tooltip_html: null, - username: 'johndoe', - web_url: 'https://gitlab.com/johndoe', - }, - createdAt: release.created_at, - assetsCount: release.assets.count, - sources: release.assets.sources, - links: release.assets.links, - }; - let vm; beforeEach(() => { - vm = mountComponent(Component, props); + vm = mountComponent(Component, { release }); }); afterEach(() => { diff --git a/spec/javascripts/releases/mock_data.js b/spec/javascripts/releases/mock_data.js new file mode 100644 index 00000000000..2855eca1711 --- /dev/null +++ b/spec/javascripts/releases/mock_data.js @@ -0,0 +1,128 @@ +export const release = { + name: 'Bionic Beaver', + tag_name: '18.04', + description: '## changelog\n\n* line 1\n* line2', + description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>', + author_name: 'Release bot', + author_email: 'release-bot@example.com', + created_at: '2012-05-28T05:00:00-07:00', + commit: { + id: '2695effb5807a22ff3d138d593fd856244e155e7', + short_id: '2695effb', + title: 'Initial commit', + created_at: '2017-07-26T11:08:53.000+02:00', + parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'], + message: 'Initial commit', + author: { + avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png', + id: 482476, + name: 'John Doe', + path: '/johndoe', + state: 'active', + status_tooltip_html: null, + username: 'johndoe', + web_url: 'https://gitlab.com/johndoe', + }, + authored_date: '2012-05-28T04:42:42-07:00', + committer_name: 'Jack Smith', + committer_email: 'jack@example.com', + committed_date: '2012-05-28T04:42:42-07:00', + }, + assets: { + count: 6, + sources: [ + { + format: 'zip', + url: 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.zip', + }, + { + format: 'tar.gz', + url: 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz', + }, + { + format: 'tar.bz2', + url: + 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2', + }, + { + format: 'tar', + url: 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar', + }, + ], + links: [ + { + name: 'release-18.04.dmg', + url: 'https://my-external-hosting.example.com/scrambled-url/', + external: true, + }, + { + name: 'binary-linux-amd64', + url: + 'https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50', + external: false, + }, + ], + }, +}; + +export const releases = [ + release, + { + name: 'JoJos Bizarre Adventure', + tag_name: '19.00', + description: '## changelog\n\n* line 1\n* line2', + description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>', + author_name: 'Release bot', + author_email: 'release-bot@example.com', + created_at: '2012-05-28T05:00:00-07:00', + commit: { + id: '2695effb5807a22ff3d138d593fd856244e155e7', + short_id: '2695effb', + title: 'Initial commit', + created_at: '2017-07-26T11:08:53.000+02:00', + parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'], + message: 'Initial commit', + author: { + avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png', + id: 482476, + name: 'John Doe', + path: '/johndoe', + state: 'active', + status_tooltip_html: null, + username: 'johndoe', + web_url: 'https://gitlab.com/johndoe', + }, + authored_date: '2012-05-28T04:42:42-07:00', + committer_name: 'Jack Smith', + committer_email: 'jack@example.com', + committed_date: '2012-05-28T04:42:42-07:00', + }, + assets: { + count: 4, + sources: [ + { + format: 'tar.gz', + url: + 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.gz', + }, + { + format: 'tar.bz2', + url: + 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar.bz2', + }, + { + format: 'tar', + url: 'https://gitlab.com/gitlab-org/gitlab-ce/-/archive/v11.3.12/gitlab-ce-v11.3.12.tar', + }, + ], + links: [ + { + name: 'binary-linux-amd64', + url: + 'https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50', + external: false, + }, + ], + }, + }, +]; diff --git a/spec/javascripts/releases/store/actions_spec.js b/spec/javascripts/releases/store/actions_spec.js new file mode 100644 index 00000000000..6eb8e681be9 --- /dev/null +++ b/spec/javascripts/releases/store/actions_spec.js @@ -0,0 +1,98 @@ +import { + requestReleases, + fetchReleases, + receiveReleasesSuccess, + receiveReleasesError, +} from '~/releases/store/actions'; +import state from '~/releases/store/state'; +import * as types from '~/releases/store/mutation_types'; +import api from '~/api'; +import testAction from 'spec/helpers/vuex_action_helper'; +import { releases } from '../mock_data'; + +describe('Releases State actions', () => { + let mockedState; + + beforeEach(() => { + mockedState = state(); + }); + + describe('requestReleases', () => { + it('should commit REQUEST_RELEASES mutation', done => { + testAction(requestReleases, null, mockedState, [{ type: types.REQUEST_RELEASES }], [], done); + }); + }); + + describe('fetchReleases', () => { + describe('success', () => { + it('dispatches requestReleases and receiveReleasesSuccess ', done => { + spyOn(api, 'releases').and.returnValue(Promise.resolve({ data: releases })); + + testAction( + fetchReleases, + releases, + mockedState, + [], + [ + { + type: 'requestReleases', + }, + { + payload: releases, + type: 'receiveReleasesSuccess', + }, + ], + done, + ); + }); + }); + + describe('error', () => { + it('dispatches requestReleases and receiveReleasesError ', done => { + spyOn(api, 'releases').and.returnValue(Promise.reject()); + + testAction( + fetchReleases, + null, + mockedState, + [], + [ + { + type: 'requestReleases', + }, + { + type: 'receiveReleasesError', + }, + ], + done, + ); + }); + }); + }); + + describe('receiveReleasesSuccess', () => { + it('should commit RECEIVE_RELEASES_SUCCESS mutation', done => { + testAction( + receiveReleasesSuccess, + releases, + mockedState, + [{ type: types.RECEIVE_RELEASES_SUCCESS, payload: releases }], + [], + done, + ); + }); + }); + + describe('receiveReleasesError', () => { + it('should commit RECEIVE_RELEASES_ERROR mutation', done => { + testAction( + receiveReleasesError, + null, + mockedState, + [{ type: types.RECEIVE_RELEASES_ERROR }], + [], + done, + ); + }); + }); +}); diff --git a/spec/javascripts/releases/store/helpers.js b/spec/javascripts/releases/store/helpers.js new file mode 100644 index 00000000000..e962b254377 --- /dev/null +++ b/spec/javascripts/releases/store/helpers.js @@ -0,0 +1,6 @@ +import state from '~/releases/store/state'; + +// eslint-disable-next-line import/prefer-default-export +export const resetStore = store => { + store.replaceState(state()); +}; diff --git a/spec/javascripts/releases/store/mutations_spec.js b/spec/javascripts/releases/store/mutations_spec.js new file mode 100644 index 00000000000..72b98529fe9 --- /dev/null +++ b/spec/javascripts/releases/store/mutations_spec.js @@ -0,0 +1,47 @@ +import state from '~/releases/store/state'; +import mutations from '~/releases/store/mutations'; +import * as types from '~/releases/store/mutation_types'; +import { releases } from '../mock_data'; + +describe('Releases Store Mutations', () => { + let stateCopy; + + beforeEach(() => { + stateCopy = state(); + }); + + describe('REQUEST_RELEASES', () => { + it('sets isLoading to true', () => { + mutations[types.REQUEST_RELEASES](stateCopy); + + expect(stateCopy.isLoading).toEqual(true); + }); + }); + + describe('RECEIVE_RELEASES_SUCCESS', () => { + beforeEach(() => { + mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, releases); + }); + + it('sets is loading to false', () => { + expect(stateCopy.isLoading).toEqual(false); + }); + + it('sets hasError to false', () => { + expect(stateCopy.hasError).toEqual(false); + }); + + it('sets data', () => { + expect(stateCopy.releases).toEqual(releases); + }); + }); + + describe('RECEIVE_RELEASES_ERROR', () => { + it('resets data', () => { + mutations[types.RECEIVE_RELEASES_ERROR](stateCopy); + + expect(stateCopy.isLoading).toEqual(false); + expect(stateCopy.releases).toEqual([]); + }); + }); +}); diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js index fcd7bea3f6d..7f20b0da991 100644 --- a/spec/javascripts/sidebar/mock_data.js +++ b/spec/javascripts/sidebar/mock_data.js @@ -66,7 +66,7 @@ const RESPONSE_MAP = { }, labels: [], }, - '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar': { + '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': { assignees: [ { name: 'User 0', @@ -181,7 +181,7 @@ const RESPONSE_MAP = { const mockData = { responseMap: RESPONSE_MAP, mediator: { - endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar', + endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras', toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription', moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move', projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15', diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js index 2d853970fc4..6c69c08e733 100644 --- a/spec/javascripts/sidebar/sidebar_mediator_spec.js +++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js @@ -37,7 +37,7 @@ describe('Sidebar mediator', function() { it('fetches the data', done => { const mockData = - Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar']; + Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras']; spyOn(this.mediator, 'processFetchedData').and.callThrough(); this.mediator @@ -51,7 +51,7 @@ describe('Sidebar mediator', function() { it('processes fetched data', () => { const mockData = - Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar']; + Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras']; this.mediator.processFetchedData(mockData); expect(this.mediator.store.assignees).toEqual(mockData.assignees); diff --git a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js index e16ab156679..25b6e3b6bc8 100644 --- a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js @@ -89,7 +89,7 @@ describe('User Popover Component', () => { expect(vm.$el.textContent).toContain('GitLab'); }); - it('should have full job line when we have bio and organization', () => { + it('should display bio and organization in separate lines', () => { const testProps = Object.assign({}, DEFAULT_PROPS); testProps.user.bio = 'Engineer'; testProps.user.organization = 'GitLab'; @@ -99,20 +99,24 @@ describe('User Popover Component', () => { target: document.querySelector('.js-user-link'), }); - expect(vm.$el.textContent).toContain('Engineer at GitLab'); + expect(vm.$el.querySelector('.js-bio').textContent).toContain('Engineer'); + expect(vm.$el.querySelector('.js-organization').textContent).toContain('GitLab'); }); - it('should not encode special characters when we have bio and organization', () => { + it('should not encode special characters in bio and organization', () => { const testProps = Object.assign({}, DEFAULT_PROPS); testProps.user.bio = 'Manager & Team Lead'; - testProps.user.organization = 'GitLab'; + testProps.user.organization = 'Me & my <funky> Company'; vm = mountComponent(UserPopover, { ...DEFAULT_PROPS, target: document.querySelector('.js-user-link'), }); - expect(vm.$el.textContent).toContain('Manager & Team Lead at GitLab'); + expect(vm.$el.querySelector('.js-bio').textContent).toContain('Manager & Team Lead'); + expect(vm.$el.querySelector('.js-organization').textContent).toContain( + 'Me & my <funky> Company', + ); }); }); diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index 3c63e601abc..f4759b69538 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -192,7 +192,7 @@ describe Gitlab::BareRepositoryImport::Importer, :seed_helper do let(:project_path) { 'a-group/a-sub-group/a-project' } before do - expect(Group).to receive(:supports_nested_groups?) { false } + expect(Group).to receive(:supports_nested_objects?) { false } end describe '#create_project_if_needed' do diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index 5eda4d041a8..e41a75c37a7 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -3,6 +3,20 @@ require 'spec_helper' # We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want # those stubs while testing the GitalyClient itself. describe Gitlab::GitalyClient do + let(:sample_cert) { Rails.root.join('spec/fixtures/clusters/sample_cert.pem').to_s } + + before do + allow(described_class) + .to receive(:stub_cert_paths) + .and_return([sample_cert]) + end + + def stub_repos_storages(address) + allow(Gitlab.config.repositories).to receive(:storages).and_return({ + 'default' => { 'gitaly_address' => address } + }) + end + describe '.stub_class' do it 'returns the gRPC health check stub' do expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub) @@ -15,12 +29,8 @@ describe Gitlab::GitalyClient do describe '.stub_address' do it 'returns the same result after being called multiple times' do - address = 'localhost:9876' - prefixed_address = "tcp://#{address}" - - allow(Gitlab.config.repositories).to receive(:storages).and_return({ - 'default' => { 'gitaly_address' => prefixed_address } - }) + address = 'tcp://localhost:9876' + stub_repos_storages address 2.times do expect(described_class.stub_address('default')).to eq('localhost:9876') @@ -28,6 +38,45 @@ describe Gitlab::GitalyClient do end end + describe '.stub_certs' do + it 'skips certificates if OpenSSLError is raised and report it' do + expect(Rails.logger).to receive(:error).at_least(:once) + expect(Gitlab::Sentry) + .to receive(:track_exception) + .with( + a_kind_of(OpenSSL::X509::CertificateError), + extra: { cert_file: a_kind_of(String) }).at_least(:once) + + expect(OpenSSL::X509::Certificate) + .to receive(:new) + .and_raise(OpenSSL::X509::CertificateError).at_least(:once) + + expect(described_class.stub_certs).to be_a(String) + end + end + describe '.stub_creds' do + it 'returns :this_channel_is_insecure if unix' do + address = 'unix:/tmp/gitaly.sock' + stub_repos_storages address + + expect(described_class.stub_creds('default')).to eq(:this_channel_is_insecure) + end + + it 'returns :this_channel_is_insecure if tcp' do + address = 'tcp://localhost:9876' + stub_repos_storages address + + expect(described_class.stub_creds('default')).to eq(:this_channel_is_insecure) + end + + it 'returns Credentials object if tls' do + address = 'tls://localhost:9876' + stub_repos_storages address + + expect(described_class.stub_creds('default')).to be_a(GRPC::Core::ChannelCredentials) + end + end + describe '.stub' do # Notice that this is referring to gRPC "stubs", not rspec stubs before do @@ -37,9 +86,19 @@ describe Gitlab::GitalyClient do context 'when passed a UNIX socket address' do it 'passes the address as-is to GRPC' do address = 'unix:/tmp/gitaly.sock' - allow(Gitlab.config.repositories).to receive(:storages).and_return({ - 'default' => { 'gitaly_address' => address } - }) + stub_repos_storages address + + expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args) + + described_class.stub(:commit_service, 'default') + end + end + + context 'when passed a TLS address' do + it 'strips tls:// prefix before passing it to GRPC::Core::Channel initializer' do + address = 'localhost:9876' + prefixed_address = "tls://#{address}" + stub_repos_storages prefixed_address expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args) @@ -51,10 +110,7 @@ describe Gitlab::GitalyClient do it 'strips tcp:// prefix before passing it to GRPC::Core::Channel initializer' do address = 'localhost:9876' prefixed_address = "tcp://#{address}" - - allow(Gitlab.config.repositories).to receive(:storages).and_return({ - 'default' => { 'gitaly_address' => prefixed_address } - }) + stub_repos_storages prefixed_address expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args) diff --git a/spec/lib/gitlab/import_export/command_line_util_spec.rb b/spec/lib/gitlab/import_export/command_line_util_spec.rb new file mode 100644 index 00000000000..8e5e0aefac0 --- /dev/null +++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::CommandLineUtil do + include ExportFileHelper + + let(:path) { "#{Dir.tmpdir}/symlink_test" } + let(:archive) { 'spec/fixtures/symlink_export.tar.gz' } + let(:shared) { Gitlab::ImportExport::Shared.new(nil) } + + subject do + Class.new do + include Gitlab::ImportExport::CommandLineUtil + + def initialize + @shared = Gitlab::ImportExport::Shared.new(nil) + end + end.new + end + + before do + FileUtils.mkdir_p(path) + subject.untar_zxf(archive: archive, dir: path) + end + + after do + FileUtils.rm_rf(path) + end + + it 'has the right mask for project.json' do + expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777 + end + + it 'has the right mask for uploads' do + expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555 + end +end diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb index bf34cefe18f..fbc9bcd2df5 100644 --- a/spec/lib/gitlab/import_export/file_importer_spec.rb +++ b/spec/lib/gitlab/import_export/file_importer_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Gitlab::ImportExport::FileImporter do + include ExportFileHelper + let(:shared) { Gitlab::ImportExport::Shared.new(nil) } let(:storage_path) { "#{Dir.tmpdir}/file_importer_spec" } let(:valid_file) { "#{shared.export_path}/valid.json" } @@ -8,6 +10,7 @@ describe Gitlab::ImportExport::FileImporter do let(:hidden_symlink_file) { "#{shared.export_path}/.hidden" } let(:subfolder_symlink_file) { "#{shared.export_path}/subfolder/invalid.json" } let(:evil_symlink_file) { "#{shared.export_path}/.\nevil" } + let(:custom_mode_symlink_file) { "#{shared.export_path}/symlink.mode" } before do stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0) @@ -45,10 +48,18 @@ describe Gitlab::ImportExport::FileImporter do expect(File.exist?(subfolder_symlink_file)).to be false end + it 'removes symlinks without any file permissions' do + expect(File.exist?(custom_mode_symlink_file)).to be false + end + it 'does not remove a valid file' do expect(File.exist?(valid_file)).to be true end + it 'does not change a valid file permissions' do + expect(file_permissions(valid_file)).not_to eq(0000) + end + it 'creates the file in the right subfolder' do expect(shared.export_path).to include('test/abcd') end @@ -84,5 +95,7 @@ describe Gitlab::ImportExport::FileImporter do FileUtils.ln_s(valid_file, subfolder_symlink_file) FileUtils.ln_s(valid_file, hidden_symlink_file) FileUtils.ln_s(valid_file, evil_symlink_file) + FileUtils.ln_s(valid_file, custom_mode_symlink_file) + FileUtils.chmod_R(0000, custom_mode_symlink_file) end end diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb new file mode 100644 index 00000000000..b52078e8556 --- /dev/null +++ b/spec/lib/gitlab/json_cache_spec.rb @@ -0,0 +1,401 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JsonCache do + let(:backend) { double('backend').as_null_object } + let(:namespace) { 'geo' } + let(:key) { 'foo' } + let(:expanded_key) { "#{namespace}:#{key}:#{Rails.version}" } + let(:broadcast_message) { create(:broadcast_message) } + + subject(:cache) { described_class.new(namespace: namespace, backend: backend) } + + describe '#active?' do + context 'when backend respond to active? method' do + it 'delegates to the underlying cache implementation' do + backend = double('backend', active?: false) + + cache = described_class.new(namespace: namespace, backend: backend) + + expect(cache.active?).to eq(false) + end + end + + context 'when backend does not respond to active? method' do + it 'returns true' do + backend = double('backend') + + cache = described_class.new(namespace: namespace, backend: backend) + + expect(cache.active?).to eq(true) + end + end + end + + describe '#cache_key' do + context 'when namespace is not defined' do + it 'expands out the key with Rails version' do + cache = described_class.new(cache_key_with_version: true) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq("#{key}:#{Rails.version}") + end + end + + context 'when cache_key_with_version is true' do + it 'expands out the key with namespace and Rails version' do + cache = described_class.new(namespace: namespace, cache_key_with_version: true) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq("#{namespace}:#{key}:#{Rails.version}") + end + end + + context 'when cache_key_with_version is false' do + it 'expands out the key with namespace' do + cache = described_class.new(namespace: namespace, cache_key_with_version: false) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq("#{namespace}:#{key}") + end + end + + context 'when namespace is nil, and cache_key_with_version is false' do + it 'returns the key' do + cache = described_class.new(namespace: nil, cache_key_with_version: false) + + cache_key = cache.cache_key(key) + + expect(cache_key).to eq(key) + end + end + end + + describe '#expire' do + it 'expires the given key from the cache' do + cache.expire(key) + + expect(backend).to have_received(:delete).with(expanded_key) + end + end + + describe '#read' do + it 'reads the given key from the cache' do + cache.read(key) + + expect(backend).to have_received(:read).with(expanded_key) + end + + it 'returns the cached value when there is data in the cache with the given key' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return("true") + + expect(cache.read(key)).to eq(true) + end + + it 'returns nil when there is no data in the cache with the given key' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return(nil) + + expect(cache.read(key)).to be_nil + end + + context 'when the cached value is a hash' do + it 'parses the cached value' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return(broadcast_message.to_json) + + expect(cache.read(key, BroadcastMessage)).to eq(broadcast_message) + end + + it 'returns nil when klass is nil' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return(broadcast_message.to_json) + + expect(cache.read(key)).to be_nil + end + + it 'gracefully handles bad cached entry' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return('{') + + expect(cache.read(key, BroadcastMessage)).to be_nil + end + + it 'gracefully handles an empty hash' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return('{}') + + expect(cache.read(key, BroadcastMessage)).to be_a(BroadcastMessage) + end + + it 'gracefully handles unknown attributes' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return(broadcast_message.attributes.merge(unknown_attribute: 1).to_json) + + expect(cache.read(key, BroadcastMessage)).to be_nil + end + end + + context 'when the cached value is an array' do + it 'parses the cached value' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return([broadcast_message].to_json) + + expect(cache.read(key, BroadcastMessage)).to eq([broadcast_message]) + end + + it 'returns an empty array when klass is nil' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return([broadcast_message].to_json) + + expect(cache.read(key)).to eq([]) + end + + it 'gracefully handles bad cached entry' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return('[') + + expect(cache.read(key, BroadcastMessage)).to be_nil + end + + it 'gracefully handles an empty array' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return('[]') + + expect(cache.read(key, BroadcastMessage)).to eq([]) + end + + it 'gracefully handles unknown attributes' do + allow(backend).to receive(:read) + .with(expanded_key) + .and_return([{ unknown_attribute: 1 }, broadcast_message.attributes].to_json) + + expect(cache.read(key, BroadcastMessage)).to eq([broadcast_message]) + end + end + end + + describe '#write' do + it 'writes value to the cache with the given key' do + cache.write(key, true) + + expect(backend).to have_received(:write).with(expanded_key, "true", nil) + end + + it 'writes a string containing a JSON representation of the value to the cache' do + cache.write(key, broadcast_message) + + expect(backend).to have_received(:write) + .with(expanded_key, broadcast_message.to_json, nil) + end + + it 'passes options the underlying cache implementation' do + cache.write(key, true, expires_in: 15.seconds) + + expect(backend).to have_received(:write) + .with(expanded_key, "true", expires_in: 15.seconds) + end + + it 'passes options the underlying cache implementation when options is empty' do + cache.write(key, true, {}) + + expect(backend).to have_received(:write) + .with(expanded_key, "true", {}) + end + + it 'passes options the underlying cache implementation when options is nil' do + cache.write(key, true, nil) + + expect(backend).to have_received(:write) + .with(expanded_key, "true", nil) + end + end + + describe '#fetch', :use_clean_rails_memory_store_caching do + let(:backend) { Rails.cache } + + it 'requires a block' do + expect { cache.fetch(key) }.to raise_error(LocalJumpError) + end + + it 'passes options the underlying cache implementation' do + expect(backend).to receive(:write) + .with(expanded_key, "true", expires_in: 15.seconds) + + cache.fetch(key, expires_in: 15.seconds) { true } + end + + context 'when the given key does not exist in the cache' do + context 'when the result of the block is truthy' do + it 'returns the result of the block' do + result = cache.fetch(key) { true } + + expect(result).to eq(true) + end + + it 'caches the value' do + expect(backend).to receive(:write).with(expanded_key, "true", {}) + + cache.fetch(key) { true } + end + end + + context 'when the result of the block is false' do + it 'returns the result of the block' do + result = cache.fetch(key) { false } + + expect(result).to eq(false) + end + + it 'caches the value' do + expect(backend).to receive(:write).with(expanded_key, "false", {}) + + cache.fetch(key) { false } + end + end + + context 'when the result of the block is nil' do + it 'returns the result of the block' do + result = cache.fetch(key) { nil } + + expect(result).to eq(nil) + end + + it 'caches the value' do + expect(backend).to receive(:write).with(expanded_key, "null", {}) + + cache.fetch(key) { nil } + end + end + end + + context 'when the given key exists in the cache' do + context 'when the cached value is a hash' do + before do + backend.write(expanded_key, broadcast_message.to_json) + end + + it 'parses the cached value' do + result = cache.fetch(key, as: BroadcastMessage) { 'block result' } + + expect(result).to eq(broadcast_message) + end + + it "returns the result of the block when 'as' option is nil" do + result = cache.fetch(key, as: nil) { 'block result' } + + expect(result).to eq('block result') + end + + it "returns the result of the block when 'as' option is not informed" do + result = cache.fetch(key) { 'block result' } + + expect(result).to eq('block result') + end + end + + context 'when the cached value is a array' do + before do + backend.write(expanded_key, [broadcast_message].to_json) + end + + it 'parses the cached value' do + result = cache.fetch(key, as: BroadcastMessage) { 'block result' } + + expect(result).to eq([broadcast_message]) + end + + it "returns an empty array when 'as' option is nil" do + result = cache.fetch(key, as: nil) { 'block result' } + + expect(result).to eq([]) + end + + it "returns an empty array when 'as' option is not informed" do + result = cache.fetch(key) { 'block result' } + + expect(result).to eq([]) + end + end + + context 'when the cached value is true' do + before do + backend.write(expanded_key, "true") + end + + it 'returns the cached value' do + result = cache.fetch(key) { 'block result' } + + expect(result).to eq(true) + end + + it 'does not execute the block' do + expect { |block| cache.fetch(key, &block) }.not_to yield_control + end + + it 'does not write to the cache' do + expect(backend).not_to receive(:write) + + cache.fetch(key) { 'block result' } + end + end + + context 'when the cached value is false' do + before do + backend.write(expanded_key, "false") + end + + it 'returns the cached value' do + result = cache.fetch(key) { 'block result' } + + expect(result).to eq(false) + end + + it 'does not execute the block' do + expect { |block| cache.fetch(key, &block) }.not_to yield_control + end + + it 'does not write to the cache' do + expect(backend).not_to receive(:write) + + cache.fetch(key) { 'block result' } + end + end + + context 'when the cached value is nil' do + before do + backend.write(expanded_key, "null") + end + + it 'returns the result of the block' do + result = cache.fetch(key) { 'block result' } + + expect(result).to eq('block result') + end + + it 'writes the result of the block to the cache' do + expect(backend).to receive(:write) + .with(expanded_key, 'block result'.to_json, {}) + + cache.fetch(key) { 'block result' } + end + end + end + end +end diff --git a/spec/lib/gitlab/group_hierarchy_spec.rb b/spec/lib/gitlab/object_hierarchy_spec.rb index f3de7adcec7..4700a7ad2e1 100644 --- a/spec/lib/gitlab/group_hierarchy_spec.rb +++ b/spec/lib/gitlab/object_hierarchy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GroupHierarchy, :postgresql do +describe Gitlab::ObjectHierarchy, :postgresql do let!(:parent) { create(:group) } let!(:child1) { create(:group, parent: parent) } let!(:child2) { create(:group, parent: child1) } @@ -105,9 +105,9 @@ describe Gitlab::GroupHierarchy, :postgresql do end end - describe '#all_groups' do + describe '#all_objects' do let(:relation) do - described_class.new(Group.where(id: child1.id)).all_groups + described_class.new(Group.where(id: child1.id)).all_objects end it 'includes the base rows' do @@ -123,13 +123,13 @@ describe Gitlab::GroupHierarchy, :postgresql do end it 'uses ancestors_base #initialize argument for ancestors' do - relation = described_class.new(Group.where(id: child1.id), Group.where(id: Group.maximum(:id).succ)).all_groups + relation = described_class.new(Group.where(id: child1.id), Group.where(id: Group.maximum(:id).succ)).all_objects expect(relation).to include(parent) end it 'uses descendants_base #initialize argument for descendants' do - relation = described_class.new(Group.where(id: Group.maximum(:id).succ), Group.where(id: child1.id)).all_groups + relation = described_class.new(Group.where(id: Group.maximum(:id).succ), Group.where(id: child1.id)).all_objects expect(relation).to include(child2) end diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index 00c62c7bf96..bd0bc2c9044 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -20,7 +20,7 @@ describe Gitlab::ProjectAuthorizations do end let(:authorizations) do - klass = if Group.supports_nested_groups? + klass = if Group.supports_nested_objects? Gitlab::ProjectAuthorizations::WithNestedGroups else Gitlab::ProjectAuthorizations::WithoutNestedGroups @@ -46,7 +46,7 @@ describe Gitlab::ProjectAuthorizations do expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER) end - if Group.supports_nested_groups? + if Group.supports_nested_objects? context 'with nested groups' do let!(:nested_group) { create(:group, parent: group) } let!(:nested_project) { create(:project, namespace: nested_group) } diff --git a/spec/lib/gitlab/prometheus/query_variables_spec.rb b/spec/lib/gitlab/prometheus/query_variables_spec.rb index 78974cadb69..78c74266c61 100644 --- a/spec/lib/gitlab/prometheus/query_variables_spec.rb +++ b/spec/lib/gitlab/prometheus/query_variables_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe Gitlab::Prometheus::QueryVariables do describe '.call' do - set(:environment) { create(:environment) } + let(:environment) { create(:environment) } let(:slug) { environment.slug } subject { described_class.call(environment) } @@ -20,7 +20,7 @@ describe Gitlab::Prometheus::QueryVariables do it { is_expected.to include(kube_namespace: '') } end - context 'with deplyoment platform' do + context 'with deployment platform' do let(:kube_namespace) { environment.deployment_platform.actual_namespace } before do diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb deleted file mode 100644 index 6106f13c774..00000000000 --- a/spec/lib/gitlab/upgrader_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Upgrader do - let(:upgrader) { described_class.new } - let(:current_version) { Gitlab::VERSION } - - describe 'current_version_raw' do - it { expect(upgrader.current_version_raw).to eq(current_version) } - end - - describe 'latest_version?' do - it 'is true if newest version' do - allow(upgrader).to receive(:latest_version_raw).and_return(current_version) - expect(upgrader.latest_version?).to be_truthy - end - end - - describe 'latest_version_raw' do - it 'is the latest version for GitLab 5' do - allow(upgrader).to receive(:current_version_raw).and_return("5.3.0") - expect(upgrader.latest_version_raw).to eq("v5.4.2") - end - - it 'gets the latest version from tags' do - allow(upgrader).to receive(:fetch_git_tags).and_return([ - '6f0733310546402c15d3ae6128a95052f6c8ea96 refs/tags/v7.1.1', - 'facfec4b242ce151af224e20715d58e628aa5e74 refs/tags/v7.1.1^{}', - 'f7068d99c79cf79befbd388030c051bb4b5e86d4 refs/tags/v7.10.4', - '337225a4fcfa9674e2528cb6d41c46556bba9dfa refs/tags/v7.10.4^{}', - '880e0ba0adbed95d087f61a9a17515e518fc6440 refs/tags/v7.11.1', - '6584346b604f981f00af8011cd95472b2776d912 refs/tags/v7.11.1^{}', - '43af3e65a486a9237f29f56d96c3b3da59c24ae0 refs/tags/v7.11.2', - 'dac18e7728013a77410e926a1e64225703754a2d refs/tags/v7.11.2^{}', - '0bf21fd4b46c980c26fd8c90a14b86a4d90cc950 refs/tags/v7.9.4', - 'b10de29edbaff7219547dc506cb1468ee35065c3 refs/tags/v7.9.4^{}' - ]) - expect(upgrader.latest_version_raw).to eq("v7.11.2") - end - end -end diff --git a/spec/lib/gitlab/utils/override_spec.rb b/spec/lib/gitlab/utils/override_spec.rb index fc08ebcfc6d..9e7c97f8095 100644 --- a/spec/lib/gitlab/utils/override_spec.rb +++ b/spec/lib/gitlab/utils/override_spec.rb @@ -25,11 +25,21 @@ describe Gitlab::Utils::Override do let(:klass) { subject } - def good(mod) + def good(mod, bad_arity: false, negative_arity: false) mod.module_eval do override :good - def good - super.succ + + if bad_arity + def good(num) + end + elsif negative_arity + def good(*args) + super.succ + end + else + def good + super.succ + end end end @@ -56,6 +66,14 @@ describe Gitlab::Utils::Override do described_class.verify! end + it 'checks ok for overriding method using negative arity' do + good(subject, negative_arity: true) + result = instance.good + + expect(result).to eq(1) + described_class.verify! + end + it 'raises NotImplementedError when it is not overriding anything' do expect do bad(subject) @@ -63,6 +81,14 @@ describe Gitlab::Utils::Override do described_class.verify! end.to raise_error(NotImplementedError) end + + it 'raises NotImplementedError when overriding a method with different arity' do + expect do + good(subject, bad_arity: true) + instance.good(1) + described_class.verify! + end.to raise_error(NotImplementedError) + end end shared_examples 'checking as intended, nothing was overridden' do diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index f6e5c9d33ac..f2d99872401 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -890,22 +890,14 @@ describe Notify do shared_examples 'an email for a note on a diff discussion' do |model| let(:note) { create(model, author: note_author) } - context 'when note is on image' do + context 'when note is not on text' do before do - allow_any_instance_of(DiffDiscussion).to receive(:on_image?).and_return(true) + allow_any_instance_of(DiffDiscussion).to receive(:on_text?).and_return(false) end it 'does not include diffs with character-level highlighting' do is_expected.not_to have_body_text '<span class="p">}</span></span>' end - - it 'ends the intro with a dot' do - is_expected.to have_body_text "#{note.diff_file.file_path}</a>." - end - end - - it 'ends the intro with a colon' do - is_expected.to have_body_text "#{note.diff_file.file_path}</a>:" end it 'includes diffs with character-level highlighting' do diff --git a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb new file mode 100644 index 00000000000..b2d8f476bb2 --- /dev/null +++ b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb') + +describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do + include Gitlab::Database::MigrationHelpers + + context 'when there are jobs in the queue' do + it 'correctly migrates queue when migrating up' do + Sidekiq::Testing.disable! do + stubbed_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) + + described_class.new.up + + expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 0 + expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).to eq 2 + end + end + + it 'does not affect other queues under the same namespace' do + Sidekiq::Testing.disable! do + stubbed_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1]) + stubbed_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1]) + + described_class.new.up + + expect(sidekiq_queue_length('gcp_cluster:cluster_install_app')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:cluster_provision')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_app_installation')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:wait_for_cluster_creation')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_ingress_ip_address')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:cluster_project_configure')).to eq 1 + end + end + + it 'correctly migrates queue when migrating down' do + Sidekiq::Testing.disable! do + stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) + + described_class.new.down + + expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 1 + expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).to eq 0 + end + end + end + + context 'when there are no jobs in the queues' do + it 'does not raise error when migrating up' do + expect { described_class.new.up }.not_to raise_error + end + + it 'does not raise error when migrating down' do + expect { described_class.new.down }.not_to raise_error + end + end + + def stubbed_worker(queue:) + Class.new do + include Sidekiq::Worker + sidekiq_options queue: queue + end + end +end diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index d6e5b557870..89839709131 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -49,7 +49,7 @@ describe BroadcastMessage do it 'caches the output of the query' do create(:broadcast_message) - expect(described_class).to receive(:where).and_call_original.once + expect(described_class).to receive(:current_and_future_messages).and_call_original.once described_class.current @@ -93,27 +93,6 @@ describe BroadcastMessage do expect(Rails.cache).to receive(:delete).with(described_class::LEGACY_CACHE_KEY) expect(described_class.current.length).to eq(0) end - - it 'gracefully handles bad cache entry' do - allow(described_class).to receive(:current_and_future_messages).and_return('{') - - expect(described_class.current).to be_empty - end - - it 'gracefully handles an empty hash' do - allow(described_class).to receive(:current_and_future_messages).and_return('{}') - - expect(described_class.current).to be_empty - end - - it 'gracefully handles unknown attributes' do - message = create(:broadcast_message) - - allow(described_class).to receive(:current_and_future_messages) - .and_return([{ bad_attr: 1 }, message]) - - expect(described_class.current).to eq([message]) - end end describe '#active?' do diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index 062d2fd0768..f3af9d59786 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -394,7 +394,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching context 'when namespace is updated' do it 'should call ConfigureWorker' do - expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id).once + expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id).once platform.namespace = 'new-namespace' platform.save @@ -403,7 +403,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching context 'when namespace is not updated' do it 'should not call ConfigureWorker' do - expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async) + expect(ClusterConfigureWorker).not_to receive(:perform_async) platform.username = "new-username" platform.save diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb index 7d617cb7b19..1ea7f2b9985 100644 --- a/spec/models/concerns/avatarable_spec.rb +++ b/spec/models/concerns/avatarable_spec.rb @@ -33,6 +33,43 @@ describe Avatarable do end describe '#avatar_path' do + context 'with caching enabled', :request_store do + let!(:avatar_path) { [relative_url_root, project.avatar.local_url].join } + let!(:avatar_url) { [gitlab_host, relative_url_root, project.avatar.local_url].join } + + it 'only calls local_url once' do + expect(project.avatar).to receive(:local_url).once.and_call_original + + 2.times do + expect(project.avatar_path).to eq(avatar_path) + end + end + + it 'calls local_url twice for path and URLs' do + expect(project.avatar).to receive(:local_url).exactly(2).times.and_call_original + + expect(project.avatar_path(only_path: true)).to eq(avatar_path) + expect(project.avatar_path(only_path: false)).to eq(avatar_url) + end + + it 'calls local_url twice for different sizes' do + expect(project.avatar).to receive(:local_url).exactly(2).times.and_call_original + + expect(project.avatar_path).to eq(avatar_path) + expect(project.avatar_path(size: 40)).to eq(avatar_path + "?width=40") + end + + it 'handles unpersisted objects' do + new_project = build(:project, :with_avatar) + path = [relative_url_root, new_project.avatar.local_url].join + expect(new_project.avatar).to receive(:local_url).exactly(2).times.and_call_original + + 2.times do + expect(new_project.avatar_path).to eq(path) + end + end + end + using RSpec::Parameterized::TableSyntax where(:has_asset_host, :visibility_level, :only_path, :avatar_path_prefix) do diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb index 73eb7a1160d..4b16e6e3902 100644 --- a/spec/models/concerns/discussion_on_diff_spec.rb +++ b/spec/models/concerns/discussion_on_diff_spec.rb @@ -50,11 +50,17 @@ describe DiscussionOnDiff do end context "when the diff line does not exist on a legacy diff note" do + subject { create(:legacy_diff_note_on_merge_request).to_discussion } + it "returns an empty array" do - legacy_note = LegacyDiffNote.new + expect(truncated_lines).to eq([]) + end + end - allow(subject).to receive(:first_note).and_return(legacy_note) + context 'when the discussion is on an image' do + subject { create(:image_diff_note_on_merge_request).to_discussion } + it 'returns an empty array' do expect(truncated_lines).to eq([]) end end diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 40ce8ab736a..fda00a693f0 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -337,24 +337,9 @@ describe DiffNote do end describe "image diff notes" do - let(:path) { "files/images/any_image.png" } - - let!(:position) do - Gitlab::Diff::Position.new( - old_path: path, - new_path: path, - width: 10, - height: 10, - x: 1, - y: 1, - diff_refs: merge_request.diff_refs, - position_type: "image" - ) - end + subject { build(:image_diff_note_on_merge_request, project: project, noteable: merge_request) } describe "validations" do - subject { build(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request) } - it { is_expected.not_to validate_presence_of(:line_code) } it "does not validate diff line" do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 18b54cce834..475fbe56e4d 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -337,32 +337,40 @@ describe Namespace do end end - it 'updates project full path in .git/config for each project inside namespace' do - parent = create(:group, name: 'mygroup', path: 'mygroup') - subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent) - project_in_parent_group = create(:project, :legacy_storage, :repository, namespace: parent, name: 'foo1') - hashed_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo2') - legacy_project_in_subgroup = create(:project, :legacy_storage, :repository, namespace: subgroup, name: 'foo3') - - parent.update(path: 'mygroup_new') - - # Routes are loaded when creating the projects, so we need to manually - # reload them for the below code to be aware of the above UPDATE. - [ - project_in_parent_group, - hashed_project_in_subgroup, - legacy_project_in_subgroup - ].each do |project| - project.route.reload + context 'for each project inside the namespace' do + let!(:parent) { create(:group, name: 'mygroup', path: 'mygroup') } + let!(:subgroup) { create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent) } + let!(:project_in_parent_group) { create(:project, :legacy_storage, :repository, namespace: parent, name: 'foo1') } + let!(:hashed_project_in_subgroup) { create(:project, :repository, namespace: subgroup, name: 'foo2') } + let!(:legacy_project_in_subgroup) { create(:project, :legacy_storage, :repository, namespace: subgroup, name: 'foo3') } + + it 'updates project full path in .git/config' do + parent.update(path: 'mygroup_new') + + expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" + expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" + expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" end - expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" - expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" - expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" - end + it 'updates the project storage location' do + repository_project_in_parent_group = create(:project_repository, project: project_in_parent_group) + repository_hashed_project_in_subgroup = create(:project_repository, project: hashed_project_in_subgroup) + repository_legacy_project_in_subgroup = create(:project_repository, project: legacy_project_in_subgroup) + + parent.update(path: 'mygroup_moved') + + expect(repository_project_in_parent_group.reload.disk_path).to eq "mygroup_moved/#{project_in_parent_group.path}" + expect(repository_hashed_project_in_subgroup.reload.disk_path).to eq hashed_project_in_subgroup.disk_path + expect(repository_legacy_project_in_subgroup.reload.disk_path).to eq "mygroup_moved/mysubgroup/#{legacy_project_in_subgroup.path}" + end + + def project_rugged(project) + # Routes are loaded when creating the projects, so we need to manually + # reload them for the below code to be aware of the above UPDATE. + project.route.reload - def project_rugged(project) - rugged_repo(project.repository) + rugged_repo(project.repository) + end end end diff --git a/spec/models/pool_repository_spec.rb b/spec/models/pool_repository_spec.rb index 3d3878b8c39..112d4ab56fc 100644 --- a/spec/models/pool_repository_spec.rb +++ b/spec/models/pool_repository_spec.rb @@ -23,4 +23,25 @@ describe PoolRepository do expect(pool.disk_path).to match(%r{\A@pools/\h{2}/\h{2}/\h{64}}) end end + + describe '#unlink_repository' do + let(:pool) { create(:pool_repository, :ready) } + + context 'when the last member leaves' do + it 'schedules pool removal' do + expect(::ObjectPool::DestroyWorker).to receive(:perform_async).with(pool.id).and_call_original + + pool.unlink_repository(pool.source_project.repository) + end + end + + context 'when the second member leaves' do + it 'does not schedule pool removal' do + create(:project, :repository, pool_repository: pool) + expect(::ObjectPool::DestroyWorker).not_to receive(:perform_async).with(pool.id) + + pool.unlink_repository(pool.source_project.repository) + end + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5e63f14b720..a01f76a5bab 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -145,25 +145,10 @@ describe Project do end describe 'ci_pipelines association' do - context 'when feature flag pipeline_ci_sources_only is enabled' do - it 'returns only pipelines from ci_sources' do - stub_feature_flags(pipeline_ci_sources_only: true) + it 'returns only pipelines from ci_sources' do + expect(Ci::Pipeline).to receive(:ci_sources).and_call_original - expect(Ci::Pipeline).to receive(:ci_sources).and_call_original - - subject.ci_pipelines - end - end - - context 'when feature flag pipeline_ci_sources_only is disabled' do - it 'returns all pipelines' do - stub_feature_flags(pipeline_ci_sources_only: false) - - expect(Ci::Pipeline).not_to receive(:ci_sources).and_call_original - expect(Ci::Pipeline).to receive(:all).and_call_original.at_least(:once) - - subject.ci_pipelines - end + subject.ci_pipelines end end end @@ -1666,26 +1651,54 @@ describe Project do end describe '#track_project_repository' do - let(:project) { create(:project, :repository) } + shared_examples 'tracks storage location' do + context 'when a project repository entry does not exist' do + it 'creates a new entry' do + expect { project.track_project_repository }.to change(project, :project_repository) + end + + it 'tracks the project storage location' do + project.track_project_repository + + expect(project.project_repository).to have_attributes( + disk_path: project.disk_path, + shard_name: project.repository_storage + ) + end + end + + context 'when a tracking entry exists' do + let!(:project_repository) { create(:project_repository, project: project) } + let!(:shard) { create(:shard, name: 'foo') } + + it 'does not create a new entry in the database' do + expect { project.track_project_repository }.not_to change(project, :project_repository) + end + + it 'updates the project storage location' do + allow(project).to receive(:disk_path).and_return('fancy/new/path') + allow(project).to receive(:repository_storage).and_return('foo') - it 'creates a project_repository' do - project.track_project_repository + project.track_project_repository - expect(project.reload.project_repository).to be_present - expect(project.project_repository.disk_path).to eq(project.disk_path) - expect(project.project_repository.shard_name).to eq(project.repository_storage) + expect(project.project_repository).to have_attributes( + disk_path: 'fancy/new/path', + shard_name: 'foo' + ) + end + end end - it 'updates the project_repository' do - project.track_project_repository + context 'with projects on legacy storage' do + let(:project) { create(:project, :repository, :legacy_storage) } - allow(project).to receive(:disk_path).and_return('@fancy/new/path') + it_behaves_like 'tracks storage location' + end - expect do - project.track_project_repository - end.not_to change(ProjectRepository, :count) + context 'with projects on hashed storage' do + let(:project) { create(:project, :repository) } - expect(project.reload.project_repository.disk_path).to eq(project.disk_path) + it_behaves_like 'tracks storage location' end end @@ -3690,7 +3703,7 @@ describe Project do expect(project.badges.count).to eq 3 end - if Group.supports_nested_groups? + if Group.supports_nested_objects? context 'with nested_groups' do let(:parent_group) { create(:group) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8b3021113bc..33842e74b92 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1966,7 +1966,7 @@ describe User do subject { user.membership_groups } - if Group.supports_nested_groups? + if Group.supports_nested_objects? it { is_expected.to contain_exactly parent_group, child_group } else it { is_expected.to contain_exactly parent_group } @@ -2347,7 +2347,7 @@ describe User do group.add_owner(user) end - if Group.supports_nested_groups? + if Group.supports_nested_objects? it 'returns all groups' do is_expected.to match_array [ group, diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 9d0093e8159..baf21efa75c 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -147,7 +147,7 @@ describe GroupPolicy do let(:current_user) { owner } it do - allow(Group).to receive(:supports_nested_groups?).and_return(true) + allow(Group).to receive(:supports_nested_objects?).and_return(true) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -161,7 +161,7 @@ describe GroupPolicy do let(:current_user) { admin } it do - allow(Group).to receive(:supports_nested_groups?).and_return(true) + allow(Group).to receive(:supports_nested_objects?).and_return(true) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -173,7 +173,7 @@ describe GroupPolicy do describe 'when nested group support feature is disabled' do before do - allow(Group).to receive(:supports_nested_groups?).and_return(false) + allow(Group).to receive(:supports_nested_objects?).and_return(false) end context 'admin' do @@ -282,7 +282,7 @@ describe GroupPolicy do let(:current_user) { owner } it do - allow(Group).to receive(:supports_nested_groups?).and_return(true) + allow(Group).to receive(:supports_nested_objects?).and_return(true) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb index 8c58ba45ce9..0ac23505de7 100644 --- a/spec/requests/api/events_spec.rb +++ b/spec/requests/api/events_spec.rb @@ -226,7 +226,7 @@ describe API::Events do end it 'correctly returns the second page without inaccessible events' do - get api("/projects/#{public_project.id}/events", user), per_page: 2, page: 2 + get api("/projects/#{public_project.id}/events", user), params: { per_page: 2, page: 2 } titles = json_response.map { |event| event['target_title'] } @@ -235,7 +235,7 @@ describe API::Events do end it 'correctly returns the first page without inaccessible events' do - get api("/projects/#{public_project.id}/events", user), per_page: 2, page: 1 + get api("/projects/#{public_project.id}/events", user), params: { per_page: 2, page: 1 } titles = json_response.map { |event| event['target_title'] } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index e6d82448c0d..0ba1f2d7a2b 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -54,7 +54,7 @@ describe API::Files do describe "HEAD /projects/:id/repository/files/:file_path" do shared_examples_for 'repository files' do it 'returns file attributes in headers' do - head api(route(file_path), current_user), params + head api(route(file_path), current_user), params: params expect(response).to have_gitlab_http_status(200) expect(response.headers['X-Gitlab-File-Path']).to eq(CGI.unescape(file_path)) @@ -68,7 +68,7 @@ describe API::Files do file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee" params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" - head api(route(file_path), current_user), params + head api(route(file_path), current_user), params: params expect(response).to have_gitlab_http_status(200) expect(response.headers['X-Gitlab-File-Name']).to eq('commit.js.coffee') @@ -87,7 +87,7 @@ describe API::Files do it "responds with a 404 status" do params[:ref] = 'master' - head api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params + head api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params: params expect(response).to have_gitlab_http_status(404) end @@ -97,7 +97,7 @@ describe API::Files do include_context 'disabled repository' it "responds with a 403 status" do - head api(route(file_path), current_user), params + head api(route(file_path), current_user), params: params expect(response).to have_gitlab_http_status(403) end @@ -115,7 +115,7 @@ describe API::Files do it "responds with a 404 status" do current_user = nil - head api(route(file_path), current_user), params + head api(route(file_path), current_user), params: params expect(response).to have_gitlab_http_status(404) end @@ -136,7 +136,7 @@ describe API::Files do context 'when authenticated', 'as a guest' do it_behaves_like '403 response' do - let(:request) { head api(route(file_path), guest), params } + let(:request) { head api(route(file_path), guest), params: params } end end end diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index ec546db335a..2b148c1b563 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -104,7 +104,7 @@ describe 'OpenID Connect requests' do expect(json_response).to match(id_token_claims.merge(user_info_claims)) expected_groups = [group1.full_path, group3.full_path] - expected_groups << group4.full_path if Group.supports_nested_groups? + expected_groups << group4.full_path if Group.supports_nested_objects? expect(json_response['groups']).to match_array(expected_groups) end diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index c27e27d3648..49021f5d1b7 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -345,7 +345,7 @@ describe 'Rack Attack global throttles' do end def api_get_args_with_token_headers(partial_url, token_headers) - ["/api/#{API::API.version}#{partial_url}", nil, token_headers] + ["/api/#{API::API.version}#{partial_url}", params: nil, headers: token_headers] end def rss_url(user) diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb index 36da8d33a44..ae0f917415c 100644 --- a/spec/serializers/entity_date_helper_spec.rb +++ b/spec/serializers/entity_date_helper_spec.rb @@ -50,7 +50,7 @@ describe EntityDateHelper do end context 'when less than 31 days remaining' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 12.days.from_now.utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words(12.days.from_now.utc.to_date) } it 'returns days remaining' do expect(milestone_remaining).to eq("<strong>12</strong> days remaining") @@ -58,7 +58,7 @@ describe EntityDateHelper do end context 'when less than 1 year and more than 30 days remaining' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 2.months.from_now.utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words(2.months.from_now.utc.to_date) } it 'returns months remaining' do expect(milestone_remaining).to eq("<strong>2</strong> months remaining") @@ -66,7 +66,7 @@ describe EntityDateHelper do end context 'when more than 1 year remaining' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: (1.year.from_now + 2.days).utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words((1.year.from_now + 2.days).utc.to_date) } it 'returns years remaining' do expect(milestone_remaining).to eq("<strong>1</strong> year remaining") @@ -74,7 +74,7 @@ describe EntityDateHelper do end context 'when milestone is expired' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 2.days.ago.utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words(2.days.ago.utc.to_date) } it 'returns "Past due"' do expect(milestone_remaining).to eq("<strong>Past due</strong>") @@ -82,7 +82,7 @@ describe EntityDateHelper do end context 'when milestone has start_date in the future' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, start_date: 2.days.from_now.utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words(nil, 2.days.from_now.utc.to_date) } it 'returns "Upcoming"' do expect(milestone_remaining).to eq("<strong>Upcoming</strong>") @@ -90,7 +90,7 @@ describe EntityDateHelper do end context 'when milestone has start_date in the past' do - let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, start_date: 2.days.ago.utc)) } + let(:milestone_remaining) { date_helper_class.remaining_days_in_words(nil, 2.days.ago.utc.to_date) } it 'returns days elapsed' do expect(milestone_remaining).to eq("<strong>2</strong> days elapsed") diff --git a/spec/serializers/environment_entity_spec.rb b/spec/serializers/environment_entity_spec.rb index b7324a26ed2..791b64dc356 100644 --- a/spec/serializers/environment_entity_spec.rb +++ b/spec/serializers/environment_entity_spec.rb @@ -40,4 +40,34 @@ describe EnvironmentEntity do expect(subject).to include(:metrics_path) end end + + context 'with deployment platform' do + let(:project) { create(:project, :repository) } + let(:environment) { create(:environment, project: project) } + + context 'when deployment platform is a cluster' do + before do + create(:cluster, + :provided_by_gcp, + :project, + environment_scope: '*', + projects: [project]) + end + + it 'should include cluster_type' do + expect(subject).to include(:cluster_type) + expect(subject[:cluster_type]).to eq('project_type') + end + end + + context 'when deployment platform is a Kubernetes Service' do + before do + create(:kubernetes_service, project: project) + end + + it 'should not include cluster_type' do + expect(subject).not_to include(:cluster_type) + end + end + end end diff --git a/spec/serializers/issue_serializer_spec.rb b/spec/serializers/issue_serializer_spec.rb index e8c46c0cdee..b8255e004d0 100644 --- a/spec/serializers/issue_serializer_spec.rb +++ b/spec/serializers/issue_serializer_spec.rb @@ -20,11 +20,19 @@ describe IssueSerializer do context 'sidebar issue serialization' do let(:serializer) { 'sidebar' } - it 'matches sidebar issue json schema' do + it 'matches issue_sidebar json schema' do expect(json_entity).to match_schema('entities/issue_sidebar') end end + context 'sidebar extras issue serialization' do + let(:serializer) { 'sidebar_extras' } + + it 'matches issue_sidebar_extras json schema' do + expect(json_entity).to match_schema('entities/issue_sidebar_extras') + end + end + context 'board issue serialization' do let(:serializer) { 'board' } diff --git a/spec/serializers/merge_request_basic_serializer_spec.rb b/spec/serializers/merge_request_basic_serializer_spec.rb deleted file mode 100644 index 1fad8e6bc5d..00000000000 --- a/spec/serializers/merge_request_basic_serializer_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'spec_helper' - -describe MergeRequestBasicSerializer do - let(:resource) { create(:merge_request) } - let(:user) { create(:user) } - - let(:json_entity) do - described_class.new(current_user: user) - .represent(resource, serializer: 'basic') - .with_indifferent_access - end - - it 'matches basic merge request json' do - expect(json_entity).to match_schema('entities/merge_request_basic') - end -end diff --git a/spec/serializers/merge_request_serializer_spec.rb b/spec/serializers/merge_request_serializer_spec.rb index b259cb92962..276e0f6ff3d 100644 --- a/spec/serializers/merge_request_serializer_spec.rb +++ b/spec/serializers/merge_request_serializer_spec.rb @@ -20,8 +20,16 @@ describe MergeRequestSerializer do context 'sidebar merge request serialization' do let(:serializer) { 'sidebar' } - it 'matches basic merge request json schema' do - expect(json_entity).to match_schema('entities/merge_request_basic') + it 'matches merge_request_sidebar json schema' do + expect(json_entity).to match_schema('entities/merge_request_sidebar') + end + end + + context 'sidebar_extras merge request serialization' do + let(:serializer) { 'sidebar_extras' } + + it 'matches merge_request_sidebar_extras json schema' do + expect(json_entity).to match_schema('entities/merge_request_sidebar_extras') end end diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb index d69678c1277..2664649df47 100644 --- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb +++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb @@ -20,7 +20,7 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do subject { described_class.new.execute(provider) } before do - allow(ClusterPlatformConfigureWorker).to receive(:perform_async) + allow(ClusterConfigureWorker).to receive(:perform_async) end shared_examples 'success' do @@ -43,8 +43,8 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do expect(platform.token).to eq(token) end - it 'calls ClusterPlatformConfigureWorker in a ascync fashion' do - expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id) + it 'calls ClusterConfigureWorker in a ascync fashion' do + expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id) subject end diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb index 73f9be242a3..b2e6ebecd4a 100644 --- a/spec/services/clusters/update_service_spec.rb +++ b/spec/services/clusters/update_service_spec.rb @@ -37,7 +37,7 @@ describe Clusters::UpdateService do end before do - allow(ClusterPlatformConfigureWorker).to receive(:perform_async) + allow(ClusterConfigureWorker).to receive(:perform_async) stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace') end diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index 224e933bebc..fe6a8691ae0 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -55,7 +55,7 @@ describe Groups::CreateService, '#execute' do context 'when nested groups feature is disabled' do it 'does not save group and returns an error' do - allow(Group).to receive(:supports_nested_groups?).and_return(false) + allow(Group).to receive(:supports_nested_objects?).and_return(false) is_expected.not_to be_persisted expect(subject.errors[:parent_id]).to include('You don’t have permission to create a subgroup in this group.') @@ -66,7 +66,7 @@ describe Groups::CreateService, '#execute' do context 'when nested groups feature is enabled' do before do - allow(Group).to receive(:supports_nested_groups?).and_return(true) + allow(Group).to receive(:supports_nested_objects?).and_return(true) end context 'as guest' do diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb index 86fdd43c1e5..75d6ddb0a2c 100644 --- a/spec/services/groups/nested_create_service_spec.rb +++ b/spec/services/groups/nested_create_service_spec.rb @@ -30,7 +30,7 @@ describe Groups::NestedCreateService do let(:params) { { group_path: 'a-group' } } before do - allow(Group).to receive(:supports_nested_groups?) { false } + allow(Group).to receive(:supports_nested_objects?) { false } end it 'creates the group' do diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb index dd8a1cee074..6b48c993c57 100644 --- a/spec/services/groups/transfer_service_spec.rb +++ b/spec/services/groups/transfer_service_spec.rb @@ -9,7 +9,7 @@ describe Groups::TransferService, :postgresql do shared_examples 'ensuring allowed transfer for a group' do context 'with other database than PostgreSQL' do before do - allow(Group).to receive(:supports_nested_groups?).and_return(false) + allow(Group).to receive(:supports_nested_objects?).and_return(false) end it 'should return false' do diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 68ac3a00ab0..d20e712d365 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -2250,7 +2250,7 @@ describe NotificationService, :mailer do # Creates a nested group only if supported # to avoid errors on MySQL def create_nested_group - if Group.supports_nested_groups? + if Group.supports_nested_objects? parent_group = create(:group, :public) child_group = create(:group, :public, parent: parent_group) @@ -2277,7 +2277,7 @@ describe NotificationService, :mailer do end def add_member_for_parent_group(user, project) - return unless Group.supports_nested_groups? + return unless Group.supports_nested_objects? project.reload @@ -2285,13 +2285,13 @@ describe NotificationService, :mailer do end def should_email_nested_group_user(user, times: 1, recipients: email_recipients) - return unless Group.supports_nested_groups? + return unless Group.supports_nested_objects? should_email(user, times: 1, recipients: email_recipients) end def should_not_email_nested_group_user(user, recipients: email_recipients) - return unless Group.supports_nested_groups? + return unless Group.supports_nested_objects? should_not_email(user, recipients: email_recipients) end diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb index b4718a07204..59c08b30f9f 100644 --- a/spec/services/projects/after_rename_service_spec.rb +++ b/spec/services/projects/after_rename_service_spec.rb @@ -99,6 +99,17 @@ describe Projects::AfterRenameService do expect(rugged_config['gitlab.fullpath']).to eq(project.full_path) end + + it 'updates storage location' do + allow(project_storage).to receive(:rename_repo).and_return(true) + + described_class.new(project).execute + + expect(project.project_repository).to have_attributes( + disk_path: project.disk_path, + shard_name: project.repository_storage + ) + end end context 'using hashed storage' do @@ -193,6 +204,15 @@ describe Projects::AfterRenameService do expect(rugged_config['gitlab.fullpath']).to eq(project.full_path) end + + it 'updates storage location' do + described_class.new(project).execute + + expect(project.project_repository).to have_attributes( + disk_path: project.disk_path, + shard_name: project.repository_storage + ) + end end end end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 132ad9a2646..766276fdba3 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -63,6 +63,15 @@ describe Projects::TransferService do expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" end + it 'updates storage location' do + transfer_project(project, user, group) + + expect(project.project_repository).to have_attributes( + disk_path: "#{group.full_path}/#{project.path}", + shard_name: project.repository_storage + ) + end + context 'new group has a kubernetes cluster' do let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) } let(:group) { group_cluster.group } @@ -139,6 +148,17 @@ describe Projects::TransferService do expect(service).not_to receive(:execute_system_hooks) end end + + it 'does not update storage location' do + create(:project_repository, project: project) + + attempt_project_transfer + + expect(project.project_repository).to have_attributes( + disk_path: project.disk_path, + shard_name: project.repository_storage + ) + end end context 'namespace -> no namespace' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e8554377d77..89357056c93 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -228,7 +228,7 @@ RSpec.configure do |config| end config.around(:each, :nested_groups) do |example| - example.run if Group.supports_nested_groups? + example.run if Group.supports_nested_objects? end config.around(:each, :postgresql) do |example| diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb index 943c1f6ffd7..592962ebf7c 100644 --- a/spec/support/api/boards_shared_examples.rb +++ b/spec/support/api/boards_shared_examples.rb @@ -88,7 +88,7 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false| let(:url) { "#{root_url}/#{board.id}/lists" } it 'creates a new issue board list for labels' do - post api(url, user), label_id: ux_label.id + post api(url, user), params: { label_id: ux_label.id } expect(response).to have_gitlab_http_status(201) expect(json_response['label']['name']).to eq(ux_label.title) @@ -96,13 +96,13 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false| end it 'returns 400 when creating a new list if label_id is invalid' do - post api(url, user), label_id: 23423 + post api(url, user), params: { label_id: 23423 } expect(response).to have_gitlab_http_status(400) end it 'returns 403 for members with guest role' do - put api("#{url}/#{test_list.id}", guest), position: 1 + put api("#{url}/#{test_list.id}", guest), params: { position: 1 } expect(response).to have_gitlab_http_status(403) end @@ -112,23 +112,20 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false| let(:url) { "#{root_url}/#{board.id}/lists" } it "updates a list" do - put api("#{url}/#{test_list.id}", user), - position: 1 + put api("#{url}/#{test_list.id}", user), params: { position: 1 } expect(response).to have_gitlab_http_status(200) expect(json_response['position']).to eq(1) end it "returns 404 error if list id not found" do - put api("#{url}/44444", user), - position: 1 + put api("#{url}/44444", user), params: { position: 1 } expect(response).to have_gitlab_http_status(404) end it "returns 403 for members with guest role" do - put api("#{url}/#{test_list.id}", guest), - position: 1 + put api("#{url}/#{test_list.id}", guest), params: { position: 1 } expect(response).to have_gitlab_http_status(403) end diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb index 3bebb7aae90..5f709831ce1 100644 --- a/spec/support/api/milestones_shared_examples.rb +++ b/spec/support/api/milestones_shared_examples.rb @@ -45,7 +45,7 @@ shared_examples_for 'group and project milestones' do |route_definition| it 'returns an array of milestones specified by iids' do other_milestone = create(:milestone, project: try(:project), group: try(:group)) - get api(route, user), iids: [closed_milestone.iid, other_milestone.iid] + get api(route, user), params: { iids: [closed_milestone.iid, other_milestone.iid] } expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array @@ -54,7 +54,7 @@ shared_examples_for 'group and project milestones' do |route_definition| end it 'does not return any milestone if none found' do - get api(route, user), iids: [Milestone.maximum(:iid).succ] + get api(route, user), params: { iids: [Milestone.maximum(:iid).succ] } expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array @@ -73,7 +73,7 @@ shared_examples_for 'group and project milestones' do |route_definition| end it 'returns a milestone by searching for title' do - get api(route, user), search: 'version2' + get api(route, user), params: { search: 'version2' } expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers @@ -83,7 +83,7 @@ shared_examples_for 'group and project milestones' do |route_definition| end it 'returns a milestones by searching for description' do - get api(route, user), search: 'open' + get api(route, user), params: { search: 'open' } expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers @@ -117,7 +117,7 @@ shared_examples_for 'group and project milestones' do |route_definition| describe "POST #{route_definition}" do it 'creates a new milestone' do - post api(route, user), title: 'new milestone' + post api(route, user), params: { title: 'new milestone' } expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('new milestone') @@ -125,8 +125,7 @@ shared_examples_for 'group and project milestones' do |route_definition| end it 'creates a new milestone with description and dates' do - post api(route, user), - title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' + post api(route, user), params: { title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' } expect(response).to have_gitlab_http_status(201) expect(json_response['description']).to eq('release') @@ -141,14 +140,13 @@ shared_examples_for 'group and project milestones' do |route_definition| end it 'returns a 400 error if params are invalid (duplicate title)' do - post api(route, user), - title: milestone.title, description: 'release', due_date: '2013-03-02' + post api(route, user), params: { title: milestone.title, description: 'release', due_date: '2013-03-02' } expect(response).to have_gitlab_http_status(400) end it 'creates a new milestone with reserved html characters' do - post api(route, user), title: 'foo & bar 1.1 -> 2.2' + post api(route, user), params: { title: 'foo & bar 1.1 -> 2.2' } expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2') @@ -158,8 +156,7 @@ shared_examples_for 'group and project milestones' do |route_definition| describe "PUT #{route_definition}/:milestone_id" do it 'updates a milestone' do - put api(resource_route, user), - title: 'updated title' + put api(resource_route, user), params: { title: 'updated title' } expect(response).to have_gitlab_http_status(200) expect(json_response['title']).to eq('updated title') @@ -168,29 +165,27 @@ shared_examples_for 'group and project milestones' do |route_definition| it 'removes a due date if nil is passed' do milestone.update!(due_date: "2016-08-05") - put api(resource_route, user), due_date: nil + put api(resource_route, user), params: { due_date: nil } expect(response).to have_gitlab_http_status(200) expect(json_response['due_date']).to be_nil end it 'returns a 404 error if milestone id not found' do - put api("#{route}/1234", user), - title: 'updated title' + put api("#{route}/1234", user), params: { title: 'updated title' } expect(response).to have_gitlab_http_status(404) end it 'closes milestone' do - put api(resource_route, user), - state_event: 'close' + put api(resource_route, user), params: { state_event: 'close' } expect(response).to have_gitlab_http_status(200) expect(json_response['state']).to eq('closed') end it 'updates milestone with only start date' do - put api(resource_route, user), start_date: Date.tomorrow + put api(resource_route, user), params: { start_date: Date.tomorrow } expect(response).to have_gitlab_http_status(200) end diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb index d7cef137989..683234264a8 100644 --- a/spec/support/api/scopes/read_user_shared_examples.rb +++ b/spec/support/api/scopes/read_user_shared_examples.rb @@ -77,7 +77,7 @@ shared_examples_for 'does not allow the "read_user" scope' do let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) } it 'returns a "403" response' do - post api_call.call(path, user, personal_access_token: token), attributes_for(:user, projects_limit: 3) + post api_call.call(path, user, personal_access_token: token), params: attributes_for(:user, projects_limit: 3) expect(response).to have_gitlab_http_status(403) end diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb index fee464c15a3..e883d33f671 100644 --- a/spec/support/api/time_tracking_shared_examples.rb +++ b/spec/support/api/time_tracking_shared_examples.rb @@ -7,13 +7,13 @@ shared_examples 'time tracking endpoints' do |issuable_name| describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_estimate" do context 'with an unauthorized user' do - subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), duration: '1w') } + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), params: { duration: '1w' }) } it_behaves_like 'an unauthorized API user' end it "sets the time estimate for #{issuable_name}" do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '1w' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' } expect(response).to have_gitlab_http_status(200) expect(json_response['human_time_estimate']).to eq('1w') @@ -21,12 +21,12 @@ shared_examples 'time tracking endpoints' do |issuable_name| describe 'updating the current estimate' do before do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '1w' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' } end context 'when duration has a bad format' do it 'does not modify the original estimate' do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: 'foo' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: 'foo' } expect(response).to have_gitlab_http_status(400) expect(issuable.reload.human_time_estimate).to eq('1w') @@ -35,7 +35,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| context 'with a valid duration' do it 'updates the estimate' do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '3w1h' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '3w1h' } expect(response).to have_gitlab_http_status(200) expect(issuable.reload.human_time_estimate).to eq('3w 1h') @@ -62,8 +62,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/add_spent_time" do context 'with an unauthorized user' do subject do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", non_member), - duration: '2h' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", non_member), params: { duration: '2h' } end it_behaves_like 'an unauthorized API user' @@ -72,8 +71,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| it "add spent time for #{issuable_name}" do Timecop.travel(1.minute.from_now) do expect do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), - duration: '2h' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '2h' } end.to change { issuable.reload.updated_at } end @@ -89,8 +87,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| end.to change { issuable.reload.updated_at } end - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), - duration: '-1h' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1h' } expect(response).to have_gitlab_http_status(201) expect(json_response['total_time_spent']).to eq(3600) @@ -103,8 +100,7 @@ shared_examples 'time tracking endpoints' do |issuable_name| Timecop.travel(1.minute.from_now) do expect do - post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), - duration: '-1w' + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1w' } end.not_to change { issuable.reload.updated_at } end diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index 140490f2dc2..697f999e4c4 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -17,7 +17,7 @@ shared_examples 'a GitHub-ish import controller: POST personal_access_token' do allow_any_instance_of(Gitlab::LegacyGithubImport::Client) .to receive(:user).and_return(true) - post :personal_access_token, personal_access_token: token + post :personal_access_token, params: { personal_access_token: token } expect(session[:"#{provider}_access_token"]).to eq(token) expect(controller).to redirect_to(status_import_url) @@ -29,7 +29,7 @@ shared_examples 'a GitHub-ish import controller: POST personal_access_token' do allow_any_instance_of(Gitlab::LegacyGithubImport::Client) .to receive(:user).and_return(true) - post :personal_access_token, personal_access_token: " #{token} " + post :personal_access_token, params: { personal_access_token: " #{token} " } expect(session[:"#{provider}_access_token"]).to eq(token) expect(controller).to redirect_to(status_import_url) @@ -214,7 +214,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do expect(Gitlab::LegacyGithubImport::ProjectCreator) .to receive(:new).and_return(double(execute: project)) - expect { post :create, target_namespace: provider_repo.name, format: :json }.to change(Namespace, :count).by(1) + expect { post :create, params: { target_namespace: provider_repo.name }, format: :json }.to change(Namespace, :count).by(1) end it "takes the new namespace" do @@ -222,7 +222,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider) .and_return(double(execute: project)) - post :create, target_namespace: provider_repo.name, format: :json + post :create, params: { target_namespace: provider_repo.name }, format: :json end end @@ -261,7 +261,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :json } + post :create, params: { target_namespace: test_namespace.name, new_name: test_name }, format: :json end it 'takes the selected name and default namespace' do @@ -269,7 +269,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { new_name: test_name, format: :json } + post :create, params: { new_name: test_name }, format: :json end end @@ -288,7 +288,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, nested_namespace, user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :json } + post :create, params: { target_namespace: nested_namespace.full_path, new_name: test_name }, format: :json end end @@ -300,7 +300,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } + post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json end it 'creates the namespaces' do @@ -308,7 +308,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: project)) - expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } } + expect { post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json } .to change { Namespace.count }.by(2) end @@ -317,7 +317,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } + post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo') end @@ -336,7 +336,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: project)) - post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } + post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json end it 'creates the namespaces' do @@ -344,7 +344,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: project)) - expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } } + expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json } .to change { Namespace.count }.by(2) end @@ -353,7 +353,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider) .and_return(double(execute: build_stubbed(:project))) - expect { post :create, { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name, format: :js } } + expect { post :create, params: { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name }, format: :js } .not_to change { Namespace.count } end end @@ -367,7 +367,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider) .and_return(double(execute: build_stubbed(:project))) - post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } + post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js end it 'does not create the namespaces' do @@ -375,7 +375,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .and_return(double(execute: build_stubbed(:project))) - expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } } + expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js } .not_to change { Namespace.count } end end @@ -392,7 +392,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do .to receive(:new).with(provider_repo, test_name, group, user, access_params, type: provider) .and_return(double(execute: build_stubbed(:project))) - post :create, { target_namespace: 'foo', new_name: test_name, format: :js } + post :create, params: { target_namespace: 'foo', new_name: test_name }, format: :js end end @@ -400,7 +400,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do it 'returns 422 response' do other_namespace = create(:group, name: 'other_namespace') - post :create, { target_namespace: other_namespace.name, format: :json } + post :create, params: { target_namespace: other_namespace.name }, format: :json expect(response).to have_gitlab_http_status(422) end diff --git a/spec/support/features/variable_list_shared_examples.rb b/spec/support/features/variable_list_shared_examples.rb index bce1fb01355..0a464d77cb7 100644 --- a/spec/support/features/variable_list_shared_examples.rb +++ b/spec/support/features/variable_list_shared_examples.rb @@ -63,6 +63,52 @@ shared_examples 'variable list' do end end + context 'defaults to the application setting' do + context 'application setting is true' do + before do + stub_application_setting(protected_ci_variables: true) + + visit page_path + end + + it 'defaults to protected' do + page.within('.js-ci-variable-list-section .js-row:last-child') do + find('.js-ci-variable-input-key').set('key') + end + + values = all('.js-ci-variable-input-protected', visible: false).map(&:value) + + expect(values).to eq %w(false true true) + end + + it 'shows a message regarding the changed default' do + expect(page).to have_content 'Environment variables are configured by your administrator to be protected by default' + end + end + + context 'application setting is false' do + before do + stub_application_setting(protected_ci_variables: false) + + visit page_path + end + + it 'defaults to unprotected' do + page.within('.js-ci-variable-list-section .js-row:last-child') do + find('.js-ci-variable-input-key').set('key') + end + + values = all('.js-ci-variable-input-protected', visible: false).map(&:value) + + expect(values).to eq %w(false false false) + end + + it 'does not show a message regarding the default' do + expect(page).not_to have_content 'Environment variables are configured by your administrator to be protected by default' + end + end + end + it 'reveals and hides variables' do page.within('.js-ci-variable-list-section') do expect(first('.js-ci-variable-input-key').value).to eq(variable.key) diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb index 9a5845af90c..cd49bb148f2 100644 --- a/spec/support/helpers/git_http_helpers.rb +++ b/spec/support/helpers/git_http_helpers.rb @@ -1,18 +1,18 @@ module GitHttpHelpers def clone_get(project, options = {}) - get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token)) + get "/#{project}/info/refs", params: { service: 'git-upload-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def clone_post(project, options = {}) - post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token)) + post "/#{project}/git-upload-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def push_get(project, options = {}) - get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token)) + get "/#{project}/info/refs", params: { service: 'git-receive-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def push_post(project, options = {}) - post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token)) + post "/#{project}/git-receive-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def download(project, user: nil, password: nil, spnego_request_token: nil) diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index 75827df80dc..dd32ea3985f 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -107,7 +107,7 @@ module GraphqlHelpers end def post_graphql(query, current_user: nil, variables: nil) - post api('/', current_user, version: 'graphql'), query: query, variables: variables + post api('/', current_user, version: 'graphql'), params: { query: query, variables: variables } end def post_graphql_mutation(mutation, current_user: nil) diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index a49036c3b80..ac320934f5a 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -133,6 +133,6 @@ module ExportFileHelper end def file_permissions(file) - File.stat(file).mode & 0777 + File.lstat(file).mode & 0777 end end diff --git a/spec/support/issuables_requiring_filter_shared_examples.rb b/spec/support/issuables_requiring_filter_shared_examples.rb index 439ef5ed92e..71bcc82ee58 100644 --- a/spec/support/issuables_requiring_filter_shared_examples.rb +++ b/spec/support/issuables_requiring_filter_shared_examples.rb @@ -10,6 +10,6 @@ shared_examples 'issuables requiring filter' do |action| it "loads issuables if at least one filter is set" do expect_any_instance_of(described_class).to receive(:issuables_collection).and_call_original - get action, author_id: user.id + get action, params: { author_id: user.id } end end diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb index 7088fb1e5fb..59708173716 100644 --- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb +++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb @@ -8,8 +8,7 @@ shared_examples 'handle uploads' do describe "POST #create" do context 'when a user is not authorized to upload a file' do it 'returns 404 status' do - post :create, params.merge(file: jpg, format: :json) - + post :create, params: params.merge(file: jpg), format: :json expect(response.status).to eq(404) end end @@ -22,7 +21,7 @@ shared_examples 'handle uploads' do context "without params['file']" do it "returns an error" do - post :create, params.merge(format: :json) + post :create, params: params, format: :json expect(response).to have_gitlab_http_status(422) end @@ -30,7 +29,7 @@ shared_examples 'handle uploads' do context 'with valid image' do before do - post :create, params.merge(file: jpg, format: :json) + post :create, params: params.merge(file: jpg), format: :json end it 'returns a content with original filename, new link, and correct type.' do @@ -54,7 +53,7 @@ shared_examples 'handle uploads' do context 'with valid non-image file' do before do - post :create, params.merge(file: txt, format: :json) + post :create, params: params.merge(file: txt), format: :json end it 'returns a content with original filename, new link, and correct type.' do @@ -67,7 +66,7 @@ shared_examples 'handle uploads' do describe "GET #show" do let(:show_upload) do - get :show, params.merge(secret: secret, filename: "rails_sample.jpg") + get :show, params: params.merge(secret: secret, filename: "rails_sample.jpg") end before do diff --git a/spec/support/shared_examples/milestone_tabs_examples.rb b/spec/support/shared_examples/milestone_tabs_examples.rb index 70b499198bf..8b757586941 100644 --- a/spec/support/shared_examples/milestone_tabs_examples.rb +++ b/spec/support/shared_examples/milestone_tabs_examples.rb @@ -10,7 +10,7 @@ shared_examples 'milestone tabs' do { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } end - get path, params.merge(extra_params) + get path, params: params.merge(extra_params) end describe '#merge_requests' do diff --git a/spec/support/shared_examples/requests/api/diff_discussions.rb b/spec/support/shared_examples/requests/api/diff_discussions.rb index 85a4bd8ca27..366c2955359 100644 --- a/spec/support/shared_examples/requests/api/diff_discussions.rb +++ b/spec/support/shared_examples/requests/api/diff_discussions.rb @@ -27,7 +27,8 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name| it "creates a new diff note" do position = diff_note.position.to_h - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!', position: position + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), + params: { body: 'hi!', position: position } expect(response).to have_gitlab_http_status(201) expect(json_response['notes'].first['body']).to eq('hi!') @@ -38,7 +39,8 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name| it "returns a 400 bad request error when position is invalid" do position = diff_note.position.to_h.merge(new_line: '100000') - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!', position: position + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), + params: { body: 'hi!', position: position } expect(response).to have_gitlab_http_status(400) end @@ -47,7 +49,7 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name| describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do it 'adds a new note to the diff discussion' do post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{diff_note.discussion_id}/notes", user), body: 'hi!' + "discussions/#{diff_note.discussion_id}/notes", user), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb index b6aeb30d69c..e44da4faa5a 100644 --- a/spec/support/shared_examples/requests/api/discussions.rb +++ b/spec/support/shared_examples/requests/api/discussions.rb @@ -42,7 +42,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do it "creates a new note" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(201) expect(json_response['notes'].first['body']).to eq('hi!') @@ -56,7 +56,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| end it "returns a 401 unauthorized error if user not authenticated" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), body: 'hi!' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(401) end @@ -65,7 +65,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| it 'accepts the creation date to be set' do creation_time = 2.weeks.ago post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), - body: 'hi!', created_at: creation_time + params: { body: 'hi!', created_at: creation_time } expect(response).to have_gitlab_http_status(201) expect(json_response['notes'].first['body']).to eq('hi!') @@ -81,7 +81,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| it 'responds with 404' do post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user), - body: 'Foo' + params: { body: 'Foo' } expect(response).to have_gitlab_http_status(404) end @@ -91,7 +91,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do it 'adds a new note to the discussion' do post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes", user), body: 'Hello!' + "discussions/#{note.discussion_id}/notes", user), params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('Hello!') @@ -109,7 +109,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| note.update_attribute(:type, nil) post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes", user), body: 'hi!' + "discussions/#{note.discussion_id}/notes", user), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(400) end @@ -118,7 +118,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do it 'returns modified note' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes/#{note.id}", user), body: 'Hello!' + "discussions/#{note.discussion_id}/notes/#{note.id}", user), params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(200) expect(json_response['body']).to eq('Hello!') @@ -127,7 +127,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name| it 'returns a 404 error when note id not found' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ "discussions/#{note.discussion_id}/notes/12345", user), - body: 'Hello!' + params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(404) end diff --git a/spec/support/shared_examples/requests/api/merge_requests_list.rb b/spec/support/shared_examples/requests/api/merge_requests_list.rb index 92d4dd598d5..453f42251c8 100644 --- a/spec/support/shared_examples/requests/api/merge_requests_list.rb +++ b/spec/support/shared_examples/requests/api/merge_requests_list.rb @@ -123,7 +123,7 @@ shared_examples 'merge requests list' do end it 'returns an empty array if no issue matches milestone' do - get api(endpoint_path, user), milestone: '1.0.0' + get api(endpoint_path, user), params: { milestone: '1.0.0' } expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array @@ -131,7 +131,7 @@ shared_examples 'merge requests list' do end it 'returns an empty array if milestone does not exist' do - get api(endpoint_path, user), milestone: 'foo' + get api(endpoint_path, user), params: { milestone: 'foo' } expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array @@ -139,7 +139,7 @@ shared_examples 'merge requests list' do end it 'returns an array of merge requests in given milestone' do - get api(endpoint_path, user), milestone: '0.9' + get api(endpoint_path, user), params: { milestone: '0.9' } closed_issues = json_response.select { |mr| mr['id'] == merge_request_closed.id } expect(closed_issues.length).to eq(1) @@ -147,7 +147,7 @@ shared_examples 'merge requests list' do end it 'returns an array of merge requests matching state in milestone' do - get api(endpoint_path, user), milestone: '0.9', state: 'closed' + get api(endpoint_path, user), params: { milestone: '0.9', state: 'closed' } expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array @@ -187,7 +187,7 @@ shared_examples 'merge requests list' do end it 'returns an array of merge requests with any label when filtering by any label' do - get api(endpoint_path, user), labels: IssuesFinder::FILTER_ANY + get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY } expect_paginated_array_response expect(json_response.length).to eq(1) @@ -195,7 +195,7 @@ shared_examples 'merge requests list' do end it 'returns an array of merge requests without a label when filtering by no label' do - get api(endpoint_path, user), labels: IssuesFinder::FILTER_NONE + get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_NONE } response_ids = json_response.map { |merge_request| merge_request['id'] } @@ -286,7 +286,7 @@ shared_examples 'merge requests list' do context 'source_branch param' do it 'returns merge requests with the given source branch' do - get api(endpoint_path, user), source_branch: merge_request_closed.source_branch, state: 'all' + get api(endpoint_path, user), params: { source_branch: merge_request_closed.source_branch, state: 'all' } expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked) end @@ -294,7 +294,7 @@ shared_examples 'merge requests list' do context 'target_branch param' do it 'returns merge requests with the given target branch' do - get api(endpoint_path, user), target_branch: merge_request_closed.target_branch, state: 'all' + get api(endpoint_path, user), params: { target_branch: merge_request_closed.target_branch, state: 'all' } expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked) end diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb index 0e20dfe0725..71499e85654 100644 --- a/spec/support/shared_examples/requests/api/notes.rb +++ b/spec/support/shared_examples/requests/api/notes.rb @@ -86,7 +86,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do it "creates a new note" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -100,7 +100,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| end it "returns a 401 unauthorized error if user not authenticated" do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), body: 'hi!' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), params: { body: 'hi!' } expect(response).to have_gitlab_http_status(401) end @@ -108,7 +108,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it "creates an activity event when a note is created" do expect(Event).to receive(:create!) - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' } end context 'setting created_at' do @@ -118,7 +118,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'by an admin' do it 'sets the creation time on the new note' do admin = create(:admin) - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params: params expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -131,7 +131,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| if parent_type == 'projects' context 'by a project owner' do it 'sets the creation time on the new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -149,7 +149,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| parent.update!(namespace: group) user2.refresh_authorized_projects - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params: params expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -161,7 +161,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| elsif parent_type == 'groups' context 'by a group owner' do it 'sets the creation time on the new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -176,7 +176,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it 'ignores the given creation time' do user2 = create(:user) parent.add_developer(user2) - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params: params expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq('hi!') @@ -190,7 +190,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'when the user is posting an award emoji on a noteable created by someone else' do it 'creates a new note' do parent.add_developer(private_user) - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), body: ':+1:' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), params: { body: ':+1:' } expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq(':+1:') @@ -199,7 +199,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| context 'when the user is posting an award emoji on his/her own noteable' do it 'creates a new note' do - post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: ':+1:' + post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: ':+1:' } expect(response).to have_gitlab_http_status(201) expect(json_response['body']).to eq(':+1:') @@ -213,7 +213,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it 'responds with 404' do post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), - body: 'Foo' + params: { body: 'Foo' } expect(response).to have_gitlab_http_status(404) end @@ -223,7 +223,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do it 'returns modified note' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "notes/#{note.id}", user), body: 'Hello!' + "notes/#{note.id}", user), params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(200) expect(json_response['body']).to eq('Hello!') @@ -231,7 +231,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| it 'returns a 404 error when note id not found' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user), - body: 'Hello!' + params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(404) end diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions.rb b/spec/support/shared_examples/requests/api/resolvable_discussions.rb index 408ad08cc48..7e2416b23f3 100644 --- a/spec/support/shared_examples/requests/api/resolvable_discussions.rb +++ b/spec/support/shared_examples/requests/api/resolvable_discussions.rb @@ -2,7 +2,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do it "resolves discussion if resolved is true" do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}", user), resolved: true + "discussions/#{note.discussion_id}", user), params: { resolved: true } expect(response).to have_gitlab_http_status(200) expect(json_response['notes'].size).to eq(1) @@ -11,7 +11,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ it "unresolves discussion if resolved is false" do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}", user), resolved: false + "discussions/#{note.discussion_id}", user), params: { resolved: false } expect(response).to have_gitlab_http_status(200) expect(json_response['notes'].size).to eq(1) @@ -27,14 +27,14 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ it "returns a 401 unauthorized error if user is not authenticated" do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}"), resolved: true + "discussions/#{note.discussion_id}"), params: { resolved: true } expect(response).to have_gitlab_http_status(401) end it "returns a 403 error if user resolves discussion of someone else" do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}", private_user), resolved: true + "discussions/#{note.discussion_id}", private_user), params: { resolved: true } expect(response).to have_gitlab_http_status(403) end @@ -46,7 +46,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ it 'responds with 404' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}", private_user), resolved: true + "discussions/#{note.discussion_id}", private_user), params: { resolved: true } expect(response).to have_gitlab_http_status(404) end @@ -56,7 +56,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do it 'returns resolved note when resolved parameter is true' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes/#{note.id}", user), resolved: true + "discussions/#{note.discussion_id}/notes/#{note.id}", user), params: { resolved: true } expect(response).to have_gitlab_http_status(200) expect(json_response['resolved']).to eq(true) @@ -65,7 +65,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ it 'returns a 404 error when note id not found' do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ "discussions/#{note.discussion_id}/notes/12345", user), - body: 'Hello!' + params: { body: 'Hello!' } expect(response).to have_gitlab_http_status(404) end @@ -79,7 +79,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_ it "returns a 403 error if user resolves note of someone else" do put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\ - "discussions/#{note.discussion_id}/notes/#{note.id}", private_user), resolved: true + "discussions/#{note.discussion_id}/notes/#{note.id}", private_user), params: { resolved: true } expect(response).to have_gitlab_http_status(403) end diff --git a/spec/tasks/gitlab/storage_rake_spec.rb b/spec/tasks/gitlab/storage_rake_spec.rb index 233076ad6fa..be902d7c679 100644 --- a/spec/tasks/gitlab/storage_rake_spec.rb +++ b/spec/tasks/gitlab/storage_rake_spec.rb @@ -46,6 +46,16 @@ describe 'rake gitlab:storage:*' do describe 'gitlab:storage:migrate_to_hashed' do let(:task) { 'gitlab:storage:migrate_to_hashed' } + context 'read-only database' do + it 'does nothing' do + expect(Gitlab::Database).to receive(:read_only?).and_return(true) + + expect(Project).not_to receive(:with_unmigrated_storage) + + expect { run_rake_task(task) }.to output(/This task requires database write access. Exiting./).to_stderr + end + end + context '0 legacy projects' do it 'does nothing' do expect(StorageMigratorWorker).not_to receive(:perform_async) @@ -92,7 +102,7 @@ describe 'rake gitlab:storage:*' do stub_env('ID_FROM', 99999) stub_env('ID_TO', 99999) - expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=99999/).to_stdout + expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=99999/).to_stderr end it 'displays a message when project exists but its already migrated' do @@ -100,7 +110,7 @@ describe 'rake gitlab:storage:*' do stub_env('ID_FROM', project.id) stub_env('ID_TO', project.id) - expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=#{project.id}/).to_stdout + expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=#{project.id}/).to_stderr end it 'enqueues migration when project can be found' do diff --git a/spec/views/notify/changed_milestone_email.html.haml_spec.rb b/spec/views/notify/changed_milestone_email.html.haml_spec.rb new file mode 100644 index 00000000000..194b58840a3 --- /dev/null +++ b/spec/views/notify/changed_milestone_email.html.haml_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'notify/changed_milestone_email.html.haml' do + let(:milestone) { create(:milestone, title: 'some-milestone') } + let(:milestone_link) { milestone_url(milestone) } + + before do + assign(:milestone, milestone) + assign(:milestone_url, milestone_link) + end + + context 'milestone without start and due dates' do + it 'renders without date range' do + render + + expect(rendered).to have_content('Milestone changed to some-milestone', exact: true) + expect(rendered).to have_link('some-milestone', href: milestone_link) + end + end + + context 'milestone with start and due dates' do + before do + milestone.update(start_date: '2018-01-01', due_date: '2018-12-31') + end + + it 'renders with date range' do + render + + expect(rendered).to have_content('Milestone changed to some-milestone (Jan 1, 2018–Dec 31, 2018)', exact: true) + expect(rendered).to have_link('some-milestone', href: milestone_link) + end + end +end diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb index fa6c4ce4ac8..b0042be339c 100644 --- a/spec/views/projects/merge_requests/show.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb @@ -32,6 +32,11 @@ describe 'projects/merge_requests/show.html.haml' do assign(:noteable, closed_merge_request) assign(:notes, []) assign(:pipelines, Ci::Pipeline.none) + assign( + :issuable_sidebar, + MergeRequestSerializer.new(current_user: user, project: project) + .represent(closed_merge_request, serializer: 'sidebar') + ) preload_view_requirements diff --git a/spec/workers/cluster_platform_configure_worker_spec.rb b/spec/workers/cluster_configure_worker_spec.rb index 0eead0ab13d..6918ee3d7d8 100644 --- a/spec/workers/cluster_platform_configure_worker_spec.rb +++ b/spec/workers/cluster_configure_worker_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ClusterPlatformConfigureWorker, '#perform' do +describe ClusterConfigureWorker, '#perform' do let(:worker) { described_class.new } context 'when group cluster' do diff --git a/spec/workers/cluster_provision_worker_spec.rb b/spec/workers/cluster_provision_worker_spec.rb index 0a2dfef36a4..da32f29fec0 100644 --- a/spec/workers/cluster_provision_worker_spec.rb +++ b/spec/workers/cluster_provision_worker_spec.rb @@ -23,7 +23,7 @@ describe ClusterProvisionWorker do end it 'configures kubernetes platform' do - expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id) + expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id) described_class.new.perform(cluster.id) end @@ -32,7 +32,7 @@ describe ClusterProvisionWorker do context 'when cluster does not exist' do it 'does not provision a cluster' do expect_any_instance_of(Clusters::Gcp::ProvisionService).not_to receive(:execute) - expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async) + expect(ClusterConfigureWorker).not_to receive(:perform_async) described_class.new.perform(123) end diff --git a/spec/workers/object_pool/destroy_worker_spec.rb b/spec/workers/object_pool/destroy_worker_spec.rb new file mode 100644 index 00000000000..ef74f0ba87c --- /dev/null +++ b/spec/workers/object_pool/destroy_worker_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +describe ObjectPool::DestroyWorker do + describe '#perform' do + context 'when no pool is in the database' do + it "doesn't raise an error" do + expect do + described_class.new.perform(987654321) + end.not_to raise_error + end + end + + context 'when a pool is present' do + let(:pool) { create(:pool_repository, :obsolete) } + + subject { described_class.new } + + it 'requests Gitaly to remove the object pool' do + expect(Gitlab::GitalyClient).to receive(:call).with(pool.shard_name, :object_pool_service, :delete_object_pool, Object) + + subject.perform(pool.id) + end + + it 'destroys the pool' do + subject.perform(pool.id) + + expect(PoolRepository.find_by_id(pool.id)).to be_nil + end + end + end +end diff --git a/spec/workers/stuck_merge_jobs_worker_spec.rb b/spec/workers/stuck_merge_jobs_worker_spec.rb index c2c2a5f9121..5aaff27a6b2 100644 --- a/spec/workers/stuck_merge_jobs_worker_spec.rb +++ b/spec/workers/stuck_merge_jobs_worker_spec.rb @@ -38,7 +38,8 @@ describe StuckMergeJobsWorker do create(:merge_request, :locked, merge_jid: '123') create(:merge_request, :locked, merge_jid: '456') - expect(Rails).to receive_message_chain(:logger, :info).with('Updated state of locked merge jobs. JIDs: 123, 456') + expect(described_class).to receive_message_chain(:logger, :info) + .with('Updated state of locked merge jobs. JIDs: 123, 456') worker.perform end diff --git a/yarn.lock b/yarn.lock index ae9975831dc..90d3d6fb7cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -641,10 +641,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.43.0.tgz#28dee2122d068cd3b925cd9884d97465ebaca12d" integrity sha512-wuN3NITmyBV9bOXsFfAjtndFrjTlH6Kf3+6aqT5kHKKLe/B4w7uTU1L9H/cyR0wGD7HbOh584a05eDcuH04fPA== -"@gitlab/ui@^1.15.0": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.15.0.tgz#288e189cb99de354aeb4598f9ac8cced5f47e139" - integrity sha512-Aiv/WABr8lBVJk0eoanSoO07Lr5Nnvuq82IjDnNzcw9enB1DAKvlstC2r9iiMfg1pVgV/uLdDeRFqH9eI1X4Rg== +"@gitlab/ui@^1.18.0": + version "1.18.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.18.0.tgz#5cc591b2c7958e59fa7b1b443d4235e0e8f956c9" + integrity sha512-JqmiRSGYmK0DbGBQJBpjeRrcgjK25rCqG6QW6/GPTVLtRjbPPZYGvVg5PyA6nJUGAnwFoeApUZVML6X3OpnV1Q== dependencies: babel-standalone "^6.26.0" bootstrap-vue "^2.0.0-rc.11" @@ -654,7 +654,7 @@ js-beautify "^1.8.8" lodash "^4.17.11" url-search-params-polyfill "^5.0.0" - vue "^2.5.16" + vue "^2.5.21" vue-loader "^15.4.2" "@sindresorhus/is@^0.7.0": @@ -9904,11 +9904,16 @@ vue-virtual-scroll-list@^1.2.5: resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.2.5.tgz#bcbd010f7cdb035eba8958ebf807c6214d9a167a" integrity sha1-vL0BD3zbA166iVjr+AfGIU2aFno= -vue@^2.5.16, vue@^2.5.17: +vue@^2.5.17: version "2.5.17" resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada" integrity sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ== +vue@^2.5.21: + version "2.5.21" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85" + integrity sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ== + vuex@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2" |