summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/fly_out_nav.js13
-rw-r--r--app/assets/javascripts/issue_show/components/edited.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue (renamed from app/assets/javascripts/monitoring/components/monitoring.vue)56
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_state.vue)52
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_column.vue)26
-rw-r--r--app/assets/javascripts/monitoring/components/graph/deployment.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_deployment.vue)2
-rw-r--r--app/assets/javascripts/monitoring/components/graph/flag.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_flag.vue)2
-rw-r--r--app/assets/javascripts/monitoring/components/graph/legend.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_legends.vue)4
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue21
-rw-r--r--app/assets/javascripts/monitoring/components/graph_row.vue (renamed from app/assets/javascripts/monitoring/components/monitoring_row.vue)14
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js6
-rw-r--r--app/assets/javascripts/new_sidebar.js5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines.vue4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss4
-rw-r--r--app/assets/stylesheets/framework/selects.scss1
-rw-r--r--app/assets/stylesheets/framework/typography.scss1
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss2
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss4
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/helpers/tab_helper.rb4
-rw-r--r--app/models/environment.rb2
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/models/project.rb6
-rw-r--r--app/models/repository.rb67
-rw-r--r--app/models/user.rb3
-rw-r--r--app/services/projects/after_import_service.rb29
-rw-r--r--app/services/projects/housekeeping_service.rb2
-rw-r--r--app/views/layouts/nav/_new_admin_sidebar.html.haml24
-rw-r--r--app/views/layouts/nav/_new_group_sidebar.html.haml10
-rw-r--r--app/views/layouts/nav/_new_profile_sidebar.html.haml24
-rw-r--r--app/views/layouts/nav/_new_project_sidebar.html.haml18
-rw-r--r--app/views/profiles/gpg_keys/index.html.haml2
-rw-r--r--app/views/projects/commit/_signature_badge.html.haml2
33 files changed, 243 insertions, 173 deletions
diff --git a/app/assets/javascripts/fly_out_nav.js b/app/assets/javascripts/fly_out_nav.js
index 32cb42c8b10..81697af189b 100644
--- a/app/assets/javascripts/fly_out_nav.js
+++ b/app/assets/javascripts/fly_out_nav.js
@@ -1,4 +1,3 @@
-import Cookies from 'js-cookie';
import bp from './breakpoints';
const HIDE_INTERVAL_TIMEOUT = 300;
@@ -8,9 +7,11 @@ const IS_SHOWING_FLY_OUT_CLASS = 'is-showing-fly-out';
let currentOpenMenu = null;
let menuCornerLocs;
let timeoutId;
+let sidebar;
export const mousePos = [];
+export const setSidebar = (el) => { sidebar = el; };
export const setOpenMenu = (menu = null) => { currentOpenMenu = menu; };
export const slope = (a, b) => (b.y - a.y) / (b.x - a.x);
@@ -20,10 +21,8 @@ let headerHeight = 50;
export const getHeaderHeight = () => headerHeight;
export const canShowActiveSubItems = (el) => {
- const isHiddenByMedia = bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md';
-
- if (el.classList.contains('active') && !isHiddenByMedia) {
- return Cookies.get('sidebar_collapsed') === 'true';
+ if (el.classList.contains('active') && (sidebar && !sidebar.classList.contains('sidebar-icons-only'))) {
+ return false;
}
return true;
@@ -143,13 +142,13 @@ export const documentMouseMove = (e) => {
};
export default () => {
- const sidebar = document.querySelector('.sidebar-top-level-items');
+ sidebar = document.querySelector('.nav-sidebar');
if (!sidebar) return;
const items = [...sidebar.querySelectorAll('.sidebar-top-level-items > li')];
- sidebar.addEventListener('mouseleave', () => {
+ sidebar.querySelector('.sidebar-top-level-items').addEventListener('mouseleave', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
diff --git a/app/assets/javascripts/issue_show/components/edited.vue b/app/assets/javascripts/issue_show/components/edited.vue
index d59e6d11032..992b7064c13 100644
--- a/app/assets/javascripts/issue_show/components/edited.vue
+++ b/app/assets/javascripts/issue_show/components/edited.vue
@@ -37,7 +37,7 @@ export default {
Edited
<time-ago-tooltip
v-if="updatedAt"
- placement="bottom"
+ tooltip-placement="bottom"
:time="updatedAt"
/>
<span
diff --git a/app/assets/javascripts/monitoring/components/monitoring.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index a6a2d3119e3..74244faa5d9 100644
--- a/app/assets/javascripts/monitoring/components/monitoring.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -3,8 +3,9 @@
import _ from 'underscore';
import statusCodes from '../../lib/utils/http_status';
import MonitoringService from '../services/monitoring_service';
- import monitoringRow from './monitoring_row.vue';
- import monitoringState from './monitoring_state.vue';
+ import GraphGroup from './graph_group.vue';
+ import GraphRow from './graph_row.vue';
+ import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub';
@@ -31,8 +32,9 @@
},
components: {
- monitoringRow,
- monitoringState,
+ GraphGroup,
+ GraphRow,
+ EmptyState,
},
methods: {
@@ -94,7 +96,6 @@
this.updatedAspectRatios = 0;
}
},
-
},
created() {
@@ -118,40 +119,27 @@
},
};
</script>
+
<template>
- <div
- class="prometheus-graphs"
- v-if="!showEmptyState">
- <div
- class="row"
+ <div v-if="!showEmptyState" class="prometheus-graphs">
+ <graph-group
v-for="(groupData, index) in store.groups"
- :key="index">
- <div
- class="col-md-12">
- <div
- class="panel panel-default prometheus-panel">
- <div
- class="panel-heading">
- <h4>{{groupData.group}}</h4>
- </div>
- <div
- class="panel-body">
- <monitoring-row
- v-for="(row, index) in groupData.metrics"
- :key="index"
- :row-data="row"
- :update-aspect-ratio="updateAspectRatio"
- :deployment-data="store.deploymentData"
- />
- </div>
- </div>
- </div>
- </div>
+ :key="index"
+ :name="groupData.group"
+ >
+ <graph-row
+ v-for="(row, index) in groupData.metrics"
+ :key="index"
+ :row-data="row"
+ :update-aspect-ratio="updateAspectRatio"
+ :deployment-data="store.deploymentData"
+ />
+ </graph-group>
</div>
- <monitoring-state
+ <empty-state
+ v-else
:selected-state="state"
:documentation-path="documentationPath"
:settings-path="settingsPath"
- v-else
/>
</template>
diff --git a/app/assets/javascripts/monitoring/components/monitoring_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 598021aa4df..a8708be76de 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -62,49 +62,33 @@
},
};
</script>
+
<template>
- <div
- class="prometheus-state">
- <div
- class="row">
- <div
- class="col-md-4 col-md-offset-4 state-svg"
- v-html="currentState.svg">
- </div>
+ <div class="prometheus-state">
+ <div class="row">
+ <div class="col-md-4 col-md-offset-4 state-svg" v-html="currentState.svg"></div>
</div>
- <div
- class="row">
- <div
- class="col-md-6 col-md-offset-3">
- <h4
- class="text-center state-title">
+ <div class="row">
+ <div class="col-md-6 col-md-offset-3">
+ <h4 class="text-center state-title">
{{currentState.title}}
</h4>
</div>
</div>
- <div
- class="row">
- <div
- class="col-md-6 col-md-offset-3">
- <div
- class="description-text text-center state-description">
- {{currentState.description}}
- <a
- :href="settingsPath"
- v-if="showButtonDescription">
- Prometheus server
- </a>
+ <div class="row">
+ <div class="col-md-6 col-md-offset-3">
+ <div class="description-text text-center state-description">
+ {{currentState.description}}
+ <a v-if="showButtonDescription" :href="settingsPath">
+ Prometheus server
+ </a>
</div>
</div>
</div>
- <div
- class="row state-button-section">
- <div
- class="col-md-4 col-md-offset-4 text-center state-button">
- <a
- class="btn btn-success"
- :href="buttonPath">
- {{currentState.buttonText}}
+ <div class="row state-button-section">
+ <div class="col-md-4 col-md-offset-4 text-center state-button">
+ <a class="btn btn-success" :href="buttonPath">
+ {{currentState.buttonText}}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/monitoring/components/monitoring_column.vue b/app/assets/javascripts/monitoring/components/graph.vue
index a31c26fb4fc..6f6da9e1463 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_column.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -1,8 +1,8 @@
<script>
import d3 from 'd3';
- import monitoringLegends from './monitoring_legends.vue';
- import monitoringFlag from './monitoring_flag.vue';
- import monitoringDeployment from './monitoring_deployment.vue';
+ import GraphLegend from './graph/legend.vue';
+ import GraphFlag from './graph/flag.vue';
+ import GraphDeployment from './graph/deployment.vue';
import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub';
import measurements from '../utils/measurements';
@@ -14,7 +14,7 @@
export default {
props: {
- columnData: {
+ graphData: {
type: Object,
required: true,
},
@@ -66,9 +66,9 @@
},
components: {
- monitoringLegends,
- monitoringFlag,
- monitoringDeployment,
+ GraphLegend,
+ GraphFlag,
+ GraphDeployment,
},
computed: {
@@ -97,7 +97,7 @@
methods: {
draw() {
const breakpointSize = bp.getBreakpointSize();
- const query = this.columnData.queries[0];
+ const query = this.graphData.queries[0];
this.margin = measurements.large.margin;
if (breakpointSize === 'xs' || breakpointSize === 'sm') {
this.graphHeight = 300;
@@ -106,7 +106,7 @@
}
this.data = query.result[0].values;
this.unitOfDisplay = query.unit || '';
- this.yAxisLabel = this.columnData.y_label || 'Values';
+ this.yAxisLabel = this.graphData.y_label || 'Values';
this.legendTitle = query.label || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth -
this.margin.left - this.margin.right;
@@ -224,7 +224,7 @@
:class="classType">
<h5
class="text-center graph-title">
- {{columnData.title}}
+ {{graphData.title}}
</h5>
<div
class="prometheus-svg-container"
@@ -240,7 +240,7 @@
class="y-axis"
transform="translate(70, 20)">
</g>
- <monitoring-legends
+ <graph-legend
:graph-width="graphWidth"
:graph-height="graphHeight"
:margin="margin"
@@ -268,13 +268,13 @@
stroke-width="2"
transform="translate(-5, 20)">
</path>
- <monitoring-deployment
+ <graph-deployment
:show-deploy-info="showDeployInfo"
:deployment-data="reducedDeploymentData"
:graph-height="graphHeight"
:graph-height-offset="graphHeightOffset"
/>
- <monitoring-flag
+ <graph-flag
v-if="showFlag"
:current-x-coordinate="currentXCoordinate"
:current-y-coordinate="currentYCoordinate"
diff --git a/app/assets/javascripts/monitoring/components/monitoring_deployment.vue b/app/assets/javascripts/monitoring/components/graph/deployment.vue
index dadbcd1aaa6..3623d2ed946 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_deployment.vue
+++ b/app/assets/javascripts/monitoring/components/graph/deployment.vue
@@ -1,5 +1,5 @@
<script>
- import { dateFormat, timeFormat } from '../utils/date_time_formatters';
+ import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
export default {
props: {
diff --git a/app/assets/javascripts/monitoring/components/monitoring_flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue
index 61cbeeebb17..c4d4647d240 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_flag.vue
+++ b/app/assets/javascripts/monitoring/components/graph/flag.vue
@@ -1,5 +1,5 @@
<script>
- import { dateFormat, timeFormat } from '../utils/date_time_formatters';
+ import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
export default {
props: {
diff --git a/app/assets/javascripts/monitoring/components/monitoring_legends.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue
index 922a5e1bf0e..d08f9cbffd4 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_legends.vue
+++ b/app/assets/javascripts/monitoring/components/graph/legend.vue
@@ -74,7 +74,7 @@
};
</script>
<template>
- <g
+ <g
class="axis-label-container">
<line
class="label-x-axis-line"
@@ -100,7 +100,7 @@
:width="yLabelWidth"
:height="yLabelHeight">
</rect>
- <text
+ <text
class="label-axis-text y-label-text"
text-anchor="middle"
:transform="textTransform"
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
new file mode 100644
index 00000000000..32c90fda8cc
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -0,0 +1,21 @@
+<script>
+export default {
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="panel panel-default prometheus-panel">
+ <div class="panel-heading">
+ <h4>{{name}}</h4>
+ </div>
+ <div class="panel-body">
+ <slot />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/monitoring_row.vue b/app/assets/javascripts/monitoring/components/graph_row.vue
index e5528f17880..bdb9149c3b4 100644
--- a/app/assets/javascripts/monitoring/components/monitoring_row.vue
+++ b/app/assets/javascripts/monitoring/components/graph_row.vue
@@ -1,5 +1,5 @@
<script>
- import monitoringColumn from './monitoring_column.vue';
+ import Graph from './graph.vue';
export default {
props: {
@@ -17,7 +17,7 @@
},
},
components: {
- monitoringColumn,
+ Graph,
},
computed: {
bootstrapClass() {
@@ -26,12 +26,12 @@
},
};
</script>
+
<template>
- <div
- class="prometheus-row row">
- <monitoring-column
- v-for="(column, index) in rowData"
- :column-data="column"
+ <div class="prometheus-row row">
+ <graph
+ v-for="(graphData, index) in rowData"
+ :graph-data="graphData"
:class-type="bootstrapClass"
:key="index"
:update-aspect-ratio="updateAspectRatio"
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index 5d5cb56af72..ef280e02092 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -1,10 +1,10 @@
import Vue from 'vue';
-import Monitoring from './components/monitoring.vue';
+import Dashboard from './components/dashboard.vue';
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#prometheus-graphs',
components: {
- 'monitoring-dashboard': Monitoring,
+ Dashboard,
},
- render: createElement => createElement('monitoring-dashboard'),
+ render: createElement => createElement('dashboard'),
}));
diff --git a/app/assets/javascripts/new_sidebar.js b/app/assets/javascripts/new_sidebar.js
index b18d12b48b5..05e3f33f5ed 100644
--- a/app/assets/javascripts/new_sidebar.js
+++ b/app/assets/javascripts/new_sidebar.js
@@ -15,6 +15,7 @@ export default class NewNavSidebar {
this.$openSidebar = $('.toggle-mobile-nav');
this.$closeSidebar = $('.close-nav-button');
this.$sidebarToggle = $('.js-toggle-sidebar');
+ this.$topLevelLinks = $('.sidebar-top-level-items > li > a');
}
bindEvents() {
@@ -50,6 +51,10 @@ export default class NewNavSidebar {
this.$page.toggleClass('page-with-icon-sidebar', breakpoint === 'sm' ? true : collapsed);
}
NewNavSidebar.setCollapsedCookie(collapsed);
+
+ this.$topLevelLinks.attr('title', function updateTopLevelTitle() {
+ return collapsed ? this.getAttribute('aria-label') : '';
+ });
}
render() {
diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue
index 5df317a76bf..010063a0240 100644
--- a/app/assets/javascripts/pipelines/components/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines.vue
@@ -139,7 +139,9 @@
};
</script>
<template>
- <div :class="cssClass">
+ <div
+ class="pipelines-container"
+ :class="cssClass">
<div
class="top-area scrolling-tabs-container inner-page-scroll-tabs"
v-if="!isLoading && !shouldRenderEmptyState">
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 4cf2f46c6d3..5871383a57b 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -189,7 +189,7 @@
width: auto;
top: 100%;
left: 0;
- z-index: 9;
+ z-index: 200;
min-width: 240px;
max-width: 500px;
margin-top: 2px;
@@ -797,3 +797,5 @@
margin-top: 2px;
}
}
+
+@include new-style-dropdown('.js-namespace-select + ');
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 8018eb8ba84..a39927eb0df 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -267,6 +267,7 @@
// TODO: change global style
.ajax-project-dropdown,
+body[data-page="projects:new"] #select2-drop,
body[data-page="projects:blob:new"] #select2-drop,
body[data-page="profiles:show"] #select2-drop,
body[data-page="projects:blob:edit"] #select2-drop {
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index b2423bc1a66..3c0b4c82d19 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -25,6 +25,7 @@
min-width: inherit;
min-height: inherit;
background-color: inherit;
+ max-width: 100%;
}
p a:not(.no-attachment-icon) img {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 334bec8dd7e..9d51c0b7a8a 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -612,6 +612,8 @@
}
.mr-version-controls {
+ @include new-style-dropdown;
+
position: relative;
background: $gray-light;
color: $gl-text-color;
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index a408bde37d6..51656669c98 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -927,3 +927,7 @@ button.mini-pipeline-graph-dropdown-toggle {
}
}
}
+
+.pipelines-container .top-area .nav-controls > .btn:last-child {
+ float: none;
+}
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 54f78fc8719..59be955599d 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -55,7 +55,7 @@ class AutocompleteController < ApplicationController
.limit(AWARD_EMOJI_MAX)
.where(user: current_user)
.group(:name)
- .order(count: :desc, name: :asc)
+ .order('count_all DESC, name ASC')
.count
# Transform from hash to array to guarantee json order
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index ee701076a14..3308ab0c259 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -119,4 +119,8 @@ module TabHelper
'active' if current_controller?('oauth/applications')
end
+
+ def sidebar_link(href, title: nil, css: nil, &block)
+ link_to capture(&block), href, title: (title if collapsed_sidebar?), class: css, aria: { label: title }
+ end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index e9ebf0637f3..435eeaf0e2e 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -114,7 +114,7 @@ class Environment < ActiveRecord::Base
end
def ref_path
- "refs/environments/#{Shellwords.shellescape(name)}"
+ "refs/#{Repository::REF_ENVIRONMENTS}/#{Shellwords.shellescape(name)}"
end
def formatted_external_url
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 7f73de67625..5be2f6d4e82 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -803,7 +803,7 @@ class MergeRequest < ActiveRecord::Base
end
def ref_path
- "refs/merge-requests/#{iid}/head"
+ "refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/head"
end
def ref_fetched?
diff --git a/app/models/project.rb b/app/models/project.rb
index d5324ceac31..9d7bea4eb66 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -372,11 +372,7 @@ class Project < ActiveRecord::Base
if Gitlab::ImportSources.importer_names.include?(project.import_type) && project.repo_exists?
project.run_after_commit do
- begin
- Projects::HousekeepingService.new(project).execute
- rescue Projects::HousekeepingService::LeaseTaken => e
- Rails.logger.info("Could not perform housekeeping for project #{project.full_path} (#{project.id}): #{e}")
- end
+ Projects::AfterImportService.new(project).execute
end
end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index cb7aba89020..d29d2a83708 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1,6 +1,18 @@
require 'securerandom'
class Repository
+ REF_MERGE_REQUEST = 'merge-requests'.freeze
+ REF_KEEP_AROUND = 'keep-around'.freeze
+ REF_ENVIRONMENTS = 'environments'.freeze
+
+ RESERVED_REFS_NAMES = %W[
+ heads
+ tags
+ #{REF_ENVIRONMENTS}
+ #{REF_KEEP_AROUND}
+ #{REF_ENVIRONMENTS}
+ ].freeze
+
include Gitlab::ShellAdapter
include RepositoryMirroring
@@ -60,6 +72,10 @@ class Repository
@project = project
end
+ def ==(other)
+ @disk_path == other.disk_path
+ end
+
def raw_repository
return nil unless full_path
@@ -75,6 +91,10 @@ class Repository
)
end
+ def inspect
+ "#<#{self.class.name}:#{@disk_path}>"
+ end
+
#
# Git repository can contains some hidden refs like:
# /refs/notes/*
@@ -234,10 +254,10 @@ class Repository
begin
write_ref(keep_around_ref_name(sha), sha)
rescue Rugged::ReferenceError => ex
- Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
+ Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}"
rescue Rugged::OSError => ex
raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
- Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
+ Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}"
end
end
@@ -992,25 +1012,22 @@ class Repository
end
def with_repo_branch_commit(start_repository, start_branch_name)
- return yield(nil) if start_repository.empty_repo?
+ return yield nil if start_repository.empty_repo?
- branch_name_or_sha =
- if start_repository == self
- start_branch_name
- else
- tmp_ref = fetch_ref(
- start_repository.path_to_repo,
- "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
- "refs/tmp/#{SecureRandom.hex}/head"
- )
+ if start_repository == self
+ yield commit(start_branch_name)
+ else
+ sha = start_repository.commit(start_branch_name).sha
- start_repository.commit(start_branch_name).sha
+ if branch_commit = commit(sha)
+ yield branch_commit
+ else
+ with_repo_tmp_commit(
+ start_repository, start_branch_name, sha) do |tmp_commit|
+ yield tmp_commit
+ end
end
-
- yield(commit(branch_name_or_sha))
-
- ensure
- rugged.references.delete(tmp_ref) if tmp_ref
+ end
end
def add_remote(name, url)
@@ -1159,7 +1176,7 @@ class Repository
end
def keep_around_ref_name(sha)
- "refs/keep-around/#{sha}"
+ "refs/#{REF_KEEP_AROUND}/#{sha}"
end
def repository_event(event, tags = {})
@@ -1219,4 +1236,16 @@ class Repository
.commits_by_message(query, revision: ref, path: path, limit: limit, offset: offset)
.map { |c| commit(c) }
end
+
+ def with_repo_tmp_commit(start_repository, start_branch_name, sha)
+ tmp_ref = fetch_ref(
+ start_repository.path_to_repo,
+ "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
+ "refs/tmp/#{SecureRandom.hex}/head"
+ )
+
+ yield commit(sha)
+ ensure
+ delete_refs(tmp_ref) if tmp_ref
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index fbd08bc4d0a..70787de4b40 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -5,6 +5,7 @@ class User < ActiveRecord::Base
include Gitlab::ConfigHelper
include Gitlab::CurrentSettings
+ include Gitlab::SQL::Pattern
include Avatarable
include Referable
include Sortable
@@ -303,7 +304,7 @@ class User < ActiveRecord::Base
# Returns an ActiveRecord::Relation.
def search(query)
table = arel_table
- pattern = "%#{query}%"
+ pattern = User.to_pattern(query)
order = <<~SQL
CASE
diff --git a/app/services/projects/after_import_service.rb b/app/services/projects/after_import_service.rb
new file mode 100644
index 00000000000..e6a68d983ef
--- /dev/null
+++ b/app/services/projects/after_import_service.rb
@@ -0,0 +1,29 @@
+module Projects
+ class AfterImportService
+ RESERVED_REFS_REGEXP =
+ %r{\Arefs/(?:#{Regexp.union(*Repository::RESERVED_REFS_NAMES)})/}
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ Projects::HousekeepingService.new(@project).execute do
+ repository.delete_refs(*garbage_refs)
+ end
+ rescue Projects::HousekeepingService::LeaseTaken => e
+ Rails.logger.info(
+ "Could not perform housekeeping for project #{@project.full_path} (#{@project.id}): #{e}")
+ end
+
+ private
+
+ def garbage_refs
+ @garbage_refs ||= repository.all_ref_names_except(RESERVED_REFS_REGEXP)
+ end
+
+ def repository
+ @repository ||= @project.repository
+ end
+ end
+end
diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb
index d66ef676088..dcef8b66215 100644
--- a/app/services/projects/housekeeping_service.rb
+++ b/app/services/projects/housekeeping_service.rb
@@ -26,6 +26,8 @@ module Projects
lease_uuid = try_obtain_lease
raise LeaseTaken unless lease_uuid.present?
+ yield if block_given?
+
execute_gitlab_shell_gc(lease_uuid)
end
diff --git a/app/views/layouts/nav/_new_admin_sidebar.html.haml b/app/views/layouts/nav/_new_admin_sidebar.html.haml
index 9294529f496..3b53117deb6 100644
--- a/app/views/layouts/nav/_new_admin_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_admin_sidebar.html.haml
@@ -7,7 +7,7 @@
.sidebar-context-title Admin Area
%ul.sidebar-top-level-items
= nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts), html_options: {class: 'home'}) do
- = link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
+ = sidebar_link admin_root_path, title: _('Overview'), css: 'shortcuts-tree' do
.nav-icon-container
= custom_icon('overview')
%span.nav-item-name
@@ -48,7 +48,7 @@
ConvDev Index
= nav_link(controller: %w(conversational_development_index system_info background_jobs logs health_check requests_profiles)) do
- = link_to admin_conversational_development_index_path, title: 'Monitoring' do
+ = sidebar_link admin_conversational_development_index_path, title: _('Monitoring') do
.nav-icon-container
= custom_icon('monitoring')
%span.nav-item-name
@@ -77,28 +77,28 @@
Requests Profiles
= nav_link(controller: :broadcast_messages) do
- = link_to admin_broadcast_messages_path, title: 'Messages' do
+ = sidebar_link admin_broadcast_messages_path, title: _('Messages') do
.nav-icon-container
= custom_icon('messages')
%span.nav-item-name
Messages
= nav_link(controller: [:hooks, :hook_logs]) do
- = link_to admin_hooks_path, title: 'Hooks' do
+ = sidebar_link admin_hooks_path, title: _('Hooks') do
.nav-icon-container
= custom_icon('system_hooks')
%span.nav-item-name
System Hooks
= nav_link(controller: :applications) do
- = link_to admin_applications_path, title: 'Applications' do
+ = sidebar_link admin_applications_path, title: _('Applications') do
.nav-icon-container
= custom_icon('applications')
%span.nav-item-name
Applications
= nav_link(controller: :abuse_reports) do
- = link_to admin_abuse_reports_path, title: "Abuse Reports" do
+ = sidebar_link admin_abuse_reports_path, title: _("Abuse Reports") do
.nav-icon-container
= custom_icon('abuse_reports')
%span.nav-item-name
@@ -107,42 +107,42 @@
- if akismet_enabled?
= nav_link(controller: :spam_logs) do
- = link_to admin_spam_logs_path, title: "Spam Logs" do
+ = sidebar_link admin_spam_logs_path, title: _("Spam Logs") do
.nav-icon-container
= custom_icon('spam_logs')
%span.nav-item-name
Spam Logs
= nav_link(controller: :deploy_keys) do
- = link_to admin_deploy_keys_path, title: 'Deploy Keys' do
+ = sidebar_link admin_deploy_keys_path, title: _('Deploy Keys') do
.nav-icon-container
= custom_icon('key')
%span.nav-item-name
Deploy Keys
= nav_link(controller: :services) do
- = link_to admin_application_settings_services_path, title: 'Service Templates' do
+ = sidebar_link admin_application_settings_services_path, title: _('Service Templates') do
.nav-icon-container
= custom_icon('service_templates')
%span.nav-item-name
Service Templates
= nav_link(controller: :labels) do
- = link_to admin_labels_path, title: 'Labels' do
+ = sidebar_link admin_labels_path, title: _('Labels') do
.nav-icon-container
= custom_icon('labels')
%span.nav-item-name
Labels
= nav_link(controller: :appearances) do
- = link_to admin_appearances_path, title: 'Appearances' do
+ = sidebar_link admin_appearances_path, title: _('Appearances') do
.nav-icon-container
= custom_icon('appearance')
%span.nav-item-name
Appearance
= nav_link(controller: :application_settings) do
- = link_to admin_application_settings_path, title: 'Settings' do
+ = sidebar_link admin_application_settings_path, title: _('Settings') do
.nav-icon-container
= custom_icon('settings')
%span.nav-item-name
diff --git a/app/views/layouts/nav/_new_group_sidebar.html.haml b/app/views/layouts/nav/_new_group_sidebar.html.haml
index d90aea2e361..5a1511b262f 100644
--- a/app/views/layouts/nav/_new_group_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_group_sidebar.html.haml
@@ -8,7 +8,7 @@
= @group.name
%ul.sidebar-top-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
- = link_to group_path(@group), title: 'Group overview' do
+ = sidebar_link group_path(@group), title: _('Group overview') do
.nav-icon-container
= custom_icon('project')
%span.nav-item-name
@@ -26,7 +26,7 @@
Activity
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
- = link_to issues_group_path(@group), title: 'Issues' do
+ = sidebar_link issues_group_path(@group), title: _('Issues') do
.nav-icon-container
= custom_icon('issues')
%span.nav-item-name
@@ -51,7 +51,7 @@
Milestones
= nav_link(path: 'groups#merge_requests') do
- = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
+ = sidebar_link merge_requests_group_path(@group), title: _('Merge Requests') do
.nav-icon-container
= custom_icon('mr_bold')
%span.nav-item-name
@@ -59,14 +59,14 @@
Merge Requests
%span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(path: 'group_members#index') do
- = link_to group_group_members_path(@group), title: 'Members' do
+ = sidebar_link group_group_members_path(@group), title: _('Members') do
.nav-icon-container
= custom_icon('members')
%span.nav-item-name
Members
- if current_user && can?(current_user, :admin_group, @group)
= nav_link(path: %w[groups#projects groups#edit ci_cd#show]) do
- = link_to edit_group_path(@group), title: 'Settings' do
+ = sidebar_link edit_group_path(@group), title: _('Settings') do
.nav-icon-container
= custom_icon('settings')
%span.nav-item-name
diff --git a/app/views/layouts/nav/_new_profile_sidebar.html.haml b/app/views/layouts/nav/_new_profile_sidebar.html.haml
index 85b2c7630c8..ccb6d1492f1 100644
--- a/app/views/layouts/nav/_new_profile_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_profile_sidebar.html.haml
@@ -7,76 +7,76 @@
.sidebar-context-title User Settings
%ul.sidebar-top-level-items
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
- = link_to profile_path, title: 'Profile Settings' do
+ = sidebar_link profile_path, title: _('Profile Settings') do
.nav-icon-container
= custom_icon('profile')
%span.nav-item-name
Profile
= nav_link(controller: [:accounts, :two_factor_auths]) do
- = link_to profile_account_path, title: 'Account' do
+ = sidebar_link profile_account_path, title: _('Account') do
.nav-icon-container
= custom_icon('account')
%span.nav-item-name
Account
- if current_application_settings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do
- = link_to applications_profile_path, title: 'Applications' do
+ = sidebar_link applications_profile_path, title: _('Applications') do
.nav-icon-container
= custom_icon('applications')
%span.nav-item-name
Applications
= nav_link(controller: :chat_names) do
- = link_to profile_chat_names_path, title: 'Chat' do
+ = sidebar_link profile_chat_names_path, title: _('Chat') do
.nav-icon-container
= custom_icon('chat')
%span.nav-item-name
Chat
= nav_link(controller: :personal_access_tokens) do
- = link_to profile_personal_access_tokens_path, title: 'Access Tokens' do
+ = sidebar_link profile_personal_access_tokens_path, title: _('Access Tokens') do
.nav-icon-container
= custom_icon('access_tokens')
%span.nav-item-name
Access Tokens
= nav_link(controller: :emails) do
- = link_to profile_emails_path, title: 'Emails' do
+ = sidebar_link profile_emails_path, title: _('Emails') do
.nav-icon-container
= custom_icon('emails')
%span.nav-item-name
Emails
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
- = link_to edit_profile_password_path, title: 'Password' do
+ = sidebar_link edit_profile_password_path, title: _('Password') do
.nav-icon-container
= custom_icon('lock')
%span.nav-item-name
Password
= nav_link(controller: :notifications) do
- = link_to profile_notifications_path, title: 'Notifications' do
+ = sidebar_link profile_notifications_path, title: _('Notifications') do
.nav-icon-container
= custom_icon('notifications')
%span.nav-item-name
Notifications
= nav_link(controller: :keys) do
- = link_to profile_keys_path, title: 'SSH Keys' do
+ = sidebar_link profile_keys_path, title: _('SSH Keys') do
.nav-icon-container
= custom_icon('key')
%span.nav-item-name
SSH Keys
= nav_link(controller: :gpg_keys) do
- = link_to profile_gpg_keys_path, title: 'GPG Keys' do
+ = sidebar_link profile_gpg_keys_path, title: _('GPG Keys') do
.nav-icon-container
= custom_icon('key_2')
%span.nav-item-name
GPG Keys
= nav_link(controller: :preferences) do
- = link_to profile_preferences_path, title: 'Preferences' do
+ = sidebar_link profile_preferences_path, title: _('Preferences') do
.nav-icon-container
= custom_icon('preferences')
%span.nav-item-name
Preferences
= nav_link(path: 'profiles#audit_log') do
- = link_to audit_log_profile_path, title: 'Authentication log' do
+ = sidebar_link audit_log_profile_path, title: _('Authentication log') do
.nav-icon-container
= custom_icon('authentication_log')
%span.nav-item-name
diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml
index 341943cf833..53dbf9e2f2b 100644
--- a/app/views/layouts/nav/_new_project_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_project_sidebar.html.haml
@@ -9,7 +9,7 @@
= @project.name
%ul.sidebar-top-level-items
= nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
- = link_to project_path(@project), title: 'Project overview', class: 'shortcuts-project' do
+ = sidebar_link project_path(@project), title: _('Project overview'), css: 'shortcuts-project' do
.nav-icon-container
= custom_icon('project')
%span.nav-item-name
@@ -31,7 +31,7 @@
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare projects/repositories tags branches releases graphs network)) do
- = link_to project_tree_path(@project), title: 'Repository', class: 'shortcuts-tree' do
+ = sidebar_link project_tree_path(@project), title: _('Repository'), css: 'shortcuts-tree' do
.nav-icon-container
= custom_icon('doc_text')
%span.nav-item-name
@@ -72,7 +72,7 @@
- if project_nav_tab? :container_registry
= nav_link(controller: %w[projects/registry/repositories]) do
- = link_to project_container_registry_index_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
+ = sidebar_link project_container_registry_index_path(@project), title: _('Container Registry'), css: 'shortcuts-container-registry' do
.nav-icon-container
= custom_icon('container_registry')
%span.nav-item-name
@@ -80,7 +80,7 @@
- if project_nav_tab? :issues
= nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do
- = link_to project_issues_path(@project), title: 'Issues', class: 'shortcuts-issues' do
+ = sidebar_link project_issues_path(@project), title: _('Issues'), css: 'shortcuts-issues' do
.nav-icon-container
= custom_icon('issues')
%span.nav-item-name
@@ -112,7 +112,7 @@
- if project_nav_tab? :merge_requests
= nav_link(controller: @project.issues_enabled? ? :merge_requests : [:merge_requests, :labels, :milestones]) do
- = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = sidebar_link project_merge_requests_path(@project), title: _('Merge Requests'), css: 'shortcuts-merge_requests' do
.nav-icon-container
= custom_icon('mr_bold')
%span.nav-item-name
@@ -122,7 +122,7 @@
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :environments, :artifacts]) do
- = link_to project_pipelines_path(@project), title: 'CI / CD', class: 'shortcuts-pipelines' do
+ = sidebar_link project_pipelines_path(@project), title: _('CI / CD'), css: 'shortcuts-pipelines' do
.nav-icon-container
= custom_icon('pipeline')
%span.nav-item-name
@@ -161,7 +161,7 @@
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
- = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
+ = sidebar_link get_project_wiki_path(@project), title: _('Wiki'), css: 'shortcuts-wiki' do
.nav-icon-container
= custom_icon('wiki')
%span.nav-item-name
@@ -169,7 +169,7 @@
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
- = link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
+ = sidebar_link project_snippets_path(@project), title: _('Snippets'), css: 'shortcuts-snippets' do
.nav-icon-container
= custom_icon('snippets')
%span.nav-item-name
@@ -177,7 +177,7 @@
- if project_nav_tab? :settings
= nav_link(path: %w[projects#edit project_members#index integrations#show services#edit repository#show ci_cd#show pages#show]) do
- = link_to edit_project_path(@project), title: 'Settings', class: 'shortcuts-tree' do
+ = sidebar_link edit_project_path(@project), title: _('Settings'), css: 'shortcuts-tree' do
.nav-icon-container
= custom_icon('settings')
%span.nav-item-name
diff --git a/app/views/profiles/gpg_keys/index.html.haml b/app/views/profiles/gpg_keys/index.html.haml
index 720a97cddb7..8dbb8aef31b 100644
--- a/app/views/profiles/gpg_keys/index.html.haml
+++ b/app/views/profiles/gpg_keys/index.html.haml
@@ -12,7 +12,7 @@
Add a GPG key
%p.profile-settings-content
Before you can add a GPG key you need to
- = link_to 'generate it.', help_page_path('user/project/gpg_signed_commits/index.md')
+ = link_to 'generate it.', help_page_path('user/project/repository/gpg_signed_commits/index.md')
= render 'form'
%hr
%h5
diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml
index a3783b31b86..d06b29db838 100644
--- a/app/views/projects/commit/_signature_badge.html.haml
+++ b/app/views/projects/commit/_signature_badge.html.haml
@@ -12,7 +12,7 @@
%span.monospace= signature.gpg_key_primary_keyid
- = link_to('Learn more about signing commits', help_page_path('user/project/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link')
+ = link_to('Learn more about signing commits', help_page_path('user/project/repository/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link')
%button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto top', title: title, content: content } }
= label