diff options
39 files changed, 657 insertions, 199 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 7827c78b658..1825e118575 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -124,6 +124,11 @@ export default { required: false, default: false, }, + mrReviews: { + type: Object, + required: false, + default: () => ({}), + }, }, data() { const treeWidth = @@ -161,7 +166,12 @@ export default { 'hasConflicts', 'viewDiffsFileByFile', ]), - ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']), + ...mapGetters('diffs', [ + 'whichCollapsedTypes', + 'isParallelView', + 'currentDiffIndex', + 'fileReviews', + ]), ...mapGetters(['isNotesFetched', 'getNoteableData']), diffs() { if (!this.viewDiffsFileByFile) { @@ -261,6 +271,7 @@ export default { dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, viewDiffsFileByFile: fileByFile(this.fileByFileUserPreference), + mrReviews: this.mrReviews || {}, }); if (this.shouldShow) { @@ -519,6 +530,7 @@ export default { v-for="(file, index) in diffs" :key="file.newPath" :file="file" + :reviewed="fileReviews[index]" :is-first-file="index === 0" :is-last-file="index === diffs.length - 1" :help-page-path="helpPagePath" diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index ed94cabe124..343cee7ad83 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -37,6 +37,11 @@ export default { type: Object, required: true, }, + reviewed: { + type: Boolean, + required: false, + default: false, + }, isFirstFile: { type: Boolean, required: false, diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index 587220488be..6cc9cbf750d 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -5,6 +5,10 @@ import { parseBoolean } from '~/lib/utils/common_utils'; import FindFile from '~/vue_shared/components/file_finder/index.vue'; import eventHub from '../notes/event_hub'; import diffsApp from './components/app.vue'; + +import { getDerivedMergeRequestInformation } from './utils/merge_request'; +import { getReviewsForMergeRequest } from './utils/file_reviews'; + import { TREE_LIST_STORAGE_KEY, DIFF_WHITESPACE_COOKIE_NAME } from './constants'; export default function initDiffsApp(store) { @@ -102,6 +106,8 @@ export default function initDiffsApp(store) { ...mapActions('diffs', ['setRenderTreeList', 'setShowWhitespace']), }, render(createElement) { + const { mrPath } = getDerivedMergeRequestInformation({ endpoint: this.endpoint }); + return createElement('diffs-app', { props: { endpoint: this.endpoint, @@ -117,6 +123,7 @@ export default function initDiffsApp(store) { dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, fileByFileUserPreference: this.viewDiffsFileByFile, + mrReviews: getReviewsForMergeRequest(mrPath), }, }); }, diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 5b410051705..f2d9d86997d 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -50,6 +50,8 @@ import { } from '../constants'; import { diffViewerModes } from '~/ide/constants'; import { isCollapsed } from '../utils/diff_file'; +import { getDerivedMergeRequestInformation } from '../utils/merge_request'; +import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews'; export const setBaseConfig = ({ commit }, options) => { const { @@ -61,6 +63,7 @@ export const setBaseConfig = ({ commit }, options) => { dismissEndpoint, showSuggestPopover, viewDiffsFileByFile, + mrReviews, } = options; commit(types.SET_BASE_CONFIG, { endpoint, @@ -71,6 +74,7 @@ export const setBaseConfig = ({ commit }, options) => { dismissEndpoint, showSuggestPopover, viewDiffsFileByFile, + mrReviews, }); }; @@ -741,3 +745,13 @@ export const setFileByFile = ({ commit }, { fileByFile }) => { mergeUrlParams({ [DIFF_FILE_BY_FILE_COOKIE_NAME]: fileViewMode }, window.location.href), ); }; + +export function reviewFile({ commit, state, getters }, { file, reviewed = true }) { + const { mrPath } = getDerivedMergeRequestInformation({ endpoint: file.load_collapsed_diff_url }); + const reviews = setReviewsForMergeRequest( + mrPath, + markFileReview(getters.fileReviews(state), file, reviewed), + ); + + commit(types.SET_MR_FILE_REVIEWS, reviews); +} diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index baf54188932..6afc6f91fec 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,5 +1,6 @@ import { __, n__ } from '~/locale'; import { parallelizeDiffLines } from './utils'; +import { isFileReviewed } from '../utils/file_reviews'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE, @@ -149,3 +150,7 @@ export const diffLines = state => (file, unifiedDiffComponents) => { state.diffViewType === INLINE_DIFF_VIEW_TYPE, ); }; + +export function fileReviews(state) { + return state.diffFiles.map(file => isFileReviewed(state.mrReviews, file)); +} diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index c331e52c887..2aa971374ec 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -45,4 +45,5 @@ export default () => ({ fileFinderVisible: false, dismissEndpoint: '', showSuggestPopover: true, + mrReviews: {}, }); diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 30097239aaa..4641731c4b6 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -7,6 +7,8 @@ export const SET_DIFF_METADATA = 'SET_DIFF_METADATA'; export const SET_DIFF_DATA_BATCH = 'SET_DIFF_DATA_BATCH'; export const SET_DIFF_FILES = 'SET_DIFF_FILES'; +export const SET_MR_FILE_REVIEWS = 'SET_MR_FILE_REVIEWS'; + export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE'; export const SET_COVERAGE_DATA = 'SET_COVERAGE_DATA'; export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 19122c3096f..d3827a92426 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -37,6 +37,7 @@ export default { dismissEndpoint, showSuggestPopover, viewDiffsFileByFile, + mrReviews, } = options; Object.assign(state, { endpoint, @@ -47,6 +48,7 @@ export default { dismissEndpoint, showSuggestPopover, viewDiffsFileByFile, + mrReviews, }); }, @@ -353,4 +355,7 @@ export default { [types.SET_FILE_BY_FILE](state, fileByFile) { state.viewDiffsFileByFile = fileByFile; }, + [types.SET_MR_FILE_REVIEWS](state, newReviews) { + state.mrReviews = newReviews; + }, }; diff --git a/app/assets/javascripts/diffs/utils/file_reviews.js b/app/assets/javascripts/diffs/utils/file_reviews.js new file mode 100644 index 00000000000..0047955643a --- /dev/null +++ b/app/assets/javascripts/diffs/utils/file_reviews.js @@ -0,0 +1,61 @@ +function getFileReviewsKey(mrPath) { + return `${mrPath}-file-reviews`; +} + +export function getReviewsForMergeRequest(mrPath) { + const reviewsForMr = localStorage.getItem(getFileReviewsKey(mrPath)); + let reviews = {}; + + if (reviewsForMr) { + try { + reviews = JSON.parse(reviewsForMr); + } catch (err) { + reviews = {}; + } + } + + return reviews; +} + +export function setReviewsForMergeRequest(mrPath, reviews) { + localStorage.setItem(getFileReviewsKey(mrPath), JSON.stringify(reviews)); + + return reviews; +} + +export function isFileReviewed(reviews, file) { + const fileReviews = reviews[file.file_identifier_hash]; + + return file?.id && fileReviews?.length ? new Set(fileReviews).has(file.id) : false; +} + +export function reviewable(file) { + return Boolean(file.id) && Boolean(file.file_identifier_hash); +} + +export function markFileReview(reviews, file, reviewed = true) { + const usableReviews = { ...(reviews || {}) }; + let updatedReviews = usableReviews; + let fileReviews; + + if (reviewable(file)) { + fileReviews = new Set([...(usableReviews[file.file_identifier_hash] || [])]); + + if (reviewed) { + fileReviews.add(file.id); + } else { + fileReviews.delete(file.id); + } + + updatedReviews = { + ...usableReviews, + [file.file_identifier_hash]: Array.from(fileReviews), + }; + + if (updatedReviews[file.file_identifier_hash].length === 0) { + delete updatedReviews[file.file_identifier_hash]; + } + } + + return updatedReviews; +} diff --git a/app/assets/javascripts/diffs/utils/merge_request.js b/app/assets/javascripts/diffs/utils/merge_request.js new file mode 100644 index 00000000000..10e2a4b2cf2 --- /dev/null +++ b/app/assets/javascripts/diffs/utils/merge_request.js @@ -0,0 +1,10 @@ +export function getDerivedMergeRequestInformation({ endpoint } = {}) { + const mrPath = endpoint + ?.split('/') + .slice(0, -1) + .join('/'); + + return { + mrPath, + }; +} diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 1f029612c29..54b16e9b8af 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -74,8 +74,11 @@ export default { fileEditor() { return getFileEditorOrDefault(this.fileEditors, this.file.path); }, + isBinaryFile() { + return !isTextFile(this.file); + }, shouldHideEditor() { - return this.file && !this.file.loading && !isTextFile(this.file); + return this.file && !this.file.loading && this.isBinaryFile; }, showContentViewer() { return ( @@ -244,6 +247,10 @@ export default { ); }, createEditorInstance() { + if (this.isBinaryFile) { + return; + } + this.editor.dispose(); this.$nextTick(() => { diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index 70a6a6b423d..6d012ee5854 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -27,9 +27,12 @@ export default { return Promise.resolve(file.raw); } + const options = file.binary ? { responseType: 'arraybuffer' } : {}; + return axios .get(file.rawPath, { transformResponse: [f => f], + ...options, }) .then(({ data }) => data); }, diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue index 5ac30424f98..fa5707c306c 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue @@ -11,7 +11,7 @@ export default { }, props: { content: { - type: String, + type: [String, ArrayBuffer], default: '', required: false, }, diff --git a/app/models/project.rb b/app/models/project.rb index daa5605c2e0..c72cad54834 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2430,10 +2430,6 @@ class Project < ApplicationRecord protected_branches.limit(limit) end - def alerts_service_activated? - alerts_service&.active? - end - def self_monitoring? Gitlab::CurrentSettings.self_monitoring_project_id == id end diff --git a/config/feature_flags/development/sourcegraph.yml b/config/feature_flags/development/sourcegraph.yml new file mode 100644 index 00000000000..12170aec869 --- /dev/null +++ b/config/feature_flags/development/sourcegraph.yml @@ -0,0 +1,8 @@ +--- +name: sourcegraph +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16556 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/292199 +milestone: '12.5' +type: development +group: group::editor +default_enabled: false diff --git a/doc/.vale/gitlab/CurlStringsQuoted.yml b/doc/.vale/gitlab/CurlStringsQuoted.yml index e9fbabf5ffc..32bf662f2ae 100644 --- a/doc/.vale/gitlab/CurlStringsQuoted.yml +++ b/doc/.vale/gitlab/CurlStringsQuoted.yml @@ -1,5 +1,5 @@ --- -# Warning: gitlab.CurlStringsQuoted +# Error: gitlab.CurlStringsQuoted # # Ensures all code blocks using curl quote any URL strings. # diff --git a/doc/api/epics.md b/doc/api/epics.md index dc582808578..d501d61bfb8 100644 --- a/doc/api/epics.md +++ b/doc/api/epics.md @@ -11,9 +11,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w Every API call to epic must be authenticated. -If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code. +If a user is not a member of a private group, a `GET` request on that group results in a `404` status code. -If epics feature is not available a `403` status code will be returned. +If epics feature is not available a `403` status code is returned. ## Epic issues API @@ -23,9 +23,10 @@ The [epic issues API](epic_issues.md) allows you to interact with issues associa > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6448) in GitLab 11.3. -Since start date and due date can be dynamically sourced from related issue milestones, when user has edit permission, -additional fields will be shown. These include two boolean fields `start_date_is_fixed` and `due_date_is_fixed`, -and four date fields `start_date_fixed`, `start_date_from_inherited_source`, `due_date_fixed` and `due_date_from_inherited_source`. +Because start date and due date can be dynamically sourced from related issue milestones, +additional fields are shown when user has edit permission. These include two boolean +fields `start_date_is_fixed` and `due_date_is_fixed`, and four date fields `start_date_fixed`, +`start_date_from_inherited_source`, `due_date_fixed` and `due_date_from_inherited_source`. - `end_date` has been deprecated in favor of `due_date`. - `start_date_from_milestones` has been deprecated in favor of `start_date_from_inherited_source` @@ -40,7 +41,7 @@ Read more on [pagination](README.md#pagination). WARNING: > `reference` attribute in response is deprecated in favour of `references`. -> Introduced [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354) +> Introduced in [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354) NOTE: > `references.relative` is relative to the group that the epic is being requested. When epic is fetched from its origin group @@ -62,7 +63,7 @@ GET /groups/:id/epics?state=opened | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `author_id` | integer | no | Return epics created by the given user `id` | | `labels` | string | no | Return epics matching a comma separated list of labels names. Label names from the epic group or a parent group can be used | -| `with_labels_details` | boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Introduced in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413)| +| `with_labels_details` | boolean | no | If `true`, response returns more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. Available in [GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) and later | | `order_by` | string | no | Return epics ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return epics sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search epics against their `title` and `description` | @@ -73,7 +74,7 @@ GET /groups/:id/epics?state=opened | `updated_before` | datetime | no | Return epics updated on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | | `include_ancestor_groups` | boolean | no | Include epics from the requested group's ancestors. Default is `false` | | `include_descendant_groups` | boolean | no | Include epics from the requested group's descendants. Default is `true` | -| `my_reaction_emoji` | string | no | Return epics reacted by the authenticated user by the given emoji. `None` returns epics not given a reaction. `Any` returns epics given at least one reaction. Introduced in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31479)| +| `my_reaction_emoji` | string | no | Return epics reacted by the authenticated user by the given emoji. `None` returns epics not given a reaction. `Any` returns epics given at least one reaction. Available in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31479) and later | ```shell curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics" @@ -267,12 +268,12 @@ POST /groups/:id/epics | `labels` | string | no | The comma separated list of labels | | `description` | string | no | The description of the epic. Limited to 1,048,576 characters. | | `confidential` | boolean | no | Whether the epic should be confidential | -| `created_at` | string | no | When the epic was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5) | -| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (since 11.3) | -| `start_date_fixed` | string | no | The fixed start date of an epic (since 11.3) | -| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (since 11.3) | -| `due_date_fixed` | string | no | The fixed due date of an epic (since 11.3) | -| `parent_id` | integer/string | no | The ID of a parent epic (since 11.11) | +| `created_at` | string | no | When the epic was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([available](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5 and later) | +| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (in GitLab 11.3 and later) | +| `start_date_fixed` | string | no | The fixed start date of an epic (in GitLab 11.3 and later) | +| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (in GitLab 11.3 and later) | +| `due_date_fixed` | string | no | The fixed due date of an epic (in GitLab 11.3 and later) | +| `parent_id` | integer/string | no | The ID of a parent epic (in GitLab 11.11 and later) | ```shell curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics?title=Epic&description=Epic%20description" @@ -352,12 +353,12 @@ PUT /groups/:id/epics/:epic_iid | `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. | | `add_labels` | string | no | Comma-separated label names to add to an issue. | | `remove_labels` | string | no | Comma-separated label names to remove from an issue. | -| `updated_at` | string | no | When the epic was updated. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5) | -| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (since 11.3) | -| `start_date_fixed` | string | no | The fixed start date of an epic (since 11.3) | -| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (since 11.3) | -| `due_date_fixed` | string | no | The fixed due date of an epic (since 11.3) | -| `state_event` | string | no | State event for an epic. Set `close` to close the epic and `reopen` to reopen it (since 11.4) | +| `updated_at` | string | no | When the epic was updated. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([available](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5 and later) | +| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (in GitLab 11.3 and later) | +| `start_date_fixed` | string | no | The fixed start date of an epic (in GitLab 11.3 and later) | +| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (in GitLab 11.3 and later) | +| `due_date_fixed` | string | no | The fixed due date of an epic (in GitLab 11.3 and later) | +| `state_event` | string | no | State event for an epic. Set `close` to close the epic and `reopen` to reopen it (in GitLab 11.4 and later) | ```shell curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics/5?title=New%20Title" diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 06a2d937297..31eabfc0908 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -25047,6 +25047,11 @@ type Vulnerability implements Noteable { confirmedAt: Time """ + The user that confirmed the vulnerability. + """ + confirmedBy: User + + """ Description of the vulnerability """ description: String diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index e1fe89e192a..6ca3dc5aae4 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -72962,6 +72962,20 @@ "deprecationReason": null }, { + "name": "confirmedBy", + "description": "The user that confirmed the vulnerability.", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "description", "description": "Description of the vulnerability", "args": [ diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b542e10dd5c..fcff5f23a82 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -3776,6 +3776,7 @@ Represents a vulnerability. | Field | Type | Description | | ----- | ---- | ----------- | | `confirmedAt` | Time | Timestamp of when the vulnerability state was changed to confirmed | +| `confirmedBy` | User | The user that confirmed the vulnerability. | | `description` | String | Description of the vulnerability | | `detectedAt` | Time! | Timestamp of when the vulnerability was first detected | | `discussions` | DiscussionConnection! | All discussions on this noteable | diff --git a/doc/api/issues.md b/doc/api/issues.md index f6bab9ce676..3e23460740d 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Issues API -If a user is not a member of a project and the project is private, a `GET` +If a user is not a member of a private project, a `GET` request on that project results in a `404` status code. ## Issues pagination @@ -22,8 +22,8 @@ Introduced in [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_request NOTE: The `references.relative` attribute is relative to the group or project of the issue being requested. -When an issue is fetched from its project, the `relative` format is the same as the `short` format, -and when requested across groups or projects it's expected to be the same as the `full` format. +When an issue is fetched from its project, the `relative` format is the same as the `short` format. +When requested across groups or projects, it's expected to be the same as the `full` format. ## List issues @@ -57,7 +57,7 @@ GET /issues?state=opened | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | | `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | -| `due_date` | string | no | Return issues that have no due date (`0`) or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | +| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `iids[]` | integer array | no | Return only the issues having the given `iid` | | `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` | | `iteration_id` **(STARTER)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.6)_ | @@ -239,7 +239,7 @@ GET /groups/:id/issues?state=opened | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | | `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | -| `due_date` | string | no | Return issues that have no due date (`0`) or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | +| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `iids[]` | integer array | no | Return only the issues having the given `iid` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | @@ -416,7 +416,7 @@ GET /projects/:id/issues?state=opened | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | | `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | -| `due_date` | string | no | Return issues that have no due date (`0`) or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | +| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `iids[]` | integer array | no | Return only the issues having the given `iid` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | @@ -424,7 +424,7 @@ GET /projects/:id/issues?state=opened | `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | | `order_by` | string | no | Return issues ordered by `created_at`, `updated_at`, `priority`, `due_date`, `relative_position`, `label_priority`, `milestone_due`, `popularity`, `weight` fields. Default is `created_at` | -| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | +| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | | `search` | string | no | Search project issues against their `title` and `description` | | `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `state` | string | no | Return all issues or just those that are `opened` or `closed` | @@ -721,7 +721,7 @@ The `assignee` column is deprecated. We now show it as a single-sized array `ass to the GitLab EE API. WARNING: -The `epic_iid` attribute is deprecated, and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). +The `epic_iid` attribute is deprecated, and [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). Please use `iid` of the `epic` attribute instead. NOTE: @@ -882,7 +882,7 @@ WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. WARNING: -The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). +The `epic_iid` attribute is deprecated and [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). Please use `iid` of the `epic` attribute instead. NOTE: @@ -904,9 +904,9 @@ POST /projects/:id/issues | `created_at` | string | no | When the issue was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z`. Requires administrator or project/group owner rights. | | `description` | string | no | The description of an issue. Limited to 1,048,576 characters. | | `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This fills out the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. | -| `due_date` | string | no | The due date. Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` | +| `due_date` | string | no | The due date. Date time string in the format `YYYY-MM-DD`, for example `2016-03-11` | | `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. | -| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | +| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `iid` | integer/string | no | The internal ID of the project's issue (requires administrator or project owner rights) | | `labels` | string | no | Comma-separated label names for an issue | @@ -1048,9 +1048,9 @@ PUT /projects/:id/issues/:issue_iid | `confidential` | boolean | no | Updates an issue to be confidential | | `description` | string | no | The description of an issue. Limited to 1,048,576 characters. | | `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. | -| `due_date` | string | no | The due date. Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` | +| `due_date` | string | no | The due date. Date time string in the format `YYYY-MM-DD`, for example `2016-03-11` | | `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. | -| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | +| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `issue_iid` | integer | yes | The internal ID of a project's issue | | `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. | @@ -1168,7 +1168,7 @@ WARNING: ## Delete an issue -Only for admins and project owners. Deletes the issue in question. +Only for administrators and project owners. Deletes an issue. ```plaintext DELETE /projects/:id/issues/:issue_iid @@ -1207,8 +1207,8 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab ## Move an issue Moves an issue to a different project. If the target project -equals the source project or the user has insufficient permissions to move an -issue, status code `400` and an error message is returned. +is the source project or the user has insufficient permissions, +an error message with status code `400` is returned. If a given label or milestone with the same name also exists in the target project, it's then assigned to the issue being moved. @@ -1987,9 +1987,9 @@ Example response: ] ``` -## List merge requests that will close issue on merge +## List merge requests that close a particular issue on merge -Get all the merge requests that will close an issue when merged. +Get all merge requests that close a particular issue when merged. If the project is private or the issue is confidential, you need to provide credentials to authorize. The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). @@ -2112,7 +2112,7 @@ Comments are done via the [notes](notes.md) resource. ## Get user agent details -Available only for admins. +Available only for administrators. ```plaintext GET /projects/:id/issues/:issue_iid/user_agent_detail diff --git a/doc/api/projects.md b/doc/api/projects.md index 319290c3e19..0a42034ab22 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -297,7 +297,7 @@ When the user is authenticated and `simple` is not set this returns something li NOTE: For users of GitLab [Silver, Premium, or higher](https://about.gitlab.com/pricing/), -the `marked_for_deletion_at` attribute has been deprecated, and will be removed +the `marked_for_deletion_at` attribute has been deprecated, and is removed in API v5 in favor of the `marked_for_deletion_on` attribute. Users of GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) @@ -2250,7 +2250,7 @@ POST /projects/:id/push_rule | `id` | integer/string | **{check-circle}** Yes | The ID of the project or NAMESPACE/PROJECT_NAME. | | `max_file_size` **(STARTER)** | integer | **{dotted-circle}** No | Maximum file size (MB). | | `member_check` **(STARTER)** | boolean | **{dotted-circle}** No | Restrict commits by author (email) to existing GitLab users. | -| `prevent_secrets` **(STARTER)** | boolean | **{dotted-circle}** No | GitLab will reject any files that are likely to contain secrets. | +| `prevent_secrets` **(STARTER)** | boolean | **{dotted-circle}** No | GitLab rejects any files that are likely to contain secrets. | | `reject_unsigned_commits` **(PREMIUM)** | boolean | **{dotted-circle}** No | Reject commit when it's not signed through GPG. | ### Edit project push rule @@ -2273,7 +2273,7 @@ PUT /projects/:id/push_rule | `id` | integer/string | **{check-circle}** Yes | The ID of the project or NAMESPACE/PROJECT_NAME. | | `max_file_size` **(STARTER)** | integer | **{dotted-circle}** No | Maximum file size (MB). | | `member_check` **(STARTER)** | boolean | **{dotted-circle}** No | Restrict commits by author (email) to existing GitLab users. | -| `prevent_secrets` **(STARTER)** | boolean | **{dotted-circle}** No | GitLab will reject any files that are likely to contain secrets. | +| `prevent_secrets` **(STARTER)** | boolean | **{dotted-circle}** No | GitLab rejects any files that are likely to contain secrets. | | `reject_unsigned_commits` **(PREMIUM)** | boolean | **{dotted-circle}** No | Reject commits when they are not GPG signed. | ### Delete project push rule diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md index d2e3f473532..561727648f0 100644 --- a/doc/development/documentation/testing.md +++ b/doc/development/documentation/testing.md @@ -183,7 +183,8 @@ Vale configuration is found in the following projects: - [`charts`](https://gitlab.com/gitlab-org/charts/gitlab/-/tree/master/doc/.vale/gitlab) - [`gitlab-development-kit`](https://gitlab.com/gitlab-org/gitlab-development-kit/-/tree/master/doc/.vale/gitlab) -This configuration is also used within build pipelines. +This configuration is also used within build pipelines, where +[error-level rules](#vale-result-types) are enforced. You can use Vale: @@ -197,14 +198,17 @@ You can use Vale: Vale returns three types of results: `suggestion`, `warning`, and `error`: - **Suggestion**-level results are writing tips and aren't displayed in CI - job output. Suggestions don't break CI. + job output. Suggestions don't break CI. See a list of + [suggestion-level rules](https://gitlab.com/search?utf8=✓&snippets=false&scope=&repository_ref=master&search=path%3Adoc%2F.vale%2Fgitlab+Suggestion%3A&group_id=9970&project_id=278964). - **Warning**-level results are [Style Guide](styleguide/index.md) violations, aren't displayed in CI job output, and should contain clear explanations of how to resolve the warning. Warnings may be technical debt, or can be future error-level test items - (after the Technical Writing team completes its cleanup). Warnings don't break CI. + (after the Technical Writing team completes its cleanup). Warnings don't break CI. See a list of + [warning-level rules](https://gitlab.com/search?utf8=✓&snippets=false&scope=&repository_ref=master&search=path%3Adoc%2F.vale%2Fgitlab+Warning%3A&group_id=9970&project_id=278964). - **Error**-level results are Style Guide violations, and should contain clear explanations about how to resolve the error. Errors break CI and are displayed in CI job output. - of how to resolve the error. Errors break CI and are displayed in CI job output. + of how to resolve the error. Errors break CI and are displayed in CI job output. See a list of + [error-level rules](https://gitlab.com/search?utf8=✓&snippets=false&scope=&repository_ref=master&search=path%3Adoc%2F.vale%2Fgitlab+Error%3A&group_id=9970&project_id=278964). ### Install linters diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md index d7710c362e5..9838dc61c2d 100644 --- a/doc/user/admin_area/license.md +++ b/doc/user/admin_area/license.md @@ -120,6 +120,11 @@ You can upload and view more than one license, but only the latest license in th range is used as the active license. When you upload a future-dated license, it doesn't take effect until its applicable date. +NOTE: +In GitLab 13.6 and earlier, a notification banner about an expiring license may continue to be displayed even after a new license has been uploaded. +This happens when the newly uploaded license's start date is in the future and the expiring one is still active. +The banner disappears after the new license becomes active. + ## Troubleshooting ### There is no License tab in the Admin Area diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md index 4c012fbf1d9..60453b007ba 100644 --- a/doc/user/infrastructure/index.md +++ b/doc/user/infrastructure/index.md @@ -8,11 +8,37 @@ info: To determine the technical writer assigned to the Stage/Group associated w ## Motivation -The Terraform integration features within GitLab enable your GitOps / Infrastructure-as-Code (IaC) +The Terraform integration features in GitLab enable your GitOps / Infrastructure-as-Code (IaC) workflows to tie into GitLab authentication and authorization. These features focus on -lowering the barrier to entry for teams to adopt Terraform, collaborate effectively within +lowering the barrier to entry for teams to adopt Terraform, collaborate effectively in GitLab, and support Terraform best practices. +## Quick Start + +Use the following `.gitlab-ci.yml` to set up a basic Terraform project integration +for GitLab versions 13.5 and later: + +```yaml +include: + - template: Terraform.latest.gitlab-ci.yml + +variables: + # If not using GitLab's HTTP backend, remove this line and specify TF_HTTP_* variables + TF_STATE_NAME: default + TF_CACHE_KEY: default +``` + +This template uses `.latest.`, instead of stable, and may include breaking changes. +This template also includes some opinionated decisions, which you can override: + +- Including the latest [GitLab Terraform Image](https://gitlab.com/gitlab-org/terraform-images). +- Using the [GitLab managed Terraform State](#gitlab-managed-terraform-state) as + the Terraform state storage backend. +- Creating [four pipeline stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml): + `init`, `validate`, `build`, and `deploy`. These stages + [run the Terraform commands](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml) + `init`, `validate`, `plan`, `plan-json`, and `apply`. The `apply` command only runs on `master`. + ## GitLab Managed Terraform state [Terraform remote backends](https://www.terraform.io/docs/backends/index.html) @@ -22,7 +48,7 @@ to securely store the state files in local storage (the default) or [the remote store of your choice](../../administration/terraform_state.md). The GitLab managed Terraform state backend can store your Terraform state easily and -securely, and spares you from setting up additional remote resources like +securely. It spares you from setting up additional remote resources like Amazon S3 or Google Cloud Storage. Its features include: - Supporting encryption of the state file both in transit and at rest. @@ -39,32 +65,23 @@ recommends encrypting plan output or modifying the project visibility settings. ## Terraform integration in Merge Requests -Collaborating around Infrastructure as Code (IaC) changes requires both code changes and expected infrastructure changes to be checked and approved. GitLab provides a solution to help collaboration around Terraform code changes and their expected effects using the Merge Request pages. This way users don't have to build custom tools or rely on 3rd party solutions to streamline their IaC workflows. +Collaborating around Infrastructure as Code (IaC) changes requires both code changes +and expected infrastructure changes to be checked and approved. GitLab provides a +solution to help collaboration around Terraform code changes and their expected +effects using the Merge Request pages. This way users don't have to build custom +tools or rely on 3rd party solutions to streamline their IaC workflows. Read more on setting up and [using the merge request integrations](mr_integration.md). -## Quick Start - -Use the following `.gitlab-ci.yml` to set up a simple Terraform project integration -for GitLab versions 13.5 and greater: +## The GitLab terraform provider -```yaml -include: - - template: Terraform.latest.gitlab-ci.yml - -variables: - # If not using GitLab's HTTP backend, remove this line and specify TF_HTTP_* variables - TF_STATE_NAME: default - TF_CACHE_KEY: default -``` +WARNING: +The GitLab Terraform provider is released separately from GitLab. +We are working on migrating the GitLab Terraform provider for GitLab.com. -This template uses `.latest.`, instead of stable, and may include breaking changes. -This template also includes some opinionated decisions, which you can override: +You can use the [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab) +to manage various aspects of GitLab using Terraform. The provider is an open source project, +owned by GitLab, where everyone can contribute. -- Including the latest [GitLab Terraform Image](https://gitlab.com/gitlab-org/terraform-images). -- Using the [GitLab managed Terraform State](#gitlab-managed-terraform-state) as - the Terraform state storage backend. -- Creating [four pipeline stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml): - `init`, `validate`, `build`, and `deploy`. These stages - [run the Terraform commands](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml) - `init`, `validate`, `plan`, `plan-json`, and `apply`. The `apply` command only runs on `master`. +The [documentation of the provider](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs) +is available as part of the official Terraform provider documentations. diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md index b5d3b71e679..250fa618dd8 100644 --- a/doc/user/project/issues/crosslinking_issues.md +++ b/doc/user/project/issues/crosslinking_issues.md @@ -31,10 +31,9 @@ git commit -m "this is my commit message. Related to https://gitlab.com/<usernam Of course, you can replace `gitlab.com` with the URL of your own GitLab instance. -NOTE: -Linking your first commit to your issue is going to be relevant +Linking your first commit to your issue is relevant for tracking your process with [GitLab Value Stream Analytics](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/). -It will measure the time taken for planning the implementation of that issue, +It measures the time taken for planning the implementation of that issue, which is the time between creating an issue and making the first commit. ## From Related Issues @@ -45,7 +44,7 @@ issues regarding the same topic. You do that as explained above, when [mentioning an issue from a commit message](#from-commit-messages). -When mentioning issue `#111` in issue `#222`, issue `#111` will also display a notification +When mentioning issue `#111` in issue `#222`, issue `#111` also displays a notification in its tracker. That is, you only need to mention the relationship once for it to display in both issues. The same is valid when mentioning issues in [merge requests](#from-merge-requests). @@ -56,8 +55,8 @@ display in both issues. The same is valid when mentioning issues in [merge reque Mentioning issues in merge request comments works exactly the same way as they do for [related issues](#from-related-issues). -When you mention an issue in a merge request description, it will simply -[link the issue and merge request together](#from-related-issues). Additionally, +When you mention an issue in a merge request description, it +[links the issue and merge request together](#from-related-issues). Additionally, you can also [set an issue to close automatically](managing_issues.md#closing-issues-automatically) as soon as the merge request is merged. diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index 05e7eb3021a..74311eefd83 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -22,8 +22,8 @@ their implementation between: They can also be used for a variety of other purposes, customized to your needs and workflow. -Issues are always associated with a specific project, but if you have multiple projects in a group, -you can also view all the issues collectively at the group level. +Issues are always associated with a specific project. If you have multiple projects in a group, +you can view all of the issues collectively at the group level. **Common use cases include:** @@ -91,9 +91,13 @@ must be set. ## Viewing and managing issues -While you can view and manage the full details of an issue on the [issue page](#issue-page), -you can also work with multiple issues at a time using the [Issues List](#issues-list), -[Issue Boards](#issue-boards), Issue references, and [Epics](#epics). **(PREMIUM)** +While you can view and manage details of an issue on the [issue page](#issue-page), +you can also work with multiple issues at a time using: + +- [Issues List](#issues-list). +- [Issue Boards](#issue-boards). +- Issue references. +- [Epics](#epics) **(PREMIUM)**. Key actions for issues include: @@ -117,14 +121,17 @@ and modify them if you have the necessary [permissions](../../permissions.md). Assignees in the sidebar are updated in real time. This feature is **disabled by default**. To enable, you need to enable [ActionCable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html). -### Issues list +### Issues List + +![Project Issues List view](img/project_issues_list_view.png) + +On the Issues List, you can: -![Project issues list view](img/project_issues_list_view.png) +- View all issues in a project when opening the Issues List from a project context. +- View all issues in a groups's projects when opening the Issues List from a group context. -On the Issues List, you can view all issues in the current project, or from multiple -projects when opening the Issues List from the higher-level group context. Filter the -issue list with a [search query](../../search/index.md#filtering-issue-and-merge-request-lists), -including specific metadata, such as label(s), assignees(s), status, and more. From this +You can filter the Issues List with a [search query](../../search/index.md#filtering-issue-and-merge-request-lists), +including specific metadata, such as labels, assignees, status, and more. From this view, you can also make certain changes [in bulk](../bulk_editing.md) to the displayed issues. For more information, see the [Issue Data and Actions](issue_data_and_actions.md) page @@ -140,21 +147,21 @@ You can sort a list of issues in several ways, for example by issue creation dat labels or their assignees**(PREMIUM)**. They offer the flexibility to manage issues using highly customizable workflows. -You can reorder issues within a column. If you drag an issue card to another column, its -associated label or assignee will change to match that of the new column. The entire +You can reorder issues in the column. If you drag an issue card to another column, its +associated label or assignee is changed to match that of the new column. The entire board can also be filtered to only include issues from a certain milestone or an overarching label. ### Design Management With [Design Management](design_management.md), you can upload design -assets to issues and view them all together to easily share and -collaborate with your team. +assets to issues and view them all together for sharing and +collaboration with your team. ### Epics **(PREMIUM)** [Epics](../../group/epics/index.md) let you manage your portfolio of projects more -efficiently and with less effort by tracking groups of issues that share a theme, across +efficiently and with less effort. Epics track groups of issues that share a theme, across projects and milestones. ### Related issues @@ -179,10 +186,10 @@ message in the Activity stream about the reference, with a link to the other iss To prevent duplication of issues for the same topic, GitLab searches for similar issues when new issues are being created. -When typing in the title in the **New Issue** page, GitLab searches titles and descriptions -across all issues the user has access to in the current project. Up to five similar issues, -sorted by most recently updated, are displayed below the title box. Note that this feature -requires [GraphQL](../../../api/graphql/index.md) to be enabled. +As you type in the title field of the **New Issue** page, GitLab searches titles and descriptions +across all issues to in the current project. Only issues you have access to are returned. +Up to five similar issues, sorted by most recently updated, are displayed below the title box. +[GraphQL](../../../api/graphql/index.md) must be enabled to use this feature. ![Similar issues](img/similar_issues.png) @@ -193,8 +200,8 @@ requires [GraphQL](../../../api/graphql/index.md) to be enabled. > - Issue health status visible in issue lists [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45141) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.6. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/213567) in GitLab 13.7. -To help you track the status of your issues, you can assign a status to each issue to flag work -that's progressing as planned or needs attention to keep on schedule: +To help you track issue statuses, you can assign a status to each issue. +This marks issues as progressing as planned or needs attention to keep on schedule: - **On track** (green) - **Needs attention** (amber) diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md index 4f3ca12c582..52686d3c243 100644 --- a/doc/user/project/service_desk.md +++ b/doc/user/project/service_desk.md @@ -10,18 +10,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w > - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/214839) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.0. > - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/215364) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.2. -Service Desk is a module that allows your team to connect directly -with any external party through email right inside of GitLab; no external tools required. -An ongoing conversation right where your software is built ensures that user feedback ends -up directly where it's needed, helping you build the right features to solve your users' -real problems. +Service Desk is a module that allows your team to connect +with any external party through email, without any external tools. +An ongoing conversation in the same place as where your software +is built ensures user feedback ends up where it's needed. -With Service Desk, you can provide efficient email support to your customers, who can now -email you bug reports, feature requests, or general feedback that will all end up in your -GitLab project as new issues. In turn, your team can respond straight from the project. +With Service Desk, you can provide efficient email support to your customers. They can +email you bug reports, feature requests, or general feedback. They all end up in your +GitLab project as new issues. In turn, your team can respond directly from the project. As Service Desk is built right into GitLab itself, the complexity and inefficiencies -of multiple tools and external integrations are eliminated, significantly shortening +of multiple tools and external integrations are eliminated. This significantly shortens the cycle time from feedback to software update. For an overview, check the video demonstration on [GitLab Service Desk](https://about.gitlab.com/blog/2017/05/09/demo-service-desk/). @@ -32,10 +31,10 @@ For instance, let's assume you develop a game for iOS or Android. The codebase is hosted in your GitLab instance, built and deployed with GitLab CI/CD. -Here's how Service Desk will work for you: +Here's how Service Desk works for you: 1. You provide a project-specific email address to your paying customers, who can email you directly - from within the app. + from the application. 1. Each email they send creates an issue in the appropriate project. 1. Your team members navigate to the Service Desk issue tracker, where they can see new support requests and respond inside associated issues. @@ -43,19 +42,19 @@ Here's how Service Desk will work for you: 1. Your team starts working on implementing code to solve your customer's problem. 1. When your team finishes the implementation, whereupon the merge request is merged and the issue is closed automatically. -1. The customer will have been attended successfully via email, without having real access to your +1. The customer's requests are handled through email, without ever having access to your GitLab instance. 1. Your team saved time by not having to leave GitLab (or setup any integrations) to follow up with your customer. ## How it works -GitLab Service Desk is a simple way to allow people to create issues in your +GitLab Service Desk enables people to create issues in your GitLab instance without needing their own user account. -It provides a unique email address for end users to create issues in a project, -and replies can be sent either through the GitLab interface or by email. End -users will only see the thread through email. +It provides a unique email address for end users to create issues in a project. +Follow-up notes can be sent either through the GitLab interface or by email. End +users only see the thread through email. ## Configuring Service Desk @@ -71,15 +70,15 @@ Follow these steps to do so: but in GitLab 11.7 and later you can also use [catch-all mailboxes](../../administration/incoming_email.md#catch-all-mailbox). 1. Navigate to your project's **Settings > General** and locate the **Service Desk** section. 1. Enable the **Activate Service Desk** toggle. This reveals a unique email address to email issues - to the project. These issues will be [confidential](issues/confidential_issues.md), so they will - only be visible to project members. Note that in GitLab 11.7, we updated the generated email + to the project. These issues are [confidential](issues/confidential_issues.md), so they are + only visible to project members. Note that in GitLab 11.7, we updated the generated email address's format. The older format is still supported, however, allowing existing aliases or contacts to continue working. WARNING: - This email address can be used by anyone to create an issue on this project, whether or not they - have access to your GitLab instance. We recommend **putting this behind an alias** so it can be - changed if needed, and **[enabling Akismet](../../integration/akismet.md)** on your GitLab + This email address can be used by anyone to create an issue on this project, regardless + of their access level to your GitLab instance. We recommend **putting this behind an alias** so it can be + changed if needed. We also recommend **[enabling Akismet](../../integration/akismet.md)** on your GitLab instance to add spam checking to this service. Unblocked email spam would result in many spam issues being created. @@ -97,7 +96,10 @@ navigation's **Issues** menu. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2460) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.7. -When a user submits a new issue using Service Desk, or when a new note is created on a Service Desk issue, an email is sent to the author. +An email is sent to the author when: + +- A user submits a new issue using Service Desk. +- A new note is created on a Service Desk issue. The body of these email messages can be customized by using templates. To create a new customized template, create a new Markdown (`.md`) file inside the `.gitlab/service_desk_templates/` @@ -106,25 +108,30 @@ directory in your repository. Commit and push to your default branch. #### Thank you email The **Thank you email** is the email sent to a user after they submit an issue. -The file name of the template has to be `thank_you.md`. -You can use `%{ISSUE_ID}` placeholder which will be replaced by an issue IID in the email and -`%{ISSUE_PATH}` placeholder which will be replaced by project path and the issue IID. +The filename of the template has to be `thank_you.md`. +There are a few placeholders you can use which are automatically replaced in the email: + +- `%{ISSUE_ID}`: issue IID +- `%{ISSUE_PATH}`: project path appended with the issue IID + As the Service Desk issues are created as confidential (only project members can see them) the response email does not provide the issue link. #### New note email -The **New note email** is the email sent to a user when the issue they submitted has a new comment. -The file name of the template has to be `new_note.md`. -You can use `%{ISSUE_ID}` placeholder which will be replaced by an issue IID -in the email, `%{ISSUE_PATH}` placeholder which will be replaced by - project path and the issue IID and `%{NOTE_TEXT}` placeholder which will be replaced by the note text. +When a user-submitted issue receives a new comment, GitLab sends a **New note email** +to the user. The filename of this template must be `new_note.md`, and you can +use these placeholders in the email: + +- `%{ISSUE_ID}`: issue IID +- `%{ISSUE_PATH}`: project path appended with the issue IID +- `%{NOTE_TEXT}`: note text ### Using custom email display name > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7529) in GitLab 12.8. -You can customize the email display name. Emails sent from Service Desk will have +You can customize the email display name. Emails sent from Service Desk have this name in the `From` header. The default display name is `GitLab Support Bot`. ### Using custom email address **(CORE ONLY)** @@ -136,10 +143,9 @@ this name in the `From` header. The default display name is `GitLab Support Bot` > - It's recommended for production use. > - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#disable-custom-email-address). **(CORE ONLY)** -If the `service_desk_email` feature flag is enabled in your configuration, -then it's possible to create Service Desk issues by sending emails to the -custom Service Desk email address, which should have the following format: -`project_contact+%{key}@example.com`. +If the `service_desk_email` feature flag is enabled, then you can +create Service Desk issues by sending emails to the Service Desk email address. +The default address has the following format: `project_contact+%{key}@example.com`. The `%{key}` part is used to find the project where the issue should be created. The `%{key}` part combines the path to the project and configurable project name suffix: @@ -235,29 +241,31 @@ receive an email back confirming receipt: This also gives the end user an option to unsubscribe. If they don't choose to unsubscribe, then any new comments added to the issue -will be sent as emails: +are sent as emails: ![Service Desk reply email](img/service_desk_reply.png) -And any responses they send will be displayed in the issue itself. +Any responses they send via email are displayed in the issue itself. ### As a responder to the issue -For responders to the issue, everything works as usual. They will see a familiar looking -issue tracker, where they can see issues created via customer support requests and -filter and interact with them just like other GitLab issues. +For responders to the issue, everything works just like other GitLab issues. +GitLab displays a familiar-looking issue tracker where responders can see +issues created through customer support requests, and filter or interact with them. ![Service Desk Issue tracker](img/service_desk_issue_tracker.png) -Messages from the end user will show as coming from the special Support Bot user, but apart from that, -you can read and write comments as you normally do: +Messages from the end user are shown as coming from the special Support Bot user. Apart from this, +Messages from the end user are shown as coming from the special +[Support Bot user](../../subscriptions/self_managed/index.md#billable-users). +You can read and write comments as you normally do in GitLab: ![Service Desk issue thread](img/service_desk_thread.png) Note that: - The project's visibility (private, internal, public) does not affect Service Desk. -- The path to the project, including its group or namespace, will be shown on emails. +- The path to the project, including its group or namespace, are shown in emails. ### Support Bot user diff --git a/lib/gitlab/sourcegraph.rb b/lib/gitlab/sourcegraph.rb index 231d5aea129..7ef6ab32bd4 100644 --- a/lib/gitlab/sourcegraph.rb +++ b/lib/gitlab/sourcegraph.rb @@ -13,7 +13,8 @@ module Gitlab end def feature_enabled?(actor = nil) - feature.enabled?(actor) + # Some CI jobs grep for Feature.enabled? in our codebase, so it is important this reference stays around. + Feature.enabled?(:sourcegraph, actor) end private diff --git a/package.json b/package.json index 14c3fd8533e..b5bd5081489 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "sql.js": "^0.4.0", "stickyfilljs": "^2.1.0", "string-hash": "1.1.3", - "style-loader": "^1.1.3", + "style-loader": "^1.3.0", "swagger-ui-dist": "^3.32.4", "three": "^0.84.0", "three-orbit-controls": "^82.1.0", diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js index fef7676e795..55e744e573b 100644 --- a/spec/frontend/diffs/store/actions_spec.js +++ b/spec/frontend/diffs/store/actions_spec.js @@ -49,6 +49,7 @@ import { setCurrentDiffFileIdFromNote, navigateToDiffFileIndex, setFileByFile, + reviewFile, } from '~/diffs/store/actions'; import eventHub from '~/notes/event_hub'; import * as types from '~/diffs/store/mutation_types'; @@ -1472,4 +1473,46 @@ describe('DiffsStoreActions', () => { ); }); }); + + describe('reviewFile', () => { + const file = { + id: '123', + file_identifier_hash: 'abc', + load_collapsed_diff_url: 'gitlab-org/gitlab-test/-/merge_requests/1/diffs', + }; + it.each` + reviews | diffFile | reviewed + ${{ abc: ['123'] }} | ${file} | ${true} + ${{}} | ${file} | ${false} + `( + 'sets reviews ($reviews) to localStorage and state for file $file if it is marked reviewed=$reviewed', + ({ reviews, diffFile, reviewed }) => { + const commitSpy = jest.fn(); + const getterSpy = jest.fn().mockReturnValue([]); + + reviewFile( + { + commit: commitSpy, + getters: { + fileReviews: getterSpy, + }, + state: { + mrReviews: { abc: ['123'] }, + }, + }, + { + file: diffFile, + reviewed, + }, + ); + + expect(localStorage.setItem).toHaveBeenCalledTimes(1); + expect(localStorage.setItem).toHaveBeenCalledWith( + 'gitlab-org/gitlab-test/-/merge_requests/1-file-reviews', + JSON.stringify(reviews), + ); + expect(commitSpy).toHaveBeenCalledWith(types.SET_MR_FILE_REVIEWS, reviews); + }, + ); + }); }); diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js index 7e936c561fc..8cbcefa28d1 100644 --- a/spec/frontend/diffs/store/getters_spec.js +++ b/spec/frontend/diffs/store/getters_spec.js @@ -372,4 +372,26 @@ describe('Diffs Module Getters', () => { }); }); }); + + describe('fileReviews', () => { + const file1 = { id: '123', file_identifier_hash: 'abc' }; + const file2 = { id: '098', file_identifier_hash: 'abc' }; + + it.each` + reviews | files | fileReviews + ${{}} | ${[file1, file2]} | ${[false, false]} + ${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]} + ${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]} + ${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]} + ${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]} + `( + 'returns $fileReviews based on the diff files in state and the existing reviews $reviews', + ({ reviews, files, fileReviews }) => { + localState.diffFiles = files; + localState.mrReviews = reviews; + + expect(getters.fileReviews(localState)).toStrictEqual(fileReviews); + }, + ); + }); }); diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index 13e7cad835d..be187c49a20 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -906,4 +906,19 @@ describe('DiffsStoreMutations', () => { expect(state.viewDiffsFileByFile).toBe(value); }); }); + + describe('SET_MR_FILE_REVIEWS', () => { + it.each` + newReviews | oldReviews + ${{ abc: ['123'] }} | ${{}} + ${{ abc: [] }} | ${{ abc: ['123'] }} + ${{}} | ${{ abc: ['123'] }} + `('sets mrReviews to $newReviews', ({ newReviews, oldReviews }) => { + const state = { mrReviews: oldReviews }; + + mutations[types.SET_MR_FILE_REVIEWS](state, newReviews); + + expect(state.mrReviews).toStrictEqual(newReviews); + }); + }); }); diff --git a/spec/frontend/diffs/utils/file_reviews_spec.js b/spec/frontend/diffs/utils/file_reviews_spec.js new file mode 100644 index 00000000000..819426ee75f --- /dev/null +++ b/spec/frontend/diffs/utils/file_reviews_spec.js @@ -0,0 +1,146 @@ +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; + +import { + getReviewsForMergeRequest, + setReviewsForMergeRequest, + isFileReviewed, + markFileReview, + reviewable, +} from '~/diffs/utils/file_reviews'; + +function getDefaultReviews() { + return { + abc: ['123', '098'], + }; +} + +describe('File Review(s) utilities', () => { + const mrPath = 'my/fake/mr/42'; + const storageKey = `${mrPath}-file-reviews`; + const file = { id: '123', file_identifier_hash: 'abc' }; + const storedValue = JSON.stringify(getDefaultReviews()); + let reviews; + + useLocalStorageSpy(); + + beforeEach(() => { + reviews = getDefaultReviews(); + localStorage.clear(); + }); + + describe('getReviewsForMergeRequest', () => { + it('fetches the appropriate stored reviews from localStorage', () => { + getReviewsForMergeRequest(mrPath); + + expect(localStorage.getItem).toHaveBeenCalledTimes(1); + expect(localStorage.getItem).toHaveBeenCalledWith(storageKey); + }); + + it('returns an empty object if there have never been stored reviews for this MR', () => { + expect(getReviewsForMergeRequest(mrPath)).toStrictEqual({}); + }); + + it.each` + data + ${'+++'} + ${'{ lookinGood: "yeah!", missingClosingBrace: "yeah :(" '} + `( + "returns an empty object if the stored reviews are corrupted/aren't parseable as JSON (like: $data)", + ({ data }) => { + localStorage.getItem.mockReturnValueOnce(data); + + expect(getReviewsForMergeRequest(mrPath)).toStrictEqual({}); + }, + ); + + it('fetches the reviews for the MR if they exist', () => { + localStorage.setItem(storageKey, storedValue); + + expect(getReviewsForMergeRequest(mrPath)).toStrictEqual(reviews); + }); + }); + + describe('setReviewsForMergeRequest', () => { + it('sets the new value to localStorage', () => { + setReviewsForMergeRequest(mrPath, reviews); + + expect(localStorage.setItem).toHaveBeenCalledTimes(1); + expect(localStorage.setItem).toHaveBeenCalledWith(storageKey, storedValue); + }); + + it('returns the new value for chainability', () => { + expect(setReviewsForMergeRequest(mrPath, reviews)).toStrictEqual(reviews); + }); + }); + + describe('isFileReviewed', () => { + it.each` + description | diffFile | fileReviews + ${'the file does not have an `id`'} | ${{ ...file, id: undefined }} | ${getDefaultReviews()} + ${'there are no reviews for the file'} | ${file} | ${{ ...getDefaultReviews(), abc: undefined }} + `('returns `false` if $description', ({ diffFile, fileReviews }) => { + expect(isFileReviewed(fileReviews, diffFile)).toBe(false); + }); + + it("returns `true` for a file if it's available in the provided reviews", () => { + expect(isFileReviewed(reviews, file)).toBe(true); + }); + }); + + describe('reviewable', () => { + it.each` + response | diffFile | description + ${true} | ${file} | ${'has an `.id` and a `.file_identifier_hash`'} + ${false} | ${{ file_identifier_hash: 'abc' }} | ${'does not have an `.id`'} + ${false} | ${{ ...file, id: undefined }} | ${'has an undefined `.id`'} + ${false} | ${{ ...file, id: null }} | ${'has a null `.id`'} + ${false} | ${{ ...file, id: 0 }} | ${'has an `.id` set to 0'} + ${false} | ${{ ...file, id: false }} | ${'has an `.id` set to false'} + ${false} | ${{ id: '123' }} | ${'does not have a `.file_identifier_hash`'} + ${false} | ${{ ...file, file_identifier_hash: undefined }} | ${'has an undefined `.file_identifier_hash`'} + ${false} | ${{ ...file, file_identifier_hash: null }} | ${'has a null `.file_identifier_hash`'} + ${false} | ${{ ...file, file_identifier_hash: 0 }} | ${'has a `.file_identifier_hash` set to 0'} + ${false} | ${{ ...file, file_identifier_hash: false }} | ${'has a `.file_identifier_hash` set to false'} + `('returns `$response` when the file $description`', ({ response, diffFile }) => { + expect(reviewable(diffFile)).toBe(response); + }); + }); + + describe('markFileReview', () => { + it("adds a review when there's nothing that already exists", () => { + expect(markFileReview(null, file)).toStrictEqual({ abc: ['123'] }); + }); + + it("overwrites an existing review if it's for the same file (identifier hash)", () => { + expect(markFileReview(reviews, file)).toStrictEqual(getDefaultReviews()); + }); + + it('removes a review from the list when `reviewed` is `false`', () => { + expect(markFileReview(reviews, file, false)).toStrictEqual({ abc: ['098'] }); + }); + + it('adds a new review if the file ID is new', () => { + const updatedFile = { ...file, id: '098' }; + const allReviews = markFileReview({ abc: ['123'] }, updatedFile); + + expect(allReviews).toStrictEqual(getDefaultReviews()); + expect(allReviews.abc).toStrictEqual(['123', '098']); + }); + + it.each` + description | diffFile + ${'missing an `.id`'} | ${{ file_identifier_hash: 'abc' }} + ${'missing a `.file_identifier_hash`'} | ${{ id: '123' }} + `("doesn't modify the reviews if the file is $description", ({ diffFile }) => { + expect(markFileReview(reviews, diffFile)).toStrictEqual(getDefaultReviews()); + }); + + it('removes the file key if there are no more reviews for it', () => { + let updated = markFileReview(reviews, file, false); + + updated = markFileReview(updated, { ...file, id: '098' }, false); + + expect(updated).toStrictEqual({}); + }); + }); +}); diff --git a/spec/frontend/diffs/utils/merge_request_spec.js b/spec/frontend/diffs/utils/merge_request_spec.js new file mode 100644 index 00000000000..e949a70dfe7 --- /dev/null +++ b/spec/frontend/diffs/utils/merge_request_spec.js @@ -0,0 +1,19 @@ +import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request'; +import { diffMetadata } from '../mock_data/diff_metadata'; + +describe('Merge Request utilities', () => { + describe('getDerivedMergeRequestInformation', () => { + const endpoint = `${diffMetadata.latest_version_path}.json?searchParam=irrelevant`; + const mrPath = diffMetadata.latest_version_path.replace(/\/diffs$/, ''); + + it.each` + argument | response + ${{ endpoint }} | ${{ mrPath }} + ${{}} | ${{ mrPath: undefined }} + ${{ endpoint: undefined }} | ${{ mrPath: undefined }} + ${{ endpoint: null }} | ${{ mrPath: undefined }} + `('generates the correct derived results based on $argument', ({ argument, response }) => { + expect(getDerivedMergeRequestInformation(argument)).toStrictEqual(response); + }); + }); +}); diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js index 71a4f08cfb4..7f80fb56ee0 100644 --- a/spec/frontend/ide/components/repo_editor_spec.js +++ b/spec/frontend/ide/components/repo_editor_spec.js @@ -205,6 +205,8 @@ describe('RepoEditor', () => { beforeEach(done => { vm.file.name = 'file.dat'; vm.file.content = '🐱'; // non-ascii binary content + jest.spyOn(vm.editor, 'createInstance').mockImplementation(); + jest.spyOn(vm.editor, 'createDiffInstance').mockImplementation(); vm.$nextTick(done); }); @@ -212,6 +214,16 @@ describe('RepoEditor', () => { it('does not render the IDE', () => { expect(vm.shouldHideEditor).toBeTruthy(); }); + + it('does not call createInstance', async () => { + // Mirror the act's in the `createEditorInstance` + vm.createEditorInstance(); + + await vm.$nextTick(); + + expect(vm.editor.createInstance).not.toHaveBeenCalled(); + expect(vm.editor.createDiffInstance).not.toHaveBeenCalled(); + }); }); describe('createEditorInstance', () => { diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js index d2c32a81811..e9bdb9197bb 100644 --- a/spec/frontend/ide/services/index_spec.js +++ b/spec/frontend/ide/services/index_spec.js @@ -117,6 +117,21 @@ describe('IDE services', () => { it('sends a request to file.rawPath', () => { return services.getRawFileData(file).then(raw => { + expect(axios.get).toHaveBeenCalledWith(file.rawPath, { + transformResponse: [expect.any(Function)], + }); + expect(raw).toEqual('raw content'); + }); + }); + + it('returns arraybuffer for binary files', () => { + file.binary = true; + + return services.getRawFileData(file).then(raw => { + expect(axios.get).toHaveBeenCalledWith(file.rawPath, { + transformResponse: [expect.any(Function)], + responseType: 'arraybuffer', + }); expect(raw).toEqual('raw content'); }); }); diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index a71b0eb842a..0a6af753283 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -6275,28 +6275,6 @@ RSpec.describe Project, factory_default: :keep do end end - describe '#alerts_service_activated?' do - let!(:project) { create(:project) } - - subject { project.alerts_service_activated? } - - context 'when project has an activated alerts service' do - before do - create(:alerts_service, project: project) - end - - it { is_expected.to be_truthy } - end - - context 'when project has an inactive alerts service' do - before do - create(:alerts_service, :inactive, project: project) - end - - it { is_expected.to be_falsey } - end - end - describe '#prometheus_service_active?' do let(:project) { create(:project) } diff --git a/yarn.lock b/yarn.lock index 58e3a393196..85b811b84fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1304,10 +1304,10 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/json-schema@^7.0.3": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" - integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== "@types/minimatch@*": version "3.0.3" @@ -1684,15 +1684,15 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" integrity sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk= -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -7654,6 +7654,15 @@ loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2 emojis-list "^3.0.0" json5 "^1.0.1" +loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -10528,13 +10537,14 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.5.0, schema-utils@^2.6.1, schema-utils@^2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" - integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== +schema-utils@^2.0.0, schema-utils@^2.5.0, schema-utils@^2.6.1, schema-utils@^2.7.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== dependencies: - ajv "^6.10.2" - ajv-keywords "^3.4.1" + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" scope-css@^1.2.1: version "1.2.1" @@ -11299,13 +11309,13 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -style-loader@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.1.3.tgz#9e826e69c683c4d9bf9db924f85e9abb30d5e200" - integrity sha512-rlkH7X/22yuwFYK357fMN/BxYOorfnfq0eD7+vqlemSK4wEcejFF1dg4zxP0euBW8NrYx2WZzZ8PPFevr7D+Kw== +style-loader@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" + integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== dependencies: - loader-utils "^1.2.3" - schema-utils "^2.6.4" + loader-utils "^2.0.0" + schema-utils "^2.7.0" style-search@^0.1.0: version "0.1.0" |