summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.babelrc21
-rw-r--r--.gitlab-ci.yml6
-rw-r--r--CHANGELOG.md15
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/boards/components/modal/empty_state.js4
-rw-r--r--app/assets/javascripts/boards/components/modal/index.js4
-rw-r--r--app/assets/javascripts/boards/components/modal/tabs.js2
-rw-r--r--app/assets/javascripts/dispatcher.js3
-rw-r--r--app/assets/javascripts/due_date_select.js2
-rw-r--r--app/assets/javascripts/environments/components/environment_external_url.js1
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js3
-rw-r--r--app/assets/javascripts/issue.js8
-rw-r--r--app/assets/javascripts/labels_select.js2
-rw-r--r--app/assets/javascripts/merge_request_widget.js4
-rw-r--r--app/assets/javascripts/milestone_select.js4
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js6
-rw-r--r--app/assets/javascripts/monitoring/prometheus_graph.js34
-rw-r--r--app/assets/javascripts/users_select.js4
-rw-r--r--app/assets/stylesheets/framework/common.scss6
-rw-r--r--app/assets/stylesheets/framework/filters.scss23
-rw-r--r--app/assets/stylesheets/pages/note_form.scss12
-rw-r--r--app/controllers/dashboard/todos_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/wikis_controller.rb3
-rw-r--r--app/finders/todos_finder.rb12
-rw-r--r--app/helpers/blob_helper.rb2
-rw-r--r--app/helpers/commits_helper.rb2
-rw-r--r--app/helpers/import_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb1
-rw-r--r--app/helpers/todos_helper.rb10
-rw-r--r--app/models/ci/build.rb10
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/concerns/routable.rb10
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/issue.rb8
-rw-r--r--app/models/merge_request.rb5
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/route.rb2
-rw-r--r--app/models/wiki_page.rb8
-rw-r--r--app/services/merge_requests/build_service.rb2
-rw-r--r--app/services/projects/import_service.rb3
-rw-r--r--app/services/system_hooks_service.rb9
-rw-r--r--app/validators/importable_url_validator.rb11
-rw-r--r--app/views/admin/appearances/_form.html.haml2
-rw-r--r--app/views/admin/application_settings/_form.html.haml2
-rw-r--r--app/views/events/_event.atom.builder2
-rw-r--r--app/views/events/event/_note.html.haml2
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/import/bitbucket/status.html.haml6
-rw-r--r--app/views/import/gitlab/status.html.haml2
-rw-r--r--app/views/import/google_code/new.html.haml2
-rw-r--r--app/views/import/google_code/status.html.haml6
-rw-r--r--app/views/issues/_issue.atom.builder4
-rw-r--r--app/views/koding/index.html.haml2
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/projects/blob/_image.html.haml2
-rw-r--r--app/views/projects/blob/_text.html.haml2
-rw-r--r--app/views/projects/blob/edit.html.haml2
-rw-r--r--app/views/projects/buttons/_koding.html.haml2
-rw-r--r--app/views/projects/cycle_analytics/_overview.html.haml2
-rw-r--r--app/views/projects/environments/_external_url.html.haml2
-rw-r--r--app/views/projects/environments/metrics.html.haml3
-rw-r--r--app/views/projects/issues/index.html.haml17
-rw-r--r--app/views/projects/issues/show.html.haml57
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml2
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml4
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_help.html.haml2
-rw-r--r--app/views/projects/services/slack_slash_commands/_help.html.haml4
-rw-r--r--app/views/shared/_sort_dropdown.html.haml1
-rw-r--r--app/views/shared/empty_states/_issues.html.haml5
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml10
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--changelogs/unreleased/24683-sidebar-spinners.yml4
-rw-r--r--changelogs/unreleased/28058-hide-emails-in-atom-feeds.yml4
-rw-r--r--changelogs/unreleased/28499-fix-large-text-tooltip-in-diff-file-name.yml4
-rw-r--r--changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml4
-rw-r--r--changelogs/unreleased/28890-allow-creating-mr-without-target-branch-in-url.yml5
-rw-r--r--changelogs/unreleased/29405-fix-project-wiki-update.yml4
-rw-r--r--changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml4
-rw-r--r--changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml4
-rw-r--r--changelogs/unreleased/bugfix-systemhook.yml4
-rw-r--r--changelogs/unreleased/fix-prometheus-including-d3-main-bundle.yml4
-rw-r--r--changelogs/unreleased/issue_27212.yml4
-rw-r--r--changelogs/unreleased/make-karma-fast-again.yml4
-rw-r--r--changelogs/unreleased/rename_all_issues.yml4
-rw-r--r--changelogs/unreleased/routes-lower-case.yml4
-rw-r--r--changelogs/unreleased/simplify-docs-trigger.yml4
-rw-r--r--changelogs/unreleased/ssrf-protections.yml4
-rw-r--r--config/karma.config.js32
-rw-r--r--config/webpack.config.js11
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb2
-rw-r--r--db/migrate/20170313213916_add_index_to_user_ghost.rb24
-rw-r--r--db/migrate/20170315194013_add_closed_at_to_issues.rb7
-rw-r--r--db/schema.rb10
-rw-r--r--doc/administration/monitoring/prometheus/index.md16
-rw-r--r--doc/api/branches.md5
-rw-r--r--doc/api/v3_to_v4.md60
-rw-r--r--doc/ssh/README.md6
-rw-r--r--doc/update/8.12-to-8.13.md2
-rw-r--r--doc/update/8.17-to-9.0.md8
-rw-r--r--lib/api/branches.rb2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/helpers/runner.rb8
-rw-r--r--lib/api/runner.rb20
-rw-r--r--lib/api/triggers.rb2
-rw-r--r--lib/api/v3/triggers.rb2
-rw-r--r--lib/banzai/filter/image_link_filter.rb4
-rw-r--r--lib/banzai/filter/video_link_filter.rb1
-rw-r--r--lib/gitlab/url_blocker.rb59
-rw-r--r--lib/support/nginx/gitlab7
-rw-r--r--lib/support/nginx/gitlab-ssl7
-rw-r--r--package.json11
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb29
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb18
-rw-r--r--spec/factories/merge_requests.rb1
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb15
-rw-r--r--spec/features/atom/issues_spec.rb11
-rw-r--r--spec/features/groups/group_name_toggle_spec.rb (renamed from spec/features/groups/group_name_toggle.rb)2
-rw-r--r--spec/features/issues_spec.rb20
-rw-r--r--spec/features/merge_requests/reset_filters_spec.rb20
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb1
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb33
-rw-r--r--spec/helpers/todos_helper_spec.rb34
-rw-r--r--spec/javascripts/issue_spec.js15
-rw-r--r--spec/javascripts/test_bundle.js39
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb31
-rw-r--r--spec/models/issue_spec.rb24
-rw-r--r--spec/models/project_spec.rb14
-rw-r--r--spec/models/route_spec.rb12
-rw-r--r--spec/requests/api/branches_spec.rb181
-rw-r--r--spec/requests/api/runner_spec.rb78
-rw-r--r--spec/requests/api/triggers_spec.rb30
-rw-r--r--spec/requests/api/v3/triggers_spec.rb28
-rw-r--r--spec/services/merge_requests/build_service_spec.rb5
-rw-r--r--spec/services/projects/import_service_spec.rb20
-rw-r--r--spec/services/system_hooks_service_spec.rb3
-rw-r--r--yarn.lock70
141 files changed, 1136 insertions, 410 deletions
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000000..ee4c391da30
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,21 @@
+{
+ "presets": [
+ ["latest", { "es2015": { "modules": false } }],
+ "stage-2"
+ ],
+ "env": {
+ "coverage": {
+ "plugins": [
+ ["istanbul", {
+ "exclude": [
+ "app/assets/javascripts/droplab/**/*",
+ "spec/javascripts/**/*"
+ ]
+ }],
+ ["transform-define", {
+ "process.env.BABEL_ENV": "coverage"
+ }]
+ ]
+ }
+ }
+}
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 080d8cd6c7f..34c10b3b77f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -277,6 +277,8 @@ rake karma:
stage: test
<<: *use-db
<<: *dedicated-runner
+ variables:
+ BABEL_ENV: "coverage"
script:
- bundle exec rake karma
artifacts:
@@ -389,9 +391,11 @@ trigger_docs:
cache: {}
artifacts: {}
script:
- - "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=ce 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:
- master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
# Notify slack in the end
notify:slack:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42e094bdfc6..da1898e3770 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 8.17.4 (2017-03-19)
+
+- Only show public emails in atom feeds.
+- 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.
+
## 8.17.3 (2017-03-07)
- Fix the redirect to custom home page URL. !9518
@@ -210,6 +215,11 @@ entry.
- Remove deprecated GitlabCiService.
- Requeue pending deletion projects.
+## 8.16.8 (2017-03-19)
+
+- Only show public emails in atom feeds.
+- 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.
+
## 8.16.7 (2017-02-27)
- No changes.
@@ -411,6 +421,11 @@ entry.
- Add margin to markdown math blocks.
- Add hover state to MR comment reply button.
+## 8.15.8 (2017-03-19)
+
+- Only show public emails in atom feeds.
+- 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.
+
## 8.15.7 (2017-02-15)
- No changes.
diff --git a/Gemfile.lock b/Gemfile.lock
index 734911baf3f..043ca4f8800 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -304,7 +304,7 @@ GEM
multi_json (~> 1.10)
retriable (~> 1.4)
signet (~> 0.6)
- google-protobuf (3.2.0)
+ google-protobuf (3.2.0.2)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
diff --git a/app/assets/javascripts/boards/components/modal/empty_state.js b/app/assets/javascripts/boards/components/modal/empty_state.js
index 9538f5b69e9..e6973c3fd59 100644
--- a/app/assets/javascripts/boards/components/modal/empty_state.js
+++ b/app/assets/javascripts/boards/components/modal/empty_state.js
@@ -30,7 +30,7 @@
if (this.activeTab === 'selected') {
obj.title = 'You haven\'t selected any issues yet';
obj.content = `
- Go back to <strong>All issues</strong> and select some issues
+ Go back to <strong>Open issues</strong> and select some issues
to add to your board.
`;
}
@@ -59,7 +59,7 @@
class="btn btn-default"
@click="changeTab('all')"
v-if="activeTab === 'selected'">
- All issues
+ Open issues
</button>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/modal/index.js b/app/assets/javascripts/boards/components/modal/index.js
index 1b66c8b922d..4240c97617d 100644
--- a/app/assets/javascripts/boards/components/modal/index.js
+++ b/app/assets/javascripts/boards/components/modal/index.js
@@ -64,6 +64,7 @@ require('./empty_state');
},
filter: {
handler() {
+ this.page = 1;
this.loadIssues(true);
},
deep: true,
@@ -115,6 +116,9 @@ require('./empty_state');
return this.activeTab === 'selected' && this.selectedIssues.length === 0;
},
},
+ created() {
+ this.page = 1;
+ },
components: {
'modal-header': gl.issueBoards.ModalHeader,
'modal-list': gl.issueBoards.ModalList,
diff --git a/app/assets/javascripts/boards/components/modal/tabs.js b/app/assets/javascripts/boards/components/modal/tabs.js
index e8cb43f3503..1cd6ca0ee88 100644
--- a/app/assets/javascripts/boards/components/modal/tabs.js
+++ b/app/assets/javascripts/boards/components/modal/tabs.js
@@ -23,7 +23,7 @@
href="#"
role="button"
@click.prevent="changeTab('all')">
- All issues
+ Open issues
<span class="badge">
{{ issuesCount }}
</span>
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index db1a2848d8d..3557f6f617e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -1,4 +1,3 @@
-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 */
/* global UsernameValidator */
/* global ActiveTabMemoizer */
@@ -329,8 +328,6 @@ const UserCallout = require('./user_callout');
case 'ci:lints:show':
new gl.CILintEditor();
break;
- case 'projects:environments:metrics':
- new PrometheusGraph();
case 'users:show':
new UserCallout();
break;
diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js
index fdbb4644971..db10b383913 100644
--- a/app/assets/javascripts/due_date_select.js
+++ b/app/assets/javascripts/due_date_select.js
@@ -132,7 +132,7 @@ class DueDateSelect {
const selectedDateValue = this.datePayload[this.abilityName].due_date;
const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
- this.$loading.fadeIn();
+ this.$loading.removeClass('hidden').fadeIn();
if (isDropdown) {
this.$dropdown.trigger('loading.gl.dropdown');
diff --git a/app/assets/javascripts/environments/components/environment_external_url.js b/app/assets/javascripts/environments/components/environment_external_url.js
index a554998f52c..b4f9eb357fd 100644
--- a/app/assets/javascripts/environments/components/environment_external_url.js
+++ b/app/assets/javascripts/environments/components/environment_external_url.js
@@ -14,6 +14,7 @@ export default {
class="btn external_url"
:href="externalUrl"
target="_blank"
+ rel="noopener noreferrer"
title="Environment external URL">
<i class="fa fa-external-link" aria-hidden="true"></i>
</a>
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
index 134bdc6ad80..e7bf530d343 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
@@ -38,6 +38,7 @@
gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value, true);
}
+ this.resetFilters();
this.dismissDropdown();
this.dispatchInputEvent();
}
@@ -107,7 +108,7 @@
const hook = this.getCurrentHook();
if (hook) {
- const data = hook.list.data;
+ const data = hook.list.data || [];
const results = data.map((o) => {
const updated = o;
updated.droplab_hidden = false;
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index ef4029a8623..47e675f537e 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -2,6 +2,7 @@
/* global Flash */
require('./flash');
+require('~/lib/utils/text_utility');
require('vendor/jquery.waitforimages');
require('./task_list');
@@ -50,20 +51,21 @@ class Issue {
success: function(data, textStatus, jqXHR) {
if ('id' in data) {
$(document).trigger('issuable:change');
- const currentTotal = Number($('.issue_counter').text());
+ let total = Number($('.issue_counter').text().replace(/[^\d]/, ''));
if (isClose) {
$('a.btn-close').addClass('hidden');
$('a.btn-reopen').removeClass('hidden');
$('div.status-box-closed').removeClass('hidden');
$('div.status-box-open').addClass('hidden');
- $('.issue_counter').text(currentTotal - 1);
+ total -= 1;
} else {
$('a.btn-reopen').addClass('hidden');
$('a.btn-close').removeClass('hidden');
$('div.status-box-closed').addClass('hidden');
$('div.status-box-open').removeClass('hidden');
- $('.issue_counter').text(currentTotal + 1);
+ total += 1;
}
+ $('.issue_counter').text(gl.text.addDelimiter(total));
} else {
new Flash(issueFailMessage, 'alert');
}
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index c648a0f076c..443fb3e0ca9 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -76,7 +76,7 @@
if (!selected.length) {
data[abilityName].label_ids = [''];
}
- $loading.fadeIn();
+ $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
diff --git a/app/assets/javascripts/merge_request_widget.js b/app/assets/javascripts/merge_request_widget.js
index 94a4f24f1d7..0e2af3df071 100644
--- a/app/assets/javascripts/merge_request_widget.js
+++ b/app/assets/javascripts/merge_request_widget.js
@@ -14,13 +14,13 @@ import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
<%= ci_success_icon %>
<span>
Deployed to
- <a href="<%- url %>" target="_blank" class="environment">
+ <a href="<%- url %>" target="_blank" rel="noopener noreferrer" class="environment">
<%- name %>
</a>
<span class="js-environment-timeago" data-toggle="tooltip" data-placement="top" data-title="<%- deployed_at_formatted %>">
<%- deployed_at %>
</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>
View on <%- external_url_formatted %>
</a>
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index 02ff6f5682c..40e977df693 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -159,7 +159,7 @@
}
$dropdown.trigger('loading.gl.dropdown');
- $loading.fadeIn();
+ $loading.removeClass('hidden').fadeIn();
gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update'))
.then(function () {
@@ -171,7 +171,7 @@
data = {};
data[abilityName] = {};
data[abilityName].milestone_id = selected != null ? selected : null;
- $loading.fadeIn();
+ $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
new file mode 100644
index 00000000000..b3ce9310417
--- /dev/null
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -0,0 +1,6 @@
+import PrometheusGraph from './prometheus_graph';
+
+document.addEventListener('DOMContentLoaded', function onLoad() {
+ document.removeEventListener('DOMContentLoaded', onLoad, false);
+ return new PrometheusGraph();
+}, false);
diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js
index 71eb746edac..fcffc11a2df 100644
--- a/app/assets/javascripts/monitoring/prometheus_graph.js
+++ b/app/assets/javascripts/monitoring/prometheus_graph.js
@@ -2,10 +2,9 @@
/* global Flash */
import d3 from 'd3';
-import _ from 'underscore';
import statusCodes from '~/lib/utils/http_status';
-import '~/lib/utils/common_utils';
-import '~/flash';
+import '../lib/utils/common_utils';
+import '../flash';
const prometheusGraphsContainer = '.prometheus-graph';
const metricsEndpoint = 'metrics.json';
@@ -31,22 +30,21 @@ class PrometheusGraph {
}
createGraph() {
- const self = this;
- _.each(this.data, (value, key) => {
- if (value.length > 0 && (key === 'cpu_values' || key === 'memory_values')) {
- self.plotValues(value, key);
+ Object.keys(this.data).forEach((key) => {
+ const value = this.data[key];
+ if (value.length > 0) {
+ this.plotValues(value, key);
}
});
}
init() {
- const self = this;
this.getData().then((metricsResponse) => {
- if (metricsResponse === {}) {
+ if (Object.keys(metricsResponse).length === 0) {
new Flash('Empty metrics', 'alert');
} else {
- self.transformData(metricsResponse);
- self.createGraph();
+ this.transformData(metricsResponse);
+ this.createGraph();
}
});
}
@@ -321,12 +319,14 @@ class PrometheusGraph {
transformData(metricsResponse) {
const metricTypes = {};
- _.each(metricsResponse.metrics, (value, key) => {
- const metricValues = value[0].values;
- metricTypes[key] = _.map(metricValues, metric => ({
- time: new Date(metric[0] * 1000),
- value: metric[1],
- }));
+ Object.keys(metricsResponse.metrics).forEach((key) => {
+ if (key === 'cpu_values' || key === 'memory_values') {
+ const metricValues = (metricsResponse.metrics[key])[0];
+ metricTypes[key] = metricValues.values.map(metric => ({
+ time: new Date(metric[0] * 1000),
+ value: metric[1],
+ }));
+ }
});
this.data = metricTypes;
}
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index c7a57b47834..eb897e9dfe9 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -53,7 +53,7 @@
$loading = $block.find('.block-loading').fadeOut();
var updateIssueBoardsIssue = function () {
- $loading.fadeIn();
+ $loading.removeClass('hidden').fadeIn();
gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update'))
.then(function () {
$loading.fadeOut();
@@ -90,7 +90,7 @@
data = {};
data[abilityName] = {};
data[abilityName].assignee_id = selected != null ? selected : null;
- $loading.fadeIn();
+ $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index a4b38723bbd..2c33b235980 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -429,3 +429,9 @@ table {
@include str-truncated(100%);
}
}
+
+.tooltip {
+ .tooltip-inner {
+ word-wrap: break-word;
+ }
+}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index a1b0025a519..51805c5d734 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -76,12 +76,14 @@
}
.input-token {
- flex: 1;
- -webkit-flex: 1;
+ max-width: 200px;
}
- .filtered-search-token + .input-token:not(:last-child) {
- max-width: 200px;
+ .input-token:only-child,
+ .input-token:last-child {
+ flex: 1;
+ -webkit-flex: 1;
+ max-width: initial;
}
}
@@ -158,8 +160,8 @@
background-color: $white-light;
@media (max-width: $screen-xs-min) {
- -webkit-flex: 1 1 100%;
- flex: 1 1 100%;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
margin-bottom: 10px;
.dropdown-menu {
@@ -188,8 +190,7 @@
.form-control {
position: relative;
min-width: 200px;
- padding-left: 0;
- padding-right: 25px;
+ padding: 5px 25px 6px 0;
border-color: transparent;
&:focus,
@@ -231,6 +232,10 @@
.filter-dropdown-container {
display: -webkit-flex;
display: flex;
+
+ .dropdown-toggle {
+ line-height: 22px;
+ }
}
.dropdown-menu .filter-dropdown-item {
@@ -256,7 +261,9 @@
background-color: $white-light;
border-top: 0;
}
+}
+@media (max-width: $screen-xs) {
.filter-dropdown-container {
.dropdown-toggle,
.dropdown {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index c2156a5ac69..927bf9805ce 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -148,6 +148,18 @@
.error-alert > .alert {
margin-top: 5px;
margin-bottom: 5px;
+
+ &.alert-dismissable {
+ .close {
+ color: $white-light;
+ opacity: 0.85;
+ font-weight: normal;
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+ }
}
.discussion-body,
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 498690e8f11..096de8032ae 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -51,7 +51,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
private
def find_todos
- @todos ||= TodosFinder.new(current_user, params).execute
+ @todos ||= TodosFinder.new(current_user, params.merge(include_associations: true)).execute
end
def todos_counts
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index f2fee62ebd6..cdb5b4173d3 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -6,6 +6,8 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableCollections
include SpammableActions
+ prepend_before_action :authenticate_user!, only: [:new]
+
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
@@ -146,7 +148,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
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
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 82f9b6e06db..677a8a1a73a 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -308,7 +308,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
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
rescue ActiveRecord::StaleObjectError
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 8b6c83d4fed..f210f7e61d2 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -45,8 +45,9 @@ class Projects::WikisController < Projects::ApplicationController
return render('empty') unless can?(current_user, :create_wiki, @project)
@page = @project_wiki.find_page(params[:id])
+ @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
- if @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
+ if @page.valid?
redirect_to(
namespace_project_wiki_path(@project.namespace, @project, @page),
notice: 'Wiki was successfully updated.'
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index b7f091f334d..13d33a1c31b 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -24,6 +24,7 @@ class TodosFinder
def execute
items = current_user.todos
+ items = include_associations(items)
items = by_action_id(items)
items = by_action(items)
items = by_author(items)
@@ -38,6 +39,17 @@ class TodosFinder
private
+ def include_associations(items)
+ return items unless params[:include_associations]
+
+ items.includes(
+ [
+ target: { project: [:route, namespace: :route] },
+ author: { namespace: :route },
+ ]
+ )
+ end
+
def action_id?
action_id.present? && Todo::ACTION_NAMES.has_key?(action_id.to_i)
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 0b0c6a07efd..8631bc54509 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -215,6 +215,6 @@ module BlobHelper
end
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
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 8aad39e148b..cef624430da 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -211,7 +211,7 @@ module CommitsHelper
external_url = environment.external_url_for(diff_new_path, commit_sha)
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')
end
end
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index a0642a1894b..a57b5a8fea5 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -7,7 +7,7 @@ module ImportHelper
def provider_project_link(provider, 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
private
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index c1523b4dabf..a8f167cbff2 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -16,6 +16,7 @@ module NavHelper
"page-gutter build-sidebar right-sidebar-expanded"
elsif current_path?('wikis#show') ||
current_path?('wikis#edit') ||
+ current_path?('wikis#update') ||
current_path?('wikis#history') ||
current_path?('wikis#git_access')
"page-gutter wiki-sidebar right-sidebar-expanded"
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 4f5adf623f2..847a8fdfca6 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -39,9 +39,13 @@ module TodosHelper
namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project,
todo.target, anchor: anchor)
else
- path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target]
-
- path.unshift(:pipelines) if todo.build_failed?
+ if todo.build_failed?
+ # associated namespace and route would be loaded from the db again if todo.project was used
+ project = todo.target.project
+ path = [:pipelines, project.namespace.becomes(Namespace), project, todo.target]
+ else
+ path = [todo.target]
+ end
polymorphic_path(path, anchor: anchor)
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 53fc0d87823..ad0be70c32a 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -539,6 +539,16 @@ module Ci
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
end
+ def dependencies
+ depended_jobs = depends_on_builds
+
+ return depended_jobs unless options[:dependencies].present?
+
+ depended_jobs.select do |job|
+ options[:dependencies].include?(job.name)
+ end
+ end
+
private
def update_artifacts_size
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 91f4eb13ecc..e7bd20b322a 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -48,11 +48,13 @@ module Issuable
delegate :name,
:email,
+ :public_email,
to: :author,
prefix: true
delegate :name,
:email,
+ :public_email,
to: :assignee,
allow_nil: true,
prefix: true
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 9f6d215ceb3..529fb5ce988 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -51,11 +51,13 @@ module Routable
paths.each do |path|
path = connection.quote(path)
- where = "(routes.path = #{path})"
- if cast_lower
- where = "(#{where} OR (LOWER(routes.path) = LOWER(#{path})))"
- end
+ where =
+ if cast_lower
+ "(LOWER(routes.path) = LOWER(#{path}))"
+ else
+ "(routes.path = #{path})"
+ end
wheres << where
end
diff --git a/app/models/event.rb b/app/models/event.rb
index d7ca8e3c599..5c34844b5d3 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -16,7 +16,7 @@ class Event < ActiveRecord::Base
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: :merge_request, prefix: true, allow_nil: true
delegate :title, to: :note, prefix: true, allow_nil: true
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 1427fdc31a4..602eed86d9e 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -55,6 +55,14 @@ class Issue < ActiveRecord::Base
state :opened
state :reopened
state :closed
+
+ before_transition any => :closed do |issue|
+ issue.closed_at = Time.zone.now
+ end
+
+ before_transition closed: any do |issue|
+ issue.closed_at = nil
+ end
end
def hook_attrs
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 4759829a15c..cef8ad76b07 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -7,6 +7,7 @@ class MergeRequest < ActiveRecord::Base
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
+ belongs_to :project, foreign_key: :target_project_id
belongs_to :merge_user, class_name: "User"
has_many :merge_request_diffs, dependent: :destroy
@@ -540,10 +541,6 @@ class MergeRequest < ActiveRecord::Base
target_project != source_project
end
- def project
- target_project
- end
-
# If the merge request closes any issues, save this information in the
# `MergeRequestsClosingIssues` model. This is a performance optimization.
# Calculating this information for a number of merge requests requires
diff --git a/app/models/project.rb b/app/models/project.rb
index 17cf8226bcc..4a3faff7d5b 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -196,6 +196,7 @@ class Project < ActiveRecord::Base
validates :name, uniqueness: { scope: :namespace_id }
validates :path, uniqueness: { scope: :namespace_id }
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 }
validate :check_limit, on: :create
validate :avatar_type,
diff --git a/app/models/route.rb b/app/models/route.rb
index 73574a6206b..41e6eb7cb73 100644
--- a/app/models/route.rb
+++ b/app/models/route.rb
@@ -21,7 +21,7 @@ class Route < ActiveRecord::Base
attributes[:path] = route.path.sub(path_was, path)
end
- if name_changed? && route.name.present?
+ if name_changed? && name_was.present? && route.name.present?
attributes[:name] = route.name.sub(name_was, name)
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 465c4d903ac..c771c22f46a 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -155,7 +155,7 @@ class WikiPage
end
# Returns boolean True or False if this instance
- # has been fully saved to disk or not.
+ # has been fully created on disk or not.
def persisted?
@persisted == true
end
@@ -226,6 +226,8 @@ class WikiPage
end
def save(method, *args)
+ saved = false
+
project_wiki = wiki
if valid? && project_wiki.send(method, *args)
@@ -243,10 +245,10 @@ class WikiPage
set_attributes
@persisted = true
+ saved = true
else
errors.add(:base, project_wiki.error_message) if project_wiki.error_message
- @persisted = false
end
- @persisted
+ saved
end
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 9d4739e37bb..fdce542bd9e 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -6,7 +6,7 @@ module MergeRequests
merge_request.source_project = find_source_project
merge_request.target_project = find_target_project
merge_request.target_branch = find_target_branch
- merge_request.can_be_created = branches_valid? && source_branch_specified? && target_branch_specified?
+ merge_request.can_be_created = branches_valid?
compare_branches if branches_present?
assign_title_and_description if merge_request.can_be_created
diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb
index 1c5a549feb9..d484a96f785 100644
--- a/app/services/projects/import_service.rb
+++ b/app/services/projects/import_service.rb
@@ -33,6 +33,7 @@ module Projects
def import_repository
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)
rescue => e
# Expire cache to prevent scenarios such as:
@@ -40,7 +41,7 @@ module Projects
# 2. Retried import, repo is broken or not imported but +exists?+ still returns true
project.repository.before_import if project.repository_exists?
- raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}"
+ raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}"
end
end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 868fa7b3f21..af0ddbe5934 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -24,10 +24,9 @@ class SystemHooksService
key: model.key,
id: model.id
)
+
if model.user
- data.merge!(
- username: model.user.username
- )
+ data[:username] = model.user.username
end
when Project
data.merge!(project_data(model))
@@ -35,8 +34,6 @@ class SystemHooksService
if event == :rename || event == :transfer
data[:old_path_with_namespace] = model.old_path_with_namespace
end
-
- data
when User
data.merge!({
name: model.name,
@@ -59,6 +56,8 @@ class SystemHooksService
when GroupMember
data.merge!(group_member_data(model))
end
+
+ data
end
def build_event_name(model, event)
diff --git a/app/validators/importable_url_validator.rb b/app/validators/importable_url_validator.rb
new file mode 100644
index 00000000000..37a314adee6
--- /dev/null
+++ b/app/validators/importable_url_validator.rb
@@ -0,0 +1,11 @@
+# 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
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
index 9175b3d3f96..e403a9da616 100644
--- a/app/views/admin/appearances/_form.html.haml
+++ b/app/views/admin/appearances/_form.html.haml
@@ -48,7 +48,7 @@
.form-actions
= f.submit 'Save', class: 'btn btn-save append-right-10'
- 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
%span.pull-right
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 00366b0a8c9..3eab065bb9f 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -404,7 +404,7 @@
Enable Sentry
.help-block
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
= f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2'
diff --git a/app/views/events/_event.atom.builder b/app/views/events/_event.atom.builder
index 43a52cf3002..158061579f6 100644
--- a/app/views/events/_event.atom.builder
+++ b/app/views/events/_event.atom.builder
@@ -9,7 +9,7 @@ xml.entry do
xml.author do
xml.name event.author_name
- xml.email event.author_email
+ xml.email event.author_public_email
end
xml.summary(type: "xhtml") do |summary|
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index f08c96df309..64b5a733b77 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -15,6 +15,6 @@
= link_to note.attachment.url, target: '_blank' do
= image_tag note.attachment.url, class: 'note-image-attach'
- 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
= note.attachment_identifier
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 31631887317..f93b6b63426 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -17,7 +17,7 @@
%br
Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.
%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_page_text.present?
%hr
= markdown_field(current_application_settings, :help_page_text)
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index e18bd47798b..e6058617ac9 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -33,7 +33,7 @@
- @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
%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
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
@@ -50,7 +50,7 @@
- @repos.each do |repo|
%tr{ id: "repo_#{repo.owner}___#{repo.slug}" }
%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
%fieldset.row
.input-group
@@ -70,7 +70,7 @@
- @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.owner}___#{repo.slug}" }
%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-actions-job-status
= label_tag 'Incompatible Project', nil, class: 'label label-danger'
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index d5b88709a34..7456799ca0e 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -43,7 +43,7 @@
- @repos.each do |repo|
%tr{ id: "repo_#{repo["id"]}" }
%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
= import_project_target(repo['namespace']['path'], repo['name'])
%td.import-actions.job-status
diff --git a/app/views/import/google_code/new.html.haml b/app/views/import/google_code/new.html.haml
index 336becd229e..c5800a1cca0 100644
--- a/app/views/import/google_code/new.html.haml
+++ b/app/views/import/google_code/new.html.haml
@@ -13,7 +13,7 @@
%li
%p
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
%p
Make sure you're logged into the account that owns the projects you'd like to import.
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index 5e01af008be..60de6bfe816 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -36,7 +36,7 @@
- @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
%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
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
@@ -53,7 +53,7 @@
- @repos.each do |repo|
%tr{ id: "repo_#{repo.id}" }
%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
#{current_user.username}/#{repo.name}
%td.import-actions.job-status
@@ -63,7 +63,7 @@
- @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.id}" }
%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-actions-job-status
= label_tag "Incompatible Project", nil, class: "label label-danger"
diff --git a/app/views/issues/_issue.atom.builder b/app/views/issues/_issue.atom.builder
index fcd30c8c765..23a88448055 100644
--- a/app/views/issues/_issue.atom.builder
+++ b/app/views/issues/_issue.atom.builder
@@ -7,7 +7,7 @@ xml.entry do
xml.author do
xml.name issue.author_name
- xml.email issue.author_email
+ xml.email issue.author_public_email
end
xml.summary issue.title
@@ -26,7 +26,7 @@ xml.entry do
if issue.assignee
xml.assignee do
xml.name issue.assignee.name
- xml.email issue.assignee.email
+ xml.email issue.assignee_public_email
end
end
end
diff --git a/app/views/koding/index.html.haml b/app/views/koding/index.html.haml
index 65887aacbaf..04e2d4b63e6 100644
--- a/app/views/koding/index.html.haml
+++ b/app/views/koding/index.html.haml
@@ -2,5 +2,5 @@
%p
= icon('circle', class: 'cgreen')
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}
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index d551754a2e5..c74b3249a13 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -18,7 +18,7 @@
or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
.col-lg-9
.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'
%h5.prepend-top-0
Upload new avatar
diff --git a/app/views/projects/blob/_image.html.haml b/app/views/projects/blob/_image.html.haml
index f864702d862..ea3cecb86a9 100644
--- a/app/views/projects/blob/_image.html.haml
+++ b/app/views/projects/blob/_image.html.haml
@@ -9,7 +9,7 @@
- else
.nothing-here-block
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.
- else
%img{ src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path)), alt: "#{blob.name}" }
diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml
index b1e1be49de9..7b16d266982 100644
--- a/app/views/projects/blob/_text.html.haml
+++ b/app/views/projects/blob/_text.html.haml
@@ -3,7 +3,7 @@
.nothing-here-block
File too large, you can
= 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
- blob.load_all_data!(@repository)
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index 8853801016b..3bcddcb37f1 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -9,7 +9,7 @@
- if @conflict
.alert.alert-danger
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.
.file-editor
diff --git a/app/views/projects/buttons/_koding.html.haml b/app/views/projects/buttons/_koding.html.haml
index 5d9a776da89..a5a9e4d0621 100644
--- a/app/views/projects/buttons/_koding.html.haml
+++ b/app/views/projects/buttons/_koding.html.haml
@@ -1,3 +1,3 @@
- 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)
diff --git a/app/views/projects/cycle_analytics/_overview.html.haml b/app/views/projects/cycle_analytics/_overview.html.haml
index c8f0b547f80..9007f2c24ba 100644
--- a/app/views/projects/cycle_analytics/_overview.html.haml
+++ b/app/views/projects/cycle_analytics/_overview.html.haml
@@ -9,7 +9,7 @@
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.
%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
%span.overview-icon
= custom_icon ('icon_cycle_analytics_overview')
diff --git a/app/views/projects/environments/_external_url.html.haml b/app/views/projects/environments/_external_url.html.haml
index 4c8fe1c271b..bf0f1819073 100644
--- a/app/views/projects/environments/_external_url.html.haml
+++ b/app/views/projects/environments/_external_url.html.haml
@@ -1,3 +1,3 @@
- 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')
diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml
index f8e94ca98ae..b8c1782f050 100644
--- a/app/views/projects/environments/metrics.html.haml
+++ b/app/views/projects/environments/metrics.html.haml
@@ -1,5 +1,8 @@
- @no_container = true
- 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"
%div{ class: container_class }
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 7b7d7b1e00e..f3a429d12d9 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -19,15 +19,14 @@
.nav-controls
= link_to params.merge(rss_url_options), class: 'btn append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss')
- - if can? current_user, :create_issue, @project
- = link_to new_namespace_project_issue_path(@project.namespace,
- @project,
- issue: { assignee_id: issues_finder.assignee.try(:id),
- milestone_id: issues_finder.milestones.first.try(:id) }),
- class: "btn btn-new",
- title: "New Issue",
- id: "new_issue_link" do
- New Issue
+ = link_to new_namespace_project_issue_path(@project.namespace,
+ @project,
+ issue: { assignee_id: issues_finder.assignee.try(:id),
+ milestone_id: issues_finder.milestones.first.try(:id) }),
+ class: "btn btn-new",
+ title: "New Issue",
+ id: "new_issue_link" do
+ New Issue
= render 'shared/issuable/search_bar', type: :issues
.issues-holder
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index d39f36e94c7..6ac05bf3afe 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -20,37 +20,34 @@
= confidential_icon(@issue)
= issuable_meta(@issue, @project, "Issue")
- - if can?(current_user, :create_issue, @project) || can?(current_user, :update_issue, @issue)
- .issuable-actions
- .clearfix.issue-btn-group.dropdown
- %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } }
- Options
- = icon('caret-down')
- .dropdown-menu.dropdown-menu-align-right.hidden-lg
- %ul
- - if can?(current_user, :create_issue, @project)
- %li
- = 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)
- %li
- = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, class: "btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
- %li
- = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
- %li
- = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue)
- - if @issue.submittable_as_spam_by?(current_user)
- %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'
-
- - 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
- New issue
- - if can?(current_user, :update_issue, @issue)
- = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
- = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
+ .issuable-actions
+ .clearfix.issue-btn-group.dropdown
+ %button.btn.btn-default.pull-left.hidden-md.hidden-lg{ type: "button", data: { toggle: "dropdown" } }
+ Options
+ = icon('caret-down')
+ .dropdown-menu.dropdown-menu-align-right.hidden-lg
+ %ul
+ %li
+ = 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)
+ %li
+ = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, class: "btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
+ %li
+ = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
+ %li
+ = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue)
- if @issue.submittable_as_spam_by?(current_user)
- = link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'hidden-xs hidden-sm btn btn-grouped btn-spam', title: 'Submit as spam'
- = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit'
+ %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 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
+ - if can?(current_user, :update_issue, @issue)
+ = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
+ = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
+ - if @issue.submittable_as_spam_by?(current_user)
+ = link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'hidden-xs hidden-sm btn btn-grouped btn-spam', title: 'Submit as spam'
+ = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit'
.issue-details.issuable-details
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index c8f097c69da..6682a85ffa6 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -16,7 +16,7 @@
.pull-right
- if @merge_request.source_branch_exists?
- 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)
= link_to "#modal_merge_info", class: "btn inline btn-grouped btn-sm", "data-toggle" => "modal" do
Check out branch
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index 93ed4b68e0e..cde0ce08e14 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -49,7 +49,7 @@
%strong Tip:
= succeed '.' do
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
$(function(){
diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
index 3a323d94cc2..2fb88297fb3 100644
--- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
@@ -4,13 +4,13 @@
%ul.list-unstyled.indent-list
%li
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
= icon('external-link')
on your Mattermost installation
%li
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
= icon('external-link')
in your Mattermost team with these options:
diff --git a/app/views/projects/services/mattermost_slash_commands/_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_help.html.haml
index a04fd5035a6..2a1b9d4c465 100644
--- a/app/views/projects/services/mattermost_slash_commands/_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_help.html.haml
@@ -4,7 +4,7 @@
%p
This service allows users to perform common operations on this
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
= icon('external-link')
%p.inline
diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml
index 0d973a20d4c..078b7be6865 100644
--- a/app/views/projects/services/slack_slash_commands/_help.html.haml
+++ b/app/views/projects/services/slack_slash_commands/_help.html.haml
@@ -5,7 +5,7 @@
%p
This service allows users to perform common operations on this
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
= icon('external-link')
%p.inline
@@ -57,7 +57,7 @@
= label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block
= 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
= label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label'
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index 367aa550a78..a212c714826 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -1,6 +1,5 @@
.dropdown.inline.prepend-left-10
%button.dropdown-toggle{ type: 'button', data: {toggle: 'dropdown' } }
- %span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml
index e2033654018..7a7e3d46796 100644
--- a/app/views/shared/empty_states/_issues.html.haml
+++ b/app/views/shared/empty_states/_issues.html.haml
@@ -16,7 +16,6 @@
Also, issues are searchable and filterable.
- if project_select_button
= render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue'
- - else
- = 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.
+ %h4 There are no issues to show.
+ = link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 0b0f2c9cd1a..17107f55a2d 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -8,7 +8,7 @@
.alert.alert-danger
Someone edited the #{issuable.class.model_name.human.downcase} the same time you did.
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
.form-group
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 048fc488207..25a4aec0a38 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -30,7 +30,7 @@
= icon('user', 'aria-hidden': 'true')
.title.hide-collapsed
Assignee
- = icon('spinner spin', class: 'block-loading', 'aria-hidden': 'true')
+ = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed
@@ -64,7 +64,7 @@
None
.title.hide-collapsed
Milestone
- = icon('spinner spin', class: 'block-loading', 'aria-hidden': 'true')
+ = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed
@@ -91,7 +91,7 @@
= issuable.due_date.try(:to_s, :medium) || 'None'
.title.hide-collapsed
Due date
- = icon('spinner spin', class: 'block-loading', 'aria-hidden': 'true')
+ = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed
@@ -121,12 +121,12 @@
- selected_labels = issuable.labels
.block.labels
.sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(issuable.labels_array), data: { placement: "left", container: "body" } }
- = icon('tags', 'aria-hidden': 'true')
+ = icon('tags', class: 'hidden', 'aria-hidden': 'true')
%span
= selected_labels.size
.title.hide-collapsed
Labels
- = icon('spinner spin', class: 'block-loading', 'aria-hidden': 'true')
+ = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.issuable-show-labels.hide-collapsed{ class: ("has-labels" if selected_labels.any?) }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 76cd330e80a..dc9a3b0d0df 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -33,7 +33,7 @@
.profile-header
.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: ''
.user-info
diff --git a/changelogs/unreleased/24683-sidebar-spinners.yml b/changelogs/unreleased/24683-sidebar-spinners.yml
new file mode 100644
index 00000000000..3fec273152f
--- /dev/null
+++ b/changelogs/unreleased/24683-sidebar-spinners.yml
@@ -0,0 +1,4 @@
+---
+title: hide loading spinners for server-rendered sidebar fields
+merge_request:
+author:
diff --git a/changelogs/unreleased/28058-hide-emails-in-atom-feeds.yml b/changelogs/unreleased/28058-hide-emails-in-atom-feeds.yml
new file mode 100644
index 00000000000..e0e826a67f8
--- /dev/null
+++ b/changelogs/unreleased/28058-hide-emails-in-atom-feeds.yml
@@ -0,0 +1,4 @@
+---
+title: Only show public emails in atom feeds
+merge_request:
+author:
diff --git a/changelogs/unreleased/28499-fix-large-text-tooltip-in-diff-file-name.yml b/changelogs/unreleased/28499-fix-large-text-tooltip-in-diff-file-name.yml
new file mode 100644
index 00000000000..660a881e094
--- /dev/null
+++ b/changelogs/unreleased/28499-fix-large-text-tooltip-in-diff-file-name.yml
@@ -0,0 +1,4 @@
+---
+title: Fixes large file name tooltip cutoff in diff header
+merge_request: 9529
+author:
diff --git a/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml b/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml
new file mode 100644
index 00000000000..8b592766bf3
--- /dev/null
+++ b/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml
@@ -0,0 +1,4 @@
+---
+title: Fixes dismissable error close is not visible enough
+merge_request: 9516
+author:
diff --git a/changelogs/unreleased/28890-allow-creating-mr-without-target-branch-in-url.yml b/changelogs/unreleased/28890-allow-creating-mr-without-target-branch-in-url.yml
new file mode 100644
index 00000000000..114a14ec2df
--- /dev/null
+++ b/changelogs/unreleased/28890-allow-creating-mr-without-target-branch-in-url.yml
@@ -0,0 +1,5 @@
+---
+title: Allow creating merge request even if target branch is not specified in query
+ params
+merge_request: 9968
+author:
diff --git a/changelogs/unreleased/29405-fix-project-wiki-update.yml b/changelogs/unreleased/29405-fix-project-wiki-update.yml
new file mode 100644
index 00000000000..85be36f7902
--- /dev/null
+++ b/changelogs/unreleased/29405-fix-project-wiki-update.yml
@@ -0,0 +1,4 @@
+---
+title: Fix Project Wiki update
+merge_request: 9990
+author: Dongqing Hu
diff --git a/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml b/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml
new file mode 100644
index 00000000000..61ffb64fa8f
--- /dev/null
+++ b/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml
@@ -0,0 +1,4 @@
+---
+title: Fix trigger webhook for ref with a dot
+merge_request: 10001
+author: George Andrinopoulos
diff --git a/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml b/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml
new file mode 100644
index 00000000000..15d7b9dcafb
--- /dev/null
+++ b/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml
@@ -0,0 +1,4 @@
+---
+title: Allow unauthenticated access to some Branch API GET endpoints
+merge_request:
+author:
diff --git a/changelogs/unreleased/bugfix-systemhook.yml b/changelogs/unreleased/bugfix-systemhook.yml
new file mode 100644
index 00000000000..4c4d0dcc7a2
--- /dev/null
+++ b/changelogs/unreleased/bugfix-systemhook.yml
@@ -0,0 +1,4 @@
+---
+title: Fix bug when system hook for deploy key
+merge_request: 9796
+author: billy.lb
diff --git a/changelogs/unreleased/fix-prometheus-including-d3-main-bundle.yml b/changelogs/unreleased/fix-prometheus-including-d3-main-bundle.yml
new file mode 100644
index 00000000000..a42b0db3cfc
--- /dev/null
+++ b/changelogs/unreleased/fix-prometheus-including-d3-main-bundle.yml
@@ -0,0 +1,4 @@
+---
+title: Removed d3 from the main application.js bundle
+merge_request: 10062
+author:
diff --git a/changelogs/unreleased/issue_27212.yml b/changelogs/unreleased/issue_27212.yml
new file mode 100644
index 00000000000..7a7e04f7ca7
--- /dev/null
+++ b/changelogs/unreleased/issue_27212.yml
@@ -0,0 +1,4 @@
+---
+title: Add closed_at field to issues
+merge_request:
+author:
diff --git a/changelogs/unreleased/make-karma-fast-again.yml b/changelogs/unreleased/make-karma-fast-again.yml
new file mode 100644
index 00000000000..9b95e06954a
--- /dev/null
+++ b/changelogs/unreleased/make-karma-fast-again.yml
@@ -0,0 +1,4 @@
+---
+title: Only add code coverage instrumentation when generating coverage report
+merge_request: 9987
+author:
diff --git a/changelogs/unreleased/rename_all_issues.yml b/changelogs/unreleased/rename_all_issues.yml
new file mode 100644
index 00000000000..d3109bdb17e
--- /dev/null
+++ b/changelogs/unreleased/rename_all_issues.yml
@@ -0,0 +1,4 @@
+---
+title: Rename 'All issues' to 'Open issues' in Add issues modal
+merge_request: 10042
+author: blackst0ne
diff --git a/changelogs/unreleased/routes-lower-case.yml b/changelogs/unreleased/routes-lower-case.yml
new file mode 100644
index 00000000000..2110956680c
--- /dev/null
+++ b/changelogs/unreleased/routes-lower-case.yml
@@ -0,0 +1,4 @@
+---
+title: Remove repeated routes.path check for postgresql database
+merge_request:
+author: mhasbini
diff --git a/changelogs/unreleased/simplify-docs-trigger.yml b/changelogs/unreleased/simplify-docs-trigger.yml
new file mode 100644
index 00000000000..062626359ef
--- /dev/null
+++ b/changelogs/unreleased/simplify-docs-trigger.yml
@@ -0,0 +1,4 @@
+---
+title: Simplify trigger_docs build job for CE and EE
+merge_request: 9820
+author: winniehell
diff --git a/changelogs/unreleased/ssrf-protections.yml b/changelogs/unreleased/ssrf-protections.yml
new file mode 100644
index 00000000000..8d803738009
--- /dev/null
+++ b/changelogs/unreleased/ssrf-protections.yml
@@ -0,0 +1,4 @@
+---
+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:
diff --git a/config/karma.config.js b/config/karma.config.js
index c1d3751d88f..eb082dd28bf 100644
--- a/config/karma.config.js
+++ b/config/karma.config.js
@@ -3,17 +3,6 @@ var webpack = require('webpack');
var webpackConfig = require('./webpack.config.js');
var ROOT_PATH = path.resolve(__dirname, '..');
-// add coverage instrumentation to babel config
-if (webpackConfig.module && webpackConfig.module.rules) {
- var babelConfig = webpackConfig.module.rules.find(function (rule) {
- return rule.loader === 'babel-loader';
- });
-
- babelConfig.options = babelConfig.options || {};
- babelConfig.options.plugins = babelConfig.options.plugins || [];
- babelConfig.options.plugins.push('istanbul');
-}
-
// remove problematic plugins
if (webpackConfig.plugins) {
webpackConfig.plugins = webpackConfig.plugins.filter(function (plugin) {
@@ -27,7 +16,8 @@ if (webpackConfig.plugins) {
// Karma configuration
module.exports = function(config) {
var progressReporter = process.env.CI ? 'mocha' : 'progress';
- config.set({
+
+ var karmaConfig = {
basePath: ROOT_PATH,
browsers: ['PhantomJS'],
frameworks: ['jasmine'],
@@ -38,14 +28,20 @@ module.exports = function(config) {
preprocessors: {
'spec/javascripts/**/*.js': ['webpack', 'sourcemap'],
},
- reporters: [progressReporter, 'coverage-istanbul'],
- coverageIstanbulReporter: {
+ reporters: [progressReporter],
+ webpack: webpackConfig,
+ webpackMiddleware: { stats: 'errors-only' },
+ };
+
+ if (process.env.BABEL_ENV === 'coverage' || process.env.NODE_ENV === 'coverage') {
+ karmaConfig.reporters.push('coverage-istanbul');
+ karmaConfig.coverageIstanbulReporter = {
reports: ['html', 'text-summary'],
dir: 'coverage-javascript/',
subdir: '.',
fixWebpackSourcePaths: true
- },
- webpack: webpackConfig,
- webpackMiddleware: { stats: 'errors-only' },
- });
+ };
+ }
+
+ config.set(karmaConfig);
};
diff --git a/config/webpack.config.js b/config/webpack.config.js
index cbcc9ac5aea..c6794d6b944 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -35,6 +35,7 @@ var config = {
issuable: './issuable/issuable_bundle.js',
merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js',
merge_request_widget: './merge_request_widget/ci_bundle.js',
+ monitoring: './monitoring/monitoring_bundle.js',
network: './network/network_bundle.js',
profile: './profile/profile_bundle.js',
protected_branches: './protected_branches/protected_branches_bundle.js',
@@ -58,13 +59,7 @@ var config = {
{
test: /\.js$/,
exclude: /(node_modules|vendor\/assets)/,
- loader: 'babel-loader',
- options: {
- presets: [
- ["es2015", {"modules": false}],
- 'stage-2'
- ]
- }
+ loader: 'babel-loader'
},
{
test: /\.svg$/,
@@ -120,7 +115,7 @@ var config = {
// create cacheable common library bundle for all d3 chunks
new webpack.optimize.CommonsChunkPlugin({
name: 'common_d3',
- chunks: ['graphs', 'users'],
+ chunks: ['graphs', 'users', 'monitoring'],
}),
// create cacheable common library bundles
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index aea0a72b633..4bc735916c1 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -155,7 +155,7 @@ class Gitlab::Seeder::CycleAnalytics
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)
GitPushService.new(issue.project,
diff --git a/db/migrate/20170313213916_add_index_to_user_ghost.rb b/db/migrate/20170313213916_add_index_to_user_ghost.rb
new file mode 100644
index 00000000000..c429039c275
--- /dev/null
+++ b/db/migrate/20170313213916_add_index_to_user_ghost.rb
@@ -0,0 +1,24 @@
+# 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
diff --git a/db/migrate/20170315194013_add_closed_at_to_issues.rb b/db/migrate/20170315194013_add_closed_at_to_issues.rb
new file mode 100644
index 00000000000..1326118cc8d
--- /dev/null
+++ b/db/migrate/20170315194013_add_closed_at_to_issues.rb
@@ -0,0 +1,7 @@
+class AddClosedAtToIssues < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column :issues, :closed_at, :datetime
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 634d02bb5bc..f96a7d21890 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170315174634) do
+ActiveRecord::Schema.define(version: 20170315194013) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -61,7 +61,6 @@ ActiveRecord::Schema.define(version: 20170315174634) do
t.boolean "shared_runners_enabled", default: true, null: false
t.integer "max_artifacts_size", default: 100, null: false
t.string "runners_registration_token"
- t.integer "max_pages_size", default: 100, null: false
t.boolean "require_two_factor_authentication", default: false
t.integer "two_factor_grace_period", default: 48
t.boolean "metrics_enabled", default: false
@@ -111,6 +110,7 @@ ActiveRecord::Schema.define(version: 20170315174634) do
t.string "plantuml_url"
t.boolean "plantuml_enabled"
t.integer "terminal_max_session_time", default: 0, null: false
+ t.integer "max_pages_size", default: 100, null: false
t.string "default_artifacts_expire_in", default: "0", null: false
t.integer "unique_ips_limit_per_user"
t.integer "unique_ips_limit_time_window"
@@ -445,6 +445,7 @@ ActiveRecord::Schema.define(version: 20170315174634) do
t.text "description_html"
t.integer "time_estimate"
t.integer "relative_position"
+ t.datetime "closed_at"
end
add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
@@ -687,8 +688,8 @@ ActiveRecord::Schema.define(version: 20170315174634) do
t.integer "visibility_level", default: 20, null: false
t.boolean "request_access_enabled", default: false, null: false
t.datetime "deleted_at"
- t.text "description_html"
t.boolean "lfs_enabled"
+ t.text "description_html"
t.integer "parent_id"
end
@@ -1230,8 +1231,8 @@ ActiveRecord::Schema.define(version: 20170315174634) do
t.datetime "otp_grace_period_started_at"
t.boolean "ldap_email", default: false, null: false
t.boolean "external", default: false
- t.string "incoming_email_token"
t.string "organization"
+ t.string "incoming_email_token"
t.boolean "authorized_projects_populated"
t.boolean "ghost"
end
@@ -1243,6 +1244,7 @@ ActiveRecord::Schema.define(version: 20170315174634) do
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_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", ["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"}
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index 69b16b7c483..b2445d1c0e5 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -96,21 +96,15 @@ Sample Prometheus queries:
> Introduced in GitLab 9.0.
-If your GitLab server is running within Kubernetes, an option is now available
-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.
+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.
-When enabled, the bundled Prometheus server monitors Kubernetes and automatically
-[collects metrics][prometheus-cadvisor-metrics] from each Node in the cluster.
-
-To enable the Kubernetes monitoring:
+To disable the monitoring of Kubernetes:
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
- prometheus['monitor_kubernetes'] = true
+ prometheus['monitor_kubernetes'] = false
```
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.
[reconfigure]: ../../restart_gitlab.md#omnibus-gitlab-reconfigure
[1261]: https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1261
[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
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 83705106160..815aabda8e3 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -3,6 +3,8 @@
## List repository branches
Get a list of repository branches from a project, sorted by name alphabetically.
+This endpoint can be accessed without authentication if the repository is
+publicly accessible.
```
GET /projects/:id/repository/branches
@@ -48,7 +50,8 @@ Example response:
## Get single repository branch
-Get a single project repository branch.
+Get a single project repository branch. This endpoint can be accessed without
+authentication if the repository is publicly accessible.
```
GET /projects/:id/repository/branches/:branch
diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md
index 0794156bc39..7f4426ee85d 100644
--- a/doc/api/v3_to_v4.md
+++ b/doc/api/v3_to_v4.md
@@ -8,16 +8,16 @@ Below are the changes made between V3 and V4.
### 8.17
-- Removed `/projects/:search` (use: `/projects?search=x`) [!8877](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8877)
-- `iid` filter has been removed from `projects/:id/issues` [!8967](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8967)
-- `projects/:id/merge_requests?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793)
-- Endpoints under `projects/merge_request/:id` have been removed (use: `projects/merge_requests/:id`) [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793)
+- Removed `GET /projects/:search` (use: `GET /projects?search=x`) [!8877](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8877)
+- `iid` filter has been removed from `GET /projects/:id/issues` [!8967](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8967)
+- `GET /projects/:id/merge_requests?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793)
+- Endpoints under `GET /projects/merge_request/:id` have been removed (use: `GET /projects/merge_requests/:id`) [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793)
- Project snippets do not return deprecated field `expires_at` [!8723](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8723)
-- Endpoints under `projects/:id/keys` have been removed (use `projects/:id/deploy_keys`) [!8716](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8716)
+- Endpoints under `GET /projects/:id/keys` have been removed (use `GET /projects/:id/deploy_keys`) [!8716](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8716)
### 9.0
-- Status 409 returned for POST `project/:id/members` when a member already exists [!9093](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9093)
+- Status 409 returned for `POST /projects/:id/members` when a member already exists [!9093](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9093)
- Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` [!9328](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9328)
- Removed the following deprecated Templates endpoints (these are still accessible with `/templates` prefix) [!8853](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8853)
- `/licences`
@@ -28,31 +28,31 @@ Below are the changes made between V3 and V4.
- `/gitignores/:key`
- `/gitlab_ci_ymls/:key`
- `/dockerfiles/:key`
-- Moved `/projects/fork/:id` to `/projects/:id/fork` [!8940](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8940)
+- Moved `POST /projects/fork/:id` to `POST /projects/:id/fork` [!8940](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8940)
- Moved `DELETE /todos` to `POST /todos/mark_as_done` and `DELETE /todos/:todo_id` to `POST /todos/:todo_id/mark_as_done` [!9410](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9410)
- Project filters are no longer available as `GET /projects/foo`, but as `GET /projects?foo=true` instead [!8962](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8962)
- `GET /projects/visible` & `GET /projects/all` are consolidated into `GET /projects` and can be used with or without authorization
- `GET /projects/owned` moved to `GET /projects?owned=true`
- `GET /projects/starred` moved to `GET /projects?starred=true`
- `GET /projects` returns all projects visible to current user, even if the user is not a member [!9674](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9674)
- - To get projects the user is a member of, use `/projects?membership=true`
+ - To get projects the user is a member of, use `GET /projects?membership=true`
- Return pagination headers for all endpoints that return an array [!8606](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8606)
- Added `POST /environments/:environment_id/stop` to stop an environment [!8808](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8808)
-- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead [!9366](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9366)
+- Removed `DELETE /projects/:id/deploy_keys/:key_id/disable`. Use `DELETE /projects/:id/deploy_keys/:key_id` instead [!9366](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9366)
- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)` [!9371](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9371)
-- Make subscription API more RESTful. Use `post ":project_id/:subscribable_type/:subscribable_id/subscribe"` to subscribe and `post ":project_id/:subscribable_type/:subscribable_id/unsubscribe"` to unsubscribe from a resource. [!9325](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9325)
-- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR) [!8849](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8849)
+- Make subscription API more RESTful. Use `POST /projects/:id/:subscribable_type/:subscribable_id/subscribe` to subscribe and `POST /projects/:id/:subscribable_type/:subscribable_id/unsubscribe` to unsubscribe from a resource. [!9325](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9325)
+- Labels filter on `GET /projects/:id/issues` and `GET /issues` now matches only issues containing all labels (i.e.: Logical AND, not OR) [!8849](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8849)
- Renamed param `branch_name` to `branch` on the following endpoints [!8936](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8936)
- - POST `:id/repository/branches`
- - POST `:id/repository/commits`
- - POST/PUT/DELETE `:id/repository/files`
-- Renamed `merge when build succeeds` to merge `when pipeline succeeds parameters` on the following endpoints: [!9335](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/)
- - PUT `projects/:id/merge_requests/:merge_request_id/merge`
- - POST `projects/:id/merge_requests/:merge_request_id/cancel_merge_when_pipeline_succeeds`
- - POST `projects`
- - POST `projects/user/:user_id`
- - PUT `projects/:id`
-- Renamed `branch_name` to `branch` on DELETE `id/repository/branches/:branch` response [!8936](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8936)
+ - `POST /projects/:id/repository/branches`
+ - `POST /projects/:id/repository/commits`
+ - `POST/PUT/DELETE :id/repository/files`
+- Renamed the `merge_when_build_succeeds` parameter to `merge_when_pipeline_succeeds` on the following endpoints: [!9335](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/)
+ - `PUT /projects/:id/merge_requests/:merge_request_id/merge`
+ - `POST /projects/:id/merge_requests/:merge_request_id/cancel_merge_when_pipeline_succeeds`
+ - `POST /projects`
+ - `POST /projects/user/:user_id`
+ - `PUT /projects/:id`
+- Renamed `branch_name` to `branch` on `DELETE /projects/:id/repository/branches/:branch` response [!8936](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8936)
- Remove `public` param from create and edit actions of projects [!8736](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8736)
- Remove `subscribed` field from responses returning list of issues or merge
requests. Fetch individual issues or merge requests to obtain the value
@@ -62,21 +62,21 @@ Below are the changes made between V3 and V4.
- Notes do not return deprecated field `upvote` and `downvote` [!9384](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9384)
- Return HTTP status code `400` for all validation errors when creating or updating a member instead of sometimes `422` error. [!9523](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9523)
- Remove `GET /groups/owned`. Use `GET /groups?owned=true` instead [!9505](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9505)
-- Return 202 with JSON body on async removals on V4 API (DELETE `/projects/:id/repository/merged_branches` and DELETE `/projects/:id`) [!9449](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9449)
-- `projects/:id/milestones?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!9096](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9096)
+- Return 202 with JSON body on async removals on V4 API (`DELETE /projects/:id/repository/merged_branches` and `DELETE /projects/:id`) [!9449](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9449)
+- `GET /projects/:id/milestones?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!9096](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9096)
- Return basic info about pipeline in `GET /projects/:id/pipelines` [!8875](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8875)
- Renamed all `build` references to `job` [!9463](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9463)
-- Drop GET '/projects/:id/repository/commits/:sha/jobs' [!9463](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9463)
+- Drop `GET /projects/:id/repository/commits/:sha/jobs` [!9463](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9463)
- Rename Build Triggers to be Pipeline Triggers API [!9713](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9713)
- `POST /projects/:id/trigger/builds` to `POST /projects/:id/trigger/pipeline`
- Require description when creating a new trigger `POST /projects/:id/triggers`
- Simplify project payload exposed on Environment endpoints [!9675](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9675)
- API uses merge request `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the merge requests, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
- API uses issue `IID`s (internal ID, as in the web UI) rather than `ID`s. This affects the issues, award emoji, todos, and time tracking APIs. [!9530](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9530)
-- Change initial page from `0` to `1` on `GET projects/:id/repository/commits` (like on the rest of the API) [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
-- Return correct `Link` header data for `GET projects/:id/repository/commits` [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
+- Change initial page from `0` to `1` on `GET /projects/:id/repository/commits` (like on the rest of the API) [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
+- Return correct `Link` header data for `GET /projects/:id/repository/commits` [!9679] (https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9679)
- Update endpoints for repository files [!9637](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9637)
- - Moved `/projects/:id/repository/files?file_path=:file_path` to `/projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded)
- - `/projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath`
- - Moved `/projects/:id/repository/commits/:sha/blob?file_path=:file_path` and `/projects/:id/repository/blobs/:sha?file_path=:file_path` to `/projects/:id/repository/files/:file_path/raw?ref=:sha`
- - `/projects/:id/repository/tree` parameter `ref_name` has been renamed to `ref` for consistency
+ - Moved `GET /projects/:id/repository/files?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path` (`:file_path` should be URL-encoded)
+ - `GET /projects/:id/repository/blobs/:sha` now returns JSON attributes for the blob identified by `:sha`, instead of finding the commit identified by `:sha` and returning the raw content of the blob in that commit identified by the required `?filepath=:filepath`
+ - Moved `GET /projects/:id/repository/commits/:sha/blob?file_path=:file_path` and `GET /projects/:id/repository/blobs/:sha?file_path=:file_path` to `GET /projects/:id/repository/files/:file_path/raw?ref=:sha`
+ - `GET /projects/:id/repository/tree` parameter `ref_name` has been renamed to `ref` for consistency
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 678f5199b02..cf28f1a2eca 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -170,12 +170,12 @@ Integration (CI) server. By using deploy keys, you don't have to setup a
dummy user account.
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
-Key' button and upload a public SSH key. After this, the machine that uses
+project settings under the section 'Repository'. Specify a title for the new
+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)
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
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
diff --git a/doc/update/8.12-to-8.13.md b/doc/update/8.12-to-8.13.md
index 75956aeb360..ed0e668d854 100644
--- a/doc/update/8.12-to-8.13.md
+++ b/doc/update/8.12-to-8.13.md
@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-13-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
-sudo -u git -H git checkout v3.6.6
+sudo -u git -H git checkout v3.6.7
```
### 6. Update gitlab-workhorse
diff --git a/doc/update/8.17-to-9.0.md b/doc/update/8.17-to-9.0.md
index 626507c0482..b7ba970031c 100644
--- a/doc/update/8.17-to-9.0.md
+++ b/doc/update/8.17-to-9.0.md
@@ -115,11 +115,11 @@ sudo -u git -H bundle clean
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-# Install/update frontend asset dependencies
-sudo -u git -H npm install --production
+# Update node dependencies and recompile assets
+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
-sudo -u git -H bundle exec rake gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production
+# Clean up cache
+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).
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 2cc64fc6712..f35084a582a 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -4,7 +4,6 @@ module API
class Branches < Grape::API
include PaginationParams
- before { authenticate! }
before { authorize! :download_code, user_project }
params do
@@ -102,6 +101,7 @@ module API
end
post ":id/repository/branches" do
authorize_push_project
+
result = CreateBranchService.new(user_project, current_user).
execute(params[:branch], params[:ref])
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0a12ee72d49..5954aea8041 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -768,7 +768,7 @@ module API
end
class Dependency < Grape::Entity
- expose :id, :name
+ expose :id, :name, :token
expose :artifacts_file, using: ArtifactFile, if: ->(job, _) { job.artifacts? }
end
@@ -796,7 +796,7 @@ module API
expose :artifacts, using: Artifacts
expose :cache, using: Cache
expose :credentials, using: Credentials
- expose :depends_on_builds, as: :dependencies, using: Dependency
+ expose :dependencies, using: Dependency
end
end
end
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index ec2bcaed929..74848a6e144 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -41,14 +41,6 @@ module API
(Time.now - current_runner.contacted_at) >= contacted_at_max_age
end
- def job_not_found!
- if headers['User-Agent'].to_s =~ /gitlab(-ci-multi)?-runner \d+\.\d+\.\d+(~beta\.\d+\.g[0-9a-f]+)? /
- no_content!
- else
- not_found!
- end
- end
-
def validate_job!(job)
not_found! unless job
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index c700d2ef4a1..4c9db2c8716 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -47,11 +47,25 @@ module API
authenticate_runner!
Ci::Runner.find_by_token(params[:token]).destroy
end
+
+ desc 'Validates authentication credentials' do
+ http_codes [[200, 'Credentials are valid'], [403, 'Forbidden']]
+ end
+ params do
+ requires :token, type: String, desc: %q(Runner's authentication token)
+ end
+ post '/verify' do
+ authenticate_runner!
+ status 200
+ end
end
resource :jobs do
desc 'Request a job' do
success Entities::JobRequest::Response
+ http_codes [[201, 'Job was scheduled'],
+ [204, 'No job for Runner'],
+ [403, 'Forbidden']]
end
params do
requires :token, type: String, desc: %q(Runner's authentication token)
@@ -60,13 +74,13 @@ module API
end
post '/request' do
authenticate_runner!
- not_found! unless current_runner.active?
+ no_content! unless current_runner.active?
update_runner_info
if current_runner.is_runner_queue_value_latest?(params[:last_update])
header 'X-GitLab-Last-Update', params[:last_update]
Gitlab::Metrics.add_event(:build_not_found_cached)
- return job_not_found!
+ return no_content!
end
new_update = current_runner.ensure_runner_queue_value
@@ -80,7 +94,7 @@ module API
else
Gitlab::Metrics.add_event(:build_not_found)
header 'X-GitLab-Last-Update', new_update
- job_not_found!
+ no_content!
end
else
# We received build that is invalid due to concurrency conflict
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index aa3c9a06ed5..a9f2ca2608e 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -14,7 +14,7 @@ module API
requires :token, type: String, desc: 'The unique token of trigger'
optional :variables, type: Hash, desc: 'The list of variables to be injected into build'
end
- post ":id/(ref/:ref/)trigger/pipeline" do
+ post ":id/(ref/:ref/)trigger/pipeline", requirements: { ref: /.+/ } do
project = find_project(params[:id])
trigger = Ci::Trigger.find_by_token(params[:token].to_s)
not_found! unless project && trigger
diff --git a/lib/api/v3/triggers.rb b/lib/api/v3/triggers.rb
index b46639a2205..a23d6b6b48c 100644
--- a/lib/api/v3/triggers.rb
+++ b/lib/api/v3/triggers.rb
@@ -15,7 +15,7 @@ module API
requires :token, type: String, desc: 'The unique token of trigger'
optional :variables, type: Hash, desc: 'The list of variables to be injected into build'
end
- post ":id/(ref/:ref/)trigger/builds" do
+ post ":id/(ref/:ref/)trigger/builds", requirements: { ref: /.+/ } do
project = find_project(params[:id])
trigger = Ci::Trigger.find_by_token(params[:token].to_s)
not_found! unless project && trigger
diff --git a/lib/banzai/filter/image_link_filter.rb b/lib/banzai/filter/image_link_filter.rb
index 651b55523c0..123c92fd250 100644
--- a/lib/banzai/filter/image_link_filter.rb
+++ b/lib/banzai/filter/image_link_filter.rb
@@ -2,7 +2,6 @@ module Banzai
module Filter
# HTML filter that wraps links around inline images.
class ImageLinkFilter < HTML::Pipeline::Filter
-
# 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
# of the anchor, and then replace the img with the link-wrapped version.
@@ -12,7 +11,8 @@ module Banzai
'a',
class: 'no-attachment-icon',
href: img['src'],
- target: '_blank'
+ target: '_blank',
+ rel: 'noopener noreferrer'
)
link.children = img.clone
diff --git a/lib/banzai/filter/video_link_filter.rb b/lib/banzai/filter/video_link_filter.rb
index b64a1287d4d..35cb10eae5d 100644
--- a/lib/banzai/filter/video_link_filter.rb
+++ b/lib/banzai/filter/video_link_filter.rb
@@ -43,6 +43,7 @@ module Banzai
element['title'] || element['alt'],
href: element['src'],
target: '_blank',
+ rel: 'noopener noreferrer',
title: "Download '#{element['title'] || element['alt']}'")
download_paragraph = doc.document.create_element('p')
download_paragraph.children = link
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
new file mode 100644
index 00000000000..7e14a566696
--- /dev/null
+++ b/lib/gitlab/url_blocker.rb
@@ -0,0 +1,59 @@
+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
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 2f7c34a3f31..f25e66d54c8 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -38,6 +38,13 @@ server {
## See app/controllers/application_controller.rb for headers set
+ ## Real IP Module Config
+ ## http://nginx.org/en/docs/http/ngx_http_realip_module.html
+ real_ip_header X-Real-IP; ## X-Real-IP or X-Forwarded-For or proxy_protocol
+ real_ip_recursive off; ## If you enable 'on'
+ ## If you have a trusted IP address, uncomment it and set it
+ # set_real_ip_from YOUR_TRUSTED_ADDRESS; ## Replace this with something like 192.168.1.0/24
+
## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 330031aaddc..2b40da18bab 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -85,6 +85,13 @@ server {
## [Optional] Enable HTTP Strict Transport Security
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
+ ## Real IP Module Config
+ ## http://nginx.org/en/docs/http/ngx_http_realip_module.html
+ real_ip_header X-Real-IP; ## X-Real-IP or X-Forwarded-For or proxy_protocol
+ real_ip_recursive off; ## If you enable 'on'
+ ## If you have a trusted IP address, uncomment it and set it
+ # set_real_ip_from YOUR_TRUSTED_ADDRESS; ## Replace this with something like 192.168.1.0/24
+
## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;
diff --git a/package.json b/package.json
index 1048e29d0ac..b3d038bd3d1 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"eslint-fix": "eslint --max-warnings 0 --ext .js --fix .",
"eslint-report": "eslint --max-warnings 0 --ext .js --format html --output-file ./eslint-report.html .",
"karma": "karma start config/karma.config.js --single-run",
+ "karma-coverage": "BABEL_ENV=coverage karma start config/karma.config.js --single-run",
"karma-start": "karma start config/karma.config.js",
"webpack": "webpack --config config/webpack.config.js",
"webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js"
@@ -13,7 +14,8 @@
"dependencies": {
"babel-core": "^6.22.1",
"babel-loader": "^6.2.10",
- "babel-preset-es2015": "^6.22.0",
+ "babel-plugin-transform-define": "^1.2.0",
+ "babel-preset-latest": "^6.24.0",
"babel-preset-stage-2": "^6.22.0",
"bootstrap-sass": "^3.3.6",
"compression-webpack-plugin": "^0.3.2",
@@ -57,12 +59,5 @@
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.2",
"webpack-dev-server": "^2.3.0"
- },
- "nyc": {
- "exclude": [
- "spec/javascripts/test_bundle.js",
- "spec/javascripts/**/*_spec.js",
- "app/assets/javascripts/droplab/**/*"
- ]
}
}
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 6ceaf96f78f..57a921e3676 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -87,6 +87,12 @@ describe Projects::IssuesController do
end
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
before do
sign_in(user)
@@ -121,6 +127,11 @@ describe Projects::IssuesController do
end
context 'external issue tracker' do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
it 'redirects to the external issue tracker' do
external = double(new_issue_path: 'https://example.com/issues/new')
allow(project).to receive(:external_issue_tracker).and_return(external)
@@ -141,6 +152,24 @@ describe Projects::IssuesController do
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
let(:another_project) { create(:empty_project, :private) }
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 250d64f7055..c310d830e81 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -203,6 +203,24 @@ describe Projects::MergeRequestsController do
end
describe 'PUT update' do
+ 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
let(:project) { create(:project) }
let(:fork_project) { create(:forked_project_with_submodules) }
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index ae0bbbd6aeb..21487541507 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -4,6 +4,7 @@ FactoryGirl.define do
author
association :source_project, :repository, factory: :project
target_project { source_project }
+ project { target_project }
# $ git log --pretty=oneline feature..master
# 5937ac0a7beb003549fc5fd26fc247adbce4a52e Add submodule from gitlab.com
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index a7c22615b89..58b14e09740 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
describe "Dashboard Issues Feed", feature: true do
describe "GET /issues" do
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
@@ -31,7 +32,7 @@ describe "Dashboard Issues Feed", feature: true do
end
context "issue with basic fields" do
- let!(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'test desc') }
+ let!(:issue2) { create(:issue, author: user, assignee: assignee, project: project2, description: 'test desc') }
it "renders issue fields" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
@@ -39,8 +40,8 @@ describe "Dashboard Issues Feed", feature: true do
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
expect(entry).to be_present
- expect(entry).to have_selector('author email', text: issue2.author_email)
- expect(entry).to have_selector('assignee email', text: issue2.author_email)
+ expect(entry).to have_selector('author email', text: issue2.author_public_email)
+ expect(entry).to have_selector('assignee email', text: issue2.assignee_public_email)
expect(entry).not_to have_selector('labels')
expect(entry).not_to have_selector('milestone')
expect(entry).to have_selector('description', text: issue2.description)
@@ -50,7 +51,7 @@ describe "Dashboard Issues Feed", feature: true do
context "issue with label and milestone" do
let!(:milestone1) { create(:milestone, project: project1, title: 'v1') }
let!(:label1) { create(:label, project: project1, title: 'label1') }
- let!(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone1) }
+ let!(:issue1) { create(:issue, author: user, assignee: assignee, project: project1, milestone: milestone1) }
before do
issue1.labels << label1
@@ -62,8 +63,8 @@ describe "Dashboard Issues Feed", feature: true do
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
expect(entry).to be_present
- expect(entry).to have_selector('author email', text: issue1.author_email)
- expect(entry).to have_selector('assignee email', text: issue1.author_email)
+ expect(entry).to have_selector('author email', text: issue1.author_public_email)
+ expect(entry).to have_selector('assignee email', text: issue1.assignee_public_email)
expect(entry).to have_selector('labels label', text: label1.title)
expect(entry).to have_selector('milestone', text: milestone1.title)
expect(entry).not_to have_selector('description')
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index a01a050a013..b3903ec2faf 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -2,10 +2,11 @@ require 'spec_helper'
describe 'Issues Feed', feature: true do
describe 'GET /issues' do
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
let!(:group) { create(:group) }
let!(:project) { create(:project) }
- let!(:issue) { create(:issue, author: user, project: project) }
+ let!(:issue) { create(:issue, author: user, assignee: assignee, project: project) }
before do
project.team << [user, :developer]
@@ -20,7 +21,8 @@ describe 'Issues Feed', feature: true do
expect(response_headers['Content-Type']).
to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('author email', text: issue.author_public_email)
+ expect(body).to have_selector('assignee email', text: issue.author_public_email)
expect(body).to have_selector('entry summary', text: issue.title)
end
end
@@ -33,7 +35,8 @@ describe 'Issues Feed', feature: true do
expect(response_headers['Content-Type']).
to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('author email', text: issue.author_public_email)
+ expect(body).to have_selector('assignee email', text: issue.author_public_email)
expect(body).to have_selector('entry summary', text: issue.title)
end
end
diff --git a/spec/features/groups/group_name_toggle.rb b/spec/features/groups/group_name_toggle_spec.rb
index ada4ac66e04..8528718a2f7 100644
--- a/spec/features/groups/group_name_toggle.rb
+++ b/spec/features/groups/group_name_toggle_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Group name toggle', js: true do
+feature 'Group name toggle', feature: true, js: true do
let(:group) { create(:group) }
let(:nested_group_1) { create(:group, parent: group) }
let(:nested_group_2) { create(:group, parent: nested_group_1) }
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 1c8267b1593..a58aedc924e 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -6,7 +6,7 @@ describe 'Issues', feature: true do
include SortingHelper
include WaitForAjax
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
before do
login_as :user
@@ -565,6 +565,24 @@ describe 'Issues', feature: true do
end
describe 'new issue' do
+ context 'by unauthenticated user' do
+ before do
+ logout
+ end
+
+ it 'redirects to signin then back to new issue after signin' do
+ visit namespace_project_issues_path(project.namespace, project)
+
+ click_link 'New issue'
+
+ expect(current_path).to eq new_user_session_path
+
+ login_as :user
+
+ expect(current_path).to eq new_namespace_project_issue_path(project.namespace, project)
+ end
+ end
+
context 'dropzone upload file', js: true do
before do
visit new_namespace_project_issue_path(project.namespace, project)
diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb
index 6fed1568fcf..14511707af4 100644
--- a/spec/features/merge_requests/reset_filters_spec.rb
+++ b/spec/features/merge_requests/reset_filters_spec.rb
@@ -49,6 +49,26 @@ feature 'Merge requests filter clear button', feature: true, js: true do
end
end
+ context 'when multiple label filters have been applied' do
+ let!(:label) { create(:label, project: project, name: 'Frontend') }
+ let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") }
+
+ before do
+ visit_merge_requests(project)
+ init_label_search
+ end
+
+ it 'filters bug label' do
+ filtered_search.set('~bug')
+
+ filter_dropdown.find('.filter-dropdown-item', text: bug.title).click
+ init_label_search
+
+ expect(filter_dropdown.find('.filter-dropdown-item', text: bug.title)).to be_visible
+ expect(filter_dropdown.find('.filter-dropdown-item', text: label.title)).to be_visible
+ end
+ end
+
context 'when a text search has been conducted' do
it 'resets the text search filter' do
visit_merge_requests(project, search: 'Bug')
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 2f3c3e45ae6..a1f4eb2688b 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -133,7 +133,6 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
it 'changes target_branch in new merge_request' do
visit new_namespace_project_merge_request_path(another_project.namespace, another_project, new_url_opts)
- click_button "Compare branches and continue"
fill_in "merge_request_title", with: 'My brand new feature'
fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:"
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index f842d14fa96..aedc0333cb9 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -15,15 +15,30 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do
context 'in the user namespace' do
let(:project) { create(:project, namespace: user.namespace) }
- scenario 'the home page' do
- click_link 'Edit'
-
- fill_in :wiki_content, with: 'My awesome wiki!'
- click_button 'Save changes'
-
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
+ context 'the home page' do
+ scenario 'success when the wiki content is not empty' do
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: 'My awesome wiki!'
+ click_button 'Save changes'
+
+ expect(page).to have_content('Home')
+ expect(page).to have_content("Last edited by #{user.name}")
+ expect(page).to have_content('My awesome wiki!')
+ end
+
+ scenario 'failure when the wiki content is empty' do
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: ''
+ click_button 'Save changes'
+
+ expect(page).to have_selector('.wiki-form')
+ expect(page).to have_content('Edit Page')
+ expect(page).to have_content('The form contains the following error:')
+ expect(page).to have_content('Content can\'t be blank')
+ expect(find('textarea#wiki_content').value).to eq ''
+ end
end
end
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 50060a0925d..21e0e74e008 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -1,6 +1,40 @@
require "spec_helper"
describe TodosHelper do
+ include GitlabRoutingHelper
+
+ describe '#todo_target_path' do
+ let(:project) { create(:project) }
+ let(:merge_request) { create(:merge_request, target_project: project, source_project: project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:note) { create(:note_on_issue, noteable: issue, project: project) }
+
+ let(:mr_todo) { build(:todo, project: project, target: merge_request) }
+ let(:issue_todo) { build(:todo, project: project, target: issue) }
+ let(:note_todo) { build(:todo, project: project, target: issue, note: note) }
+ let(:build_failed_todo) { build(:todo, :build_failed, project: project, target: merge_request) }
+
+ it 'returns correct path to the todo MR' do
+ expect(todo_target_path(mr_todo)).
+ to eq("/#{project.full_path}/merge_requests/#{merge_request.iid}")
+ end
+
+ it 'returns correct path to the todo issue' do
+ expect(todo_target_path(issue_todo)).
+ to eq("/#{project.full_path}/issues/#{issue.iid}")
+ end
+
+ it 'returns correct path to the todo note' do
+ expect(todo_target_path(note_todo)).
+ to eq("/#{project.full_path}/issues/#{issue.iid}#note_#{note.id}")
+ end
+
+ it 'returns correct path to build_todo MR when pipeline failed' do
+ expect(todo_target_path(build_failed_todo)).
+ to eq("/#{project.full_path}/merge_requests/#{merge_request.iid}/pipelines")
+ end
+ end
+
describe '#todo_projects_options' do
let(:projects) { create_list(:empty_project, 3) }
let(:user) { create(:user) }
diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js
index 8d25500b9fd..aabc8bea12f 100644
--- a/spec/javascripts/issue_spec.js
+++ b/spec/javascripts/issue_spec.js
@@ -136,6 +136,21 @@ describe('Issue', function() {
expectErrorMessage();
expect($('.issue_counter')).toHaveText(1);
});
+
+ it('updates counter', () => {
+ spyOn(jQuery, 'ajax').and.callFake(function(req) {
+ expectPendingRequest(req, $btnClose);
+ req.success({
+ id: 34
+ });
+ });
+
+ expect($('.issue_counter')).toHaveText(1);
+ $('.issue_counter').text('1,001');
+ expect($('.issue_counter').text()).toEqual('1,001');
+ $btnClose.trigger('click');
+ expect($('.issue_counter').text()).toEqual('1,000');
+ });
});
describe('reopen issue', function() {
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index c12b44cea89..5cdb6473eda 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -32,10 +32,11 @@ testsContext.keys().forEach(function (path) {
}
});
-// workaround: include all source files to find files with 0% coverage
-// see also https://github.com/deepsweet/istanbul-instrumenter-loader/issues/15
-describe('Uncovered files', function () {
- // the following files throw errors because of undefined variables
+// if we're generating coverage reports, make sure to include all files so
+// that we can catch files with 0% coverage
+// see: https://github.com/deepsweet/istanbul-instrumenter-loader/issues/15
+if (process.env.BABEL_ENV === 'coverage') {
+ // exempt these files from the coverage report
const troubleMakers = [
'./blob_edit/blob_edit_bundle.js',
'./cycle_analytics/components/stage_plan_component.js',
@@ -48,21 +49,23 @@ describe('Uncovered files', function () {
'./network/branch_graph.js',
];
- const sourceFiles = require.context('~', true, /^\.\/(?!application\.js).*\.js$/);
- sourceFiles.keys().forEach(function (path) {
- // ignore if there is a matching spec file
- if (testsContext.keys().indexOf(`${path.replace(/\.js$/, '')}_spec`) > -1) {
- return;
- }
+ describe('Uncovered files', function () {
+ const sourceFiles = require.context('~', true, /\.js$/);
+ sourceFiles.keys().forEach(function (path) {
+ // ignore if there is a matching spec file
+ if (testsContext.keys().indexOf(`${path.replace(/\.js$/, '')}_spec`) > -1) {
+ return;
+ }
- it(`includes '${path}'`, function () {
- try {
- sourceFiles(path);
- } catch (err) {
- if (troubleMakers.indexOf(path) === -1) {
- expect(err).toBeNull();
+ it(`includes '${path}'`, function () {
+ try {
+ sourceFiles(path);
+ } catch (err) {
+ if (troubleMakers.indexOf(path) === -1) {
+ expect(err).toBeNull();
+ }
}
- }
+ });
});
});
-});
+}
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 042b7b0a20d..1ad16a9b57d 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -15,6 +15,7 @@ Issue:
- updated_by_id
- confidential
- deleted_at
+- closed_at
- due_date
- moved_to_id
- lock_version
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
new file mode 100644
index 00000000000..a504d299307
--- /dev/null
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Gitlab::UrlBlocker, lib: true do
+ describe '#blocked_url?' do
+ it 'allows imports from configured web host and port' do
+ import_url = "http://#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}/t.git"
+ expect(described_class.blocked_url?(import_url)).to be false
+ end
+
+ it 'allows imports from configured SSH host and port' do
+ import_url = "http://#{Gitlab.config.gitlab_shell.ssh_host}:#{Gitlab.config.gitlab_shell.ssh_port}/t.git"
+ expect(described_class.blocked_url?(import_url)).to be false
+ end
+
+ it 'returns true for bad localhost hostname' do
+ expect(described_class.blocked_url?('https://localhost:65535/foo/foo.git')).to be true
+ end
+
+ it 'returns true for bad port' do
+ expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git')).to be true
+ end
+
+ it 'returns true for invalid URL' do
+ expect(described_class.blocked_url?('http://:8080')).to be true
+ end
+
+ it 'returns false for legitimate URL' do
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git')).to be false
+ end
+ end
+end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 9ffcb88bafd..73977d031f9 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -37,6 +37,30 @@ describe Issue, models: true do
end
end
+ describe '#closed_at' do
+ after do
+ Timecop.return
+ end
+
+ let!(:now) { Timecop.freeze(Time.now) }
+
+ it 'sets closed_at to Time.now when issue is closed' do
+ issue = create(:issue, state: 'opened')
+
+ issue.close
+
+ expect(issue.closed_at).to eq(now)
+ end
+
+ it 'sets closed_at to nil when issue is reopened' do
+ issue = create(:issue, state: 'closed')
+
+ issue.reopen
+
+ expect(issue.closed_at).to be_nil
+ end
+ end
+
describe '#to_reference' do
let(:namespace) { build(:namespace, path: 'sample-namespace') }
let(:project) { build(:empty_project, name: 'sample-project', namespace: namespace) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 618ce2b6d53..f68631ebe06 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -218,6 +218,20 @@ describe Project, models: true do
expect(project2.import_data).to be_nil
end
+ it "does not allow blocked import_url localhost" do
+ project2 = build(:empty_project, import_url: 'http://localhost:9000/t.git')
+
+ expect(project2).to be_invalid
+ expect(project2.errors[:import_url]).to include('imports are not allowed from that URL')
+ end
+
+ it "does not allow blocked import_url port" do
+ project2 = build(:empty_project, import_url: 'http://github.com:25/t.git')
+
+ expect(project2).to be_invalid
+ expect(project2.errors[:import_url]).to include('imports are not allowed from that URL')
+ end
+
describe 'project pending deletion' do
let!(:project_pending_deletion) do
create(:empty_project,
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 0b222022e62..bc8ae4ae5a8 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -43,14 +43,22 @@ describe Route, models: true do
end
context 'name update' do
- before { route.update_attributes(name: 'bar') }
-
it "updates children routes with new path" do
+ route.update_attributes(name: 'bar')
+
expect(described_class.exists?(name: 'bar')).to be_truthy
expect(described_class.exists?(name: 'bar / test')).to be_truthy
expect(described_class.exists?(name: 'bar / test / foo')).to be_truthy
expect(described_class.exists?(name: 'gitlab-org')).to be_truthy
end
+
+ it 'handles a rename from nil' do
+ # Note: using `update_columns` to skip all validation and callbacks
+ route.update_columns(name: nil)
+
+ expect { route.update_attributes(name: 'bar') }
+ .to change { route.name }.from(nil).to('bar')
+ end
end
end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index ab5a7e4d3de..a70f7beaae0 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -5,77 +5,146 @@ describe API::Branches, api: true do
include ApiHelpers
let(:user) { create(:user) }
- let(:user2) { create(:user) }
let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
- let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
+ let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
let!(:branch_name) { 'feature' }
let!(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
- let!(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master") }
+ let(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master")[:branch] }
describe "GET /projects/:id/repository/branches" do
- it "returns an array of project branches" do
- project.repository.expire_all_method_caches
+ let(:route) { "/projects/#{project.id}/repository/branches" }
- get api("/projects/#{project.id}/repository/branches", user), per_page: 100
+ shared_examples_for 'repository branches' do
+ it 'returns the repository branches' do
+ get api(route, current_user), per_page: 100
- expect(response).to have_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- branch_names = json_response.map { |x| x['name'] }
- expect(branch_names).to match_array(project.repository.branch_names)
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ branch_names = json_response.map { |x| x['name'] }
+ expect(branch_names).to match_array(project.repository.branch_names)
+ end
+
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
+
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, current_user) }
+ end
+ end
end
- end
- describe "GET /projects/:id/repository/branches/:branch" do
- it "returns the branch information for a single branch" do
- get api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
- expect(response).to have_http_status(200)
+ context 'when unauthenticated', 'and project is public' do
+ it_behaves_like 'repository branches' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:current_user) { nil }
+ end
+ end
- expect(json_response['name']).to eq(branch_name)
- json_commit = json_response['commit']
- expect(json_commit['id']).to eq(branch_sha)
- expect(json_commit).to have_key('short_id')
- expect(json_commit).to have_key('title')
- expect(json_commit).to have_key('message')
- expect(json_commit).to have_key('author_name')
- expect(json_commit).to have_key('author_email')
- expect(json_commit).to have_key('authored_date')
- expect(json_commit).to have_key('committer_name')
- expect(json_commit).to have_key('committer_email')
- expect(json_commit).to have_key('committed_date')
- expect(json_commit).to have_key('parent_ids')
- expect(json_response['merged']).to eq(false)
- expect(json_response['protected']).to eq(false)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(false)
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { get api(route) }
+ let(:message) { '404 Project Not Found' }
+ end
end
- it "returns the branch information for a single branch with dots in the name" do
- get api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
+ context 'when authenticated', 'as a developer' do
+ it_behaves_like 'repository branches' do
+ let(:current_user) { user }
+ end
+ end
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq("with.1.2.3")
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, guest) }
+ end
end
+ end
+
+ describe "GET /projects/:id/repository/branches/:branch" do
+ let(:route) { "/projects/#{project.id}/repository/branches/#{branch_name}" }
- context 'on a merged branch' do
- it "returns the branch information for a single branch" do
- get api("/projects/#{project.id}/repository/branches/merge-test", user)
+ shared_examples_for 'repository branch' do |merged: false|
+ it 'returns the repository branch' do
+ get api(route, current_user)
expect(response).to have_http_status(200)
- expect(json_response['name']).to eq('merge-test')
- expect(json_response['merged']).to eq(true)
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['merged']).to eq(merged)
+ expect(json_response['protected']).to eq(false)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
+
+ json_commit = json_response['commit']
+ expect(json_commit['id']).to eq(branch_sha)
+ expect(json_commit).to have_key('short_id')
+ expect(json_commit).to have_key('title')
+ expect(json_commit).to have_key('message')
+ expect(json_commit).to have_key('author_name')
+ expect(json_commit).to have_key('author_email')
+ expect(json_commit).to have_key('authored_date')
+ expect(json_commit).to have_key('committer_name')
+ expect(json_commit).to have_key('committer_email')
+ expect(json_commit).to have_key('committed_date')
+ expect(json_commit).to have_key('parent_ids')
+ end
+
+ context 'when branch does not exist' do
+ let(:branch_name) { 'unknown' }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, current_user) }
+ let(:message) { '404 Branch Not Found' }
+ end
+ end
+
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
+
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, current_user) }
+ end
end
end
- it "returns a 403 error if guest" do
- get api("/projects/#{project.id}/repository/branches", user2)
- expect(response).to have_http_status(403)
+ context 'when unauthenticated', 'and project is public' do
+ it_behaves_like 'repository branch' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:current_user) { nil }
+ end
end
- it "returns a 404 error if branch is not available" do
- get api("/projects/#{project.id}/repository/branches/unknown", user)
- expect(response).to have_http_status(404)
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { get api(route) }
+ let(:message) { '404 Project Not Found' }
+ end
+ end
+
+ context 'when authenticated', 'as a developer' do
+ let(:current_user) { user }
+ it_behaves_like 'repository branch'
+
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
+ let(:branch_sha) { project.commit('master').sha }
+
+ it_behaves_like 'repository branch'
+ end
+
+ context 'when branch is merged' do
+ let(:branch_name) { 'merge-test' }
+ let(:branch_sha) { project.commit('merge-test').sha }
+
+ it_behaves_like 'repository branch', merged: true
+ end
+ end
+
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { get api(route, guest) }
+ end
end
end
@@ -93,10 +162,10 @@ describe API::Branches, api: true do
end
it "protects a single branch with dots in the name" do
- put api("/projects/#{project.id}/repository/branches/with.1.2.3/protect", user)
+ put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/protect", user)
expect(response).to have_http_status(200)
- expect(json_response['name']).to eq("with.1.2.3")
+ expect(json_response['name']).to eq(branch_with_dot.name)
expect(json_response['protected']).to eq(true)
end
@@ -234,7 +303,7 @@ describe API::Branches, api: true do
end
it "returns a 403 error if guest" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user2)
+ put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", guest)
expect(response).to have_http_status(403)
end
end
@@ -250,10 +319,10 @@ describe API::Branches, api: true do
end
it "update branches with dots in branch name" do
- put api("/projects/#{project.id}/repository/branches/with.1.2.3/unprotect", user)
+ put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/unprotect", user)
expect(response).to have_http_status(200)
- expect(json_response['name']).to eq("with.1.2.3")
+ expect(json_response['name']).to eq(branch_with_dot.name)
expect(json_response['protected']).to eq(false)
end
@@ -282,7 +351,7 @@ describe API::Branches, api: true do
end
it "denies for user without push access" do
- post api("/projects/#{project.id}/repository/branches", user2),
+ post api("/projects/#{project.id}/repository/branches", guest),
branch: branch_name,
ref: branch_sha
expect(response).to have_http_status(403)
@@ -330,7 +399,7 @@ describe API::Branches, api: true do
end
it "removes a branch with dots in the branch name" do
- delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
+ delete api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}", user)
expect(response).to have_http_status(204)
end
@@ -367,7 +436,7 @@ describe API::Branches, api: true do
end
it 'returns a 403 error if guest' do
- delete api("/projects/#{project.id}/repository/merged_branches", user2)
+ delete api("/projects/#{project.id}/repository/merged_branches", guest)
expect(response).to have_http_status(403)
end
end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 442b2df1952..044b989e5ba 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -152,6 +152,34 @@ describe API::Runner do
end
end
end
+
+ describe 'POST /api/v4/runners/verify' do
+ let(:runner) { create(:ci_runner) }
+
+ context 'when no token is provided' do
+ it 'returns 400 error' do
+ post api('/runners/verify')
+
+ expect(response).to have_http_status :bad_request
+ end
+ end
+
+ context 'when invalid token is provided' do
+ it 'returns 403 error' do
+ post api('/runners/verify'), token: 'invalid-token'
+
+ expect(response).to have_http_status 403
+ end
+ end
+
+ context 'when valid token is provided' do
+ it 'verifies Runner credentials' do
+ post api('/runners/verify'), token: runner.token
+
+ expect(response).to have_http_status 200
+ end
+ end
+ end
end
describe '/api/v4/jobs' do
@@ -220,18 +248,6 @@ describe API::Runner do
it { expect(response).to have_http_status(204) }
end
end
-
- context "when runner doesn't send version in User-Agent" do
- let(:user_agent) { 'Go-http-client/1.1' }
-
- it { expect(response).to have_http_status(404) }
- end
-
- context "when runner doesn't have a User-Agent" do
- let(:user_agent) { nil }
-
- it { expect(response).to have_http_status(404) }
- end
end
context 'when no token is provided' do
@@ -254,10 +270,10 @@ describe API::Runner do
context 'when Runner is not active' do
let(:runner) { create(:ci_runner, :inactive) }
- it 'returns 404 error' do
+ it 'returns 204 error' do
request_job
- expect(response).to have_http_status 404
+ expect(response).to have_http_status 204
end
end
@@ -401,9 +417,39 @@ describe API::Runner do
end
context 'when project and pipeline have multiple jobs' do
+ let!(:job) { create(:ci_build_tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
+ let!(:job2) { create(:ci_build_tag, pipeline: pipeline, name: 'rubocop', stage: 'test', stage_idx: 0) }
let!(:test_job) { create(:ci_build, pipeline: pipeline, name: 'deploy', stage: 'deploy', stage_idx: 1) }
- before { job.success }
+ before do
+ job.success
+ job2.success
+ end
+
+ it 'returns dependent jobs' do
+ request_job
+
+ expect(response).to have_http_status(201)
+ expect(json_response['id']).to eq(test_job.id)
+ expect(json_response['dependencies'].count).to eq(2)
+ expect(json_response['dependencies']).to include({ 'id' => job.id, 'name' => job.name, 'token' => job.token },
+ { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token })
+ end
+ end
+
+ context 'when explicit dependencies are defined' do
+ let!(:job) { create(:ci_build_tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
+ let!(:job2) { create(:ci_build_tag, pipeline: pipeline, name: 'rubocop', stage: 'test', stage_idx: 0) }
+ let!(:test_job) do
+ create(:ci_build, pipeline: pipeline, token: 'test-job-token', name: 'deploy',
+ stage: 'deploy', stage_idx: 1,
+ options: { dependencies: [job2.name] })
+ end
+
+ before do
+ job.success
+ job2.success
+ end
it 'returns dependent jobs' do
request_job
@@ -411,7 +457,7 @@ describe API::Runner do
expect(response).to have_http_status(201)
expect(json_response['id']).to eq(test_job.id)
expect(json_response['dependencies'].count).to eq(1)
- expect(json_response['dependencies'][0]).to include('id' => job.id, 'name' => 'spinach')
+ expect(json_response['dependencies'][0]).to include('id' => job2.id, 'name' => job2.name, 'token' => job2.token)
end
end
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index 424c02932ab..d93a734f5b6 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -59,14 +59,6 @@ describe API::Triggers do
expect(pipeline.builds.size).to eq(5)
end
- it 'creates builds on webhook from other gitlab repository and branch' do
- expect do
- post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
- end.to change(project.builds, :count).by(5)
-
- expect(response).to have_http_status(201)
- end
-
it 'returns bad request with no pipeline created if there\'s no commit for that ref' do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch')
@@ -101,6 +93,28 @@ describe API::Triggers do
end
end
end
+
+ context 'when triggering a pipeline from a trigger token' do
+ it 'creates builds from the ref given in the URL, not in the body' do
+ expect do
+ post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
+ end.to change(project.builds, :count).by(5)
+
+ expect(response).to have_http_status(201)
+ end
+
+ context 'when ref contains a dot' do
+ it 'creates builds from the ref given in the URL, not in the body' do
+ project.repository.create_file(user, '.gitlab/gitlabhq/new_feature.md', 'something valid', message: 'new_feature', branch_name: 'v.1-branch')
+
+ expect do
+ post api("/projects/#{project.id}/ref/v.1-branch/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
+ end.to change(project.builds, :count).by(4)
+
+ expect(response).to have_http_status(201)
+ end
+ end
+ end
end
describe 'GET /projects/:id/triggers' do
diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb
index 4819269d69f..9233e9621bf 100644
--- a/spec/requests/api/v3/triggers_spec.rb
+++ b/spec/requests/api/v3/triggers_spec.rb
@@ -51,13 +51,6 @@ describe API::V3::Triggers do
expect(pipeline.builds.size).to eq(5)
end
- it 'creates builds on webhook from other gitlab repository and branch' do
- expect do
- post v3_api("/projects/#{project.id}/ref/master/trigger/builds?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
- end.to change(project.builds, :count).by(5)
- expect(response).to have_http_status(201)
- end
-
it 'returns bad request with no builds created if there\'s no commit for that ref' do
post v3_api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400)
@@ -89,6 +82,27 @@ describe API::V3::Triggers do
end
end
end
+
+ context 'when triggering a pipeline from a trigger token' do
+ it 'creates builds from the ref given in the URL, not in the body' do
+ expect do
+ post v3_api("/projects/#{project.id}/ref/master/trigger/builds?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
+ end.to change(project.builds, :count).by(5)
+ expect(response).to have_http_status(201)
+ end
+
+ context 'when ref contains a dot' do
+ it 'creates builds from the ref given in the URL, not in the body' do
+ project.repository.create_file(user, '.gitlab/gitlabhq/new_feature.md', 'something valid', message: 'new_feature', branch_name: 'v.1-branch')
+
+ expect do
+ post v3_api("/projects/#{project.id}/ref/v.1-branch/trigger/builds?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
+ end.to change(project.builds, :count).by(4)
+
+ expect(response).to have_http_status(201)
+ end
+ end
+ end
end
describe 'GET /projects/:id/triggers' do
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 0768f644036..adfa75a524f 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -49,10 +49,13 @@ describe MergeRequests::BuildService, services: true do
let(:commits) { Commit.decorate([commit_1], project) }
it 'creates compare object with target branch as default branch' do
- expect(merge_request.can_be_created).to eq(false)
expect(merge_request.compare).to be_present
expect(merge_request.target_branch).to eq(project.default_branch)
end
+
+ it 'allows the merge request to be created' do
+ expect(merge_request.can_be_created).to eq(true)
+ end
end
context 'same source and target branch' do
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index ab6e8f537ba..e5917bb0b7a 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -120,6 +120,26 @@ describe Projects::ImportService, services: true do
end
end
+ context 'with blocked import_URL' do
+ it 'fails with localhost' do
+ project.import_url = 'https://localhost:9000/vim/vim.git'
+
+ result = described_class.new(project, user).execute
+
+ expect(result[:status]).to eq :error
+ expect(result[:message]).to end_with 'Blocked import URL.'
+ end
+
+ it 'fails with port 25' do
+ project.import_url = "https://github.com:25/vim/vim.git"
+
+ result = described_class.new(project, user).execute
+
+ expect(result[:status]).to eq :error
+ expect(result[:message]).to end_with 'Blocked import URL.'
+ end
+ end
+
def stub_github_omniauth_provider
provider = OpenStruct.new(
'name' => 'github',
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index db9f1231682..11037a4917b 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -5,6 +5,7 @@ describe SystemHooksService, services: true do
let(:project) { create :project }
let(:project_member) { create :project_member }
let(:key) { create(:key, user: user) }
+ let(:deploy_key) { create(:key) }
let(:group) { create(:group) }
let(:group_member) { create(:group_member) }
@@ -18,6 +19,8 @@ describe SystemHooksService, services: true do
it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) }
it { expect(event_data(key, :create)).to include(:username, :key, :id) }
it { expect(event_data(key, :destroy)).to include(:username, :key, :id) }
+ it { expect(event_data(deploy_key, :create)).to include(:key, :id) }
+ it { expect(event_data(deploy_key, :destroy)).to include(:key, :id) }
it do
project.old_path_with_namespace = 'renamed_from_path'
diff --git a/yarn.lock b/yarn.lock
index 391b1c7eccf..2500ddc6f6b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -473,6 +473,13 @@ babel-plugin-transform-decorators@^6.22.0:
babel-template "^6.22.0"
babel-types "^6.22.0"
+babel-plugin-transform-define@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.2.0.tgz#f036bda05162f29a542e434f585da1ccf1e7ec6a"
+ dependencies:
+ lodash.get "4.4.2"
+ traverse "0.6.6"
+
babel-plugin-transform-es2015-arrow-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
@@ -549,17 +556,17 @@ babel-plugin-transform-es2015-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-transform-es2015-modules-amd@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21"
+babel-plugin-transform-es2015-modules-amd@^6.24.0:
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e"
dependencies:
- babel-plugin-transform-es2015-modules-commonjs "^6.22.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.0"
babel-runtime "^6.22.0"
babel-template "^6.22.0"
-babel-plugin-transform-es2015-modules-commonjs@^6.22.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.23.0.tgz#cba7aa6379fb7ec99250e6d46de2973aaffa7b92"
+babel-plugin-transform-es2015-modules-commonjs@^6.24.0:
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f"
dependencies:
babel-plugin-transform-strict-mode "^6.22.0"
babel-runtime "^6.22.0"
@@ -574,11 +581,11 @@ babel-plugin-transform-es2015-modules-systemjs@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.23.0"
-babel-plugin-transform-es2015-modules-umd@^6.22.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.23.0.tgz#8d284ae2e19ed8fe21d2b1b26d6e7e0fcd94f0f1"
+babel-plugin-transform-es2015-modules-umd@^6.24.0:
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450"
dependencies:
- babel-plugin-transform-es2015-modules-amd "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.24.0"
babel-runtime "^6.22.0"
babel-template "^6.23.0"
@@ -669,9 +676,9 @@ babel-plugin-transform-strict-mode@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
-babel-preset-es2015@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835"
+babel-preset-es2015@^6.24.0:
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.0.tgz#c162d68b1932696e036cd3110dc1ccd303d2673a"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
@@ -684,10 +691,10 @@ babel-preset-es2015@^6.22.0:
babel-plugin-transform-es2015-for-of "^6.22.0"
babel-plugin-transform-es2015-function-name "^6.22.0"
babel-plugin-transform-es2015-literals "^6.22.0"
- babel-plugin-transform-es2015-modules-amd "^6.22.0"
- babel-plugin-transform-es2015-modules-commonjs "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.24.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.0"
babel-plugin-transform-es2015-modules-systemjs "^6.22.0"
- babel-plugin-transform-es2015-modules-umd "^6.22.0"
+ babel-plugin-transform-es2015-modules-umd "^6.24.0"
babel-plugin-transform-es2015-object-super "^6.22.0"
babel-plugin-transform-es2015-parameters "^6.22.0"
babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
@@ -698,6 +705,27 @@ babel-preset-es2015@^6.22.0:
babel-plugin-transform-es2015-unicode-regex "^6.22.0"
babel-plugin-transform-regenerator "^6.22.0"
+babel-preset-es2016@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz#b061aaa3983d40c9fbacfa3743b5df37f336156c"
+ dependencies:
+ babel-plugin-transform-exponentiation-operator "^6.22.0"
+
+babel-preset-es2017@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz#de2f9da5a30c50d293fb54a0ba15d6ddc573f0f2"
+ dependencies:
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-to-generator "^6.22.0"
+
+babel-preset-latest@^6.24.0:
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-latest/-/babel-preset-latest-6.24.0.tgz#a68d20f509edcc5d7433a48dfaebf7e4f2cd4cb7"
+ dependencies:
+ babel-preset-es2015 "^6.24.0"
+ babel-preset-es2016 "^6.22.0"
+ babel-preset-es2017 "^6.22.0"
+
babel-preset-stage-2@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07"
@@ -2900,6 +2928,10 @@ lodash.deburr@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-4.1.0.tgz#ddb1bbb3ef07458c0177ba07de14422cb033ff9b"
+lodash.get@4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+
lodash.get@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-3.7.0.tgz#3ce68ae2c91683b281cc5394128303cbf75e691f"
@@ -4271,6 +4303,10 @@ tough-cookie@~2.3.0:
dependencies:
punycode "^1.4.1"
+traverse@0.6.6:
+ version "0.6.6"
+ resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
+
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"