diff options
| author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-30 21:10:23 +0000 |
|---|---|---|
| committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-30 21:10:23 +0000 |
| commit | 07de48228886ca6afa348c92f8689b9027e4c195 (patch) | |
| tree | a3ba7bae1edb47180352d080136141af40a3e8a2 | |
| parent | d899d2a373f8be3d94760299faafa19c3c432c1e (diff) | |
| download | gitlab-ce-07de48228886ca6afa348c92f8689b9027e4c195.tar.gz | |
Add latest changes from gitlab-org/gitlab@master
28 files changed, 445 insertions, 139 deletions
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue index cbce887f491..f82d3065ca5 100644 --- a/app/assets/javascripts/environments/components/environments_table.vue +++ b/app/assets/javascripts/environments/components/environments_table.vue @@ -188,15 +188,37 @@ export default { </div> <template v-else> - <div - is="environment-item" - v-for="(children, index) in model.children" - :key="`env-item-${i}-${index}`" - :model="children" - :can-read-environment="canReadEnvironment" - :table-data="tableData" - data-qa-selector="environment_item" - /> + <template v-for="(child, index) in model.children"> + <div + is="environment-item" + :key="`environment-row-${i}-${index}`" + :model="child" + :can-read-environment="canReadEnvironment" + :table-data="tableData" + data-qa-selector="environment_item" + /> + + <div + v-if="shouldRenderDeployBoard(child)" + :key="`deploy-board-row-${i}-${index}`" + class="js-deploy-board-row" + > + <div class="deploy-board-container"> + <deploy-board + :deploy-board-data="child.deployBoardData" + :is-loading="child.isLoadingDeployBoard" + :is-empty="child.isEmptyDeployBoard" + :logs-path="child.logs_path" + @changeCanaryWeight="changeCanaryWeight(child, $event)" + /> + </div> + </div> + <environment-alert + v-if="shouldRenderAlert(model)" + :key="`alert-row-${i}-${index}`" + :environment="child" + /> + </template> <div :key="`sub-div-${i}`"> <div class="text-center gl-mt-3"> diff --git a/app/assets/javascripts/environments/stores/environments_store.js b/app/assets/javascripts/environments/stores/environments_store.js index f7fdbb03f04..a67e44b3348 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js +++ b/app/assets/javascripts/environments/stores/environments_store.js @@ -185,6 +185,8 @@ export default class EnvironmentsStore { updated.isChildren = true; + updated = setDeployBoard(env, updated); + return updated; }); diff --git a/app/assets/javascripts/environments/stores/helpers.js b/app/assets/javascripts/environments/stores/helpers.js index 89457da0614..3330edd8830 100644 --- a/app/assets/javascripts/environments/stores/helpers.js +++ b/app/assets/javascripts/environments/stores/helpers.js @@ -4,7 +4,7 @@ */ export const setDeployBoard = (oldEnvironmentState, environment) => { let parsedEnvironment = environment; - if (environment.size === 1 && environment.rollout_status) { + if (!environment.isFolder && environment.rollout_status) { parsedEnvironment = { ...environment, hasDeployBoard: true, diff --git a/app/assets/javascripts/learn_gitlab/track_learn_gitlab.js b/app/assets/javascripts/learn_gitlab/track_learn_gitlab.js new file mode 100644 index 00000000000..305d130f10c --- /dev/null +++ b/app/assets/javascripts/learn_gitlab/track_learn_gitlab.js @@ -0,0 +1,10 @@ +import Tracking from '~/tracking'; + +export default function trackLearnGitlab(learnGitlabA) { + Tracking.event('projects:learn_gitlab:index', 'page_init', { + label: 'learn_gitlab', + property: learnGitlabA + ? 'Growth::Conversion::Experiment::LearnGitLabA' + : 'Growth::Activation::Experiment::LearnGitLabB', + }); +} diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue index 6cd3bbc359b..ad6dfbf41ca 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue @@ -64,7 +64,15 @@ export default { <img :src="svg" :alt="actionLabel" /> <h6>{{ title }}</h6> <p class="gl-font-sm gl-text-gray-700">{{ description }}</p> - <gl-link :href="url" target="_blank">{{ actionLabel }}</gl-link> + <gl-link + :href="url" + target="_blank" + rel="noopener noreferrer" + data-track-action="click_link" + :data-track-label="actionLabel" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" + >{{ actionLabel }}</gl-link + > </div> </gl-card> </template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue index 6f51c7372fd..3d31ac6c267 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue @@ -34,7 +34,15 @@ export default { {{ $options.i18n.ACTION_LABELS[action].title }} </span> <span v-else> - <gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link> + <gl-link + target="_blank" + :href="value.url" + data-track-action="click_link" + :data-track-label="$options.i18n.ACTION_LABELS[action].title" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" + > + {{ $options.i18n.ACTION_LABELS[action].title }} + </gl-link> </span> <span v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only"> - {{ $options.i18n.trialOnly }} diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js index c4dec89b984..d9ad29fad99 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import trackLearnGitlab from '~/learn_gitlab/track_learn_gitlab'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import LearnGitlabA from '../components/learn_gitlab_a.vue'; import LearnGitlabB from '../components/learn_gitlab_b.vue'; @@ -14,6 +15,8 @@ function initLearnGitlab() { const { learnGitlabA } = gon.experiments; + trackLearnGitlab(learnGitlabA); + return new Vue({ el, render(createElement) { diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue index 2edc84e62cb..47e5bb0bde8 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue @@ -1,6 +1,6 @@ <script> -import { GlBadge, GlModal } from '@gitlab/ui'; -import { __, n__, sprintf } from '~/locale'; +import { GlBadge, GlFriendlyWrap, GlLink, GlModal } from '@gitlab/ui'; +import { __, n__, s__, sprintf } from '~/locale'; import CodeBlock from '~/vue_shared/components/code_block.vue'; export default { @@ -8,6 +8,8 @@ export default { components: { CodeBlock, GlBadge, + GlFriendlyWrap, + GlLink, GlModal, }, props: { @@ -50,6 +52,7 @@ export default { duration: __('Execution time'), history: __('History'), trace: __('System output'), + attachment: s__('TestReports|Attachment'), }, modalCloseButton: { text: __('Close'), @@ -85,6 +88,18 @@ export default { </div> </div> + <div v-if="testCase.attachment_url" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3"> + <strong class="gl-text-right col-sm-3">{{ $options.text.attachment }}</strong> + <gl-link + class="col-sm-9" + :href="testCase.attachment_url" + target="_blank" + data-testid="test-case-attachment-url" + > + <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.attachment_url" /> + </gl-link> + </div> + <div v-if="testCase.system_output" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3" diff --git a/app/graphql/mutations/issues/set_due_date.rb b/app/graphql/mutations/issues/set_due_date.rb index da7892f4ed4..22a72e201ba 100644 --- a/app/graphql/mutations/issues/set_due_date.rb +++ b/app/graphql/mutations/issues/set_due_date.rb @@ -7,8 +7,17 @@ module Mutations argument :due_date, Types::TimeType, - required: true, - description: 'The desired due date for the issue.' + required: false, + description: 'The desired due date for the issue, ' \ + 'due date will be removed if absent or set to null' + + def ready?(**args) + unless args.key?(:due_date) + raise Gitlab::Graphql::Errors::ArgumentError, 'Argument dueDate must be provided (`null` accepted)' + end + + super + end def resolve(project_path:, iid:, due_date:) issue = authorized_find!(project_path: project_path, iid: iid) diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb index fc03c986830..51dce76c749 100644 --- a/app/helpers/learn_gitlab_helper.rb +++ b/app/helpers/learn_gitlab_helper.rb @@ -8,6 +8,16 @@ module LearnGitlabHelper learn_gitlab_onboarding_available?(project) end + def learn_gitlab_experiment_tracking_category + return unless current_user + + if Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user) + Gitlab::Experimentation.get_experiment(:learn_gitlab_a).tracking_category + elsif Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user) + Gitlab::Experimentation.get_experiment(:learn_gitlab_b).tracking_category + end + end + def onboarding_actions_data(project) attributes = onboarding_progress(project).attributes.symbolize_keys diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb index ddf5461715f..0c9e3287e28 100644 --- a/app/helpers/sidebars_helper.rb +++ b/app/helpers/sidebars_helper.rb @@ -39,6 +39,7 @@ module SidebarsHelper current_user: user, container: project, learn_gitlab_experiment_enabled: learn_gitlab_experiment_enabled?(project), + learn_gitlab_experiment_tracking_category: learn_gitlab_experiment_tracking_category, current_ref: current_ref, jira_issues_integration: project_jira_issues_integration?, can_view_pipeline_editor: can_view_pipeline_editor?(project), diff --git a/changelogs/unreleased/accept-null-in-issuesetduedate.yml b/changelogs/unreleased/accept-null-in-issuesetduedate.yml new file mode 100644 index 00000000000..cba2b3ae340 --- /dev/null +++ b/changelogs/unreleased/accept-null-in-issuesetduedate.yml @@ -0,0 +1,5 @@ +--- +title: Allow issueSetDueDate GraphQL mutation to accept null values +merge_request: 60139 +author: +type: added diff --git a/changelogs/unreleased/afontaine-show-deploy-boards-for-folders.yml b/changelogs/unreleased/afontaine-show-deploy-boards-for-folders.yml new file mode 100644 index 00000000000..ff43117751f --- /dev/null +++ b/changelogs/unreleased/afontaine-show-deploy-boards-for-folders.yml @@ -0,0 +1,5 @@ +--- +title: Show Deploy Boards for Environments in Folders +merge_request: 60525 +author: +type: added diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index fa20e0b48e9..6c170bab6e7 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2337,7 +2337,7 @@ Input type: `IssueSetDueDateInput` | Name | Type | Description | | ---- | ---- | ----------- | | <a id="mutationissuesetduedateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| <a id="mutationissuesetduedateduedate"></a>`dueDate` | [`Time!`](#time) | The desired due date for the issue. | +| <a id="mutationissuesetduedateduedate"></a>`dueDate` | [`Time`](#time) | The desired due date for the issue, due date will be removed if absent or set to null. | | <a id="mutationissuesetduedateiid"></a>`iid` | [`String!`](#string) | The IID of the issue to mutate. | | <a id="mutationissuesetduedateprojectpath"></a>`projectPath` | [`ID!`](#id) | The project the issue to mutate is in. | diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md index 38d583cf1d8..c6d883371a3 100644 --- a/doc/api/v3_to_v4.md +++ b/doc/api/v3_to_v4.md @@ -6,87 +6,13 @@ info: To determine the technical writer assigned to the Stage/Group associated w # API V3 to API V4 -In GitLab 9.0 and later, API V4 is the preferred version to be used. +WARNING: +The GitLab API v3 was removed in [GitLab 11.0](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36819). -API V3 was unsupported from GitLab 9.5, released on August -22, 2017. API v3 was removed in [GitLab 11.0](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36819). -The V3 API documentation is still -[available](https://gitlab.com/gitlab-org/gitlab-foss/blob/8-16-stable/doc/api/README.md). +For information about the current version of the GitLab API, read the [API documentation](README.md). -Below are the changes made between V3 and V4. +## Related links -## 8.17 - -- Removed `GET /projects/:search` (use: `GET /projects?search=x`) [!8877](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8877) -- `iid` filter has been removed from `GET /projects/:id/issues` [!8967](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8967) -- `GET /projects/:id/merge_requests?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!8793](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8793) -- Endpoints under `GET /projects/merge_request/:id` have been removed (use: `GET /projects/merge_requests/:id`) [!8793](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8793) -- Project snippets do not return deprecated field `expires_at` [!8723](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8723) -- Endpoints under `GET /projects/:id/keys` have been removed (use `GET /projects/:id/deploy_keys`) [!8716](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8716) - -## 9.0 - -- Status 409 returned for `POST /projects/:id/members` when a member already exists [!9093](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9093) -- Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` [!9328](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9328) -- Removed the following deprecated Templates endpoints (these are still accessible with `/templates` prefix) [!8853](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8853) - - `/licenses` - - `/licenses/:key` - - `/gitignores` - - `/gitlab_ci_ymls` - - `/dockerfiles` - - `/gitignores/:key` - - `/gitlab_ci_ymls/:key` - - `/dockerfiles/:key` -- Moved `POST /projects/fork/:id` to `POST /projects/:id/fork` [!8940](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8940) -- Moved `DELETE /todos` to `POST /todos/mark_as_done` and `DELETE /todos/:todo_id` to `POST /todos/:todo_id/mark_as_done` [!9410](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9410) -- Project filters are no longer available as `GET /projects/foo`, but as `GET /projects?foo=true` instead [!8962](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8962) - - `GET /projects/visible` & `GET /projects/all` are consolidated into `GET /projects` and can be used with or without authorization - - `GET /projects/owned` moved to `GET /projects?owned=true` - - `GET /projects/starred` moved to `GET /projects?starred=true` -- `GET /projects` returns all projects visible to current user, even if the user is not a member [!9674](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9674) - - To get projects the user is a member of, use `GET /projects?membership=true` -- Return pagination headers for all endpoints that return an array [!8606](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8606) -- Added `POST /environments/:environment_id/stop` to stop an environment [!8808](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8808) -- Removed `DELETE /projects/:id/deploy_keys/:key_id/disable`. Use `DELETE /projects/:id/deploy_keys/:key_id` instead [!9366](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9366) -- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)` [!9371](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9371) -- Make subscription API more RESTful. Use `POST /projects/:id/:subscribable_type/:subscribable_id/subscribe` to subscribe and `POST /projects/:id/:subscribable_type/:subscribable_id/unsubscribe` to unsubscribe from a resource. [!9325](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9325) -- Labels filter on `GET /projects/:id/issues` and `GET /issues` now matches only issues containing all labels (i.e.: Logical AND, not OR) [!8849](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8849) -- Renamed parameter `branch_name` to `branch` on the following endpoints [!8936](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8936) - - `POST /projects/:id/repository/branches` - - `POST /projects/:id/repository/commits` - - `POST/PUT/DELETE :id/repository/files` -- Renamed the `merge_when_build_succeeds` parameter to `merge_when_pipeline_succeeds` on the following endpoints: [!9335](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/) - - `PUT /projects/:id/merge_requests/:merge_request_id/merge` - - `POST /projects/:id/merge_requests/:merge_request_id/cancel_merge_when_pipeline_succeeds` - - `POST /projects` - - `POST /projects/user/:user_id` - - `PUT /projects/:id` -- Renamed `branch_name` to `branch` on `DELETE /projects/:id/repository/branches/:branch` response [!8936](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8936) -- Remove `public` parameter from create and edit actions of projects [!8736](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8736) -- Remove `subscribed` field from responses returning list of issues or merge - requests. Fetch individual issues or merge requests to obtain the value - of `subscribed` - [!9661](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9661) -- Use `visibility` as string parameter everywhere [!9337](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9337) -- Notes do not return deprecated field `upvote` and `downvote` [!9384](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9384) -- Return HTTP status code `400` for all validation errors when creating or updating a member instead of sometimes `422` error. [!9523](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9523) -- Remove `GET /groups/owned`. Use `GET /groups?owned=true` instead [!9505](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9505) -- Return 202 with JSON body on asynchronous removals on V4 API (`DELETE /projects/:id/repository/merged_branches` and `DELETE /projects/:id`) [!9449](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9449) -- `GET /projects/:id/milestones?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!9096](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9096) -- Return basic information about pipeline in `GET /projects/:id/pipelines` [!8875](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8875) -- Renamed all `build` references to `job` [!9463](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9463) -- Drop `GET /projects/:id/repository/commits/:sha/jobs` [!9463](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9463) -- Rename Build Triggers to be Pipeline Triggers API [!9713](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9713) - - `POST /projects/:id/trigger/builds` to `POST /projects/:id/trigger/pipeline` - - Require description when creating a new trigger `POST /projects/:id/triggers` -- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9675) -- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, to-dos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530) -- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, to-dos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9530) -- Change initial page from `0` to `1` on `GET /projects/:id/repository/commits` (like on the rest of the API) [!9679](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9679) -- Return correct `Link` header data for `GET /projects/:id/repository/commits` [!9679](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9679) -- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9637) - - Moved `GET /projects/:id/repository/files?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded) - - `GET /projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath` - - Moved `GET /projects/:id/repository/commits/:sha/blob?file_path=:file_path` and `GET /projects/:id/repository/blobs/:sha?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path/raw?ref=:sha` - - `GET /projects/:id/repository/tree` parameter `ref_name` has been renamed to `ref` for consistency -- `confirm` parameter for `POST /users` has been deprecated in favor of `skip_confirmation` parameter +- [GitLab v3 API documentation](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/8-16-stable/doc/api/README.md) +- [Migration guide](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/11-0-stable/doc/api/v3_to_v4.md) from + v3 to v4 diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md index 368417ac00b..804c013d317 100644 --- a/doc/user/project/deploy_boards.md +++ b/doc/user/project/deploy_boards.md @@ -8,7 +8,13 @@ type: howto, reference # Deploy Boards **(FREE)** > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1589) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.0. -> - [Moved](<https://gitlab.com/gitlab-org/gitlab/-/issues/212320>) to GitLab Free in 13.8. +> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212320) to GitLab Free in 13.8. +> - In GitLab 13.5 and earlier, apps that consist of multiple deployments are shown as +> duplicates on the deploy board. This is [fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/8463) +> in GitLab 13.6. +> - In GitLab 13.11 and earlier, environments in folders do not show deploy boards. +> This is [fixed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60525) in +> GitLab 13.12. GitLab Deploy Boards offer a consolidated view of the current health and status of each CI [environment](../../ci/environments/index.md) running on [Kubernetes](https://kubernetes.io), displaying the status @@ -46,10 +52,6 @@ knowledge. In particular, you should be familiar with: - [Kubernetes namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) - [Kubernetes canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) -In GitLab 13.5 and earlier, apps that consist of multiple deployments are shown as -duplicates on the deploy board. This is [fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/8463) -in GitLab 13.6. - ## Use cases Since the Deploy Board is a visual representation of the Kubernetes pods for a diff --git a/lib/sidebars/projects/menus/learn_gitlab_menu.rb b/lib/sidebars/projects/menus/learn_gitlab_menu.rb index 62596c4fbd7..e3fcd8f25d5 100644 --- a/lib/sidebars/projects/menus/learn_gitlab_menu.rb +++ b/lib/sidebars/projects/menus/learn_gitlab_menu.rb @@ -37,7 +37,14 @@ module Sidebars override :extra_container_html_options def nav_link_html_options - { class: 'home' } + { + class: 'home', + data: { + track_action: 'click_menu', + track_property: context.learn_gitlab_experiment_tracking_category, + track_label: 'learn_gitlab' + } + } end override :image_path diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 843f35a6863..d1904a3169e 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -31588,6 +31588,9 @@ msgstr "" msgid "TestReports|%{rate}%{sign} success rate" msgstr "" +msgid "TestReports|Attachment" +msgstr "" + msgid "TestReports|Jobs" msgstr "" diff --git a/spec/frontend/environments/environment_table_spec.js b/spec/frontend/environments/environment_table_spec.js index b08fa8d5117..71426ee5170 100644 --- a/spec/frontend/environments/environment_table_spec.js +++ b/spec/frontend/environments/environment_table_spec.js @@ -89,6 +89,42 @@ describe('Environment table', () => { expect(wrapper.find('.deploy-board-icon').exists()).toBe(true); }); + it('should render deploy board container when data is provided for children', async () => { + const mockItem = { + name: 'review', + size: 1, + environment_path: 'url', + logs_path: 'url', + id: 1, + isFolder: true, + isOpen: true, + children: [ + { + name: 'review/test', + hasDeployBoard: true, + deployBoardData: deployBoardMockData, + isDeployBoardVisible: true, + isLoadingDeployBoard: false, + isEmptyDeployBoard: false, + }, + ], + }; + + await factory({ + propsData: { + environments: [mockItem], + canCreateDeployment: false, + canReadEnvironment: true, + userCalloutsPath: '/callouts', + lockPromotionSvgPath: '/assets/illustrations/lock-promotion.svg', + helpCanaryDeploymentsPath: 'help/canary-deployments', + }, + }); + + expect(wrapper.find('.js-deploy-board-row').exists()).toBe(true); + expect(wrapper.find('.deploy-board-icon').exists()).toBe(true); + }); + it('should toggle deploy board visibility when arrow is clicked', (done) => { const mockItem = { name: 'review', @@ -125,7 +161,7 @@ describe('Environment table', () => { wrapper.find('.deploy-board-icon').trigger('click'); }); - it('should set the enviornment to change and weight when a change canary weight event is recevied', async () => { + it('should set the environment to change and weight when a change canary weight event is recevied', async () => { const mockItem = { name: 'review', size: 1, diff --git a/spec/frontend/environments/environments_store_spec.js b/spec/frontend/environments/environments_store_spec.js index 4a07281353f..cb2394b224d 100644 --- a/spec/frontend/environments/environments_store_spec.js +++ b/spec/frontend/environments/environments_store_spec.js @@ -123,6 +123,29 @@ describe('Store', () => { expect(store.state.environments[1].children.length).toEqual(serverData.length); }); + + it('should parse deploy board data for children', () => { + store.storeEnvironments(serverData); + + store.setfolderContent(store.state.environments[1], [ + { + name: 'foo', + size: 1, + latest: { + id: 1, + rollout_status: deployBoardMockData, + }, + }, + ]); + const result = store.state.environments[1].children[0]; + expect(result).toMatchObject({ + deployBoardData: deployBoardMockData, + hasDeployBoard: true, + isDeployBoardVisible: true, + isLoadingDeployBoard: false, + isEmptyDeployBoard: false, + }); + }); }); describe('store pagination', () => { diff --git a/spec/frontend/learn_gitlab/track_learn_gitlab_spec.js b/spec/frontend/learn_gitlab/track_learn_gitlab_spec.js new file mode 100644 index 00000000000..3fb38a74c70 --- /dev/null +++ b/spec/frontend/learn_gitlab/track_learn_gitlab_spec.js @@ -0,0 +1,21 @@ +import { mockTracking } from 'helpers/tracking_helper'; +import trackLearnGitlab from '~/learn_gitlab/track_learn_gitlab'; + +describe('trackTrialUserErrors', () => { + let spy; + + describe('when an error is present', () => { + beforeEach(() => { + spy = mockTracking('projects:learn_gitlab_index', document.body, jest.spyOn); + }); + + it('tracks the error message', () => { + trackLearnGitlab(); + + expect(spy).toHaveBeenCalledWith('projects:learn_gitlab:index', 'page_init', { + label: 'learn_gitlab', + property: 'Growth::Activation::Experiment::LearnGitLabB', + }); + }); + }); +}); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap index 8b54a06ac7c..981e4c84323 100644 --- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap +++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap @@ -134,9 +134,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Set up CI/CD" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Set up CI/CD + + Set up CI/CD + </a> </span> @@ -148,9 +155,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Start a free Ultimate trial" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Start a free Ultimate trial + + Start a free Ultimate trial + </a> </span> @@ -162,9 +176,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Add code owners" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Add code owners + + Add code owners + </a> </span> @@ -183,9 +204,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Add merge request approval" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Add merge request approval + + Add merge request approval + </a> </span> @@ -240,9 +268,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Create an issue" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Create an issue + + Create an issue + </a> </span> @@ -254,9 +289,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Submit a merge request" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Submit a merge request + + Submit a merge request + </a> </span> @@ -304,9 +346,16 @@ exports[`Learn GitLab Design A renders correctly 1`] = ` <span> <a class="gl-link" + data-track-action="click_link" + data-track-label="Run a Security scan using CI/CD" + data-track-property="Growth::Conversion::Experiment::LearnGitLabA" href="http://example.com/" + rel="noopener noreferrer" + target="_blank" > - Run a Security scan using CI/CD + + Run a Security scan using CI/CD + </a> </span> diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap index 07c7f2df09e..3161517c916 100644 --- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap +++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap @@ -110,6 +110,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Invite your colleagues" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -168,6 +171,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Create or import a repository" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -218,6 +224,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Set-up CI/CD" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -268,6 +277,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Try GitLab Ultimate for free" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -323,6 +335,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Add code owners" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -378,6 +393,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Enable require merge approvals" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -444,6 +462,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Create an issue" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -494,6 +515,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Submit a merge request (MR)" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" @@ -560,6 +584,9 @@ exports[`Learn GitLab Design B renders correctly 1`] = ` <a class="gl-link" + data-track-action="click_link" + data-track-label="Run a Security scan using CI/CD" + data-track-property="Growth::Activation::Experiment::LearnGitLabB" href="http://example.com/" rel="noopener noreferrer" target="_blank" diff --git a/spec/frontend/pipelines/test_reports/test_case_details_spec.js b/spec/frontend/pipelines/test_reports/test_case_details_spec.js index 64c6f08dce0..c995eb864d1 100644 --- a/spec/frontend/pipelines/test_reports/test_case_details_spec.js +++ b/spec/frontend/pipelines/test_reports/test_case_details_spec.js @@ -1,5 +1,6 @@ import { GlModal } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue'; import CodeBlock from '~/vue_shared/components/code_block.vue'; @@ -18,24 +19,27 @@ describe('Test case details', () => { system_output: 'Line 42 is broken', }; - const findModal = () => wrapper.find(GlModal); - const findName = () => wrapper.find('[data-testid="test-case-name"]'); - const findDuration = () => wrapper.find('[data-testid="test-case-duration"]'); - const findRecentFailures = () => wrapper.find('[data-testid="test-case-recent-failures"]'); - const findSystemOutput = () => wrapper.find('[data-testid="test-case-trace"]'); + const findModal = () => wrapper.findComponent(GlModal); + const findName = () => wrapper.findByTestId('test-case-name'); + const findDuration = () => wrapper.findByTestId('test-case-duration'); + const findRecentFailures = () => wrapper.findByTestId('test-case-recent-failures'); + const findAttachmentUrl = () => wrapper.findByTestId('test-case-attachment-url'); + const findSystemOutput = () => wrapper.findByTestId('test-case-trace'); const createComponent = (testCase = {}) => { - wrapper = shallowMount(TestCaseDetails, { - localVue, - propsData: { - modalId: 'my-modal', - testCase: { - ...defaultTestCase, - ...testCase, + wrapper = extendedWrapper( + shallowMount(TestCaseDetails, { + localVue, + propsData: { + modalId: 'my-modal', + testCase: { + ...defaultTestCase, + ...testCase, + }, }, - }, - stubs: { CodeBlock, GlModal }, - }); + stubs: { CodeBlock, GlModal }, + }), + ); }; afterEach(() => { @@ -91,6 +95,25 @@ describe('Test case details', () => { }); }); + describe('when test case has attachment URL', () => { + it('renders the attachment URL as a link', () => { + const expectedUrl = '/my/path.jpg'; + createComponent({ attachment_url: expectedUrl }); + const attachmentUrl = findAttachmentUrl(); + + expect(attachmentUrl.exists()).toBe(true); + expect(attachmentUrl.attributes('href')).toBe(expectedUrl); + }); + }); + + describe('when test case does not have attachment URL', () => { + it('does not render the attachment URL', () => { + createComponent({ attachment_url: null }); + + expect(findAttachmentUrl().exists()).toBe(false); + }); + }); + describe('when test case has system output', () => { it('renders the test case system output', () => { createComponent(); diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb index 9f8d0d6c405..263122e5d5f 100644 --- a/spec/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/graphql/mutations/issues/set_due_date_spec.rb @@ -3,8 +3,9 @@ require 'spec_helper' RSpec.describe Mutations::Issues::SetDueDate do - let(:issue) { create(:issue) } - let(:user) { create(:user) } + let(:issue) { create(:issue, due_date: '2021-05-01') } + + let_it_be(:user) { create(:user) } subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } @@ -23,17 +24,25 @@ RSpec.describe Mutations::Issues::SetDueDate do issue.project.add_developer(user) end - it 'returns the issue with updated due date' do + it 'returns the issue with updated due date', :aggregate_failures do expect(mutated_issue).to eq(issue) expect(mutated_issue.due_date).to eq(Date.today + 2.days) expect(subject[:errors]).to be_empty end + context 'when due date is nil' do + let(:due_date) { nil } + + it 'updates due date to be nil' do + expect(mutated_issue.due_date).to be nil + end + end + context 'when passing incorrect due date value' do let(:due_date) { 'test' } - it 'does not update due date' do - expect(mutated_issue.due_date).to eq(issue.due_date) + it 'updates due date to be nil' do + expect(mutated_issue.due_date).to be nil end end end diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb index 796542aa2b5..5bbe32166ab 100644 --- a/spec/helpers/learn_gitlab_helper_spec.rb +++ b/spec/helpers/learn_gitlab_helper_spec.rb @@ -91,4 +91,37 @@ RSpec.describe LearnGitlabHelper do end end end + + describe '.learn_gitlab_experiment_tracking_category' do + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + + subject { helper.learn_gitlab_experiment_tracking_category } + + where(:experiment_a, :experiment_b, :result) do + false | false | nil + false | true | 'Growth::Activation::Experiment::LearnGitLabB' + true | false | 'Growth::Conversion::Experiment::LearnGitLabA' + true | true | 'Growth::Conversion::Experiment::LearnGitLabA' + end + + with_them do + before do + stub_experiment_for_subject(learn_gitlab_a: experiment_a, learn_gitlab_b: experiment_b) + end + + context 'when signed in' do + before do + sign_in(user) + end + + it { is_expected.to eq(result) } + end + + context 'when not signed in' do + it { is_expected.to eq(nil) } + end + end + end end diff --git a/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb b/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb index 6bcc62bd973..dc1aecc6546 100644 --- a/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb @@ -3,9 +3,18 @@ require 'spec_helper' RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do - let(:project) { build(:project) } - let(:experiment_enabled) { true } - let(:context) { Sidebars::Projects::Context.new(current_user: nil, container: project, learn_gitlab_experiment_enabled: experiment_enabled) } + let_it_be(:project) { build(:project) } + let_it_be(:experiment_enabled) { true } + let_it_be(:tracking_category) { 'Growth::Activation::Experiment::LearnGitLabB' } + + let(:context) do + Sidebars::Projects::Context.new( + current_user: nil, + container: project, + learn_gitlab_experiment_enabled: experiment_enabled, + learn_gitlab_experiment_tracking_category: tracking_category + ) + end subject { described_class.new(context) } @@ -13,6 +22,23 @@ RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do expect(subject.instance_variable_get(:@items)).to be_empty end + describe '#nav_link_html_options' do + let_it_be(:data_tracking) do + { + class: 'home', + data: { + track_action: 'click_menu', + track_property: tracking_category, + track_label: 'learn_gitlab' + } + } + end + + specify do + expect(subject.nav_link_html_options).to eq(data_tracking) + end + end + describe '#render?' do context 'when learn gitlab experiment is enabled' do it 'returns true' do diff --git a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb index b3c9b9d4995..ea5be9f9852 100644 --- a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb @@ -42,11 +42,34 @@ RSpec.describe 'Setting Due Date of an issue' do expect(graphql_errors).to include(a_hash_including('message' => error)) end - it 'updates the issue due date' do - post_graphql_mutation(mutation, current_user: current_user) + context 'when due date value is a valid date' do + it 'updates the issue due date' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['issue']['dueDate']).to eq(2.days.since.to_date.to_s) + end + end + + context 'when due date value is null' do + let(:input) { { due_date: nil } } + + it 'updates the issue to remove the due date' do + post_graphql_mutation(mutation, current_user: current_user) - expect(response).to have_gitlab_http_status(:success) - expect(mutation_response['issue']['dueDate']).to eq(2.days.since.to_date.to_s) + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['issue']['dueDate']).to be nil + end + end + + context 'when due date argument is not given' do + let(:input) { {} } + + it 'returns an error' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(graphql_errors).to include(a_hash_including('message' => /Argument dueDate must be provided/)) + end end context 'when the due date value is not a valid time' do |
