Commit 332dad45 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'ce_upstream' into 'master'

CE upstream

Closes gitlab-ce#29554

See merge request !1475
parents 28baca8a 87b81fa6
...@@ -376,7 +376,8 @@ trigger_docs: ...@@ -376,7 +376,8 @@ trigger_docs:
cache: {} cache: {}
artifacts: {} artifacts: {}
script: script:
- "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=ee https://gitlab.com/api/v3/projects/1794617/trigger/builds" - "HTTP_STATUS=$(curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=${CI_PROJECT_NAME} --silent --output curl.log --write-out '%{http_code}' https://gitlab.com/api/v3/projects/1794617/trigger/builds)"
- if [ "${HTTP_STATUS}" -ne "201" ]; then echo "Error ${HTTP_STATUS}"; cat curl.log; echo; exit 1; fi
only: only:
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 9.0.0 (2017-03-22)
- Geo: Replicate repository creation in Geo secondary node. !952
- Make approval system notes lowercase. !1125
- Issues can be exported as CSV, via email. !1126
- Try to update mirrors again after 15 minutes if the previous update failed. !1183
- Adds abitlity to render deploy boards in the frontend side. !1233
- Add filtered search to MR page. !1243
- Update project list API returns with approvals_before_merge attribute. !1245 (Geoff Webster)
- Catch Net::LDAP::DN exceptions in EE::Gitlab::LDAP::Group. !1260
- API: Use `post ":id/#{type}/:subscribable_id/subscribe"` to subscribe and `post ":id/#{type}/:subscribable_id/unsubscribe"` to unsubscribe from a resource. !1274 (Robert Schilling)
- API: Remove deprecated fields Notes#upvotes and Notes#downvotes. !1275 (Robert Schilling)
- Deploy board backend. !1278
- API: Remove the ProjectGitHook API. !1301 (Robert Schilling)
- Expose elasticsearch client params for AWS signing and HTTPS. !1305 (Matt Gresko)
- Fix LDAP DN case-mismatch bug in LDAP group sync. !1337
- Remove es6 file extension from JavaScript files. !1344 (winniehell)
- Geo: Don't load dependent models when fetching an existing GeoNode from the database. !1348
- Parallelise the gitlab:elastic:index_database Rake task. !1361
- Robustify reading attributes for elasticsearch. !1365
- Introduce one additional thread into bin/elastic_repo_indexer. !1372
- Show hook errors for fast-forward merges. !1375
- Allow all parameters of group webhooks to be set through the UI. !1376
- Fix Elasticsearch queries when a group_id is specified. !1423
- Check the right index mapping based on Rails environment for rake gitlab:elastic:add_feature_visiblity_levels_to_project. !1473
- Fix issues with another milestone that has a matching list label could not be added to a board.
- Only admins or group owners can set LDAP overrides.
- Add support for load balancing database queries.
- Only replace non-approval mr-widget-footer on getMergeStatus.
- Remove repository_storage from V4 "/application/settings" settings API.
- Added headers to protected branches access dropdowns.
- Remove support for Git Annex.
- Repositioned multiple issue boards selector.
- Added back weight in issue rows on issue list.
- Add basic support for GitLab Geo file transfers over HTTP.
- Added weight slash command.
- Set deployment status invalid when the environments does not match a k8s label.
- Combined deploy keys, push rules, protect branches and mirror repository settings options into a single one called Repository.
- Rebase - fix commiter email & name.
- Adds a EE specific dev favicon.
- Elastic security fix: Respect feature visibility level.
- Update Elasticsearch to 5.1.
- [Elasticsearch] More efficient search.
- Get Geo secondaries nodes statuses over AJAX.
## 8.17.4 (2017-03-19) ## 8.17.4 (2017-03-19)
- Elastic security fix: Respect feature visibility level. - Elastic security fix: Respect feature visibility level.
...@@ -954,51 +999,6 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -954,51 +999,6 @@ Please view this file on the master branch, on stable branches it's out of date.
- Add documentation for "Share project with group" API call - Add documentation for "Share project with group" API call
- Ability to disable 'Share with Group' feature (via UI and API) - Ability to disable 'Share with Group' feature (via UI and API)
## 9.0.0 (2017-03-22)
- Geo: Replicate repository creation in Geo secondary node. !952
- Make approval system notes lowercase. !1125
- Issues can be exported as CSV, via email. !1126
- Try to update mirrors again after 15 minutes if the previous update failed. !1183
- Adds abitlity to render deploy boards in the frontend side. !1233
- Add filtered search to MR page. !1243
- Update project list API returns with approvals_before_merge attribute. !1245 (Geoff Webster)
- Catch Net::LDAP::DN exceptions in EE::Gitlab::LDAP::Group. !1260
- API: Use `post ":id/#{type}/:subscribable_id/subscribe"` to subscribe and `post ":id/#{type}/:subscribable_id/unsubscribe"` to unsubscribe from a resource. !1274 (Robert Schilling)
- API: Remove deprecated fields Notes#upvotes and Notes#downvotes. !1275 (Robert Schilling)
- Deploy board backend. !1278
- API: Remove the ProjectGitHook API. !1301 (Robert Schilling)
- Expose elasticsearch client params for AWS signing and HTTPS. !1305 (Matt Gresko)
- Fix LDAP DN case-mismatch bug in LDAP group sync. !1337
- Remove es6 file extension from JavaScript files. !1344 (winniehell)
- Geo: Don't load dependent models when fetching an existing GeoNode from the database. !1348
- Parallelise the gitlab:elastic:index_database Rake task. !1361
- Robustify reading attributes for elasticsearch. !1365
- Introduce one additional thread into bin/elastic_repo_indexer. !1372
- Show hook errors for fast-forward merges. !1375
- Allow all parameters of group webhooks to be set through the UI. !1376
- Fix Elasticsearch queries when a group_id is specified. !1423
- Check the right index mapping based on Rails environment for rake gitlab:elastic:add_feature_visiblity_levels_to_project. !1473
- Fix issues with another milestone that has a matching list label could not be added to a board.
- Only admins or group owners can set LDAP overrides.
- Add support for load balancing database queries.
- Only replace non-approval mr-widget-footer on getMergeStatus.
- Remove repository_storage from V4 "/application/settings" settings API.
- Added headers to protected branches access dropdowns.
- Remove support for Git Annex.
- Repositioned multiple issue boards selector.
- Added back weight in issue rows on issue list.
- Add basic support for GitLab Geo file transfers over HTTP.
- Added weight slash command.
- Set deployment status invalid when the environments does not match a k8s label.
- Combined deploy keys, push rules, protect branches and mirror repository settings options into a single one called Repository.
- Rebase - fix commiter email & name.
- Adds a EE specific dev favicon.
- Elastic security fix: Respect feature visibility level.
- Update Elasticsearch to 5.1.
- [Elasticsearch] More efficient search.
- Get Geo secondaries nodes statuses over AJAX.
## 8.0.6 ## 8.0.6
- No EE-specific changes - No EE-specific changes
......
This diff is collapsed.
...@@ -65,6 +65,7 @@ require('./empty_state'); ...@@ -65,6 +65,7 @@ require('./empty_state');
}, },
filter: { filter: {
handler() { handler() {
this.page = 1;
this.loadIssues(true); this.loadIssues(true);
}, },
deep: true, deep: true,
...@@ -116,6 +117,9 @@ require('./empty_state'); ...@@ -116,6 +117,9 @@ require('./empty_state');
return this.activeTab === 'selected' && this.selectedIssues.length === 0; return this.activeTab === 'selected' && this.selectedIssues.length === 0;
}, },
}, },
created() {
this.page = 1;
},
components: { components: {
'modal-header': gl.issueBoards.ModalHeader, 'modal-header': gl.issueBoards.ModalHeader,
'modal-list': gl.issueBoards.ModalList, 'modal-list': gl.issueBoards.ModalList,
......
import PrometheusGraph from './monitoring/prometheus_graph'; // TODO: Maybe Make this a bundle
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
/* global UsernameValidator */ /* global UsernameValidator */
/* global ActiveTabMemoizer */ /* global ActiveTabMemoizer */
...@@ -341,8 +340,6 @@ const UserCallout = require('./user_callout'); ...@@ -341,8 +340,6 @@ const UserCallout = require('./user_callout');
case 'ci:lints:show': case 'ci:lints:show':
new gl.CILintEditor(); new gl.CILintEditor();
break; break;
case 'projects:environments:metrics':
new PrometheusGraph();
case 'users:show': case 'users:show':
new UserCallout(); new UserCallout();
break; break;
......
...@@ -14,6 +14,7 @@ export default { ...@@ -14,6 +14,7 @@ export default {
class="btn external_url" class="btn external_url"
:href="externalUrl" :href="externalUrl"
target="_blank" target="_blank"
rel="noopener noreferrer"
title="Environment external URL"> title="Environment external URL">
<i class="fa fa-external-link" aria-hidden="true"></i> <i class="fa fa-external-link" aria-hidden="true"></i>
</a> </a>
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value, true); gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value, true);
} }
this.resetFilters();
this.dismissDropdown(); this.dismissDropdown();
this.dispatchInputEvent(); this.dispatchInputEvent();
} }
...@@ -107,7 +108,7 @@ ...@@ -107,7 +108,7 @@
const hook = this.getCurrentHook(); const hook = this.getCurrentHook();
if (hook) { if (hook) {
const data = hook.list.data; const data = hook.list.data || [];
if (!data) return; if (!data) return;
......
...@@ -44,6 +44,8 @@ import FilteredSearchContainer from './container'; ...@@ -44,6 +44,8 @@ import FilteredSearchContainer from './container';
this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this); this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this);
this.editTokenWrapper = this.editToken.bind(this); this.editTokenWrapper = this.editToken.bind(this);
this.tokenChange = this.tokenChange.bind(this); this.tokenChange = this.tokenChange.bind(this);
this.addInputContainerFocusWrapper = this.addInputContainerFocus.bind(this);
this.removeInputContainerFocusWrapper = this.removeInputContainerFocus.bind(this);
this.filteredSearchInputForm = this.filteredSearchInput.form; this.filteredSearchInputForm = this.filteredSearchInput.form;
this.filteredSearchInputForm.addEventListener('submit', this.handleFormSubmit); this.filteredSearchInputForm.addEventListener('submit', this.handleFormSubmit);
...@@ -55,11 +57,13 @@ import FilteredSearchContainer from './container'; ...@@ -55,11 +57,13 @@ import FilteredSearchContainer from './container';
this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper); this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.addEventListener('click', this.tokenChange); this.filteredSearchInput.addEventListener('click', this.tokenChange);
this.filteredSearchInput.addEventListener('keyup', this.tokenChange); this.filteredSearchInput.addEventListener('keyup', this.tokenChange);
this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken); this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper); this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper);
this.clearSearchButton.addEventListener('click', this.clearSearchWrapper); this.clearSearchButton.addEventListener('click', this.clearSearchWrapper);
document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.addEventListener('click', this.unselectEditTokensWrapper); document.addEventListener('click', this.unselectEditTokensWrapper);
document.addEventListener('click', this.removeInputContainerFocusWrapper);
document.addEventListener('keydown', this.removeSelectedTokenWrapper); document.addEventListener('keydown', this.removeSelectedTokenWrapper);
} }
...@@ -73,11 +77,13 @@ import FilteredSearchContainer from './container'; ...@@ -73,11 +77,13 @@ import FilteredSearchContainer from './container';
this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper); this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.removeEventListener('click', this.tokenChange); this.filteredSearchInput.removeEventListener('click', this.tokenChange);
this.filteredSearchInput.removeEventListener('keyup', this.tokenChange); this.filteredSearchInput.removeEventListener('keyup', this.tokenChange);
this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken); this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper); this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper);
this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper); this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper);
document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.removeEventListener('click', this.unselectEditTokensWrapper); document.removeEventListener('click', this.unselectEditTokensWrapper);
document.removeEventListener('click', this.removeInputContainerFocusWrapper);
document.removeEventListener('keydown', this.removeSelectedTokenWrapper); document.removeEventListener('keydown', this.removeSelectedTokenWrapper);
} }
...@@ -130,6 +136,26 @@ import FilteredSearchContainer from './container'; ...@@ -130,6 +136,26 @@ import FilteredSearchContainer from './container';
} }
} }
addInputContainerFocus() {
const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container');
if (inputContainer) {
inputContainer.classList.add('focus');
}
}
removeInputContainerFocus(e) {
const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container');
const isElementInFilteredSearch = inputContainer && inputContainer.contains(e.target);
const isElementInDynamicFilterDropdown = e.target.closest('.filter-dropdown') !== null;
const isElementInStaticFilterDropdown = e.target.closest('ul[data-dropdown]') !== null;
if (!isElementInFilteredSearch && !isElementInDynamicFilterDropdown &&
!isElementInStaticFilterDropdown && inputContainer) {
inputContainer.classList.remove('focus');
}
}
static selectToken(e) { static selectToken(e) {
const button = e.target.closest('.selectable'); const button = e.target.closest('.selectable');
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Flash */ /* global Flash */
require('./flash'); require('./flash');
require('~/lib/utils/text_utility');
require('vendor/jquery.waitforimages'); require('vendor/jquery.waitforimages');
require('./task_list'); require('./task_list');
...@@ -50,20 +51,21 @@ class Issue { ...@@ -50,20 +51,21 @@ class Issue {
success: function(data, textStatus, jqXHR) { success: function(data, textStatus, jqXHR) {
if ('id' in data) { if ('id' in data) {
$(document).trigger('issuable:change'); $(document).trigger('issuable:change');
const currentTotal = Number($('.issue_counter').text()); let total = Number($('.issue_counter').text().replace(/[^\d]/, ''));
if (isClose) { if (isClose) {
$('a.btn-close').addClass('hidden'); $('a.btn-close').addClass('hidden');
$('a.btn-reopen').removeClass('hidden'); $('a.btn-reopen').removeClass('hidden');
$('div.status-box-closed').removeClass('hidden'); $('div.status-box-closed').removeClass('hidden');
$('div.status-box-open').addClass('hidden'); $('div.status-box-open').addClass('hidden');
$('.issue_counter').text(currentTotal - 1); total -= 1;
} else { } else {
$('a.btn-reopen').addClass('hidden'); $('a.btn-reopen').addClass('hidden');
$('a.btn-close').removeClass('hidden'); $('a.btn-close').removeClass('hidden');
$('div.status-box-closed').addClass('hidden'); $('div.status-box-closed').addClass('hidden');
$('div.status-box-open').removeClass('hidden'); $('div.status-box-open').removeClass('hidden');
$('.issue_counter').text(currentTotal + 1); total += 1;
} }
$('.issue_counter').text(gl.text.addDelimiter(total));
} else { } else {
new Flash(issueFailMessage, 'alert'); new Flash(issueFailMessage, 'alert');
} }
......
...@@ -14,13 +14,13 @@ import MiniPipelineGraph from './mini_pipeline_graph_dropdown'; ...@@ -14,13 +14,13 @@ import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
<%= ci_success_icon %> <%= ci_success_icon %>
<span> <span>
Deployed to Deployed to
<a href="<%- url %>" target="_blank" class="environment"> <a href="<%- url %>" target="_blank" rel="noopener noreferrer" class="environment">
<%- name %> <%- name %>
</a> </a>
<span class="js-environment-timeago" data-toggle="tooltip" data-placement="top" data-title="<%- deployed_at_formatted %>"> <span class="js-environment-timeago" data-toggle="tooltip" data-placement="top" data-title="<%- deployed_at_formatted %>">
<%- deployed_at %> <%- deployed_at %>
</span> </span>
<a class="js-environment-link" href="<%- external_url %>" target="_blank"> <a class="js-environment-link" href="<%- external_url %>" target="_blank" rel="noopener noreferrer">
<i class="fa fa-external-link"></i> <i class="fa fa-external-link"></i>
View on <%- external_url_formatted %> View on <%- external_url_formatted %>
</a> </a>
......
import PrometheusGraph from './prometheus_graph';
document.addEventListener('DOMContentLoaded', function onLoad() {
document.removeEventListener('DOMContentLoaded', onLoad, false);
return new PrometheusGraph();
}, false);
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
/* global Flash */ /* global Flash */
import d3 from 'd3'; import d3 from 'd3';
import _ from 'underscore';
import statusCodes from '~/lib/utils/http_status'; import statusCodes from '~/lib/utils/http_status';
import '~/lib/utils/common_utils'; import '../lib/utils/common_utils';
import '~/flash'; import '../flash';
const prometheusGraphsContainer = '.prometheus-graph'; const prometheusGraphsContainer = '.prometheus-graph';
const metricsEndpoint = 'metrics.json'; const metricsEndpoint = 'metrics.json';
...@@ -31,22 +30,21 @@ class PrometheusGraph { ...@@ -31,22 +30,21 @@ class PrometheusGraph {
} }
createGraph() { createGraph() {
const self = this; Object.keys(this.data).forEach((key) => {
_.each(this.data, (value, key) => { const value = this.data[key];
if (value.length > 0 && (key === 'cpu_values' || key === 'memory_values')) { if (value.length > 0) {
self.plotValues(value, key); this.plotValues(value, key);
} }
}); });
} }
init() { init() {
const self = this;
this.getData().then((metricsResponse) => { this.getData().then((metricsResponse) => {
if (metricsResponse === {}) { if (Object.keys(metricsResponse).length === 0) {
new Flash('Empty metrics', 'alert'); new Flash('Empty metrics', 'alert');
} else { } else {
self.transformData(metricsResponse); this.transformData(metricsResponse);
self.createGraph(); this.createGraph();
} }
}); });
} }
...@@ -321,12 +319,14 @@ class PrometheusGraph { ...@@ -321,12 +319,14 @@ class PrometheusGraph {
transformData(metricsResponse) { transformData(metricsResponse) {
const metricTypes = {}; const metricTypes = {};
_.each(metricsResponse.metrics, (value, key) => { Object.keys(metricsResponse.metrics).forEach((key) => {
const metricValues = value[0].values; if (key === 'cpu_values' || key === 'memory_values') {
metricTypes[key] = _.map(metricValues, metric => ({ const metricValues = (metricsResponse.metrics[key])[0];
metricTypes[key] = metricValues.values.map(metric => ({
time: new Date(metric[0] * 1000), time: new Date(metric[0] * 1000),
value: metric[1], value: metric[1],
})); }));
}
}); });
this.data = metricTypes; this.data = metricTypes;
} }
......
...@@ -433,3 +433,9 @@ table { ...@@ -433,3 +433,9 @@ table {
@include str-truncated(100%); @include str-truncated(100%);
} }
} }
.tooltip {
.tooltip-inner {
word-wrap: break-word;
}
}
...@@ -76,12 +76,14 @@ ...@@ -76,12 +76,14 @@
} }
.input-token { .input-token {
flex: 1; max-width: 200px;
-webkit-flex: 1;
} }
.filtered-search-token + .input-token:not(:last-child) { .input-token:only-child,
max-width: 200px; .input-token:last-child {
flex: 1;
-webkit-flex: 1;
max-width: initial;
} }
} }
...@@ -158,8 +160,8 @@ ...@@ -158,8 +160,8 @@
background-color: $white-light; background-color: $white-light;
@media (max-width: $screen-xs-min) { @media (max-width: $screen-xs-min) {
-webkit-flex: 1 1 100%; -webkit-flex: 1 1 auto;
flex: 1 1 100%; flex: 1 1 auto;
margin-bottom: 10px; margin-bottom: 10px;
.dropdown-menu { .dropdown-menu {
...@@ -171,17 +173,26 @@ ...@@ -171,17 +173,26 @@
} }
} }
&:hover {
@extend .form-control:hover;
}
&.focus,
&.focus:hover {
border-color: $dropdown-input-focus-border;
box-shadow: 0 0 4px $search-input-focus-shadow-color;
}
&.focus .fa-filter {
color: $common-gray-dark;
}
.form-control { .form-control {
position: relative; position: relative;
min-width: 200px; min-width: 200px;
padding-left: 0; padding: 5px 25px 6px 0;
padding-right: 25px;
border-color: transparent; border-color: transparent;
&:focus ~ .fa-filter {
color: $common-gray-dark;
}
&:focus, &:focus,
&:hover { &:hover {
outline: none; outline: none;
...@@ -221,6 +232,10 @@ ...@@ -221,6 +232,10 @@
.filter-dropdown-container { .filter-dropdown-container {
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
.dropdown-toggle {
line-height: 22px;
}
} }
.dropdown-menu .filter-dropdown-item { .dropdown-menu .filter-dropdown-item {
...@@ -246,7 +261,9 @@ ...@@ -246,7 +261,9 @@
background-color: $white-light; background-color: $white-light;
border-top: 0; border-top: 0;
} }
}
@media (max-width: $screen-xs) {
.filter-dropdown-container { .filter-dropdown-container {
.dropdown-toggle, .dropdown-toggle,
.dropdown { .dropdown {
......
...@@ -148,6 +148,18 @@ ...@@ -148,6 +148,18 @@
.error-alert > .alert { .error-alert > .alert {
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
&.alert-dismissable {
.close {
color: $white-light;
opacity: 0.85;
font-weight: normal;
&:hover {
opacity: 1;
}
}
}
} }
.discussion-body, .discussion-body,
......
...@@ -89,4 +89,9 @@ class Projects::ApplicationController < ApplicationController ...@@ -89,4 +89,9 @@ class Projects::ApplicationController < ApplicationController
def builds_enabled def builds_enabled
return render_404 unless @project.feature_available?(:builds, current_user) return render_404 unless @project.feature_available?(:builds, current_user)
end end
def update_ref
branch_exists = @repository.find_branch(@target_branch)
@ref = @target_branch if branch_exists
end
end end
...@@ -89,11 +89,6 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -89,11 +89,6 @@ class Projects::BlobController < Projects::ApplicationController
private private
def update_ref
branch_exists = @repository.find_branch(@target_branch)
@ref = @target_branch if branch_exists
end
def blob def blob
@blob ||= Blob.decorate(@repository.blob_at(@commit.id, @path)) @blob ||= Blob.decorate(@repository.blob_at(@commit.id, @path))
......
...@@ -6,7 +6,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -6,7 +6,7 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableCollections include IssuableCollections
include SpammableActions include SpammableActions
prepend_before_action :authenticate_user!, only: [:export_csv] prepend_before_action :authenticate_user!, only: [:new, :export_csv]
before_action :redirect_to_external_issue_tracker, only: [:index, :new] before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled before_action :module_enabled
...@@ -154,7 +154,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -154,7 +154,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
format.json do format.json do
render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) render json: @issue.to_json(include: { milestone: {}, assignee: { only: [:name, :username], methods: [:avatar_url] }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short])
end end
end end
......
...@@ -319,7 +319,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -319,7 +319,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
format.json do format.json do
render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) render json: @merge_request.to_json(include: { milestone: {}, assignee: { only: [:name, :username], methods: [:avatar_url] }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short])
end end
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
......
...@@ -9,6 +9,7 @@ module Projects ...@@ -9,6 +9,7 @@ module Projects
@skip_groups = @group_links.pluck(:group_id) @skip_groups = @group_links.pluck(:group_id)
@skip_groups << @project.namespace_id unless @project.personal? @skip_groups << @project.namespace_id unless @project.personal?
@skip_groups += @project.group.ancestors.pluck(:id) if @project.group
@project_members = MembersFinder.new(@project, current_user).execute @project_members = MembersFinder.new(@project, current_user).execute
......
...@@ -34,6 +34,7 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -34,6 +34,7 @@ class Projects::TreeController < Projects::ApplicationController
def create_dir def create_dir
return render_404 unless @commit_params.values.all? return render_404 unless @commit_params.values.all?
update_ref
create_commit(Files::CreateDirService, success_notice: "The directory has been successfully created.", create_commit(Files::CreateDirService, success_notice: "The directory has been successfully created.",
success_path: namespace_project_tree_path(@project.namespace, @project, File.join(@target_branch, @dir_name)), success_path: namespace_project_tree_path(@project.namespace, @project, File.join(@target_branch, @dir_name)),
failure_path: namespace_project_tree_path(@project.namespace, @project, @ref)) failure_path: namespace_project_tree_path(@project.namespace, @project, @ref))
......
...@@ -215,6 +215,6 @@ module BlobHelper ...@@ -215,6 +215,6 @@ module BlobHelper
end end
def open_raw_file_button(path) def open_raw_file_button(path)
link_to icon('file-code-o'), path, class: 'btn btn-sm has-tooltip', target: '_blank', title: 'Open raw', data: { container: 'body' } link_to icon('file-code-o'), path, class: 'btn btn-sm has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: 'Open raw', data: { container: 'body' }
end end
end end
...@@ -211,7 +211,7 @@ module CommitsHelper ...@@ -211,7 +211,7 @@ module CommitsHelper
external_url = environment.external_url_for(diff_new_path, commit_sha) external_url = environment.external_url_for(diff_new_path, commit_sha)
return unless external_url return unless external_url
link_to(external_url, class: 'btn btn-file-option has-tooltip', target: '_blank', title: "View on #{environment.formatted_external_url}", data: { container: 'body' }) do link_to(external_url, class: 'btn btn-file-option has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: "View on #{environment.formatted_external_url}", data: { container: 'body' }) do
icon('external-link') icon('external-link')
end end
end end
......
...@@ -7,7 +7,7 @@ module ImportHelper ...@@ -7,7 +7,7 @@ module ImportHelper
def provider_project_link(provider, path_with_namespace) def provider_project_link(provider, path_with_namespace)
url = __send__("#{provider}_project_url", path_with_namespace) url = __send__("#{provider}_project_url", path_with_namespace)
link_to path_with_namespace, url, target: '_blank' link_to path_with_namespace, url, target: '_blank', rel: 'noopener noreferrer'
end end
private private
......
...@@ -182,6 +182,8 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -182,6 +182,8 @@ class ApplicationSetting < ActiveRecord::Base
end end
def self.current def self.current
ensure_cache_setup
Rails.cache.fetch(CACHE_KEY) do Rails.cache.fetch(CACHE_KEY) do
ApplicationSetting.last ApplicationSetting.last
end end
...@@ -195,9 +197,16 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -195,9 +197,16 @@ class ApplicationSetting < ActiveRecord::Base
end end
def self.cached def self.cached
ensure_cache_setup
Rails.cache.fetch(CACHE_KEY) Rails.cache.fetch(CACHE_KEY)
end end
def self.ensure_cache_setup
# This is a workaround for a Rails bug that causes attribute methods not
# to be loaded when read from cache: https://github.com/rails/rails/issues/27348
ApplicationSetting.define_attribute_methods
end
def self.defaults_ce def self.defaults_ce
{ {
after_sign_up_text: nil, after_sign_up_text: nil,
......
...@@ -31,6 +31,7 @@ module HasStatus ...@@ -31,6 +31,7 @@ module HasStatus
WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending' WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending'
WHEN (#{running})+(#{pending})>0 THEN 'running' WHEN (#{running})+(#{pending})>0 THEN 'running'
WHEN (#{manual})>0 THEN 'manual' WHEN (#{manual})>0 THEN 'manual'
WHEN (#{created})>0 THEN 'running'
ELSE 'failed' ELSE 'failed'
END)" END)"
end end
......
...@@ -48,12 +48,14 @@ module Issuable ...@@ -48,12 +48,14 @@ module Issuable
delegate :name, delegate :name,
:email, :email,
:public_email,
to: :author, to: :author,
allow_nil: true, allow_nil: true,
prefix: true prefix: true
delegate :name, delegate :name,
:email, :email,
:public_email,
to: :assignee, to: :assignee,
allow_nil: true, allow_nil: true,
prefix: true prefix: true
......
...@@ -16,7 +16,7 @@ class Event < ActiveRecord::Base ...@@ -16,7 +16,7 @@ class Event < ActiveRecord::Base
RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour
delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :name, :email, :public_email, to: :author, prefix: true, allow_nil: true
delegate :title, to: :issue, prefix: true, allow_nil: true delegate :title, to: :issue, prefix: true, allow_nil: true
delegate :title, to: :merge_request, prefix: true, allow_nil: true delegate :title, to: :merge_request, prefix: true, allow_nil: true
delegate :title, to: :note, prefix: true, allow_nil: true delegate :title, to: :note, prefix: true, allow_nil: true
......
...@@ -251,7 +251,7 @@ class Group < Namespace ...@@ -251,7 +251,7 @@ class Group < Namespace
end end
def members_with_parents def members_with_parents
GroupMember.non_request.where(source_id: ancestors.map(&:id).push(id)) GroupMember.non_request.where(source_id: ancestors.pluck(:id).push(id))
end end
def users_with_parents def users_with_parents
......
...@@ -205,6 +205,7 @@ class Project < ActiveRecord::Base ...@@ -205,6 +205,7 @@ class Project < ActiveRecord::Base
validates :name, uniqueness: { scope: :namespace_id } validates :name, uniqueness: { scope: :namespace_id }
validates :path, uniqueness: { scope: :namespace_id } validates :path, uniqueness: { scope: :namespace_id }
validates :import_url, addressable_url: true, if: :external_import? validates :import_url, addressable_url: true, if: :external_import?
validates :import_url, importable_url: true, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 } validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create validate :check_limit, on: :create
validate :avatar_type, validate :avatar_type,
......
...@@ -30,7 +30,14 @@ class PrometheusService < MonitoringService ...@@ -30,7 +30,14 @@ class PrometheusService < MonitoringService
end end
def help def help
'Retrieves `container_cpu_usage_seconds_total` and `container_memory_usage_bytes` from the configured Prometheus server. An `environment` label is required on each metric to identify the Environment.' <<-MD.strip_heredoc
Retrieves the Kubernetes node metrics `container_cpu_usage_seconds_total`
and `container_memory_usage_bytes` from the configured Prometheus server.
If you are not using [Auto-Deploy](https://docs.gitlab.com/ee/ci/autodeploy/index.html)
or have set up your own Prometheus server, an `environment` label is required on each metric to
[identify the Environment](https://docs.gitlab.com/ce/user/project/integrations/prometheus.html#metrics-and-labels).
MD
end end
def self.to_param def self.to_param
......
...@@ -21,7 +21,7 @@ class Route < ActiveRecord::Base ...@@ -21,7 +21,7 @@ class Route < ActiveRecord::Base
attributes[:path] = route.path.sub(path_was, path) attributes[:path] = route.path.sub(path_was, path)
end end
if name_changed? && route.name.present? if name_changed? && name_was.present? && route.name.present?
attributes[:name] = route.name.sub(name_was, name) attributes[:name] = route.name.sub(name_was, name)
end end
......
...@@ -25,12 +25,12 @@ class CreateBranchService < BaseService ...@@ -25,12 +25,12 @@ class CreateBranchService < BaseService
private private
def create_master_branch def create_master_branch
project.repository.commit_file( project.repository.create_file(
current_user, current_user,
'/README.md', '/README.md',
'', '',
message: 'Add README.md', message: 'Add README.md',
branch_name: 'master', branch_name: 'master'
update: false) )
end end
end end
...@@ -33,6 +33,7 @@ module Projects ...@@ -33,6 +33,7 @@ module Projects
def import_repository def import_repository
begin begin
raise Error, "Blocked import URL." if Gitlab::UrlBlocker.blocked_url?(project.import_url)
gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url) gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url)
rescue => e rescue => e
# Expire cache to prevent scenarios such as: # Expire cache to prevent scenarios such as:
......
...@@ -24,10 +24,9 @@ class SystemHooksService ...@@ -24,10 +24,9 @@ class SystemHooksService
key: model.key, key: model.key,
id: model.id id: model.id
) )
if model.user if model.user
data.merge!( data[:username] = model.user.username
username: model.user.username
)
end end
when Project when Project
data.merge!(project_data(model)) data.merge!(project_data(model))
...@@ -35,8 +34,6 @@ class SystemHooksService ...@@ -35,8 +34,6 @@ class SystemHooksService
if event == :rename || event == :transfer if event == :rename || event == :transfer
data[:old_path_with_namespace] = model.old_path_with_namespace data[:old_path_with_namespace] = model.old_path_with_namespace
end end
data
when User when User
data.merge!({ data.merge!({
name: model.name, name: model.name,
...@@ -59,6 +56,8 @@ class SystemHooksService ...@@ -59,6 +56,8 @@ class SystemHooksService
when GroupMember when GroupMember
data.merge!(group_member_data(model)) data.merge!(group_member_data(model))
end end
data
end end
def build_event_name(model, event) def build_event_name(model, event)
......
# ImportableUrlValidator
#
# This validator blocks projects from using dangerous import_urls to help
# protect against Server-side Request Forgery (SSRF).
class ImportableUrlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if Gitlab::UrlBlocker.blocked_url?(value)
record.errors.add(attribute, "imports are not allowed from that URL")
end
end
end
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
.form-actions .form-actions
= f.submit 'Save', class: 'btn btn-save append-right-10' = f.submit 'Save', class: 'btn btn-save append-right-10'
- if @appearance.persisted? - if @appearance.persisted?
= link_to 'Preview last save', preview_admin_appearances_path, class: 'btn', target: '_blank' = link_to 'Preview last save', preview_admin_appearances_path, class: 'btn', target: '_blank', rel: 'noopener noreferrer'
- if @appearance.updated_at - if @appearance.updated_at
%span.pull-right %span.pull-right
......
...@@ -424,7 +424,7 @@ ...@@ -424,7 +424,7 @@
Enable Sentry Enable Sentry
.help-block .help-block
Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here: Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here:
%a{ href: 'https://getsentry.com', target: '_blank' } https://getsentry.com %a{ href: 'https://getsentry.com', target: '_blank', rel: 'noopener noreferrer' } https://getsentry.com
.form-group .form-group
= f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2' = f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2'
......
...@@ -9,7 +9,7 @@ xml.entry do ...@@ -9,7 +9,7 @@ xml.entry do
xml.author do xml.author do
xml.name event.author_name xml.name event.author_name
xml.email event.author_email xml.email event.author_public_email
end end
xml.summary(type: "xhtml") do |summary| xml.summary(type: "xhtml") do |summary|
......
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
= link_to note.attachment.url, target: '_blank' do = link_to note.attachment.url, target: '_blank' do
= image_tag note.attachment.url, class: 'note-image-attach' = image_tag note.attachment.url, class: 'note-image-attach'
- else - else
= link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do = link_to note.attachment.url, target: '_blank', class: 'note-file-attach' do
%i.fa.fa-paperclip %i.fa.fa-paperclip
= note.attachment_identifier = note.attachment_identifier
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- if current_application_settings.version_check_enabled - if current_application_settings.version_check_enabled
= version_status_badge = version_status_badge
%br %br
Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank'}. Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank', rel: 'noopener noreferrer'}.
- if current_application_settings.help_text.present? - if current_application_settings.help_text.present?
%hr %hr
%p.slead %p.slead
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
- @already_added_projects.each do |project| - @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
%td %td
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank' = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer'
%td %td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
- @repos.each do |repo| - @repos.each do |repo|
%tr{ id: "repo_#{repo.owner}___#{repo.slug}" } %tr{ id: "repo_#{repo.owner}___#{repo.slug}" }
%td %td
= link_to repo.full_name, "https://bitbucket.org/#{repo.full_name}", target: "_blank" = link_to repo.full_name, "https://bitbucket.org/#{repo.full_name}", target: '_blank', rel: 'noopener noreferrer'
%td.import-target %td.import-target
%fieldset.row %fieldset.row
.input-group .input-group
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
- @incompatible_repos.each do |repo| - @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.owner}___#{repo.slug}" } %tr{ id: "repo_#{repo.owner}___#{repo.slug}" }
%td %td
= link_to repo.full_name, "https://bitbucket.org/#{repo.full_name}", target: '_blank' = link_to repo.full_name, "https://bitbucket.org/#{repo.full_name}", target: '_blank', rel: 'noopener noreferrer'
%td.import-target %td.import-target
%td.import-actions-job-status %td.import-actions-job-status
= label_tag 'Incompatible Project', nil, class: 'label label-danger' = label_tag 'Incompatible Project', nil, class: 'label label-danger'
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
- @repos.each do |repo| - @repos.each do |repo|
%tr{ id: "repo_#{repo["id"]}" } %tr{ id: "repo_#{repo["id"]}" }
%td %td
= link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank" = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank", rel: 'noopener noreferrer'
%td.import-target %td.import-target
= import_project_target(repo['namespace']['path'], repo['name']) = import_project_target(repo['namespace']['path'], repo['name'])
%td.import-actions.job-status %td.import-actions.job-status
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
%li %li
%p %p
Go to Go to
#{link_to "Google Takeout", "https://www.google.com/settings/takeout", target: "_blank"}. #{link_to "Google Takeout", "https://www.google.com/settings/takeout", target: '_blank', rel: 'noopener noreferrer'}.
%li %li
%p %p
Make sure you're logged into the account that owns the projects you'd like to import. Make sure you're logged into the account that owns the projects you'd like to import.
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
- @already_added_projects.each do |project| - @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
%td %td
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
%td %td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status %td.job-status
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
- @repos.each do |repo| - @repos.each do |repo|
%tr{ id: "repo_#{repo.id}" } %tr{ id: "repo_#{repo.id}" }
%td %td
= link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank" = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank", rel: 'noopener noreferrer'
%td.import-target %td.import-target
#{current_user.username}/#{repo.name} #{current_user.username}/#{repo.name}
%td.import-actions.job-status %td.import-actions.job-status
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
- @incompatible_repos.each do |repo| - @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.id}" } %tr{ id: "repo_#{repo.id}" }
%td %td
= link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank" = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank", rel: 'noopener noreferrer'
%td.import-target %td.import-target
%td.import-actions-job-status %td.import-actions-job-status
= label_tag "Incompatible Project", nil, class: "label label-danger" = label_tag "Incompatible Project", nil, class: "label label-danger"
......
...@@ -7,7 +7,7 @@ xml.entry do ...@@ -7,7 +7,7 @@ xml.entry do
xml.author do xml.author do
xml.name issue.author_name xml.name issue.author_name
xml.email issue.author_email xml.email issue.author_public_email
end end
xml.summary issue.title xml.summary issue.title
...@@ -26,7 +26,7 @@ xml.entry do ...@@ -26,7 +26,7 @@ xml.entry do
if issue.assignee if issue.assignee
xml.assignee do xml.assignee do
xml.name issue.assignee.name xml.name issue.assignee.name
xml.email issue.assignee.email xml.email issue.assignee_public_email
end end
end end
end end
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
%p %p
= icon('circle', class: 'cgreen') = icon('circle', class: 'cgreen')
Integration is active for Integration is active for
= link_to koding_project_url, target: '_blank' do = link_to koding_project_url, target: '_blank', rel: 'noopener noreferrer' do
#{current_application_settings.koding_url} #{current_application_settings.koding_url}
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
.col-lg-9 .col-lg-9
.clearfix.avatar-image.append-bottom-default .clearfix.avatar-image.append-bottom-default
= link_to avatar_icon(@user, 400), target: '_blank' do = link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160'
%h5.prepend-top-0 %h5.prepend-top-0
Upload new avatar Upload new avatar
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
- else - else
.nothing-here-block .nothing-here-block
The SVG could not be displayed as it is too large, you can The SVG could not be displayed as it is too large, you can
#{link_to('view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank')} #{link_to('view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank', rel: 'noopener noreferrer')}
instead. instead.
- else - else
%img{ src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path)), alt: "#{blob.name}" } %img{ src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path)), alt: "#{blob.name}" }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.nothing-here-block .nothing-here-block
File too large, you can File too large, you can
= succeed '.' do = succeed '.' do
= link_to 'view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank' = link_to 'view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank', rel: 'noopener noreferrer'
- else - else
- blob.load_all_data!(@repository) - blob.load_all_data!(@repository)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
- if @conflict - if @conflict
.alert.alert-danger .alert.alert-danger
Someone edited the file the same time you did. Please check out Someone edited the file the same time you did. Please check out
= link_to "the file", namespace_project_blob_path(@project.namespace, @project, tree_join(@target_branch, @file_path)), target: "_blank" = link_to "the file", namespace_project_blob_path(@project.namespace, @project, tree_join(@target_branch, @file_path)), target: "_blank", rel: 'noopener noreferrer'
and make sure your changes will not unintentionally remove theirs. and make sure your changes will not unintentionally remove theirs.
.file-editor .file-editor
......
- if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch) - if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch)
= link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank' do = link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank', rel: 'noopener noreferrer' do
Run in IDE (Koding) Run in IDE (Koding)
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project. Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.
To set up CA, you must first define a production environment by setting up your CI and then deploy to production. To set up CA, you must first define a production environment by setting up your CI and then deploy to production.
%p %p
%a.btn{ href: help_page_path('user/project/cycle_analytics'), target: "_blank" } Read more %a.btn{ href: help_page_path('user/project/cycle_analytics'), target: '_blank' } Read more
.col-md-6.overview-image .col-md-6.overview-image
%span.overview-icon %span.overview-icon
= custom_icon ('icon_cycle_analytics_overview') = custom_icon ('icon_cycle_analytics_overview')
- if environment.external_url && can?(current_user, :read_environment, environment) - if environment.external_url && can?(current_user, :read_environment, environment)
= link_to environment.external_url, target: '_blank', class: 'btn external-url' do = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url' do
= icon('external-link') = icon('external-link')
- @no_container = true - @no_container = true
- page_title "Metrics for environment", @environment.name - page_title "Metrics for environment", @environment.name
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('monitoring')
= render "projects/pipelines/head" = render "projects/pipelines/head"
%div{ class: container_class } %div{ class: container_class }
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
- if current_user - if current_user
%button.csv_download_link.btn.append-right-10.has-tooltip{ title: 'Export as CSV' } %button.csv_download_link.btn.append-right-10.has-tooltip{ title: 'Export as CSV' }
= icon('download') = icon('download')
- if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, = link_to new_namespace_project_issue_path(@project.namespace,
@project, @project,
issue: { assignee_id: issues_finder.assignee.try(:id), issue: { assignee_id: issues_finder.assignee.try(:id),
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
= confidential_icon(@issue) = confidential_icon(@issue)
= issuable_meta(@issue, @project, "Issue") = issuable_meta(@issue, @project, "Issue")
- if can?(current_user, :create_issue, @project) || can?(current_user, :update_issue, @issue)
.issuable-actions .issuable-actions
.clearfix.issue-btn-group.dropdown .clearfix.issue-btn-group.dropdown
%button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } } %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } }
...@@ -28,7 +27,6 @@ ...@@ -28,7 +27,6 @@
= icon('caret-down') = icon('caret-down')
.dropdown-menu.dropdown-menu-align-right.hidden-lg .dropdown-menu.dropdown-menu-align-right.hidden-lg
%ul %ul
- if can?(current_user, :create_issue, @project)
%li %li
= link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link' = link_to 'New issue', new_namespace_project_issue_path(@project.namespace, @project), title: 'New issue', id: 'new_issue_link'
- if can?(current_user, :update_issue, @issue) - if can?(current_user, :update_issue, @issue)
...@@ -42,7 +40,6 @@ ...@@ -42,7 +40,6 @@
%li %li
= link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'btn-spam', title: 'Submit as spam' = link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'btn-spam', title: 'Submit as spam'
- if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-grouped new-issue-link btn-new btn-inverted', title: 'New issue', id: 'new_issue_link' do = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-grouped new-issue-link btn-new btn-inverted', title: 'New issue', id: 'new_issue_link' do
New issue New issue
- if can?(current_user, :update_issue, @issue) - if can?(current_user, :update_issue, @issue)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.pull-right .pull-right
- if @merge_request.source_branch_exists? - if @merge_request.source_branch_exists?
- if koding_enabled? && @repository.koding_yml - if koding_enabled? && @repository.koding_yml
= link_to koding_project_url(@merge_request.source_project, @merge_request.source_branch, @merge_request.commits.first.short_id), class: "btn inline btn-grouped btn-sm", target: '_blank' do = link_to koding_project_url(@merge_request.source_project, @merge_request.source_branch, @merge_request.commits.first.short_id), class: "btn inline btn-grouped btn-sm", target: '_blank', rel: 'noopener noreferrer' do
Run in IDE (Koding) Run in IDE (Koding)
= link_to "#modal_merge_info", class: "btn inline btn-grouped btn-sm", "data-toggle" => "modal" do = link_to "#modal_merge_info", class: "btn inline btn-grouped btn-sm", "data-toggle" => "modal" do
Check out branch Check out branch
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
%strong Tip: %strong Tip:
= succeed '.' do = succeed '.' do
You can also checkout merge requests locally by You can also checkout merge requests locally by
= link_to 'following these guidelines', help_page_path('user/project/merge_requests.md', anchor: "checkout-merge-requests-locally"), target: '_blank' = link_to 'following these guidelines', help_page_path('user/project/merge_requests.md', anchor: "checkout-merge-requests-locally"), target: '_blank', rel: 'noopener noreferrer'
:javascript :javascript
$(function(){ $(function(){
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
%ul.list-unstyled.indent-list %ul.list-unstyled.indent-list
%li %li
1. 1.
= link_to 'https://docs.mattermost.com/developer/slash-commands.html#enabling-custom-commands', target: '_blank', rel: 'noreferrer noopener nofollow' do = link_to 'https://docs.mattermost.com/developer/slash-commands.html#enabling-custom-commands', target: '_blank', rel: 'noopener noreferrer nofollow' do
Enable custom slash commands Enable custom slash commands
= icon('external-link') = icon('external-link')
on your Mattermost installation on your Mattermost installation
%li %li
2. 2.
= link_to 'https://docs.mattermost.com/developer/slash-commands.html#set-up-a-custom-command', target: '_blank', rel: 'noreferrer noopener nofollow' do = link_to 'https://docs.mattermost.com/developer/slash-commands.html#set-up-a-custom-command', target: '_blank', rel: 'noopener noreferrer nofollow' do
Add a slash command Add a slash command
= icon('external-link') = icon('external-link')
in your Mattermost team with these options: in your Mattermost team with these options:
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%p %p
This service allows users to perform common operations on this This service allows users to perform common operations on this
project by entering slash commands in Mattermost. project by entering slash commands in Mattermost.
= link_to help_page_path('user/project/integrations/mattermost_slash_commands.md'), target: '_blank', ref: 'noreferrer nofollow noopener' do = link_to help_page_path('user/project/integrations/mattermost_slash_commands.md'), target: '_blank' do
View documentation View documentation
= icon('external-link') = icon('external-link')
%p.inline %p.inline
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
%p %p
This service allows users to perform common operations on this This service allows users to perform common operations on this
project by entering slash commands in Slack. project by entering slash commands in Slack.
= link_to help_page_path('user/project/integrations/slack_slash_commands.md'), target: '_blank', ref: 'noreferrer nofollow noopener' do = link_to help_page_path('user/project/integrations/slack_slash_commands.md'), target: '_blank' do
View documentation View documentation
= icon('external-link') = icon('external-link')
%p.inline %p.inline
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
= label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block .col-sm-10.col-xs-12.text-block
= image_tag(asset_url('slash-command-logo.png'), width: 36, height: 36) = image_tag(asset_url('slash-command-logo.png'), width: 36, height: 36)
= link_to('Download image', asset_url('gitlab_logo.png'), class: 'btn btn-sm', target: '_blank') = link_to('Download image', asset_url('gitlab_logo.png'), class: 'btn btn-sm', target: '_blank', rel: 'noopener noreferrer')
.form-group .form-group
= label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label'
......
.dropdown.inline.prepend-left-10 .dropdown.inline.prepend-left-10
%button.dropdown-toggle{ type: 'button', data: {toggle: 'dropdown' } } %button.dropdown-toggle{ type: 'button', data: {toggle: 'dropdown' } }
%span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- else - else
......
...@@ -17,6 +17,5 @@ ...@@ -17,6 +17,5 @@
- if project_select_button - if project_select_button
= render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue' = render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue'
- else - else
%h4 There are no issues to show.
= link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link' = link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link'
- else
%h4.text-center There are no issues to show.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.alert.alert-danger .alert.alert-danger
Someone edited the #{issuable.class.model_name.human.downcase} the same time you did. Someone edited the #{issuable.class.model_name.human.downcase} the same time you did.
Please check out Please check out
= link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank" = link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank", rel: 'noopener noreferrer'
and make sure your changes will not unintentionally remove theirs and make sure your changes will not unintentionally remove theirs
.form-group .form-group
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
.profile-header .profile-header
.avatar-holder .avatar-holder
= link_to avatar_icon(@user, 400), target: '_blank' do = link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon(@user, 90), class: "avatar s90", alt: '' = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: ''
.user-info .user-info
......
---
title: Only show public emails in atom feeds
merge_request:
author:
---
title: Fixes large file name tooltip cutoff in diff header
merge_request: 9529
author:
---
title: Fixes dismissable error close is not visible enough
merge_request: 9516
author:
---
title: New directory from interface on existing branch
merge_request: 9921
author: Jacopo Beschi @jacopo-beschi
---
title: Added tests for the w.gl.utils.backOff promise
merge_request:
author:
---
title: Return 404 in project issues API endpoint when project cannot be found
merge_request: 10093
author:
---
title: Fix bug when system hook for deploy key
merge_request: 9796
author: billy.lb
---
title: Hide ancestor groups in the share group dropdown list
merge_request: 9965
author:
---
title: New rake task to reset all email and private tokens
merge_request:
author:
---
title: Removed d3 from the main application.js bundle
merge_request: 10062
author:
---
title: Simplify trigger_docs build job for CE and EE
merge_request: 9820
author: winniehell
---
title: To protect against Server-side Request Forgery project import URLs are now prohibited against localhost or the server IP except for the assigned instance URL and port. Imports are also prohibited from ports below 1024 with the exception of ports 22, 80, and 443.
merge_request:
author:
...@@ -37,6 +37,7 @@ var config = { ...@@ -37,6 +37,7 @@ var config = {
merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js', merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js',
merge_request_widget: './merge_request_widget/ci_bundle.js', merge_request_widget: './merge_request_widget/ci_bundle.js',
mr_widget_ee: './merge_request_widget/widget_bundle.js', mr_widget_ee: './merge_request_widget/widget_bundle.js',
monitoring: './monitoring/monitoring_bundle.js',
network: './network/network_bundle.js', network: './network/network_bundle.js',
profile: './profile/profile_bundle.js', profile: './profile/profile_bundle.js',
protected_branches: './protected_branches/protected_branches_bundle.js', protected_branches: './protected_branches/protected_branches_bundle.js',
...@@ -117,7 +118,7 @@ var config = { ...@@ -117,7 +118,7 @@ var config = {
// create cacheable common library bundle for all d3 chunks // create cacheable common library bundle for all d3 chunks
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
name: 'common_d3', name: 'common_d3',
chunks: ['graphs', 'users'], chunks: ['graphs', 'users', 'monitoring'],
}), }),
// create cacheable common library bundles // create cacheable common library bundles
......
...@@ -155,7 +155,7 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -155,7 +155,7 @@ class Gitlab::Seeder::CycleAnalytics
issue.project.repository.add_branch(@user, branch_name, 'master') issue.project.repository.add_branch(@user, branch_name, 'master')
commit_sha = issue.project.repository.create_file(@user, filename, "content", options, message: "Commit for ##{issue.iid}", branch_name: branch_name) commit_sha = issue.project.repository.create_file(@user, filename, "content", message: "Commit for ##{issue.iid}", branch_name: branch_name)
issue.project.repository.commit(commit_sha) issue.project.repository.commit(commit_sha)
GitPushService.new(issue.project, GitPushService.new(issue.project,
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIndexToUserGhost < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
disable_ddl_transaction!
def up
add_concurrent_index :users, :ghost
end
def down
remove_index :users, :ghost
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class IndexRoutesPathForLike < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
INDEX_NAME = 'index_routes_on_path_text_pattern_ops'
disable_ddl_transaction!
def up
return unless Gitlab::Database.postgresql?
unless index_exists?(:routes, name: INDEX_NAME)
execute("CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON routes (path varchar_pattern_ops);")
end
end
def down
return unless Gitlab::Database.postgresql?
if index_exists?(:routes, name: INDEX_NAME)
execute("DROP INDEX CONCURRENTLY #{INDEX_NAME};")
end
end
end
...@@ -6,41 +6,12 @@ class RenameMoreReservedProjectNames < ActiveRecord::Migration ...@@ -6,41 +6,12 @@ class RenameMoreReservedProjectNames < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
THREAD_COUNT = 8
KNOWN_PATHS = %w(artifacts graphs refs badges).freeze KNOWN_PATHS = %w(artifacts graphs refs badges).freeze
def up def up
queues = Array.new(THREAD_COUNT) { Queue.new }
start = false
threads = Array.new(THREAD_COUNT) do |index|
Thread.new do
queue = queues[index]
# Wait until we have input to process.
until start; end
rename_projects(queue.pop) until queue.empty?
end
end
enum = queues.each
reserved_projects.each_slice(100) do |slice| reserved_projects.each_slice(100) do |slice|
begin rename_projects(slice)
queue = enum.next
rescue StopIteration
enum.rewind
retry
end
queue << slice
end end
start = true
threads.each(&:join)
end end
def down def down
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170315194013) do ActiveRecord::Schema.define(version: 20170317203554) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -1182,6 +1182,7 @@ ActiveRecord::Schema.define(version: 20170315194013) do ...@@ -1182,6 +1182,7 @@ ActiveRecord::Schema.define(version: 20170315194013) do
end end
add_index "routes", ["path"], name: "index_routes_on_path", unique: true, using: :btree add_index "routes", ["path"], name: "index_routes_on_path", unique: true, using: :btree
add_index "routes", ["path"], name: "index_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
add_index "routes", ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree add_index "routes", ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree
create_table "sent_notifications", force: :cascade do |t| create_table "sent_notifications", force: :cascade do |t|
...@@ -1444,6 +1445,7 @@ ActiveRecord::Schema.define(version: 20170315194013) do ...@@ -1444,6 +1445,7 @@ ActiveRecord::Schema.define(version: 20170315194013) do
add_index "users", ["current_sign_in_at"], name: "index_users_on_current_sign_in_at", using: :btree add_index "users", ["current_sign_in_at"], name: "index_users_on_current_sign_in_at", using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"} add_index "users", ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"}
add_index "users", ["ghost"], name: "index_users_on_ghost", using: :btree
add_index "users", ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree add_index "users", ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree
add_index "users", ["name"], name: "index_users_on_name", using: :btree add_index "users", ["name"], name: "index_users_on_name", using: :btree
add_index "users", ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} add_index "users", ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
......
...@@ -96,21 +96,15 @@ Sample Prometheus queries: ...@@ -96,21 +96,15 @@ Sample Prometheus queries:
> Introduced in GitLab 9.0. > Introduced in GitLab 9.0.
If your GitLab server is running within Kubernetes, an option is now available If your GitLab server is running within Kubernetes, Prometheus will collect metrics from the Nodes in the cluster including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration][] to monitor them.
to monitor the health of each node in the cluster. This is particularly helpful
if your CI/CD environments run in the same cluster, and you would like enable
[Prometheus integration][] to monitor them.
When enabled, the bundled Prometheus server monitors Kubernetes and automatically To disable the monitoring of Kubernetes:
[collects metrics][prometheus-cadvisor-metrics] from each Node in the cluster.
To enable the Kubernetes monitoring:
1. Edit `/etc/gitlab/gitlab.rb` 1. Edit `/etc/gitlab/gitlab.rb`
1. Add or find and uncomment the following line: 1. Add or find and uncomment the following line and set it to `false`:
```ruby ```ruby
prometheus['monitor_kubernetes'] = true prometheus['monitor_kubernetes'] = false
``` ```
1. Save the file and [reconfigure GitLab][reconfigure] for the changes to 1. Save the file and [reconfigure GitLab][reconfigure] for the changes to
...@@ -165,4 +159,4 @@ The GitLab monitor exporter allows you to measure various GitLab metrics. ...@@ -165,4 +159,4 @@ The GitLab monitor exporter allows you to measure various GitLab metrics.
[reconfigure]: ../../restart_gitlab.md#omnibus-gitlab-reconfigure [reconfigure]: ../../restart_gitlab.md#omnibus-gitlab-reconfigure
[1261]: https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1261 [1261]: https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1261
[prometheus integration]: ../../../user/project/integrations/prometheus.md [prometheus integration]: ../../../user/project/integrations/prometheus.md
[rometheus-cadvisor-metrics]: https://github.com/google/cadvisor/blob/master/docs/storage/prometheus.md [prometheus-cadvisor-metrics]: https://github.com/google/cadvisor/blob/master/docs/storage/prometheus.md
This diff is collapsed.
...@@ -170,12 +170,12 @@ Integration (CI) server. By using deploy keys, you don't have to setup a ...@@ -170,12 +170,12 @@ Integration (CI) server. By using deploy keys, you don't have to setup a
dummy user account. dummy user account.
If you are a project master or owner, you can add a deploy key in the If you are a project master or owner, you can add a deploy key in the
project settings under the section 'Deploy Keys'. Press the 'New Deploy project settings under the section 'Repository'. Specify a title for the new
Key' button and upload a public SSH key. After this, the machine that uses deploy key and paste a public SSH key. After this, the machine that uses
the corresponding private SSH key has read-only or read-write (if enabled) the corresponding private SSH key has read-only or read-write (if enabled)
access to the project. access to the project.
You can't add the same deploy key twice with the 'New Deploy Key' option. You can't add the same deploy key twice using the form.
If you want to add the same key to another project, please enable it in the If you want to add the same key to another project, please enable it in the
list that says 'Deploy keys from projects available to you'. All the deploy list that says 'Deploy keys from projects available to you'. All the deploy
keys of all the projects you have access to are available. This project keys of all the projects you have access to are available. This project
......
...@@ -115,11 +115,11 @@ sudo -u git -H bundle clean ...@@ -115,11 +115,11 @@ sudo -u git -H bundle clean
# Run database migrations # Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Install/update frontend asset dependencies # Update node dependencies and recompile assets
sudo -u git -H npm install --production sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
# Clean up assets and cache # Clean up cache
sudo -u git -H bundle exec rake gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
``` ```
**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md). **MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
......
...@@ -93,7 +93,7 @@ module API ...@@ -93,7 +93,7 @@ module API
use :issues_params use :issues_params
end end
get ":id/issues" do get ":id/issues" do
project = find_project(params[:id]) project = find_project!(params[:id])
issues = find_issues(project_id: project.id) issues = find_issues(project_id: project.id)
......
...@@ -104,7 +104,7 @@ module API ...@@ -104,7 +104,7 @@ module API
use :issues_params use :issues_params
end end
get ":id/issues" do get ":id/issues" do
project = find_project(params[:id]) project = find_project!(params[:id])
issues = find_issues(project_id: project.id) issues = find_issues(project_id: project.id)
......
...@@ -2,7 +2,6 @@ module Banzai ...@@ -2,7 +2,6 @@ module Banzai
module Filter module Filter
# HTML filter that wraps links around inline images. # HTML filter that wraps links around inline images.
class ImageLinkFilter < HTML::Pipeline::Filter class ImageLinkFilter < HTML::Pipeline::Filter
# Find every image that isn't already wrapped in an `a` tag, create # Find every image that isn't already wrapped in an `a` tag, create
# a new node (a link to the image source), copy the image as a child # a new node (a link to the image source), copy the image as a child
# of the anchor, and then replace the img with the link-wrapped version. # of the anchor, and then replace the img with the link-wrapped version.
...@@ -12,7 +11,8 @@ module Banzai ...@@ -12,7 +11,8 @@ module Banzai
'a', 'a',
class: 'no-attachment-icon', class: 'no-attachment-icon',
href: img['src'], href: img['src'],
target: '_blank' target: '_blank',
rel: 'noopener noreferrer'
) )
link.children = img.clone link.children = img.clone
......
...@@ -43,6 +43,7 @@ module Banzai ...@@ -43,6 +43,7 @@ module Banzai
element['title'] || element['alt'], element['title'] || element['alt'],
href: element['src'], href: element['src'],
target: '_blank', target: '_blank',
rel: 'noopener noreferrer',
title: "Download '#{element['title'] || element['alt']}'") title: "Download '#{element['title'] || element['alt']}'")
download_paragraph = doc.document.create_element('p') download_paragraph = doc.document.create_element('p')
download_paragraph.children = link download_paragraph.children = link
......
require 'resolv'
module Gitlab
class UrlBlocker
class << self
# Used to specify what hosts and port numbers should be prohibited for project
# imports.
VALID_PORTS = [22, 80, 443].freeze
def blocked_url?(url)
return false if url.nil?
blocked_ips = ["127.0.0.1", "::1", "0.0.0.0"]
blocked_ips.concat(Socket.ip_address_list.map(&:ip_address))
begin
uri = Addressable::URI.parse(url)
# Allow imports from the GitLab instance itself but only from the configured ports
return false if internal?(uri)
return true if blocked_port?(uri.port)
server_ips = Resolv.getaddresses(uri.hostname)
return true if (blocked_ips & server_ips).any?
rescue Addressable::URI::InvalidURIError
return true
end
false
end
private
def blocked_port?(port)
return false if port.blank?
port < 1024 && !VALID_PORTS.include?(port)
end
def internal?(uri)
internal_web?(uri) || internal_shell?(uri)
end
def internal_web?(uri)
uri.hostname == config.gitlab.host &&
(uri.port.blank? || uri.port == config.gitlab.port)
end
def internal_shell?(uri)
uri.hostname == config.gitlab_shell.ssh_host &&
(uri.port.blank? || uri.port == config.gitlab_shell.ssh_port)
end
def config
Gitlab.config
end
end
end
end
...@@ -96,8 +96,8 @@ module Gitlab ...@@ -96,8 +96,8 @@ module Gitlab
end end
def level_value(level) def level_value(level)
return string_options[level] if level.is_a? String return level.to_i if level.to_i.to_s == level.to_s && string_options.key(level.to_i)
level string_options[level] || PRIVATE
end end
def string_level(level) def string_level(level)
......
...@@ -3,16 +3,16 @@ namespace :gitlab do ...@@ -3,16 +3,16 @@ namespace :gitlab do
desc 'GitLab | Assets | Compile all frontend assets' desc 'GitLab | Assets | Compile all frontend assets'
task compile: [ task compile: [
'yarn:check', 'yarn:check',
'assets:precompile', 'rake:assets:precompile',
'webpack:compile', 'webpack:compile',
'gitlab:assets:fix_urls' 'fix_urls'
] ]
desc 'GitLab | Assets | Clean up old compiled frontend assets' desc 'GitLab | Assets | Clean up old compiled frontend assets'
task clean: ['assets:clean'] task clean: ['rake:assets:clean']
desc 'GitLab | Assets | Remove all compiled frontend assets' desc 'GitLab | Assets | Remove all compiled frontend assets'
task purge: ['assets:clobber'] task purge: ['rake:assets:clobber']
desc 'GitLab | Assets | Uninstall frontend dependencies' desc 'GitLab | Assets | Uninstall frontend dependencies'
task purge_modules: ['yarn:clobber'] task purge_modules: ['yarn:clobber']
......
...@@ -3,10 +3,12 @@ require Rails.root.join('lib/gitlab/database/migration_helpers') ...@@ -3,10 +3,12 @@ require Rails.root.join('lib/gitlab/database/migration_helpers')
require Rails.root.join('db/migrate/20151007120511_namespaces_projects_path_lower_indexes') require Rails.root.join('db/migrate/20151007120511_namespaces_projects_path_lower_indexes')
require Rails.root.join('db/migrate/20151008110232_add_users_lower_username_email_indexes') require Rails.root.join('db/migrate/20151008110232_add_users_lower_username_email_indexes')
require Rails.root.join('db/migrate/20161212142807_add_lower_path_index_to_routes') require Rails.root.join('db/migrate/20161212142807_add_lower_path_index_to_routes')
require Rails.root.join('db/migrate/20170317203554_index_routes_path_for_like')
desc 'GitLab | Sets up PostgreSQL' desc 'GitLab | Sets up PostgreSQL'
task setup_postgresql: :environment do task setup_postgresql: :environment do
NamespacesProjectsPathLowerIndexes.new.up NamespacesProjectsPathLowerIndexes.new.up
AddUsersLowerUsernameEmailIndexes.new.up AddUsersLowerUsernameEmailIndexes.new.up
AddLowerPathIndexToRoutes.new.up AddLowerPathIndexToRoutes.new.up
IndexRoutesPathForLike.new.up
end end
require_relative '../../app/models/concerns/token_authenticatable.rb'
namespace :tokens do
desc "Reset all GitLab user auth tokens"
task reset_all_auth: :environment do
reset_all_users_token(:reset_authentication_token!)
end
desc "Reset all GitLab email tokens"
task reset_all_email: :environment do
reset_all_users_token(:reset_incoming_email_token!)
end
def reset_all_users_token(reset_token_method)
TmpUser.find_in_batches do |batch|
puts "Processing batch starting with user ID: #{batch.first.id}"
STDOUT.flush
batch.each(&reset_token_method)
end
end
end
class TmpUser < ActiveRecord::Base
include TokenAuthenticatable
self.table_name = 'users'
def reset_authentication_token!
write_new_token(:authentication_token)
save!(validate: false)
end
def reset_incoming_email_token!
write_new_token(:incoming_email_token)
save!(validate: false)
end
end
...@@ -87,6 +87,12 @@ describe Projects::IssuesController do ...@@ -87,6 +87,12 @@ describe Projects::IssuesController do
end end
describe 'GET #new' do describe 'GET #new' do
it 'redirects to signin if not logged in' do
get :new, namespace_id: project.namespace, project_id: project
expect(response).to redirect_to(new_user_session_path)
end
context 'internal issue tracker' do context 'internal issue tracker' do
before do before do
sign_in(user) sign_in(user)
...@@ -121,6 +127,11 @@ describe Projects::IssuesController do ...@@ -121,6 +127,11 @@ describe Projects::IssuesController do
end end
context 'external issue tracker' do context 'external issue tracker' do
before do
sign_in(user)
project.team << [user, :developer]
end
it 'redirects to the external issue tracker' do it 'redirects to the external issue tracker' do
external = double(new_issue_path: 'https://example.com/issues/new') external = double(new_issue_path: 'https://example.com/issues/new')
allow(project).to receive(:external_issue_tracker).and_return(external) allow(project).to receive(:external_issue_tracker).and_return(external)
...@@ -141,6 +152,24 @@ describe Projects::IssuesController do ...@@ -141,6 +152,24 @@ describe Projects::IssuesController do
it_behaves_like 'update invalid issuable', Issue it_behaves_like 'update invalid issuable', Issue
context 'changing the assignee' do
it 'limits the attributes exposed on the assignee' do
assignee = create(:user)
project.add_developer(assignee)
put :update,
namespace_id: project.namespace.to_param,
project_id: project,
id: issue.iid,
issue: { assignee_id: assignee.id },
format: :json
body = JSON.parse(response.body)
expect(body['assignee'].keys)
.to match_array(%w(name username avatar_url))
end
end
context 'when moving issue to another private project' do context 'when moving issue to another private project' do
let(:another_project) { create(:empty_project, :private) } let(:another_project) { create(:empty_project, :private) }
......
...@@ -374,6 +374,24 @@ describe Projects::MergeRequestsController do ...@@ -374,6 +374,24 @@ describe Projects::MergeRequestsController do
merge_request: params merge_request: params
end end
context 'changing the assignee' do
it 'limits the attributes exposed on the assignee' do
assignee = create(:user)
project.add_developer(assignee)
put :update,
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.iid,
merge_request: { assignee_id: assignee.id },
format: :json
body = JSON.parse(response.body)
expect(body['assignee'].keys)
.to match_array(%w(name username avatar_url))
end
end
context 'there is no source project' do context 'there is no source project' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:fork_project) { create(:forked_project_with_submodules) } let(:fork_project) { create(:forked_project_with_submodules) }
......
...@@ -9,6 +9,13 @@ feature 'Admin updates settings', feature: true do ...@@ -9,6 +9,13 @@ feature 'Admin updates settings', feature: true do
visit admin_application_settings_path visit admin_application_settings_path
end end
scenario 'Change visibility settings' do
choose "application_setting_default_project_visibility_20"
click_button 'Save'
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change application settings' do scenario 'Change application settings' do
uncheck 'Gravatar enabled' uncheck 'Gravatar enabled'
fill_in 'Home page URL', with: 'https://about.gitlab.com/' fill_in 'Home page URL', with: 'https://about.gitlab.com/'
......
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