diff --git a/.nvmrc b/.nvmrc index f8c17e78090..4de623cfefa 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12.4.0 +12.10.0 diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index 3bc7f13a9e6..a32ebdab5e1 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -35,10 +35,10 @@ export default { title() { const timeago = getTimeago(); const { timeDifference, standardDateFormat } = this; - const formatedDate = standardDateFormat; + const formattedDate = standardDateFormat; if (timeDifference >= -1 && timeDifference < 7) { - return `${timeago.format(this.issueDueDate)} (${formatedDate})`; + return `${timeago.format(this.issueDueDate)} (${formattedDate})`; } return timeago.format(this.issueDueDate); diff --git a/app/assets/javascripts/deploy_keys/components/key.vue b/app/assets/javascripts/deploy_keys/components/key.vue index 6ffb8c4e1c0..4d36a492c1c 100644 --- a/app/assets/javascripts/deploy_keys/components/key.vue +++ b/app/assets/javascripts/deploy_keys/components/key.vue @@ -159,7 +159,7 @@ export default {
{{ __('Created') }}
- {{ timeFormated(deployKey.created_at) }} + {{ timeFormatted(deployKey.created_at) }}
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 6cfc95c0117..8fc8a8d0495 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -177,6 +177,7 @@ export default { projectPath: this.projectPath, dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, + useSingleDiffStyle: this.glFeatures.singleMrDiffView, }); if (this.shouldShow) { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 1fab922d220..44672659f56 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -46,6 +46,7 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, } = options; commit(types.SET_BASE_CONFIG, { endpoint, @@ -54,11 +55,15 @@ export const setBaseConfig = ({ commit }, options) => { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, }); }; export const fetchDiffFiles = ({ state, commit }) => { const worker = new TreeWorker(); + const urlParams = { + w: state.showWhitespace ? '0' : '1', + }; commit(types.SET_LOADING, true); @@ -69,9 +74,10 @@ export const fetchDiffFiles = ({ state, commit }) => { }); return axios - .get(mergeUrlParams({ w: state.showWhitespace ? '0' : '1' }, state.endpoint)) + .get(mergeUrlParams(urlParams, state.endpoint)) .then(res => { commit(types.SET_LOADING, false); + commit(types.SET_MERGE_REQUEST_DIFFS, res.data.merge_request_diffs || []); commit(types.SET_DIFF_DATA, res.data); diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 8c52e3178e5..7366c50752c 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -31,4 +31,5 @@ export default () => ({ fileFinderVisible: false, dismissEndpoint: '', showSuggestPopover: true, + useSingleDiffStyle: false, }); diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index fccfd950d75..859f43b3b6d 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -19,6 +19,7 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, } = options; Object.assign(state, { endpoint, @@ -27,6 +28,7 @@ export default { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, }); }, diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 64e698a0bc9..9cf141589db 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -56,7 +56,7 @@ export default { __('Reported %{timeAgo} by %{reportedBy}'), { reportedBy: `${this.error.culprit}`, - timeAgo: this.timeFormated(this.stacktraceData.date_received), + timeAgo: this.timeFormatted(this.stacktraceData.date_received), }, false, ); @@ -107,7 +107,7 @@ export default { this.$refs.sentryIssueForm.submit(); }, formatDate(date) { - return `${this.timeFormated(date)} (${dateFormat(date, 'UTC:yyyy-mm-dd h:MM:ssTT Z')})`; + return `${this.timeFormatted(date)} (${dateFormat(date, 'UTC:yyyy-mm-dd h:MM:ssTT Z')})`; }, }, }; diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index 326589fa50f..6eaf08e8033 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -22,7 +22,7 @@ export default { mixins: [timeAgoMixin], data() { return { - lastCommitFormatedAge: null, + lastCommitFormattedAge: null, }; }, computed: { @@ -62,7 +62,7 @@ export default { }, commitAgeUpdate() { if (this.lastCommit) { - this.lastCommitFormatedAge = this.timeFormated(this.lastCommit.committed_date); + this.lastCommitFormattedAge = this.timeFormatted(this.lastCommit.committed_date); } }, getCommitPath(shortSha) { @@ -118,7 +118,7 @@ export default { :title="tooltipTitle(lastCommit.committed_date)" data-placement="top" data-container="body" - >{{ lastCommitFormatedAge }}{{ lastCommitFormattedAge }} diff --git a/app/assets/javascripts/issuable_suggestions/components/item.vue b/app/assets/javascripts/issuable_suggestions/components/item.vue index 7629e04684c..66a4cc44d51 100644 --- a/app/assets/javascripts/issuable_suggestions/components/item.vue +++ b/app/assets/javascripts/issuable_suggestions/components/item.vue @@ -91,7 +91,7 @@ export default { /> - {{ stateTitle }} {{ timeFormated(closedOrCreatedDate) }} + {{ stateTitle }} {{ timeFormatted(closedOrCreatedDate) }} {{ tooltipTitle(closedOrCreatedDate) }} diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index 1df57f1aa14..415fa46835b 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -168,13 +168,13 @@ export default { /> diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js index 179d0bc4e0f..0b28c52a78f 100644 --- a/app/assets/javascripts/jobs/store/utils.js +++ b/app/assets/javascripts/jobs/store/utils.js @@ -114,7 +114,7 @@ export const logLinesParser = (lines = [], accumulator = []) => acc.push(parseHeaderLine(line, lineNumber)); } else if (isCollapsibleSection(acc, last, line)) { // if the object belongs to a nested section, we append it to the new `lines` array of the - // previously formated header + // previously formatted header last.lines.push(parseLine(line, lineNumber)); } else if (line.section_duration) { // if the line has section_duration, we look for the correct header to add it diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 177ae4f9838..ddd698fefeb 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -5,7 +5,7 @@ import $ from 'jquery'; import axios from './axios_utils'; import { getLocationHash } from './url_utility'; -import { convertToCamelCase } from './text_utility'; +import { convertToCamelCase, convertToSnakeCase } from './text_utility'; import { isObject } from './type_utility'; import breakpointInstance from '../../breakpoints'; @@ -697,6 +697,22 @@ export const convertObjectPropsToCamelCase = (obj = {}, options = {}) => { }, initial); }; +/** + * Converts all the object keys to snake case + * + * @param {Object} obj Object to transform + * @returns {Object} + */ +// Follow up to add additional options param: +// https://gitlab.com/gitlab-org/gitlab/issues/39173 +export const convertObjectPropsToSnakeCase = (obj = {}) => + obj + ? Object.entries(obj).reduce( + (acc, [key, value]) => ({ ...acc, [convertToSnakeCase(key)]: value }), + {}, + ) + : {}; + export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index bc742179279..996692bacb3 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -447,7 +447,7 @@ export const parsePikadayDate = dateString => { /** * Used `onSelect` method in pickaday * @param {Date} date UTC format - * @return {String} Date formated in yyyy-mm-dd + * @return {String} Date formatted in yyyy-mm-dd */ export const pikadayToString = date => { const day = pad(date.getDate()); @@ -513,8 +513,8 @@ export const stringifyTime = (timeObject, fullNameFormat = false) => { if (fullNameFormat && isNonZero) { // Remove traling 's' if unit value is singular - const formatedUnitName = unitValue > 1 ? unitName : unitName.replace(/s$/, ''); - return `${memo} ${unitValue} ${formatedUnitName}`; + const formattedUnitName = unitValue > 1 ? unitName : unitName.replace(/s$/, ''); + return `${memo} ${unitValue} ${formattedUnitName}`; } return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; diff --git a/app/assets/javascripts/mr_popover/components/mr_popover.vue b/app/assets/javascripts/mr_popover/components/mr_popover.vue index b81600660f6..ce08b0964a1 100644 --- a/app/assets/javascripts/mr_popover/components/mr_popover.vue +++ b/app/assets/javascripts/mr_popover/components/mr_popover.vue @@ -45,7 +45,7 @@ export default { return this.mergeRequest.headPipeline && this.mergeRequest.headPipeline.detailedStatus; }, formattedTime() { - return this.timeFormated(this.mergeRequest.createdAt); + return this.timeFormatted(this.mergeRequest.createdAt); }, statusBoxClass() { switch (this.mergeRequest.state) { diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue index 2ed0c24825c..2a23a0f6744 100644 --- a/app/assets/javascripts/pipelines/components/time_ago.vue +++ b/app/assets/javascripts/pipelines/components/time_ago.vue @@ -31,7 +31,7 @@ export default { hasFinishedTime() { return this.finishedTime !== ''; }, - durationFormated() { + durationFormatted() { const date = new Date(this.duration * 1000); let hh = date.getUTCHours(); @@ -59,7 +59,7 @@ export default {
{{ s__('Pipeline|Duration') }}

- {{ durationFormated }} + {{ durationFormatted }}

@@ -71,7 +71,7 @@ export default { data-placement="top" data-container="body" > - {{ timeFormated(finishedTime) }} + {{ timeFormatted(finishedTime) }}

diff --git a/app/assets/javascripts/registry/list/components/table_registry.vue b/app/assets/javascripts/registry/list/components/table_registry.vue index e682a0e0019..4e14db7f578 100644 --- a/app/assets/javascripts/registry/list/components/table_registry.vue +++ b/app/assets/javascripts/registry/list/components/table_registry.vue @@ -247,7 +247,7 @@ export default { {{ - timeFormated(item.createdAt) + timeFormatted(item.createdAt) }} diff --git a/app/assets/javascripts/releases/list/components/release_block.vue b/app/assets/javascripts/releases/list/components/release_block.vue index 09ef857ae4a..4d8d8682401 100644 --- a/app/assets/javascripts/releases/list/components/release_block.vue +++ b/app/assets/javascripts/releases/list/components/release_block.vue @@ -48,7 +48,7 @@ export default { }, releasedTimeAgo() { return sprintf(__('released %{time}'), { - time: this.timeFormated(this.release.released_at), + time: this.timeFormatted(this.release.released_at), }); }, userImageAltDescription() { diff --git a/app/assets/javascripts/releases/list/components/release_block_footer.vue b/app/assets/javascripts/releases/list/components/release_block_footer.vue index 4189268eea9..8533fc17ffd 100644 --- a/app/assets/javascripts/releases/list/components/release_block_footer.vue +++ b/app/assets/javascripts/releases/list/components/release_block_footer.vue @@ -50,7 +50,7 @@ export default { }, computed: { releasedAtTimeAgo() { - return this.timeFormated(this.releasedAt); + return this.timeFormatted(this.releasedAt); }, userImageAltDescription() { return this.author && this.author.username diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue index 47e70e972cf..db4a4ece002 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue @@ -41,7 +41,7 @@ export default { }, computed: { deployTimeago() { - return this.timeFormated(this.deployment.deployed_at); + return this.timeFormatted(this.deployment.deployed_at); }, deployedText() { return this.$options.deployedTextMap[this.computedDeploymentStatus]; diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue b/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue index 9b2ee5062b1..cfbc5b0df3c 100644 --- a/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue +++ b/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue @@ -54,7 +54,7 @@ export default { return timeFor( this.milestoneDue, sprintf(__('Expired %{expiredOn}'), { - expiredOn: this.timeFormated(this.milestoneDue), + expiredOn: this.timeFormatted(this.milestoneDue), }), ); } @@ -62,7 +62,7 @@ export default { return sprintf( this.isMilestoneStarted ? __('Started %{startsIn}') : __('Starts %{startsIn}'), { - startsIn: this.timeFormated(this.milestoneStart), + startsIn: this.timeFormatted(this.milestoneStart), }, ); } diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue index c1f3d86335a..80c61627b8f 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue @@ -64,7 +64,7 @@ export default { tooltipText(dateType = 'min') { const defaultText = dateType === 'min' ? __('Start date') : __('Due date'); const date = this[`${dateType}Date`]; - const timeAgo = dateType === 'min' ? this.timeFormated(date) : timeFor(date); + const timeAgo = dateType === 'min' ? this.timeFormatted(date) : timeFor(date); const dateText = date ? [this.dateText(dateType), `(${timeAgo})`].join(' ') : ''; if (date) { diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue index 43935cf31d5..b1a4f3dccaf 100644 --- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue +++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue @@ -35,7 +35,7 @@ export default { v-gl-tooltip.viewport="{ placement: tooltipPlacement }" :class="cssClass" :title="tooltipTitle(time)" - v-text="timeFormated(time)" + v-text="timeFormatted(time)" > diff --git a/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js index 3c727cb7b3f..fbebd7c7945 100644 --- a/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js +++ b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js @@ -159,7 +159,7 @@ const mixins = { return this.displayReference.split(this.pathIdSeparator).pop(); }, createdAtInWords() { - return this.createdAt ? this.timeFormated(this.createdAt) : ''; + return this.createdAt ? this.timeFormatted(this.createdAt) : ''; }, createdAtTimestamp() { return this.createdAt ? formatDate(new Date(this.createdAt)) : ''; @@ -168,10 +168,10 @@ const mixins = { return this.mergedAt ? formatDate(new Date(this.mergedAt)) : ''; }, mergedAtInWords() { - return this.mergedAt ? this.timeFormated(this.mergedAt) : ''; + return this.mergedAt ? this.timeFormatted(this.mergedAt) : ''; }, closedAtInWords() { - return this.closedAt ? this.timeFormated(this.closedAt) : ''; + return this.closedAt ? this.timeFormatted(this.closedAt) : ''; }, closedAtTimestamp() { return this.closedAt ? formatDate(new Date(this.closedAt)) : ''; diff --git a/app/assets/javascripts/vue_shared/mixins/timeago.js b/app/assets/javascripts/vue_shared/mixins/timeago.js index 4e3b9d7b767..af14c6d9486 100644 --- a/app/assets/javascripts/vue_shared/mixins/timeago.js +++ b/app/assets/javascripts/vue_shared/mixins/timeago.js @@ -5,7 +5,7 @@ import { formatDate, getTimeago } from '../../lib/utils/datetime_utility'; */ export default { methods: { - timeFormated(time) { + timeFormatted(time) { const timeago = getTimeago(); return timeago.format(time); diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 07f568e2a04..69e3e7c7acb 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -20,6 +20,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :check_user_can_push_to_source_branch!, only: [:rebase] before_action only: [:show] do push_frontend_feature_flag(:diffs_batch_load, @project) + push_frontend_feature_flag(:single_mr_diff_view, @project) end before_action do diff --git a/changelogs/unreleased/nfriend-atmtwps-merge-immediately-dialog.yml b/changelogs/unreleased/nfriend-atmtwps-merge-immediately-dialog.yml new file mode 100644 index 00000000000..eb3323f8630 --- /dev/null +++ b/changelogs/unreleased/nfriend-atmtwps-merge-immediately-dialog.yml @@ -0,0 +1,5 @@ +--- +title: Show merge immediately dialog even if the MR's pipeline hasn't finished +merge_request: 21556 +author: +type: changed diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 2b021264345..08242b3c65b 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -219,6 +219,94 @@ build_latest_vulnerabilities: The above template will work for a GitLab Docker registry running on a local installation, however, if you're using a non-GitLab Docker registry, you'll need to change the `$CI_REGISTRY` value and the `docker login` credentials to match the details of your local registry. +## Reports JSON format + +CAUTION: **Caution:** +The JSON report artifacts are not a public API of Container Scanning and their format may change in the future. + +The Container Scanning tool emits a JSON report file. Here is an example of the report structure with all important parts of +it highlighted: + +```json-doc +{ + "version": "2.3", + "vulnerabilities": [ + { + "category": "container_scanning", + "message": "CVE-2019-3462 in apt", + "description": "Incorrect sanitation of the 302 redirect field in HTTP transport method of apt versions 1.4.8 and earlier can lead to content injection by a MITM attacker, potentially leading to remote code execution on the target machine.", + "cve": "debian:9:apt:CVE-2019-3462", + "severity": "High", + "confidence": "Unknown", + "solution": "Upgrade apt from 1.4.8 to 1.4.9", + "scanner": { + "id": "klar", + "name": "klar" + }, + "location": { + "dependency": { + "package": { + "name": "apt" + }, + "version": "1.4.8" + }, + "operating_system": "debian:9", + "image": "registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-3462", + "value": "CVE-2019-3462", + "url": "https://security-tracker.debian.org/tracker/CVE-2019-3462" + } + ], + "links": [ + { + "url": "https://security-tracker.debian.org/tracker/CVE-2019-3462" + } + ] + } + ], + "remediations": [ + ] +} +``` + +Here is the description of the report file structure nodes and their meaning. All fields are mandatory to be present in +the report JSON unless stated otherwise. Presence of optional fields depends on the underlying analyzers being used. + +| Report JSON node | Description | +|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `version` | Report syntax version used to generate this JSON. | +| `vulnerabilities` | Array of vulnerability objects. | +| `vulnerabilities[].category` | Where this vulnerability belongs (SAST, Container Scanning etc.). For Container Scanning, it will always be `container_scanning`. | +| `vulnerabilities[].message` | A short text that describes the vulnerability, it may include occurrence's specific information. Optional. | +| `vulnerabilities[].description` | A long text that describes the vulnerability. Optional. | +| `vulnerabilities[].cve` | A fingerprint string value that represents a concrete occurrence of the vulnerability. It's used to determine whether two vulnerability occurrences are same or different. May not be 100% accurate. **This is NOT a [CVE](https://cve.mitre.org/)**. | +| `vulnerabilities[].severity` | How much the vulnerability impacts the software. Possible values: `Undefined` (an analyzer has not provided this info), `Info`, `Unknown`, `Low`, `Medium`, `High`, `Critical`. **Note:** Our current container scanning tool based on [klar](https://github.com/optiopay/klar) only provides the following levels: `Unknown`, `Low`, `Medium`, `High`, `Critical`. | +| `vulnerabilities[].confidence` | How reliable the vulnerability's assessment is. Possible values: `Undefined` (an analyzer has not provided this info), `Ignore`, `Unknown`, `Experimental`, `Low`, `Medium`, `High`, `Confirmed`. **Note:** Our current container scanning tool based on [klar](https://github.com/optiopay/klar) does not provide a confidence level, so this value is currently hardcoded to `Unknown`. | +| `vulnerabilities[].solution` | Explanation of how to fix the vulnerability. Optional. | +| `vulnerabilities[].scanner` | A node that describes the analyzer used to find this vulnerability. | +| `vulnerabilities[].scanner.id` | Id of the scanner as a snake_case string. | +| `vulnerabilities[].scanner.name` | Name of the scanner, for display purposes. | +| `vulnerabilities[].location` | A node that tells where the vulnerability is located. | +| `vulnerabilities[].location.dependency` | A node that describes the dependency of a project where the vulnerability is located. | +| `vulnerabilities[].location.dependency.package` | A node that provides the information on the package where the vulnerability is located. | +| `vulnerabilities[].location.dependency.package.name` | Name of the package where the vulnerability is located. | +| `vulnerabilities[].location.dependency.version` | Version of the vulnerable package. Optional. | +| `vulnerabilities[].location.operating_system` | The operating system that contains the vulnerable package. | +| `vulnerabilities[].location.image` | The Docker image that was analyzed. Optional. | +| `vulnerabilities[].identifiers` | An ordered array of references that identify a vulnerability on internal or external DBs. | +| `vulnerabilities[].identifiers[].type` | Type of the identifier. Possible values: common identifier types (among `cve`, `cwe`, `osvdb`, and `usn`). | +| `vulnerabilities[].identifiers[].name` | Name of the identifier for display purpose. | +| `vulnerabilities[].identifiers[].value` | Value of the identifier for matching purpose. | +| `vulnerabilities[].identifiers[].url` | URL to identifier's documentation. Optional. | +| `vulnerabilities[].links` | An array of references to external documentation pieces or articles that describe the vulnerability further. Optional. | +| `vulnerabilities[].links[].name` | Name of the vulnerability details link. Optional. | +| `vulnerabilities[].links[].url` | URL of the vulnerability details document. Optional. | +| `remediations` | Not supported yet. | + ## Troubleshooting ### docker: Error response from daemon: failed to copy xattrs diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3b9370fee12..edd41166e5d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5202,6 +5202,9 @@ msgstr "" msgid "CustomCycleAnalytics|Add stage" msgstr "" +msgid "CustomCycleAnalytics|Editing stage" +msgstr "" + msgid "CustomCycleAnalytics|Enter a name for the stage" msgstr "" @@ -5235,6 +5238,9 @@ msgstr "" msgid "CustomCycleAnalytics|Stop event label" msgstr "" +msgid "CustomCycleAnalytics|Update stage" +msgstr "" + msgid "Customize colors" msgstr "" diff --git a/spec/frontend/environments/environment_item_spec.js b/spec/frontend/environments/environment_item_spec.js index 6184df0fdc2..52625c64a1c 100644 --- a/spec/frontend/environments/environment_item_spec.js +++ b/spec/frontend/environments/environment_item_spec.js @@ -45,9 +45,9 @@ describe('Environment item', () => { }); it('should render last deployment date', () => { - const formatedDate = format(environment.last_deployment.deployed_at); + const formattedDate = format(environment.last_deployment.deployed_at); - expect(wrapper.find('.environment-created-date-timeago').text()).toContain(formatedDate); + expect(wrapper.find('.environment-created-date-timeago').text()).toContain(formattedDate); }); describe('With user information', () => { diff --git a/spec/frontend/jobs/components/erased_block_spec.js b/spec/frontend/jobs/components/erased_block_spec.js index 5e6570f72e0..c7a53197fad 100644 --- a/spec/frontend/jobs/components/erased_block_spec.js +++ b/spec/frontend/jobs/components/erased_block_spec.js @@ -8,7 +8,7 @@ describe('Erased block', () => { const erasedAt = '2016-11-07T11:11:16.525Z'; const timeago = getTimeago(); - const formatedDate = timeago.format(erasedAt); + const formattedDate = timeago.format(erasedAt); const createComponent = props => { wrapper = mount(ErasedBlock, { @@ -41,7 +41,7 @@ describe('Erased block', () => { }); it('renders erasedAt', () => { - expect(wrapper.text().trim()).toContain(formatedDate); + expect(wrapper.text().trim()).toContain(formattedDate); }); }); @@ -57,7 +57,7 @@ describe('Erased block', () => { }); it('renders erasedAt', () => { - expect(wrapper.text().trim()).toContain(formatedDate); + expect(wrapper.text().trim()).toContain(formattedDate); }); }); }); diff --git a/spec/frontend/registry/list/components/table_registry_spec.js b/spec/frontend/registry/list/components/table_registry_spec.js index 1d31381c85b..fe099adbdfb 100644 --- a/spec/frontend/registry/list/components/table_registry_spec.js +++ b/spec/frontend/registry/list/components/table_registry_spec.js @@ -68,7 +68,7 @@ describe('table registry', () => { expect(tds.at(2).html()).toContain(repoPropsData.list[0].shortRevision); expect(tds.at(3).html()).toContain(repoPropsData.list[0].layers); expect(tds.at(3).html()).toContain(repoPropsData.list[0].size); - expect(tds.at(4).html()).toContain(wrapper.vm.timeFormated(repoPropsData.list[0].createdAt)); + expect(tds.at(4).html()).toContain(wrapper.vm.timeFormatted(repoPropsData.list[0].createdAt)); }); it('should have a label called Image ID', () => { diff --git a/spec/frontend/releases/list/components/release_block_footer_spec.js b/spec/frontend/releases/list/components/release_block_footer_spec.js index 36a94b21df1..7652acbdd62 100644 --- a/spec/frontend/releases/list/components/release_block_footer_spec.js +++ b/spec/frontend/releases/list/components/release_block_footer_spec.js @@ -8,8 +8,8 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; jest.mock('~/vue_shared/mixins/timeago', () => ({ methods: { - timeFormated() { - return '7 fortnightes ago'; + timeFormatted() { + return '7 fortnights ago'; }, tooltipTitle() { return 'February 30, 2401'; @@ -82,7 +82,7 @@ describe('Release block footer', () => { it('renders the author and creation time info', () => { expect(trimText(authorDateInfoSection().text())).toBe( - `Created 7 fortnightes ago by ${releaseClone.author.username}`, + `Created 7 fortnights ago by ${releaseClone.author.username}`, ); }); @@ -139,7 +139,7 @@ describe('Release block footer', () => { beforeEach(() => factory({ author: undefined })); it('renders the release date without the author name', () => { - expect(trimText(authorDateInfoSection().text())).toBe('Created 7 fortnightes ago'); + expect(trimText(authorDateInfoSection().text())).toBe('Created 7 fortnights ago'); }); }); diff --git a/spec/frontend/releases/list/components/release_block_spec.js b/spec/frontend/releases/list/components/release_block_spec.js index c83af01f6e0..38c5e4fc0a2 100644 --- a/spec/frontend/releases/list/components/release_block_spec.js +++ b/spec/frontend/releases/list/components/release_block_spec.js @@ -68,7 +68,7 @@ describe('Release block', () => { }); it('renders release date', () => { - expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormated(release.released_at)); + expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at)); }); it('renders number of assets provided', () => { diff --git a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js index 1500bdf9c70..3cc640cb00d 100644 --- a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js +++ b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js @@ -90,11 +90,11 @@ describe('RelatedIssuableItem', () => { it('renders state title', () => { const stateTitle = tokenState.attributes('title'); - const formatedCreateDate = formatDate(props.createdAt); + const formattedCreateDate = formatDate(props.createdAt); expect(stateTitle).toContain('Opened'); - expect(stateTitle).toContain(`${formatedCreateDate}`); + expect(stateTitle).toContain(`${formattedCreateDate}`); }); it('renders aria label', () => { diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js index dbeff7284ce..b21cab58b4e 100644 --- a/spec/javascripts/diffs/components/app_spec.js +++ b/spec/javascripts/diffs/components/app_spec.js @@ -41,6 +41,7 @@ describe('diffs/components/app', () => { changesEmptyStateIllustration: '', dismissEndpoint: '', showSuggestPopover: true, + useSingleDiffStyle: false, ...props, }, store, diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 95fd43367e5..163d530a2b6 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -75,6 +75,7 @@ describe('DiffsStoreActions', () => { const projectPath = '/root/project'; const dismissEndpoint = '/-/user_callouts'; const showSuggestPopover = false; + const useSingleDiffStyle = false; testAction( setBaseConfig, @@ -85,6 +86,7 @@ describe('DiffsStoreActions', () => { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, }, { endpoint: '', @@ -93,6 +95,7 @@ describe('DiffsStoreActions', () => { projectPath: '', dismissEndpoint: '', showSuggestPopover: true, + useSingleDiffStyle: true, }, [ { @@ -104,6 +107,7 @@ describe('DiffsStoreActions', () => { projectPath, dismissEndpoint, showSuggestPopover, + useSingleDiffStyle, }, }, ], diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 19bf5bdd592..13f16e4f9a6 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -10,11 +10,13 @@ describe('DiffsStoreMutations', () => { const state = {}; const endpoint = '/diffs/endpoint'; const projectPath = '/root/project'; + const useSingleDiffStyle = false; - mutations[types.SET_BASE_CONFIG](state, { endpoint, projectPath }); + mutations[types.SET_BASE_CONFIG](state, { endpoint, projectPath, useSingleDiffStyle }); expect(state.endpoint).toEqual(endpoint); expect(state.projectPath).toEqual(projectPath); + expect(state.useSingleDiffStyle).toEqual(useSingleDiffStyle); }); }); diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 484133c9ac4..e471be608c8 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -721,6 +721,28 @@ describe('common_utils', () => { }); }); + describe('convertObjectPropsToSnakeCase', () => { + it('converts each object key to snake case', () => { + const obj = { + some: 'some', + 'cool object': 'cool object', + likeThisLongOne: 'likeThisLongOne', + }; + + expect(commonUtils.convertObjectPropsToSnakeCase(obj)).toEqual({ + some: 'some', + cool_object: 'cool object', + like_this_long_one: 'likeThisLongOne', + }); + }); + + it('returns an empty object if there are no keys', () => { + ['', {}, [], null].forEach(badObj => { + expect(commonUtils.convertObjectPropsToSnakeCase(badObj)).toEqual({}); + }); + }); + }); + describe('with options', () => { const objWithoutChildren = { project_name: 'GitLab CE',