Commit 1db2cad4 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge commit 'f6720560' into...

Merge commit 'f6720560' into feature/gb/cross-project-pipeline-trigger

* commit 'f6720560': (101 commits)
parents b1e40bce f6720560
......@@ -11,5 +11,3 @@
/vendor/
karma.config.js
webpack.config.js
ee/app/assets/javascripts/shared/snowplow/sp.js
......@@ -79,7 +79,7 @@ stages:
.use-mysql: &use-mysql
services:
- mysql:5.7
- mysql:5.7.24
- redis:alpine
# BEGIN EE-only service helpers
......@@ -102,7 +102,7 @@ stages:
.use-mysql-with-elasticsearch: &use-mysql-with-elasticsearch
services:
- mysql:5.7
- mysql:5.7.24
- redis:alpine
- docker.elastic.co/elasticsearch/elasticsearch:5.6.12
......@@ -548,15 +548,7 @@ setup-test-env:
- vendor/gitaly-ruby
# GitLab Review apps
.review-base: &review-base
<<: *dedicated-no-docs-no-db-pull-cache-job
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
stage: test
cache: {}
dependencies: []
environment: &review-environment
name: review/${CI_COMMIT_REF_NAME}
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
.review-only: &review-only
only:
refs:
- branches@gitlab-org/gitlab-ce
......@@ -566,6 +558,17 @@ setup-test-env:
refs:
- master
- /(^docs[\/-].*|.*-docs$)/
.review-base: &review-base
<<: *dedicated-no-docs-no-db-pull-cache-job
<<: *review-only
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
stage: test
cache: {}
dependencies: []
environment: &review-environment
name: review/${CI_COMMIT_REF_NAME}
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
before_script: []
.review-docker: &review-docker
......@@ -1115,6 +1118,21 @@ no_ee_check:
- //@gitlab-org/gitlab-ce
# GitLab Review apps
review-build-cng:
<<: *single-script-job
<<: *review-only
variables:
<<: *single-script-job-variables
SCRIPT_NAME: trigger-build
script:
- gem install gitlab --no-document
- apk add --update openssl curl jq
- wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/review_apps/review-apps.sh
- chmod 755 review-apps.sh
- source ./review-apps.sh
- wait_for_job_to_be_done "gitlab:assets:compile"
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./$SCRIPT_NAME cng
review-deploy:
<<: *review-base
retry: 2
......@@ -1129,15 +1147,14 @@ review-deploy:
<<: *review-environment
on_stop: review-stop
before_script:
- apk update && apk add jq
- gem install gitlab --no-document
script:
- export GITLAB_SHELL_VERSION=$(<GITLAB_SHELL_VERSION)
- export GITALY_VERSION=$(<GITALY_SERVER_VERSION)
- export GITLAB_WORKHORSE_VERSION=$(<GITLAB_WORKHORSE_VERSION)
- apk update && apk add jq
- gem install gitlab --no-document
- source ./scripts/review_apps/review-apps.sh
- wait_for_job_to_be_done "gitlab:assets:compile"
- BUILD_TRIGGER_TOKEN=$REVIEW_APPS_BUILD_TRIGGER_TOKEN ./scripts/trigger-build cng
script:
- wait_for_job_to_be_done "review-build-cng"
- check_kube_domain
- download_gitlab_chart
- ensure_namespace
......@@ -1148,7 +1165,6 @@ review-deploy:
.review-qa-base: &review-qa-base
<<: *review-docker
retry: 2
allow_failure: true
variables:
<<: *review-docker-variables
......
......@@ -146,6 +146,7 @@ Naming/FileName:
- XMPP
- XSRF
- XSS
- GRPC
# GitLab ###################################################################
......
Please view this file on the master branch, on stable branches it's out of date.
## 11.7.0 (2019-01-22)
### Security (1 change)
- Add a shared secret to prevent abuse of the alert endpoint.
### Fixed (27 changes, 2 of them are from the community)
- Defaults to feature flags link for Operations entry. !8622
- Fix error on explore page when logged out due to gold trial callout. !8674
- Prevents the empty state from showing when the dashboard errors. !8703
- Allow matching only the repo-root for CODEOWNERS. !8708
- Fix adding labels to epics using quick actions. !8772
- Geo: Keep the minimum cursor last event. !8832
- Reinstate sorting issuable by weight. !8834
- Geo - Show the proper label for the last repository check run on Geo projects page. !8844
- Resolve Reorder gitlab:elastic:index rake tasks to ensure wikis and database are completed even if projects error out. !8852
- Remove dash on issue weight for unauthorized users. !8882 (George Tsiolis)
- Dismiss epic promotion and persist it across reloads. !8885
- Fix JIRA Development Panel links with subgroups. !8908
- Remove epic field in sidebar for projects without groups. !8919
- Remove duplicate padding from issue board switcher. !8928
- Resolve Ctrl+Enter immediately adds MR comment. !8932
- Geo: Ignore invalid attributes when updating Geo node status. !8957
- Fix border-radius for related issues. !8958 (Johann Hubert Sonntagbauer)
- Fix Security Dashboard Header font size. !9011
- Fix title and description for issue created from a vulnerability. !9022
- Pseudonymizer: Gracefully handle empty pseudo entries. !9044
- Fix permission check when creating an issue from a vulnerability. !9055
- Docfix - broken doc links for Secure/Autodevops features. !9058
- Fix Error 500 when deleting a pipeline via the API. !9104
- Uses project_id instead of project on the group security dashboard. !9109
- Recursively get all of a groups projects. !9205
- Fix data migration failure if approvals_before_merge is set to too high. !9217
- Don't remove milestones when moving issues to board backlog from non-milestone list.
### Changed (5 changes, 1 of them is from the community)
- Update Geo nodes empty state. !8576 (George Tsiolis)
- Add search field to issue board switcher. !8862
- Allow downloading package files from UI. !8888
- Changes to the data model for counts on the Group Security Dashboard. !9035
- Fix packages UI mentioned only Maven packages support. !9132
### Performance (2 changes, 1 of them is from the community)
- Fix timeout loading Open list when board contains assignee lists.
- Enable some frozen string in ee/lib. (gfyoung)
### Added (17 changes)
- Add an instance-level endpoint for downloading maven packages. !8274
- Add NPM registry support to GitLab packages. !8673
- Store container scanning CI jobs results into the database. !8797
- Add a group-level endpoint for downloading maven packages. !8798
- Add Filtering vulnerabilities in the Group Security Dashboard. !8817
- Allow to filter Feature Flags. !8821
- Geo - Show last verification time on Geo projects page. !8845
- Adds basic filtering to the Group Security Dashboard frontend. !8886
- Autocomplete issues and MRs in epics. !8936
- Adds project filtering to the GSD. !8944
- Allow using TCP for DB load balancing DNS lookups. !8961
- Add filtering for summary and history on security dashboard. !8972
- Add solution card to the vulnerability modal. !9030
- Allows the Group Security Dashboard to select multiple filters. !9031
- Added Snowplow tracking to issues export. !9045
- Add support for relationship between epics. !9051
- Added pagination to epics API endpoint.
### Other (13 changes, 3 of them are from the community)
- Promote starting a GitLab.com Gold trial on the dashboard. !6947
- Adds event tracking to navbar. !7787
- Update tracing settings to match error tracking settings. !8786
- Adapt subscriptions page for free plans and trials. !8838
- Support for new SAST and dependency scanning report format. !8869
- Remove deprecated ActionDispatch::ParamsParser. !8897 (Jasper Maes)
- Fix deprecation: Comparing equality between ActionController::Parameters and a Hash is deprecated. !8914 (Jasper Maes)
- Removes Notes from GitLab Pseudonymizer config. !8923
- Add count of projects with tracing enabled to usage ping data. !8940
- Adds dependency scanning to the report type filters on GSD. !9034
- Fix deprecation: Using positional arguments in specs for EE spes in spec/. !9040 (Jasper Maes)
- Pass issuable-type in AddIssuableForm. !9111
- Gather deepest epic relationship data.
## 11.6.5 (2019-01-17)
### Fixed (1 change)
......
This diff is collapsed.
1.13.0
\ No newline at end of file
1.14.0
\ No newline at end of file
8.0.0
8.1.0
\ No newline at end of file
11.7.0-pre
11.8.0-pre
......@@ -3,6 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import { getParameterValues, mergeUrlParams } from '~/lib/utils/url_utility';
import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue';
import CompareVersionsDropdown from './compare_versions_dropdown.vue';
......@@ -54,10 +55,19 @@ export default {
showDropdowns() {
return !this.commit && this.mergeRequestDiffs.length;
},
fileTreeIcon() {
return this.showTreeList ? 'collapse-left' : 'expand-left';
},
toggleFileBrowserTitle() {
return this.showTreeList ? __('Hide file browser') : __('Show file browser');
},
baseVersionPath() {
return this.mergeRequestDiff.base_version_path;
},
},
mounted() {
polyfillSticky(this.$el);
},
methods: {
...mapActions('diffs', [
'setInlineDiffViewType',
......@@ -73,7 +83,7 @@ export default {
</script>
<template>
<div class="mr-version-controls">
<div class="mr-version-controls" :class="{ 'is-fileTreeOpen': showTreeList }">
<div class="mr-version-menus-container content-block">
<button
v-gl-tooltip.hover
......@@ -82,10 +92,10 @@ export default {
:class="{
active: showTreeList,
}"
:title="__('Toggle file browser')"
:title="toggleFileBrowserTitle"
@click="toggleShowTreeList"
>
<icon name="hamburger" />
<icon :name="fileTreeIcon" />
</button>
<div v-if="showDropdowns" class="d-flex align-items-center compare-versions-container">
Changes between
......@@ -108,7 +118,7 @@ export default {
{{ __('Viewing commit') }}
<gl-link :href="commit.commit_url" class="monospace">{{ commit.short_id }}</gl-link>
</div>
<div class="inline-parallel-buttons d-none d-md-flex ml-auto">
<div class="inline-parallel-buttons d-none d-lg-flex ml-auto">
<gl-button
v-if="commit || startVersion"
:href="latestVersionPath"
......
......@@ -141,7 +141,7 @@ export default {
<time-ago
v-if="version.created_at"
:time="version.created_at"
class="js-timeago js-timeago-render"
class="js-timeago"
/>
</small>
</div>
......
......@@ -25,15 +25,16 @@ class DirtySubmitForm {
DirtySubmitForm.THROTTLE_DURATION,
);
this.form.addEventListener('input', throttledUpdateDirtyInput);
this.form.addEventListener('change', throttledUpdateDirtyInput);
this.form.addEventListener('submit', event => this.formSubmit(event));
}
updateDirtyInput(event) {
const input = event.target;
const { target } = event;
if (!input.dataset.isDirtySubmitInput) return;
if (!target.dataset.isDirtySubmitInput) return;
this.updateDirtyInputs(input);
this.updateDirtyInputs(target);
this.toggleSubmission();
}
......
......@@ -163,6 +163,7 @@ export default class LazyLoader {
img.removeAttribute('data-src');
img.classList.remove('lazy');
img.classList.add('js-lazy-loaded');
img.classList.add('qa-js-lazy-loaded');
}
}
}
......@@ -87,80 +87,96 @@ let timeagoInstance;
*/
export const getTimeago = () => {
if (!timeagoInstance) {
const localeRemaining = (number, index) =>
[
[s__('Timeago|just now'), s__('Timeago|right now')],
[s__('Timeago|%s seconds ago'), s__('Timeago|%s seconds remaining')],
[s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
[s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')],
[s__('Timeago|1 hour ago'), s__('Timeago|1 hour remaining')],
[s__('Timeago|%s hours ago'), s__('Timeago|%s hours remaining')],
[s__('Timeago|1 day ago'), s__('Timeago|1 day remaining')],
[s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')],
[s__('Timeago|1 week ago'), s__('Timeago|1 week remaining')],
[s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')],
[s__('Timeago|1 month ago'), s__('Timeago|1 month remaining')],
[s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')],
[s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
[s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
][index];
const locale = (number, index) =>
[
[s__('Timeago|just now'), s__('Timeago|right now')],
[s__('Timeago|%s seconds ago'), s__('Timeago|in %s seconds')],
[s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
[s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')],
[s__('Timeago|1 hour ago'), s__('Timeago|in 1 hour')],
[s__('Timeago|%s hours ago'), s__('Timeago|in %s hours')],
[s__('Timeago|1 day ago'), s__('Timeago|in 1 day')],
[s__('Timeago|%s days ago'), s__('Timeago|in %s days')],
[s__('Timeago|1 week ago'), s__('Timeago|in 1 week')],
[s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')],
[s__('Timeago|1 month ago'), s__('Timeago|in 1 month')],
[s__('Timeago|%s months ago'), s__('Timeago|in %s months')],
[s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
[s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
][index];
timeago.register(timeagoLanguageCode, locale);
timeago.register(`${timeagoLanguageCode}-remaining`, localeRemaining);
const memoizedLocaleRemaining = () => {
const cache = [];
const timeAgoLocaleRemaining = [
() => [s__('Timeago|just now'), s__('Timeago|right now')],
() => [s__('Timeago|%s seconds ago'), s__('Timeago|%s seconds remaining')],
() => [s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
() => [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')],
() => [s__('Timeago|1 hour ago'), s__('Timeago|1 hour remaining')],
() => [s__('Timeago|%s hours ago'), s__('Timeago|%s hours remaining')],
() => [s__('Timeago|1 day ago'), s__('Timeago|1 day remaining')],
() => [s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')],
() => [s__('Timeago|1 week ago'), s__('Timeago|1 week remaining')],
() => [s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')],
() => [s__('Timeago|1 month ago'), s__('Timeago|1 month remaining')],
() => [s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')],
() => [s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
() => [s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
];
return (number, index) => {
if (cache[index]) {
return cache[index];
}
cache[index] = timeAgoLocaleRemaining[index] && timeAgoLocaleRemaining[index]();
return cache[index];
};
};
const memoizedLocale = () => {
const cache = [];
const timeAgoLocale = [
() => [s__('Timeago|just now'), s__('Timeago|right now')],
() => [s__('Timeago|%s seconds ago'), s__('Timeago|in %s seconds')],
() => [s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
() => [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')],
() => [s__('Timeago|1 hour ago'), s__('Timeago|in 1 hour')],
() => [s__('Timeago|%s hours ago'), s__('Timeago|in %s hours')],
() => [s__('Timeago|1 day ago'), s__('Timeago|in 1 day')],
() => [s__('Timeago|%s days ago'), s__('Timeago|in %s days')],
() => [s__('Timeago|1 week ago'), s__('Timeago|in 1 week')],
() => [s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')],
() => [s__('Timeago|1 month ago'), s__('Timeago|in 1 month')],
() => [s__('Timeago|%s months ago'), s__('Timeago|in %s months')],
() => [s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
() => [s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
];
return (number, index) => {
if (cache[index]) {
return cache[index];
}
cache[index] = timeAgoLocale[index] && timeAgoLocale[index]();
return cache[index];
};
};
timeago.register(timeagoLanguageCode, memoizedLocale());
timeago.register(`${timeagoLanguageCode}-remaining`, memoizedLocaleRemaining());
timeagoInstance = timeago();
}
return timeagoInstance;
};
/**
* For the given element, renders a timeago instance.
* @param {jQuery} $els
*/
export const renderTimeago = $els => {
const timeagoEls = $els || document.querySelectorAll('.js-timeago-render');
// timeago.js sets timeouts internally for each timeago value to be updated in real time
getTimeago().render(timeagoEls, timeagoLanguageCode);
};
/**
* For the given elements, sets a tooltip with a formatted date.
* @param {jQuery}
* @param {JQuery} $timeagoEls
* @param {Boolean} setTimeago
*/
export const localTimeAgo = ($timeagoEls, setTimeago = true) => {
$timeagoEls.each((i, el) => {
if (setTimeago) {
getTimeago().render($timeagoEls, timeagoLanguageCode);
if (!setTimeago) {
return;
}
function addTimeAgoTooltip() {
$timeagoEls.each((i, el) => {
// Recreate with custom template
$(el).tooltip({
template:
'<div class="tooltip local-timeago" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',
});
}
el.classList.add('js-timeago-render');
});
});
}
renderTimeago($timeagoEls);
requestIdleCallback(addTimeAgoTooltip);
};
/**
......
......@@ -6,6 +6,7 @@ import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
import markdownField from '../../vue_shared/components/markdown/field.vue';
import issuableStateMixin from '../mixins/issuable_state';
import resolvable from '../mixins/resolvable';
import { __ } from '~/locale';
import noteFormMixin from 'ee/batch_comments/mixins/note_form';
export default {
......@@ -34,7 +35,7 @@ export default {
saveButtonTitle: {
type: String,
required: false,
default: 'Save comment',
default: __('Save comment'),
},
discussion: {
type: Object,
......
import initUserInternalRegexPlaceholder from '../../application_settings/account_and_limits';
document.addEventListener('DOMContentLoaded', initUserInternalRegexPlaceholder());
import initAdmin from './admin';
import initUserInternalRegexPlaceholder from './application_settings/account_and_limits';
document.addEventListener('DOMContentLoaded', () => {
initAdmin();
initUserInternalRegexPlaceholder();
});
document.addEventListener('DOMContentLoaded', initAdmin());
......@@ -104,9 +104,7 @@ export default {
</div>
<div class="title hide-collapsed">
{{
sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName })
}}
{{ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName }) }}
<button
v-if="isEditable"
class="float-right lock-edit"
......
......@@ -50,6 +50,10 @@ $item-weight-max-width: 48px;
margin-bottom: $gl-padding-8;
font-size: $gl-font-size-small;
&.mr-title {
font-weight: $gl-font-weight-bold;
}
.sortable-link {
max-width: 85%;
}
......@@ -110,7 +114,6 @@ $item-weight-max-width: 48px;
}
.item-path-id {
order: 1;
margin-top: $gl-padding-4;
font-size: $gl-font-size-xs;
white-space: nowrap;
......@@ -124,6 +127,10 @@ $item-weight-max-width: 48px;
.issue-token-state-icon-closed {
display: block;
}
&:not(.mr-item-path) {
order: 1;
}
}
.item-milestone .ic-clock {
......@@ -187,10 +194,19 @@ $item-weight-max-width: 48px;
}
}
.mr-status-wrapper,
.mr-ci-status
{
line-height: 0;
}
@include media-breakpoint-up(sm) {
.item-body {
.item-contents .item-title .sortable-link {
max-width: 90%;
.item-contents .item-title {
.mr-title-link,
.sortable-link {
max-width: 90%;
}
}
}
}
......@@ -203,12 +219,13 @@ $item-weight-max-width: 48px;
.item-title {
flex-basis: unset;
// 98% because we compensate
// 95% because we compensate
// for remove button which is
// positioned absolutely
width: 95%;
margin-bottom: $gl-padding-4;
.mr-title-link,
.sortable-link {
text-overflow: ellipsis;
overflow: hidden;
......@@ -285,6 +302,7 @@ $item-weight-max-width: 48px;
flex-basis: unset;
font-weight: $gl-font-weight-normal;
.mr-title-link,
.sortable-link {
display: block;
text-overflow: ellipsis;
......
......@@ -694,3 +694,8 @@ $priority-label-empty-state-width: 114px;
Issues Analytics
*/
$issues-analytics-popover-boarder-color: rgba(0, 0, 0, 0.15);
/*
Merge Requests
*/
$mr-tabs-height: 51px;
$mr-version-controls-height: 56px;
......@@ -9,7 +9,7 @@
@media (min-width: map-get($grid-breakpoints, md)) {
position: -webkit-sticky;
position: sticky;
top: $header-height + 51px;
top: $mr-version-controls-height + $header-height + $mr-tabs-height;
margin-left: -1px;
border-left: 1px solid $border-color;
z-index: 102;
......@@ -19,6 +19,7 @@
.with-performance-bar & {
top: $header-height + 36px + $performance-bar-height;
}
}
......@@ -34,7 +35,7 @@
}
.with-performance-bar & {
top: 127px;
top: $header-height + $performance-bar-height + $mr-version-controls-height + $mr-tabs-height;
}
}
......@@ -1026,8 +1027,9 @@
.tree-list-holder {
position: -webkit-sticky;
position: sticky;
top: 100px;
max-height: calc(100vh - 100px);
$top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px;
top: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px;
max-height: calc(100vh - $top-pos);
padding-right: $gl-padding;
.file-row {
......@@ -1036,8 +1038,9 @@
}
.with-performance-bar & {
top: 135px;
max-height: calc(100vh - 135px);
$performance-bar-top-pos: $performance-bar-height + $top-pos;
top: $performance-bar-top-pos;
max-height: calc(100vh - $performance-bar-top-pos);
}
}
......
......@@ -80,7 +80,6 @@ ul.related-merge-requests > li {
}
}
.merge-requests-title,
.related-branches-title {
font-size: 16px;
font-weight: $gl-font-weight-bold;
......@@ -91,23 +90,16 @@ ul.related-merge-requests > li {
}
.merge-request-status {
font-size: 13px;
padding: 0 5px;
color: $white-light;
height: 20px;
border-radius: 3px;
line-height: 18px;
&.merged {
background: $blue-500;
color: $blue-500;
}
&.closed {
background: $red-500;
color: $red-500;
}
&.open {
background: $green-500;
color: $green-500;
}
}
......
.issue-count-badge {
.issue-count-badge,
.mr-count-badge {
display: inline-flex;
border-radius: $border-radius-base;
border: 1px solid $border-color;
padding: 5px $gl-padding-8;
}
.issue-count-badge-count {
.issue-count-badge-count,
.mr-count-badge-count {
display: inline-flex;
align-items: center;
}
......@@ -708,6 +708,7 @@
.mr-version-controls {
position: relative;
z-index: 103;
background: $gray-light;
color: $gl-text-color;
......@@ -755,13 +756,37 @@
color: $orange-500;
padding-right: 5px;
}
@include media-breakpoint-up(md) {
position: -webkit-sticky;
position: sticky;
top: $header-height + $mr-tabs-height;
width: 100%;
border-top: 1px solid $border-color;
&.is-fileTreeOpen {
margin-left: -16px;
width: calc(100% + 32px);
}
.mr-version-menus-container {
flex-wrap: nowrap;
}
.with-performance-bar & {
top: $header-height + $performance-bar-height + $mr-tabs-height;
}
}
}
.merge-request-tabs-holder {
top: $header-height;
z-index: 200;
background-color: $white-light;
border-bottom: 1px solid $border-color;
@include media-breakpoint-down(md) {
border-bottom: 1px solid $border-color;
}
@include media-breakpoint-up(sm) {
position: sticky;
......@@ -816,7 +841,7 @@
display: flex;
justify-content: space-between;
@include media-breakpoint-down(md) {
@include media-breakpoint-down(sm) {
flex-direction: column-reverse;
}
......
......@@ -29,7 +29,13 @@ module UploadsActions
def show
return render_404 unless uploader&.exists?
expires_in 0.seconds, must_revalidate: true, private: true
if cache_publicly?
# We need to reset caching from the applications controller to get rid of the no-store value
headers['Cache-Control'] = ''
expires_in 5.minutes, public: true, must_revalidate: false
else
expires_in 0.seconds, must_revalidate: true, private: true
end
disposition = uploader.image_or_video? ? 'inline' : 'attachment'
......@@ -114,6 +120,10 @@ module UploadsActions
nil
end
def cache_publicly?
false
end
def model
strong_memoize(:model) { find_model }
end
......
......@@ -10,10 +10,10 @@ class ProjectsController < Projects::ApplicationController
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :whitelist_query_limiting, only: [:create]
before_action :authenticate_user!, except: [:index, :show, :activity, :refs]
before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :resolve]
before_action :redirect_git_extension, only: [:show]
before_action :project, except: [:index, :new, :create]
before_action :repository, except: [:index, :new, :create]
before_action :project, except: [:index, :new, :create, :resolve]
before_action :repository, except: [:index, :new, :create, :resolve]
before_action :assign_ref_vars, only: [:show], if: :repo_exists?
before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
before_action :lfs_blob_ids, only: [:show], if: [:repo_exists?, :project_view_files?]
......@@ -442,6 +442,16 @@ class ProjectsController < Projects::ApplicationController
def present_project
@project = @project.present(current_user: current_user)
end
def resolve
@project = Project.find(params[:id])
if can?(current_user, :read_project, @project)
redirect_to @project
else
render_404
end
end
end
ProjectsController.prepend(EE::ProjectsController)
......@@ -70,6 +70,10 @@ class UploadsController < ApplicationController
end
end
def cache_publicly?
User === model || Appearance === model
end
def upload_model_class
MODEL_CLASSES[params[:model]] || raise(UnknownUploadModelError)
end
......
......@@ -268,6 +268,17 @@ module ApplicationHelper
_('You are on a read-only GitLab instance.')
end
def client_class_list
"gl-browser-#{browser.id} gl-platform-#{browser.platform.id}"
end
def client_js_flags
{
"is#{browser.id.to_s.titlecase}": true,
"is#{browser.platform.id.to_s.titlecase}": true
}
end
def autocomplete_data_sources(object, noteable_type)
return {} unless object && noteable_type
......
......@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ActiveRecord::Base
VERSION = '0.1.43'.freeze
VERSION = '0.1.45'.freeze
self.table_name = 'clusters_applications_runners'
......
......@@ -49,8 +49,9 @@ module Clusters
validates :name, cluster_name: true
validates :cluster_type, presence: true
validate :restrict_modification, on: :update
validates :domain, allow_nil: true, hostname: { allow_numeric_hostname: true, require_valid_tld: true }
validate :restrict_modification, on: :update
validate :no_groups, unless: :group_type?
validate :no_projects, unless: :project_type?
......
......@@ -230,7 +230,8 @@ class Issue < ActiveRecord::Base
end
def check_for_spam?
project.public? && (title_changed? || description_changed?)
publicly_visible? &&
(title_changed? || description_changed? || confidential_changed?)
end
def as_json(options = {})
......
......@@ -214,6 +214,7 @@ class Label < ActiveRecord::Base
super(options).tap do |json|
json[:type] = self.try(:type)
json[:priority] = priority(options[:project]) if options.key?(:project)
json[:textColor] = text_color
end
end
......
......@@ -31,7 +31,7 @@ module Storage
gitlab_shell.add_namespace(repository_storage, base_dir)
end
def rename_repo
def rename_repo(old_full_path: nil, new_full_path: nil)
true
end
......
......@@ -29,18 +29,19 @@ module Storage
gitlab_shell.add_namespace(repository_storage, base_dir)
end
def rename_repo
new_full_path = project.build_full_path
def rename_repo(old_full_path: nil, new_full_path: nil)
old_full_path ||= project.full_path_was
new_full_path ||= project.build_full_path
if gitlab_shell.mv_repository(repository_storage, project.full_path_was, new_full_path)
if gitlab_shell.mv_repository(repository_storage, old_full_path, new_full_path)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository(repository_storage, "#{project.full_path_was}.wiki", "#{new_full_path}.wiki")
gitlab_shell.mv_repository(repository_storage, "#{old_full_path}.wiki", "#{new_full_path}.wiki")
return true
rescue => e
Rails.logger.error "Exception renaming #{project.full_path_was} -> #{new_full_path}: #{e}"
Rails.logger.error "Exception renaming #{old_full_path} -> #{new_full_path}: #{e}"
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
return false
......
......@@ -14,22 +14,27 @@ module Projects
class AfterRenameService
prepend ::EE::Projects::AfterRenameService # rubocop: disable Cop/InjectEnterpriseEditionModule
attr_reader :project, :full_path_before, :full_path_after, :path_before
# @return [String] The Project being renamed.
attr_reader :project
RenameFailedError = Class.new(StandardError)
# @return [String] The path slug the project was using, before the rename took place.
attr_reader :path_before
# @param [Project] project The Project of the repository to rename.
def initialize(project)
@project = project
# @return [String] The full path of the namespace + project, before the rename took place.
attr_reader :full_path_before
# The full path of the namespace + project, before the rename took place.
@full_path_before = project.full_path_was
# @return [String] The full path of the namespace + project, after the rename took place.
attr_reader :full_path_after
# The full path of the namespace + project, after the rename took place.
@full_path_after = project.build_full_path
RenameFailedError = Class.new(StandardError)
# The path of just the project, before the rename took place.
@path_before = project.path_was
# @param [Project] project The Project being renamed.
# @param [String] path_before The path slug the project was using, before the rename took place.
def initialize(project, path_before:, full_path_before:)
@project = project
@path_before = path_before
@full_path_before = full_path_before
@full_path_after = project.full_path
end
def execute
......@@ -63,7 +68,7 @@ module Projects
.new(project, full_path_before)
.execute
else
project.storage.rename_repo
project.storage.rename_repo(old_full_path: full_path_before, new_full_path: full_path_after)
end
rename_failed! unless success
......
......@@ -69,7 +69,7 @@ module Projects
end
if project.previous_changes.include?('path')
AfterRenameService.new(project).execute
after_rename_service(project).execute
else
system_hook_service.execute_hooks_for(project, :update)
end
......@@ -77,6 +77,13 @@ module Projects
update_pages_config if changing_pages_related_config?
end
def after_rename_service(project)
# The path slug the project was using, before the rename took place.
path_before = project.previous_changes['path'].first
AfterRenameService.new(project, path_before: path_before, full_path_before: project.full_path_was)
end
def changing_pages_related_config?
changing_pages_https_only? || changing_pages_access_level?
end
......
......@@ -6,8 +6,15 @@ class PersonalFileUploader < FileUploader
options.storage_path
end
def self.base_dir(model, _store = nil)
File.join(options.base_dir, model_path_segment(model))
def self.base_dir(model, store = nil)
base_dirs(model)[store || Store::LOCAL]
end
def self.base_dirs(model)
{
Store::LOCAL => File.join(options.base_dir, model_path_segment(model)),
Store::REMOTE => model_path_segment(model)
}
end
def self.model_path_segment(model)
......@@ -33,13 +40,6 @@ class PersonalFileUploader < FileUploader
store_dirs[object_store]
end
def store_dirs
{
Store::LOCAL => File.join(base_dir, dynamic_segment),
Store::REMOTE => File.join(self.class.model_path_segment(model), dynamic_segment)
}
end
private
def secure_url
......
......@@ -5,15 +5,10 @@
- subscribed = params[:subscribed]
- labels_or_filters = @labels.exists? || search.present? || subscribed.present?
- if @labels.present? && can_admin_label
- content_for(:header_content) do
.nav-controls
= link_to _('New label'), new_group_label_path(@group), class: "btn btn-success"
- if labels_or_filters
#promote-label-modal
%div{ class: container_class }
= render 'shared/labels/nav'
= render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
.labels-container.prepend-top-5
- if @labels.any?
......
- client = client_js_flags
- if client
-# haml-lint:disable InlineJavaScript
:javascript
gl = window.gl || {};
gl.client = #{client.to_json};
!!! 5
%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
%body{ class: "#{user_application_theme} #{@body_class} #{client_class_list}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
= render "layouts/init_client_detection_flags"
= render 'peek/bar'
= header_message
= render partial: "layouts/header/default", locals: { project: @project, group: @group }
......
%div{ class: container_class }
.nav-block.d-none.d-sm-block.activities
.nav-block.d-none.d-sm-flex.activities
= render 'shared/event_filter'
.controls
= link_to project_path(@project, rss_url_options), title: s_("ProjectActivityRSS|Subscribe"), class: 'btn d-none d-sm-inline-block has-tooltip' do
......
- if @merge_requests.any?
%h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list.related-merge-requests
- has_any_head_pipeline = @merge_requests.any?(&:head_pipeline_id)
- @merge_requests.each do |merge_request|
%li
%span.merge-request-ci-status
- if merge_request.head_pipeline
= render_pipeline_status(merge_request.head_pipeline)
- elsif has_any_head_pipeline
= icon('blank fw')
%span.merge-request-id
= merge_request.to_reference
%span.merge-request-info
%strong
= link_to merge_request.title, merge_request_path(merge_request), class: "row_title"
- unless @issue.project.id == merge_request.target_project.id
in
- project = merge_request.target_project
= link_to project.full_name, project_path(project)
.card-slim.mt-3
.card-header
%h2.card-title.mt-0.mb-0.h5.merge-requests-title
%span.mr-1.bold
= _('Related merge requests')
.d-inline-flex.lh-100.align-middle
.mr-count-badge
.mr-count-badge-count
= sprite_icon('merge-request', size: 16, css_class: 'mr-1 text-secondary')
= @merge_requests.count
%ul.content-list.related-items-list
- has_any_head_pipeline = @merge_requests.any?(&:head_pipeline_id)
- @merge_requests.each do |merge_request|
%li.list-item.py-0.px-0
.item-body.issuable-info-container.py-lg-3.px-lg-3.pl-md-3
.item-contents
.item-title.d-flex.align-items-center.mr-title
= render partial: 'projects/issues/merge_requests_status', locals: { merge_request: merge_request, css_class: 'd-none d-xl-block append-right-8' }
= link_to merge_request.title, merge_request_path(merge_request), { class: 'mr-title-link'}
.item-meta
= render partial: 'projects/issues/merge_requests_status', locals: { merge_request: merge_request, css_class: 'd-xl-none d-lg-block append-right-5' }
%span.d-flex.align-items-center.append-right-8.mr-item-path.item-path-id.mt-0
%span.path-id-text.bold.text-truncate{ data: { toggle: 'tooltip'}, title: merge_request.target_project.full_path }
= merge_request.target_project.full_path
= merge_request.to_reference
%span.mr-ci-status.flex-md-grow-1.justify-content-end.d-flex.ml-md-2
- if merge_request.head_pipeline
= render_pipeline_status(merge_request.head_pipeline, tooltip_placement: 'bottom')
- elsif has_any_head_pipeline
= icon('blank fw')
- if merge_request.merged?
%span.merge-request-status.prepend-left-10.merged
Merged
- elsif merge_request.closed?
%span.merge-request-status.prepend-left-10.closed
Closed
- else
%span.merge-request-status.prepend-left-10.open
Open
- if @closed_by_merge_requests.present?
%li
= render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
- if @closed_by_merge_requests.present?
%p
= render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
- time_format = '%b %e, %Y %l:%M%P %Z%z'
- if merge_request.merged?
- mr_status_date = merge_request.merged_at
- mr_status_title = _('Merged')
- mr_status_icon = 'merge'
- mr_status_class = 'merged'
- elsif merge_request.closed?
- mr_status_date = merge_request.closed_event&.created_at
- mr_status_title = _('Closed')
- mr_status_icon = 'issue-close'
- mr_status_class = 'closed'
- else
- mr_status_date = merge_request.created_at
- mr_status_title = _('Opened')
- mr_status_icon = 'issue-open-m'
- mr_status_class = 'open'
- mr_status_tooltip = "<div><span class=\"bold\">#{mr_status_title}</span> #{time_ago_in_words(mr_status_date)} ago</div><span class=\"text-tertiary\">#{l(mr_status_date.to_time, format: time_format)}</span>"
%span.mr-status-wrapper.suggestion-help-hover{ class: css_class, data: { toggle: 'tooltip', placement: 'bottom', html: 'true', title: mr_status_tooltip } }
= sprite_icon(mr_status_icon, size: 16, css_class: "merge-request-status #{mr_status_class}")
......@@ -5,15 +5,10 @@
- subscribed = params[:subscribed]
- labels_or_filters = @labels.exists? || @prioritized_labels.exists? || search.present? || subscribed.present?
- if labels_or_filters && can_admin_label
- content_for(:header_content) do
.nav-controls
= link_to _('New label'), new_project_label_path(@project), class: "btn btn-success qa-label-create-new"
- if labels_or_filters
#promote-label-modal
%div{ class: container_class }
= render 'shared/labels/nav'
= render 'shared/labels/nav', labels_or_filters: labels_or_filters, can_admin_label: can_admin_label
.labels-container.prepend-top-10
- if can_admin_label
......
.row.empty-state.labels
.col-12
.svg-content
.svg-content.qa-label-svg
= image_tag 'illustrations/labels.svg'
.col-12
.text-content
......
......@@ -18,3 +18,7 @@
%button.btn.btn-default{ type: "submit", "aria-label" => _('Submit search') }
= icon("search")
= render 'shared/labels/sort_dropdown'
- if labels_or_filters && can_admin_label && @project
= link_to _('New label'), new_project_label_path(@project), class: "btn btn-success qa-label-create-new"
- if labels_or_filters && can_admin_label && @group
= link_to _('New label'), new_group_label_path(@group), class: "btn btn-success qa-label-create-new"
......@@ -9,18 +9,28 @@ class BuildFinishedWorker
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
UpdateBuildMinutesService.new(build.project, nil).execute(build)
# We execute that in sync as this access the files in order to access local file, and reduce IO
BuildTraceSectionsWorker.new.perform(build.id)
BuildCoverageWorker.new.perform(build.id)
# We execute that async as this are two independent operations that can be executed after TraceSections and Coverage
BuildHooksWorker.perform_async(build.id)
ArchiveTraceWorker.perform_async(build.id)
process_build(build)
end
end
# rubocop: enable CodeReuse/ActiveRecord
private
# Processes a single CI build that has finished.
#
# This logic resides in a separate method so that EE can extend it more
# easily.
#
# @param [Ci::Build] build The build to process.
def process_build(build)
# We execute these in sync to reduce IO.
BuildTraceSectionsWorker.new.perform(build.id)
BuildCoverageWorker.new.perform(build.id)
# We execute these async as these are independent operations.
BuildHooksWorker.perform_async(build.id)
ArchiveTraceWorker.perform_async(build.id)
end
end
BuildFinishedWorker.prepend(EE::BuildFinishedWorker)
......@@ -7,7 +7,7 @@ class DeleteUserWorker
delete_user = User.find(delete_user_id)
current_user = User.find(current_user_id)
::Users::DestroyService.new(current_user).execute(delete_user, options.symbolize_keys)
Users::DestroyService.new(current_user).execute(delete_user, options.symbolize_keys)
rescue Gitlab::Access::AccessDeniedError => e
Rails.logger.warn("User could not be destroyed: #{e}")
end
......
......@@ -11,23 +11,9 @@ class ExpirePipelineCacheWorker
pipeline = Ci::Pipeline.find_by(id: pipeline_id)
return unless pipeline
project = pipeline.project
store = Gitlab::EtagCaching::Store.new
store.touch(project_pipelines_path(project))
store.touch(project_pipeline_path(project, pipeline))
store.touch(commit_pipelines_path(project, pipeline.commit)) unless pipeline.commit.nil?
store.touch(new_merge_request_pipelines_path(project))
each_pipelines_merge_request_path(project, pipeline) do |path|
store.touch(path)
end
triggered_by = pipeline.triggered_by_pipeline
store.touch(project_pipeline_path(triggered_by.project, triggered_by)) if triggered_by
pipeline.triggered_pipelines.each do |triggered|
store.touch(project_pipeline_path(triggered.project, triggered))
end
update_etag_cache(pipeline, store)
Gitlab::Cache::Ci::ProjectPipelineStatus.update_for_pipeline(pipeline)
end
......@@ -58,4 +44,25 @@ class ExpirePipelineCacheWorker
yield(path)
end
end
# Updates ETag caches of a pipeline.
#
# This logic resides in a separate method so that EE can more easily extend
# it.
#
# @param [Ci::Pipeline] pipeline
# @param [Gitlab::EtagCaching::Store] store
def update_etag_cache(pipeline, store)
project = pipeline.project
store.touch(project_pipelines_path(project))
store.touch(project_pipeline_path(project, pipeline))
store.touch(commit_pipelines_path(project, pipeline.commit)) unless pipeline.commit.nil?
store.touch(new_merge_request_pipelines_path(project))
each_pipelines_merge_request_path(project, pipeline) do |path|
store.touch(path)
end
end
end
ExpirePipelineCacheWorker.prepend(EE::ExpirePipelineCacheWorker)
......@@ -10,16 +10,9 @@ class StuckImportJobsWorker
import_state_without_jid_count = mark_import_states_without_jid_as_failed!
import_state_with_jid_count = mark_import_states_with_jid_as_failed!
values = {
projects_without_jid_count: import_state_without_jid_count,
projects_with_jid_count: import_state_with_jid_count
}
Gitlab::Metrics.add_event_with_values(:stuck_import_jobs, values)
stuck_import_jobs_worker_runs_counter.increment
import_state_without_jid_metric.set({}, import_state_without_jid_count)
import_state_with_jid_metric.set({}, import_state_with_jid_count)
Gitlab::Metrics.add_event(:stuck_import_jobs,
projects_without_jid_count: import_state_without_jid_count,
projects_with_jid_count: import_state_with_jid_count)
end
private
......@@ -72,17 +65,4 @@ class StuckImportJobsWorker
def error_message
_("Import timed out. Import took longer than %{import_jobs_expiration} seconds") % { import_jobs_expiration: IMPORT_JOBS_EXPIRATION }
end
def stuck_import_jobs_worker_runs_counter
@stuck_import_jobs_worker_runs_counter ||= Gitlab::Metrics.counter(:gitlab_stuck_import_jobs_worker_runs_total,
'Stuck import jobs worker runs count')
end
def import_state_without_jid_metric
@import_state_without_jid_metric ||= Gitlab::Metrics.gauge(:gitlab_projects_without_jid, 'Projects without Job ids')
end
def import_state_with_jid_metric
@import_state_with_jid_metric ||= Gitlab::Metrics.gauge(:gitlab_projects_with_jid, 'Projects with Job ids')
end
end
---
title: Handle ci.skip push option
merge_request: 15643
author: Jonathon Reinhart
type: added
---
title: Clarifies docs about CI `allow_failure`
merge_request: 23367
author: C.J. Jameson
type: other
---
title: Add markdown helper buttons to file editor
merge_request: 23480
author:
type: added
---
title: No longer require email subaddressing for issue creation by email
merge_request: 23523
author:
type: changed
---
title: Allow user to add Kubernetes cluster for clusterable when there are ancestor clusters
merge_request: 23569
author:
type: other
---
title: Show clusters of ancestors in cluster list page
merge_request: 22996
author:
type: changed
---
title: Removes all instances of deprecated Gitlab Upgrader calls
merge_request: 23603
author: '@jwolen'
type: removed
---
title: Add API Support for Kubernetes integration
merge_request: 23922
author:
type: added
---
title: Creates component for release block
merge_request: 23697
author:
type: added
---
title: Creates frontend app for releases
merge_request: 23796
author:
type: added
---
title: Extend override check to also check arity
merge_request: 23498
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Add submit feedback link to help dropdown
merge_request: 23547
author:
type: added
---
title: Improve snippet search performance by removing duplicate counts
merge_request: 23952
author:
type: performance
---
title: Refactor issuable sidebar to use serializer
merge_request: 23379
author:
type: other
---
title: Redesigned related merge requests in issue page.
merge_request: 24270
author:
type: changed
---
title: Allow merge after rebase without page refresh on FF repositories
merge_request: 23572
author:
type: fixed
---
title: Configure Auto DevOps deployed applications with secrets from prefixed CI variables
merge_request: 23719
author:
type: added
---
title: Add importing of issues from CSV file
merge_request: 23532
author:
type: added
---
title: Add CSS & JS global flags to represent browser and platform
merge_request: 24017
author:
type: other
---
title: Create system notes on issue / MR creation when labels, milestone, or due date is set
merge_request: 23859
author:
type: added
---
title: Stop autofocusing on diff comment after initial mount
merge_request: 23849
author:
type: fixed
---
title: Redesign project lists UI
merge_request: 22682
author:
type: other
---
title: Correct the ordering of metrics on the performance dashboard
merge_request: 23630
author:
type: fixed
---
title: Disable merging of labels with same names
merge_request: 23265
author:
type: changed
---
title: Don't show Auto DevOps enabled banner for projects with CI file or CI disabled
merge_request: 24067
author:
type: other
---
title: Aligns build loader animation with the job log
merge_request: 23959
author:
type: fixed
---
title: Prevent awards emoji being updated when updating status
merge_request: 23470
author:
type: fixed
---
title: Make possible to toggle file tree while scrolling through diffs
merge_request: !24103
author:
type: changed
---
title: Adds explanatory text to input fields on user profile settings page
merge_request: 23673
author:
type: other
---
title: Add project identifier as List-Id email Header to ease filtering
merge_request: 22817
author: Olivier Crête
type: added
---
title: Redirect GET projects/:id to project page
merge_request: 24467
author:
type: added
---
title: Make RBAC enabled default for new clusters
merge_request: 24119
author:
type: changed
---
title: Fix foreground color for labels to ensure consistency of label appearance
merge_request: 23873
author: Nathan Friend
type: fixed
---
title: Removed discard draft comment button form notes
merge_request: 24185
author:
type: removed
---
title: Fix suboptimal handling of checkbox and radio input events causing
group general settings submit button to stay disabled after changing its visibility
merge_request: 23022
author:
type: fixed
---
title: Add % prefix to milestone reference links
merge_request: 23928
author:
type: changed
---
title: Add date range in milestone change email notifications
merge_request: 23762
author:
type: changed
---
title: 'Hashed Storage: Only set as `read_only` when starting the per-project migration'
merge_request: 24128
author:
type: changed
---
title: Make the Pages permission setting more clear
merge_request: 23146
author:
type: changed
---
title: Fix project calendar feed when sorted by priority
merge_request: 23870
author:
type: fixed
---
title: Discussion filter only displayed in discussions tab for merge requests
merge_request: 24082
author:
type: changed
---
title: Fix error when creating labels in a new issue in the boards page
merge_request: 24039
author: Ruben Moya
type: fixed
---
title: Remove framework/mobile.scss
merge_request: 23301
author: Takuya Noguchi
type: other
---
title: Escape html entities in LabelReferenceFilter when no label found
merge_request:
author:
type: security
---
title: Fix login box bottom margins on signin page
merge_request: 23739
author: '@gear54'
type: fixed
---
title: Display empty files properly on MR diffs
merge_request: 23671
author: Sean Nichols
type: fixed
---
title: Fix label and header styles in the job details sidebar.
merge_request: 23816
author: Nathan Friend
type: changed
---
title: Use reports syntax for Dependency scanning in Auto DevOps
merge_request: 24081
author:
type: added
---
title: Return an ApplicationSetting in CurrentSettings
merge_request: 23766
author:
type: fixed
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment