From 8e812185ddf4c77ae3b1512b2d04725190e64209 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 26 Jun 2020 12:08:51 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../issuable_suggestions/components/item.vue | 6 +- .../notes/components/note_actions.vue | 18 +- .../javascripts/persistent_user_callout.js | 35 +++- .../javascripts/persistent_user_callouts.js | 1 + app/assets/stylesheets/framework/job_log.scss | 2 +- app/assets/stylesheets/pages/issuable.scss | 4 - app/assets/stylesheets/themes/_dark.scss | 3 + app/controllers/concerns/wiki_actions.rb | 6 +- app/models/environment.rb | 5 + app/models/iteration.rb | 2 +- app/services/merge_requests/base_service.rb | 5 + .../merge_requests/post_merge_service.rb | 1 + changelogs/unreleased/merge-cancel-deploy.yml | 5 + .../move-delete-to-bottom-of-list.yml | 5 + .../unreleased/psi-dark-suggestions.yml | 5 + changelogs/unreleased/psi-job-log-text.yml | 5 + .../unreleased/wiki-edit-invalid-page.yml | 5 + config/routes/snippets.rb | 2 +- doc/.vale/gitlab/Acronyms.yml | 7 + doc/.vale/gitlab/spelling-exceptions.txt | 3 + .../graphql/reference/gitlab_schema.graphql | 61 ++++++ doc/api/graphql/reference/gitlab_schema.json | 183 ++++++++++++++++++ doc/api/graphql/reference/index.md | 10 + doc/ci/pipelines/settings.md | 10 +- doc/ssh/README.md | 2 +- doc/university/README.md | 10 +- doc/university/bookclub/index.md | 2 +- .../dependency_scanning/index.md | 2 +- doc/user/clusters/applications.md | 4 +- .../compliance/license_compliance/index.md | 4 +- doc/user/group/iterations/index.md | 13 +- doc/user/group/saml_sso/index.md | 2 +- doc/user/markdown.md | 24 +-- doc/user/permissions.md | 1 + doc/user/project/integrations/prometheus.md | 3 +- .../ci/templates/Composer.gitlab-ci.yml | 19 ++ locale/gitlab.pot | 24 ++- spec/frontend/persistent_user_callout_spec.js | 66 +++++++ spec/models/iteration_spec.rb | 8 + .../merge_requests/post_merge_service_spec.rb | 61 ++++-- .../wiki_actions_shared_examples.rb | 42 ++-- 41 files changed, 595 insertions(+), 81 deletions(-) create mode 100644 changelogs/unreleased/merge-cancel-deploy.yml create mode 100644 changelogs/unreleased/move-delete-to-bottom-of-list.yml create mode 100644 changelogs/unreleased/psi-dark-suggestions.yml create mode 100644 changelogs/unreleased/psi-job-log-text.yml create mode 100644 changelogs/unreleased/wiki-edit-invalid-page.yml create mode 100644 lib/gitlab/ci/templates/Composer.gitlab-ci.yml diff --git a/app/assets/javascripts/issuable_suggestions/components/item.vue b/app/assets/javascripts/issuable_suggestions/components/item.vue index 51904c64085..dfadb9d2b24 100644 --- a/app/assets/javascripts/issuable_suggestions/components/item.vue +++ b/app/assets/javascripts/issuable_suggestions/components/item.vue @@ -75,7 +75,11 @@ export default { name="eye-slash" class="suggestion-help-hover mr-1 suggestion-confidential" /> - + {{ suggestion.title }} diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index f1af8be590a..3b0fe8105e9 100644 --- a/app/assets/javascripts/notes/components/note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -257,15 +257,6 @@ export default { {{ __('Copy link') }} -
  • - -
  • +
  • + +
  • diff --git a/app/assets/javascripts/persistent_user_callout.js b/app/assets/javascripts/persistent_user_callout.js index b3068c46bcb..b8a1397d8f6 100644 --- a/app/assets/javascripts/persistent_user_callout.js +++ b/app/assets/javascripts/persistent_user_callout.js @@ -18,17 +18,21 @@ export default class PersistentUserCallout { init() { const closeButton = this.container.querySelector('.js-close'); + const followLink = this.container.querySelector('.js-follow-link'); - if (!closeButton) { - return; + if (closeButton) { + this.handleCloseButtonCallout(closeButton); + } else if (followLink) { + this.handleFollowLinkCallout(followLink); } + } + handleCloseButtonCallout(closeButton) { closeButton.addEventListener('click', event => this.dismiss(event)); if (this.deferLinks) { this.container.addEventListener('click', event => { const isDeferredLink = event.target.classList.contains(DEFERRED_LINK_CLASS); - if (isDeferredLink) { const { href, target } = event.target; @@ -38,6 +42,10 @@ export default class PersistentUserCallout { } } + handleFollowLinkCallout(followLink) { + followLink.addEventListener('click', event => this.registerCalloutWithLink(event)); + } + dismiss(event, deferredLinkOptions = null) { event.preventDefault(); @@ -58,6 +66,27 @@ export default class PersistentUserCallout { }); } + registerCalloutWithLink(event) { + event.preventDefault(); + + const { href } = event.currentTarget; + + axios + .post(this.dismissEndpoint, { + feature_name: this.featureId, + }) + .then(() => { + window.location.assign(href); + }) + .catch(() => { + Flash( + __( + 'An error occurred while acknowledging the notification. Refresh the page and try again.', + ), + ); + }); + } + static factory(container, options) { if (!container) { return undefined; diff --git a/app/assets/javascripts/persistent_user_callouts.js b/app/assets/javascripts/persistent_user_callouts.js index 6e292299778..a3ccc551c7e 100644 --- a/app/assets/javascripts/persistent_user_callouts.js +++ b/app/assets/javascripts/persistent_user_callouts.js @@ -4,6 +4,7 @@ const PERSISTENT_USER_CALLOUTS = [ '.js-recovery-settings-callout', '.js-users-over-license-callout', '.js-admin-licensed-user-count-threshold', + '.js-buy-pipeline-minutes-notification-callout', ]; const initCallouts = () => { diff --git a/app/assets/stylesheets/framework/job_log.scss b/app/assets/stylesheets/framework/job_log.scss index 1a26c0283e5..2448be1bca3 100644 --- a/app/assets/stylesheets/framework/job_log.scss +++ b/app/assets/stylesheets/framework/job_log.scss @@ -5,7 +5,7 @@ font-size: 13px; word-break: break-all; word-wrap: break-word; - color: $gl-text-color-inverted; + color: color-yiq($builds-trace-bg); border-radius: $border-radius-small; min-height: 42px; background-color: $builds-trace-bg; diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index b2e7392b868..6fe94aa49cf 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -969,10 +969,6 @@ vertical-align: sub; } -.suggestion-item a { - color: initial; -} - .suggestion-confidential { color: $orange-600; } diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss index 1f2a7645495..1cea469e206 100644 --- a/app/assets/stylesheets/themes/_dark.scss +++ b/app/assets/stylesheets/themes/_dark.scss @@ -115,6 +115,9 @@ $secondary: $gray-600; $issues-today-bg: #333838; $issues-today-border: #333a40; +$yiq-text-dark: $gray-50; +$yiq-text-light: $gray-950; + .gl-label { filter: brightness(0.9) contrast(1.1); } diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb index b4b4fd84c37..7329b0594ef 100644 --- a/app/controllers/concerns/wiki_actions.rb +++ b/app/controllers/concerns/wiki_actions.rb @@ -19,7 +19,11 @@ module WikiActions end before_action only: [:edit, :update], unless: :valid_encoding? do - redirect_to wiki_page_path(wiki, page) + if params[:id].present? + redirect_to wiki_page_path(wiki, page || params[:id]) + else + redirect_to wiki_path(wiki) + end end end diff --git a/app/models/environment.rb b/app/models/environment.rb index a3b8f220f00..55c2e4173f6 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -226,6 +226,11 @@ class Environment < ApplicationRecord available? && stop_action.present? end + def cancel_deployment_jobs! + jobs = all_deployments.active.with_deployable + jobs.each { |deployment| deployment.deployable.cancel! } + end + def stop_with_action!(current_user) return unless available? diff --git a/app/models/iteration.rb b/app/models/iteration.rb index 2bda0725471..ce0ca64876f 100644 --- a/app/models/iteration.rb +++ b/app/models/iteration.rb @@ -93,7 +93,7 @@ class Iteration < ApplicationRecord # ensure dates do not overlap with other Iterations in the same group/project def dates_do_not_overlap - return unless resource_parent.iterations.within_timeframe(start_date, due_date).exists? + return unless resource_parent.iterations.where.not(id: self.id).within_timeframe(start_date, due_date).exists? errors.add(:base, s_("Iteration|Dates cannot overlap with other existing Iterations")) end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 7f7bfa29af7..dc08ec1b317 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -29,6 +29,11 @@ module MergeRequests .execute_for_merge_request(merge_request) end + def cancel_review_app_jobs!(merge_request) + environments = merge_request.environments.in_review_folder.available + environments.each { |environment| environment.cancel_deployment_jobs! } + end + def source_project @source_project ||= merge_request.source_project end diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index 0364c0dd479..fdf8f442297 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -18,6 +18,7 @@ module MergeRequests invalidate_cache_counts(merge_request, users: merge_request.assignees) merge_request.update_project_counter_caches delete_non_latest_diffs(merge_request) + cancel_review_app_jobs!(merge_request) cleanup_environments(merge_request) end diff --git a/changelogs/unreleased/merge-cancel-deploy.yml b/changelogs/unreleased/merge-cancel-deploy.yml new file mode 100644 index 00000000000..dc684b8292e --- /dev/null +++ b/changelogs/unreleased/merge-cancel-deploy.yml @@ -0,0 +1,5 @@ +--- +title: Cancel review app deployment when MR is merged +merge_request: 34960 +author: +type: fixed diff --git a/changelogs/unreleased/move-delete-to-bottom-of-list.yml b/changelogs/unreleased/move-delete-to-bottom-of-list.yml new file mode 100644 index 00000000000..0c6b322829d --- /dev/null +++ b/changelogs/unreleased/move-delete-to-bottom-of-list.yml @@ -0,0 +1,5 @@ +--- +title: Move 'Delete comment' button to bottom of 'More actions' list +merge_request: 35237 +author: +type: fixed diff --git a/changelogs/unreleased/psi-dark-suggestions.yml b/changelogs/unreleased/psi-dark-suggestions.yml new file mode 100644 index 00000000000..fd0d2f67b52 --- /dev/null +++ b/changelogs/unreleased/psi-dark-suggestions.yml @@ -0,0 +1,5 @@ +--- +title: Fix issue suggestion text color on dark mode +merge_request: 34899 +author: +type: fixed diff --git a/changelogs/unreleased/psi-job-log-text.yml b/changelogs/unreleased/psi-job-log-text.yml new file mode 100644 index 00000000000..81043bab09f --- /dev/null +++ b/changelogs/unreleased/psi-job-log-text.yml @@ -0,0 +1,5 @@ +--- +title: Fix job log text color in dark mode +merge_request: 35387 +author: +type: fixed diff --git a/changelogs/unreleased/wiki-edit-invalid-page.yml b/changelogs/unreleased/wiki-edit-invalid-page.yml new file mode 100644 index 00000000000..d7d0ea00776 --- /dev/null +++ b/changelogs/unreleased/wiki-edit-invalid-page.yml @@ -0,0 +1,5 @@ +--- +title: Redirect wiki edit actions for missing pages +merge_request: 35350 +author: +type: fixed diff --git a/config/routes/snippets.rb b/config/routes/snippets.rb index 259e88ba7b2..1ea9a6431d8 100644 --- a/config/routes/snippets.rb +++ b/config/routes/snippets.rb @@ -21,7 +21,7 @@ end scope path: '-' do get '/snippets/:snippet_id/raw/:ref/*path', to: 'snippets/blobs#raw', - as: :snippet_raw, + as: :snippet_blob_raw, format: false, constraints: { snippet_id: /\d+/ } end diff --git a/doc/.vale/gitlab/Acronyms.yml b/doc/.vale/gitlab/Acronyms.yml index 4bfff72c154..7d8b5218b33 100644 --- a/doc/.vale/gitlab/Acronyms.yml +++ b/doc/.vale/gitlab/Acronyms.yml @@ -24,6 +24,7 @@ exceptions: - CSV - DNS - EKS + - FAQ - GDK - GET - GNU @@ -34,11 +35,14 @@ exceptions: - HTTPS - IAM - IDE + - IRC + - IBM - JSON - LDAP - LDAPS - LESS - LFS + - LRU - NFS - NGINX - NOTE @@ -48,6 +52,7 @@ exceptions: - POST - PUT - RPC + - RAM - RSA - RSS - SAML @@ -58,11 +63,13 @@ exceptions: - SSH - SSL - SSO + - TCP - TIP - TLS - TODO - TOML - UNIX + - USB - URI - URL - VPC diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt index 7fe7fb2d6da..4d4a98aa72f 100644 --- a/doc/.vale/gitlab/spelling-exceptions.txt +++ b/doc/.vale/gitlab/spelling-exceptions.txt @@ -248,6 +248,7 @@ memoization memoize memoized memoizing +Memorystore mergeable Microsoft middleware @@ -335,6 +336,7 @@ Puma Python Qualys Rackspace +Raspbian reachability rebase rebased @@ -422,6 +424,7 @@ storages strace strikethrough strikethroughs +stunnel subpath subfolder subfolders diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index ae04a9c82ed..0cbe2bac11c 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -7944,6 +7944,7 @@ type Mutation { """ updateImageDiffNote(input: UpdateImageDiffNoteInput!): UpdateImageDiffNotePayload updateIssue(input: UpdateIssueInput!): UpdateIssuePayload + updateIteration(input: UpdateIterationInput!): UpdateIterationPayload """ Updates a Note. If the body of the Note contains only quick actions, the Note @@ -13257,6 +13258,66 @@ type UpdateIssuePayload { issue: Issue } +""" +Autogenerated input type of UpdateIteration +""" +input UpdateIterationInput { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + The description of the iteration + """ + description: String + + """ + The end date of the iteration + """ + dueDate: String + + """ + The group of the iteration + """ + groupPath: ID! + + """ + The id of the iteration + """ + id: ID! + + """ + The start date of the iteration + """ + startDate: String + + """ + The title of the iteration + """ + title: String +} + +""" +Autogenerated return type of UpdateIteration +""" +type UpdateIterationPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Errors encountered during execution of the mutation. + """ + errors: [String!]! + + """ + The updated iteration + """ + iteration: Iteration +} + """ Autogenerated input type of UpdateNote """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 1afc50aa707..b45b36ed304 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -23646,6 +23646,33 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "updateIteration", + "description": null, + "args": [ + { + "name": "input", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "UpdateIterationInput", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "UpdateIterationPayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "updateNote", "description": "Updates a Note. If the body of the Note contains only quick actions, the Note will be destroyed during the update, and no Note will be returned", @@ -39167,6 +39194,162 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "UpdateIterationInput", + "description": "Autogenerated input type of UpdateIteration", + "fields": null, + "inputFields": [ + { + "name": "groupPath", + "description": "The group of the iteration", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "id", + "description": "The id of the iteration", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "title", + "description": "The title of the iteration", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "description", + "description": "The description of the iteration", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "startDate", + "description": "The start date of the iteration", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "dueDate", + "description": "The end date of the iteration", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "UpdateIterationPayload", + "description": "Autogenerated return type of UpdateIteration", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": "Errors encountered during execution of the mutation.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "iteration", + "description": "The updated iteration", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "Iteration", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "UpdateNoteInput", diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index df25c835de8..3e55ca9fbdf 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2019,6 +2019,16 @@ Autogenerated return type of UpdateIssue | `errors` | String! => Array | Errors encountered during execution of the mutation. | | `issue` | Issue | The issue after mutation | +## UpdateIterationPayload + +Autogenerated return type of UpdateIteration + +| Name | Type | Description | +| --- | ---- | ---------- | +| `clientMutationId` | String | A unique identifier for the client performing the mutation. | +| `errors` | String! => Array | Errors encountered during execution of the mutation. | +| `iteration` | Iteration | The updated iteration | + ## UpdateNotePayload Autogenerated return type of UpdateNote diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md index 2c9d4ccf2c4..16d4fd49bbe 100644 --- a/doc/ci/pipelines/settings.md +++ b/doc/ci/pipelines/settings.md @@ -283,7 +283,7 @@ Markdown code will embed the test coverage report badge of the `coverage` job into your `README.md`: ```markdown -![coverage](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage) +![coverage](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage) ``` ### Badge styles @@ -296,7 +296,7 @@ Pipeline badges can be rendered in different styles by adding the `style=style_n https://example.gitlab.com///badges//coverage.svg?style=flat ``` -![Badge flat style](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage&style=flat) +![Badge flat style](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage&style=flat) #### Flat square @@ -306,17 +306,17 @@ https://example.gitlab.com///badges//coverage.svg?st https://example.gitlab.com///badges//coverage.svg?style=flat-square ``` -![Badge flat square style](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=coverage&style=flat-square) +![Badge flat square style](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=coverage&style=flat-square) ### Custom badge text The text for a badge can be customized. This can be useful to differentiate between multiple coverage jobs that run in the same pipeline. Customize the badge text and width by adding the `key_text=custom_text` and `key_width=custom_key_width` parameters to the URL: ```plaintext -https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100 +https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100 ``` -![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab-foss/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100) +![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100) ## Environment Variables diff --git a/doc/ssh/README.md b/doc/ssh/README.md index 5db1bde6413..980a20ade3e 100644 --- a/doc/ssh/README.md +++ b/doc/ssh/README.md @@ -412,7 +412,7 @@ are *explicitly not supported* and may stop working at any time. ### Options for Microsoft Windows -If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/en-us/install-win10) version, +If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/install-win10#update-to-wsl-2) version, support the installation of different Linux distributions, which include the Git and SSH clients. For current versions of Windows, you can also install the Git and SSH clients with diff --git a/doc/university/README.md b/doc/university/README.md index df41167dbe9..2a9111276d3 100644 --- a/doc/university/README.md +++ b/doc/university/README.md @@ -72,7 +72,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres 1. [Getting Help](https://about.gitlab.com/get-help/) - Proposing Features and Reporting and Tracking bugs for GitLab - - The GitLab IRC channel, Gitter Chat Room, Community Forum and Mailing List + - The GitLab IRC channel, Gitter Chat Room, Community Forum, and Mailing List - Getting Technical Support - Being part of our Great Community and Contributing to GitLab 1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/) @@ -140,11 +140,11 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres ## 3. GitLab Advanced -### 3.1. Dev Ops +### 3.1. DevOps -1. [Xebia Labs: Dev Ops Terminology](https://xebialabs.com/glossary/) -1. [Xebia Labs: Periodic Table of DevOps Tools](https://xebialabs.com/periodic-table-of-devops-tools/) -1. [Puppet Labs: State of Dev Ops 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/) +1. [XebiaLabs: DevOps Terminology](https://xebialabs.com/glossary/) +1. [XebiaLabs: Periodic Table of DevOps Tools](https://digital.ai/periodic-table-of-devops-tools) +1. [Puppet Labs: State of DevOps 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/) ### 3.2. Installing GitLab with Omnibus diff --git a/doc/university/bookclub/index.md b/doc/university/bookclub/index.md index c6dad663c0e..71dfe7fc3cb 100644 --- a/doc/university/bookclub/index.md +++ b/doc/university/bookclub/index.md @@ -15,7 +15,7 @@ See the [book list](booklist.md) for additional recommendations. 1. **Remote: Office not required** David Heinemeier Hansson and Jason Fried, 2013 - ([amazon](https://www.amazon.co.uk/Remote-Required-David-Heinemeier-Hansson/dp/0091954673)) + ([Amazon](https://www.amazon.co.uk/dp/0091954673/ref=cm_sw_r_tw_dp_x_0yy9EbZ2WXJ6Y)) 1. **The Year Without Pants** diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 5528d1a193f..7633711a441 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -72,7 +72,7 @@ Plans are underway for supporting the following languages, dependency managers, | Language (package managers) | Supported files | Scan tool(s) | Issue | |----------------------------- | --------------- | ------------ | ----- | -| Python ([Poetry](http://python-poetry.org/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) | +| Python ([Poetry](https://python-poetry.org/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) | | Python ([Pipenv](https://pipenv.pypa.io/en/latest/)) | `Pipfile.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#11756](https://gitlab.com/gitlab-org/gitlab/-/issues/11756) | ## Contribute your scanner diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index edf6ab9687a..77314f7fe42 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -1084,8 +1084,8 @@ customRules: ``` By default, Falco only outputs security events to logs as JSON objects. To set it to output to an -[external API](https://falco.org/docs/alerts#https-output-send-alerts-to-an-https-end-point) -or [application](https://falco.org/docs/alerts#program-output), +[external API](https://falco.org/docs/alerts/#https-output-send-alerts-to-an-https-end-point) +or [application](https://falco.org/docs/alerts/#program-output), add the following to `.gitlab/managed-apps/falco/values.yaml`: ```yaml diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md index 0b3d653a738..4fc46577d77 100644 --- a/doc/user/compliance/license_compliance/index.md +++ b/doc/user/compliance/license_compliance/index.md @@ -64,7 +64,7 @@ The following languages and package managers are supported. | Go | [Godep](https://github.com/tools/godep), [go mod](https://github.com/golang/go/wiki/Modules) |[License Finder](https://github.com/pivotal/LicenseFinder)| | Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)| | .NET | [Nuget](https://www.nuget.org/) (.NET Framework is supported via the [mono project](https://www.mono-project.com/). Windows specific dependencies are not supported at this time.) |[License Finder](https://github.com/pivotal/LicenseFinder)| -| Python | [pip](https://pip.pypa.io/en/stable/) (Python is supported through [requirements.txt](https://pip.pypa.io/en/1.1/requirements/) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock).) |[License Finder](https://github.com/pivotal/LicenseFinder)| +| Python | [pip](https://pip.pypa.io/en/stable/) (Python is supported through [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock).) |[License Finder](https://github.com/pivotal/LicenseFinder)| | Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)| | Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) |[License Finder](https://github.com/pivotal/LicenseFinder)| @@ -339,7 +339,7 @@ strict-ssl = false ### Configuring Yarn projects -You can configure Yarn projects by using a [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc/) +You can configure Yarn projects by using a [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc) file. #### Using private Yarn registries diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md index 2704147dcdd..656f461acc2 100644 --- a/doc/user/group/iterations/index.md +++ b/doc/user/group/iterations/index.md @@ -38,7 +38,7 @@ From there you can create a new iteration or click an iteration to get a more de ## Create an iteration NOTE: **Note:** -A permission level of [Developer or higher](../../permissions.md) is required to create iterations. +You need Developer [permissions](../../permissions.md) or higher to create an iteration. To create an iteration: @@ -47,7 +47,16 @@ To create an iteration: 1. Enter the title, a description (optional), a start date, and a due date. 1. Click **Create iteration**. The iteration details page opens. -### Enable Iterations **(CORE ONLY)** +## Edit an iteration + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218277) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2. + +NOTE: **Note:** +You need Developer [permissions](../../permissions.md) or higher to edit an iteration. + +To edit an iteration, click the three-dot menu (**{ellipsis_v}**) > **Edit iteration**. + +## Enable Iterations **(CORE ONLY)** GitLab Iterations feature is under development and not ready for production use. It is deployed behind a feature flag that is **disabled by default**. diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md index 289f36d6496..f934468f611 100644 --- a/doc/user/group/saml_sso/index.md +++ b/doc/user/group/saml_sso/index.md @@ -75,7 +75,7 @@ This is a [Closed Beta](https://about.gitlab.com/handbook/product/#closed-beta) > - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/709) in GitLab 12.1. > - It's deployed behind a feature flag, disabled by default. -> - It's disabled on GitLab.com. If you want to enable it for your subscription, contact Product Management through [GitLab Support](https://support.gitlab.com/hc). +> - It's disabled on GitLab.com. If you want to enable it for your subscription, contact Product Management through [GitLab Support](https://support.gitlab.com/hc/en-us). When SSO is being enforced, groups can enable an additional level of protection by enforcing the creation of dedicated user accounts to access the group. diff --git a/doc/user/markdown.md b/doc/user/markdown.md index 999c49cbc3c..91bba1cd5d7 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -54,7 +54,7 @@ repository that were written using some of the nuances of GitLab's RedCarpet ver of Markdown. Since CommonMark uses slightly stricter syntax, these documents might now appear a little differently since we have transitioned to CommonMark. -It's usually quite easy to fix. For example, numbered lists with nested lists may +For example, numbered lists with nested lists may render incorrectly: ```markdown @@ -63,8 +63,8 @@ render incorrectly: - milk ``` -Simply add a space to each nested item to align the `-` with the first character of -the top list item (`C` in this case): +To correct their rendering, add a space to each nested item to align the `-` with the first +character of the top list item (`C` in this case): ```markdown 1. Chocolate @@ -241,7 +241,7 @@ Sometimes you want to :monkey: around a bit and add some :star2: to your :speech You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that. -If you're new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up one of the supported codes. +If you're new to this, don't be :fearful:. You can join the emoji :family:. All you need to do is to look up one of the supported codes. Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup: ``` @@ -252,7 +252,7 @@ Sometimes you want to or warn about patches. And if someone improves your really code, send them some . People will you for that. -If you're new to this, don't be . You can easily join the emoji . All you need to do is to look up one of the supported codes. +If you're new to this, don't be . You can join the emoji . All you need to do is to look up one of the supported codes. Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. @@ -407,9 +407,9 @@ the [Asciidoctor user manual](https://asciidoctor.org/docs/user-manual/#activati ### Special GitLab references -GFM recognizes special GitLab related references. For example, you can easily reference +GFM recognizes special GitLab related references. For example, you can reference an issue, a commit, a team member, or even the whole team within a project. GFM will turn -that reference into a link so you can navigate between them easily. +that reference into a link so you can navigate between them. Additionally, GFM recognizes certain cross-project references and also has a shorthand version to reference other projects from the same namespace. @@ -589,7 +589,7 @@ If a functionality is extended, the new option will be listed as a sub-section. ### Blockquotes -Blockquotes are an easy way to highlight information, such as a side-note. It's generated +Blockquotes are useful to highlight information, such as a side-note. It's generated by starting the lines of the blockquote with `>`: ```markdown @@ -635,9 +635,9 @@ you can quote that without having to manually prepend `>` to every line! ### Code spans and blocks -You can easily highlight anything that should be viewed as code and not simple text. +You can highlight anything that should be viewed as code and not simple text. -Simple inline code is easily highlighted with single backticks `` ` ``: +Simple inline code is highlighted with single backticks `` ` ``: ```markdown Inline `code` has `back-ticks around` it. @@ -1148,7 +1148,7 @@ A line break will be inserted (a new paragraph will start) if the previous text ended with two newlines, like when you hit Enter twice in a row. If you only use one newline (hit Enter once), the next sentence will be part of the same paragraph. This is useful if you want to keep long lines from wrapping, and keep -them easily editable: +them editable: ```markdown Here's a line for us to start with. @@ -1273,7 +1273,7 @@ GFM will auto-link almost any URL you put into your text: ### Lists -Ordered and unordered lists can be easily created. +Ordered and unordered lists can be created. For an ordered list, add the number you want the list to start with, like `1.`, followed by a space, at the start of each line for ordered lists. diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 42606f780dc..1ccef685189 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -247,6 +247,7 @@ group. | Create project in group | | | ✓ (3) | ✓ (3) | ✓ (3) | | Share (invite) groups with groups | | | | | ✓ | | Create/edit/delete group milestones | | | ✓ | ✓ | ✓ | +| Create/edit/delete iterations | | | ✓ | ✓ | ✓ | | Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ | | Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ | | Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ | diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index 04751bd091c..bc4a372d852 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.md @@ -1050,8 +1050,7 @@ Alerts can be used to trigger actions, like opening an issue automatically (disa 1. Optionally, select whether to send an email notification to the developers of the project. 1. Click **Save changes**. -Once enabled, an issue will be opened automatically when an alert is triggered which contains values extracted from [alert's payload](https://prometheus.io/docs/alerting/configuration/#webhook_config -): +Once enabled, an issue will be opened automatically when an alert is triggered which contains values extracted from [alert's payload](https://prometheus.io/docs/alerting/latest/configuration/#webhook_config): - Issue author: `GitLab Alert Bot` - Issue title: Extract from `annotations/title`, `annotations/summary` or `labels/alertname` diff --git a/lib/gitlab/ci/templates/Composer.gitlab-ci.yml b/lib/gitlab/ci/templates/Composer.gitlab-ci.yml new file mode 100644 index 00000000000..5d9c68d3031 --- /dev/null +++ b/lib/gitlab/ci/templates/Composer.gitlab-ci.yml @@ -0,0 +1,19 @@ +# Publishes a tag/branch to Composer Packages of the current project +publish: + image: curlimages/curl:latest + stage: build + variables: + URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN" + script: + - version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG") + - insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "") + - response=$(curl -s -w "\n%{http_code}" $insecure --data $version $URL) + - code=$(echo "$response" | tail -n 1) + - body=$(echo "$response" | head -n 1) + # Output state information + - if [ $code -eq 201 ]; then + echo "Package created - Code $code - $body"; + else + echo "Could not create package - Code $code - $body"; + exit 1; + fi diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0ddbf98ccb2..1888c90fa7c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1233,6 +1233,9 @@ msgstr "" msgid "Action to take when receiving an alert." msgstr "" +msgid "Actions" +msgstr "" + msgid "Activate" msgstr "" @@ -2254,6 +2257,9 @@ msgstr "" msgid "An error occurred when updating the issue weight" msgstr "" +msgid "An error occurred while acknowledging the notification. Refresh the page and try again." +msgstr "" + msgid "An error occurred while adding formatted title for epic" msgstr "" @@ -8231,6 +8237,9 @@ msgstr "" msgid "Edit issues" msgstr "" +msgid "Edit iteration" +msgstr "" + msgid "Edit public deploy key" msgstr "" @@ -9509,6 +9518,12 @@ msgstr "" msgid "Failed to install." msgstr "" +msgid "Failed to load assignees. Please try again." +msgstr "" + +msgid "Failed to load authors. Please try again." +msgstr "" + msgid "Failed to load emoji list." msgstr "" @@ -12662,6 +12677,9 @@ msgstr "" msgid "Iteration removed" msgstr "" +msgid "Iteration updated" +msgstr "" + msgid "Iterations" msgstr "" @@ -14885,9 +14903,6 @@ msgid_plural "New Issues" msgstr[0] "" msgstr[1] "" -msgid "New Iteration" -msgstr "" - msgid "New Jira import" msgstr "" @@ -24515,6 +24530,9 @@ msgstr "" msgid "Update it" msgstr "" +msgid "Update iteration" +msgstr "" + msgid "Update now" msgstr "" diff --git a/spec/frontend/persistent_user_callout_spec.js b/spec/frontend/persistent_user_callout_spec.js index db324990e71..97985ba3a07 100644 --- a/spec/frontend/persistent_user_callout_spec.js +++ b/spec/frontend/persistent_user_callout_spec.js @@ -43,6 +43,23 @@ describe('PersistentUserCallout', () => { return fixture; } + function createFollowLinkFixture() { + const fixture = document.createElement('div'); + fixture.innerHTML = ` + + `; + + return fixture; + } + describe('dismiss', () => { let button; let mockAxios; @@ -144,6 +161,55 @@ describe('PersistentUserCallout', () => { }); }); + describe('follow links', () => { + let link; + let mockAxios; + let persistentUserCallout; + + beforeEach(() => { + const fixture = createFollowLinkFixture(); + const container = fixture.querySelector('.container'); + link = fixture.querySelector('.js-follow-link'); + mockAxios = new MockAdapter(axios); + + persistentUserCallout = new PersistentUserCallout(container); + jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {}); + + delete window.location; + window.location = { assign: jest.fn() }; + }); + + afterEach(() => { + mockAxios.restore(); + }); + + it('uses a link to trigger callout and defers following until callout is finished', () => { + const { href } = link; + mockAxios.onPost(dismissEndpoint).replyOnce(200); + + link.click(); + + return waitForPromises().then(() => { + expect(window.location.assign).toBeCalledWith(href); + expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ feature_name: featureName })); + expect(persistentUserCallout.container.remove).not.toHaveBeenCalled(); + }); + }); + + it('invokes Flash when the dismiss request fails', () => { + mockAxios.onPost(dismissEndpoint).replyOnce(500); + + link.click(); + + return waitForPromises().then(() => { + expect(window.location.assign).not.toHaveBeenCalled(); + expect(Flash).toHaveBeenCalledWith( + 'An error occurred while acknowledging the notification. Refresh the page and try again.', + ); + }); + }); + }); + describe('factory', () => { it('returns an instance of PersistentUserCallout with the provided container property', () => { const fixture = createFixture(); diff --git a/spec/models/iteration_spec.rb b/spec/models/iteration_spec.rb index 2ffbad92809..5e454b3666c 100644 --- a/spec/models/iteration_spec.rb +++ b/spec/models/iteration_spec.rb @@ -45,6 +45,14 @@ RSpec.describe Iteration do it { is_expected.to be_valid } end + context 'when updated iteration dates overlap with its own dates' do + it 'is valid' do + existing_iteration.start_date = 5.days.from_now + + expect(existing_iteration).to be_valid + end + end + context 'when dates overlap' do context 'same group' do context 'when start_date is in range' do diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index aefd3454b1b..5ecc0402420 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -7,6 +7,8 @@ RSpec.describe MergeRequests::PostMergeService do let(:merge_request) { create(:merge_request, assignees: [user]) } let(:project) { merge_request.project } + subject { described_class.new(project, user).execute(merge_request) } + before do project.add_maintainer(user) end @@ -19,10 +21,7 @@ RSpec.describe MergeRequests::PostMergeService do project.open_merge_requests_count merge_request.update!(state: 'merged') - service = described_class.new(project, user, {}) - - expect { service.execute(merge_request) } - .to change { project.open_merge_requests_count }.from(1).to(0) + expect { subject }.to change { project.open_merge_requests_count }.from(1).to(0) end it 'updates metrics' do @@ -35,7 +34,7 @@ RSpec.describe MergeRequests::PostMergeService do expect(metrics_service).to receive(:merge) - described_class.new(project, user, {}).execute(merge_request) + subject end it 'deletes non-latest diffs' do @@ -45,7 +44,7 @@ RSpec.describe MergeRequests::PostMergeService do .to receive(:new).with(merge_request) .and_return(diff_removal_service) - described_class.new(project, user, {}).execute(merge_request) + subject expect(diff_removal_service).to have_received(:execute) end @@ -56,21 +55,59 @@ RSpec.describe MergeRequests::PostMergeService do issue = create(:issue, project: project) allow(merge_request).to receive(:visible_closing_issues_for).and_return([issue]) - expect_next_instance_of(Issues::CloseService) do |service| - allow(service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError) + expect_next_instance_of(Issues::CloseService) do |close_service| + allow(close_service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError) end - expect { described_class.new(project, user).execute(merge_request) }.to raise_error(RuntimeError) + expect { subject }.to raise_error(RuntimeError) expect(merge_request.reload).to be_merged end it 'clean up environments for the merge request' do - expect_next_instance_of(Ci::StopEnvironmentsService) do |service| - expect(service).to receive(:execute_for_merge_request).with(merge_request) + expect_next_instance_of(Ci::StopEnvironmentsService) do |stop_environment_service| + expect(stop_environment_service).to receive(:execute_for_merge_request).with(merge_request) end - described_class.new(project, user).execute(merge_request) + subject + end + + context 'when the merge request has review apps' do + it 'cancels all review app deployments' do + pipeline = create(:ci_pipeline, + source: :merge_request_event, + merge_request: merge_request, + project: project, + sha: merge_request.diff_head_sha, + merge_requests_as_head_pipeline: [merge_request]) + + review_env_a = create(:environment, project: project, state: :available, name: 'review/a') + review_env_b = create(:environment, project: project, state: :available, name: 'review/b') + review_env_c = create(:environment, project: project, state: :stopped, name: 'review/c') + deploy_env = create(:environment, project: project, state: :available, name: 'deploy') + + review_job_a1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_a.name) + review_job_a2 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_a.name) + review_job_b1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_b.name) + review_job_b2 = create(:ci_build, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_b.name) + review_job_c1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_c.name) + deploy_job = create(:ci_build, :with_deployment, :deploy_to_production, + pipeline: pipeline, project: project, environment: deploy_env.name) + + subject + + expect(review_job_a1.reload.canceled?).to be true + expect(review_job_a2.reload.canceled?).to be true + expect(review_job_b1.reload.canceled?).to be true + expect(review_job_b2.reload.canceled?).to be false + expect(review_job_c1.reload.canceled?).to be false + expect(deploy_job.reload.canceled?).to be false + end end end end diff --git a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb index c128bbe5e02..6eb4d79b7d9 100644 --- a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb +++ b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb @@ -211,8 +211,26 @@ RSpec.shared_examples 'wiki controller actions' do end end - describe 'GET #edit' do - subject { get(:edit, params: routing_params.merge(id: wiki_title)) } + shared_examples 'edit action' do + context 'when the page does not exist' do + let(:id_param) { 'invalid' } + + it 'redirects to show' do + subject + + expect(response).to redirect_to_wiki(wiki, 'invalid') + end + end + + context 'when id param is blank' do + let(:id_param) { ' ' } + + it 'redirects to the home page' do + subject + + expect(response).to redirect_to_wiki(wiki, 'home') + end + end context 'when page content encoding is invalid' do it 'redirects to show' do @@ -236,6 +254,14 @@ RSpec.shared_examples 'wiki controller actions' do expect(response).to redirect_to_wiki(wiki, page) end end + end + + describe 'GET #edit' do + let(:id_param) { wiki_title } + + subject { get(:edit, params: routing_params.merge(id: id_param)) } + + it_behaves_like 'edit action' context 'when page content encoding is valid' do render_views @@ -252,23 +278,17 @@ RSpec.shared_examples 'wiki controller actions' do describe 'PATCH #update' do let(:new_title) { 'New title' } let(:new_content) { 'New content' } + let(:id_param) { wiki_title } subject do patch(:update, params: routing_params.merge( - id: wiki_title, + id: id_param, wiki: { title: new_title, content: new_content } )) end - context 'when page content encoding is invalid' do - it 'redirects to show' do - allow(controller).to receive(:valid_encoding?).and_return(false) - - subject - expect(response).to redirect_to_wiki(wiki, wiki.list_pages.first) - end - end + it_behaves_like 'edit action' context 'when page content encoding is valid' do render_views -- GitLab