summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.nvmrc2
-rw-r--r--app/assets/javascripts/boards/components/issue_due_date.vue4
-rw-r--r--app/assets/javascripts/deploy_keys/components/key.vue2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue1
-rw-r--r--app/assets/javascripts/diffs/store/actions.js8
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js1
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js2
-rw-r--r--app/assets/javascripts/error_tracking/components/error_details.vue4
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue6
-rw-r--r--app/assets/javascripts/issuable_suggestions/components/item.vue2
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue4
-rw-r--r--app/assets/javascripts/jobs/store/utils.js2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js18
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js6
-rw-r--r--app/assets/javascripts/mr_popover/components/mr_popover.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/time_ago.vue6
-rw-r--r--app/assets/javascripts/registry/list/components/table_registry.vue2
-rw-r--r--app/assets/javascripts/releases/list/components/release_block.vue2
-rw-r--r--app/assets/javascripts/releases/list/components/release_block_footer.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue2
-rw-r--r--app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js6
-rw-r--r--app/assets/javascripts/vue_shared/mixins/timeago.js2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--changelogs/unreleased/nfriend-atmtwps-merge-immediately-dialog.yml5
-rw-r--r--doc/user/application_security/container_scanning/index.md88
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/frontend/environments/environment_item_spec.js4
-rw-r--r--spec/frontend/jobs/components/erased_block_spec.js6
-rw-r--r--spec/frontend/registry/list/components/table_registry_spec.js2
-rw-r--r--spec/frontend/releases/list/components/release_block_footer_spec.js8
-rw-r--r--spec/frontend/releases/list/components/release_block_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js4
-rw-r--r--spec/javascripts/diffs/components/app_spec.js1
-rw-r--r--spec/javascripts/diffs/store/actions_spec.js4
-rw-r--r--spec/javascripts/diffs/store/mutations_spec.js4
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js22
39 files changed, 203 insertions, 48 deletions
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 {
<div role="rowheader" class="table-mobile-header">{{ __('Created') }}</div>
<div class="table-mobile-content text-secondary key-created-at">
<span v-tooltip :title="tooltipTitle(deployKey.created_at)">
- <icon name="calendar" /> <span>{{ timeFormated(deployKey.created_at) }}</span>
+ <icon name="calendar" /> <span>{{ timeFormatted(deployKey.created_at) }}</span>
</span>
</div>
</div>
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: `<strong>${this.error.culprit}</strong>`,
- 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 }}</time
+ >{{ lastCommitFormattedAge }}</time
>
</div>
<ide-status-list class="ml-auto" />
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 {
/>
<gl-tooltip :target="() => $refs.state" placement="bottom">
<span class="d-block">
- <span class="bold"> {{ stateTitle }} </span> {{ timeFormated(closedOrCreatedDate) }}
+ <span class="bold"> {{ stateTitle }} </span> {{ timeFormatted(closedOrCreatedDate) }}
</span>
<span class="text-tertiary">{{ tooltipTitle(closedOrCreatedDate) }}</span>
</gl-tooltip>
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 {
/>
<detail-row
v-if="job.finished_at"
- :value="timeFormated(job.finished_at)"
+ :value="timeFormatted(job.finished_at)"
class="js-job-finished"
title="Finished"
/>
<detail-row
v-if="job.erased_at"
- :value="timeFormated(job.erased_at)"
+ :value="timeFormatted(job.erased_at)"
class="js-job-erased"
title="Erased"
/>
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 {
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Duration') }}</div>
<div class="table-mobile-content">
<p v-if="hasDuration" class="duration">
- <span v-html="iconTimerSvg"> </span> {{ durationFormated }}
+ <span v-html="iconTimerSvg"> </span> {{ durationFormatted }}
</p>
<p v-if="hasFinishedTime" class="finished-at d-none d-sm-none d-md-block">
@@ -71,7 +71,7 @@ export default {
data-placement="top"
data-container="body"
>
- {{ timeFormated(finishedTime) }}
+ {{ timeFormatted(finishedTime) }}
</time>
</p>
</div>
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 {
<td>
<span v-gl-tooltip.bottom :title="tooltipTitle(item.createdAt)">{{
- timeFormated(item.createdAt)
+ timeFormatted(item.createdAt)
}}</span>
</td>
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)"
>
</time>
</template>
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('<span class="bold">Opened</span>');
- expect(stateTitle).toContain(`<span class="text-tertiary">${formatedCreateDate}</span>`);
+ expect(stateTitle).toContain(`<span class="text-tertiary">${formattedCreateDate}</span>`);
});
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',