Commit 70a4d996 authored by Rémy Coutable's avatar Rémy Coutable

Merge remote-tracking branch 'origin/master' into ce-to-ee-2018-01-30

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parents da3d22f8 40b6c91f
......@@ -422,7 +422,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.82.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.83.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false
......
......@@ -309,7 +309,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.82.0)
gitaly-proto (0.83.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
......@@ -365,7 +365,7 @@ GEM
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.4.1.1)
google-protobuf (3.5.1.1-universal-darwin)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
googleauth (0.5.3)
......@@ -394,7 +394,7 @@ GEM
rake
grape_logging (1.7.0)
grape
grpc (1.8.3)
grpc (1.8.3-universal-darwin)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (>= 0.5.1, < 0.7)
......@@ -1091,7 +1091,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.82.0)
gitaly-proto (~> 0.83.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0)
......
import $ from 'jquery';
import _ from 'underscore';
import axios from './lib/utils/axios_utils';
const Api = {
groupsPath: '/api/:version/groups.json',
groupPath: '/api/:version/groups/:id.json',
groupPath: '/api/:version/groups/:id',
namespacesPath: '/api/:version/namespaces.json',
groupProjectsPath: '/api/:version/groups/:id/projects.json',
projectsPath: '/api/:version/projects.json',
......@@ -25,42 +25,40 @@ const Api = {
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath)
.replace(':id', groupId);
return $.ajax({
url,
dataType: 'json',
})
.done(group => callback(group));
return axios.get(url)
.then(({ data }) => callback(data));
},
// Return groups list. Filtered by query
groups(query, options, callback = $.noop) {
const url = Api.buildUrl(Api.groupsPath);
return $.ajax({
url,
data: Object.assign({
return axios.get(url, {
params: Object.assign({
search: query,
per_page: 20,
}, options),
dataType: 'json',
})
.done(groups => callback(groups));
.then(({ data }) => {
callback(data);
return data;
});
},
// Return namespaces list. Filtered by query
namespaces(query, callback) {
const url = Api.buildUrl(Api.namespacesPath);
return $.ajax({
url,
data: {
return axios.get(url, {
params: {
search: query,
per_page: 20,
},
dataType: 'json',
}).done(namespaces => callback(namespaces));
})
.then(({ data }) => callback(data));
},
// Return projects list. Filtered by query
projects(query, options, callback) {
projects(query, options, callback = _.noop) {
const url = Api.buildUrl(Api.projectsPath);
const defaults = {
search: query,
......@@ -72,12 +70,14 @@ const Api = {
defaults.membership = true;
}
return $.ajax({
url,
data: Object.assign(defaults, options),
dataType: 'json',
return axios.get(url, {
params: Object.assign(defaults, options),
})
.done(projects => callback(projects));
.then(({ data }) => {
callback(data);
return data;
});
},
// Return single project
......@@ -99,41 +99,34 @@ const Api = {
url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespacePath);
}
return $.ajax({
url,
type: 'POST',
data: { label: data },
dataType: 'json',
return axios.post(url, {
label: data,
})
.done(label => callback(label))
.fail(message => callback(message.responseJSON));
.then(res => callback(res.data))
.catch(e => callback(e.response.data));
},
// Return group projects list. Filtered by query
groupProjects(groupId, query, callback) {
const url = Api.buildUrl(Api.groupProjectsPath)
.replace(':id', groupId);
return $.ajax({
url,
data: {
return axios.get(url, {
params: {
search: query,
per_page: 20,
},
dataType: 'json',
})
.done(projects => callback(projects));
.then(({ data }) => callback(data));
},
commitMultiple(id, data) {
// see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
const url = Api.buildUrl(Api.commitPath)
.replace(':id', encodeURIComponent(id));
return this.wrapAjaxCall({
url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
dataType: 'json',
return axios.post(url, JSON.stringify(data), {
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
});
},
......@@ -142,40 +135,37 @@ const Api = {
.replace(':id', encodeURIComponent(id))
.replace(':branch', branch);
return this.wrapAjaxCall({
url,
type: 'GET',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
});
return axios.get(url);
},
// Return text for a specific license
licenseText(key, data, callback) {
const url = Api.buildUrl(Api.licensePath)
.replace(':key', key);
return $.ajax({
url,
data,
return axios.get(url, {
params: data,
})
.done(license => callback(license));
.then(res => callback(res.data));
},
gitignoreText(key, callback) {
const url = Api.buildUrl(Api.gitignorePath)
.replace(':key', key);
return $.get(url, gitignore => callback(gitignore));
return axios.get(url)
.then(({ data }) => callback(data));
},
gitlabCiYml(key, callback) {
const url = Api.buildUrl(Api.gitlabCiYmlPath)
.replace(':key', key);
return $.get(url, file => callback(file));
return axios.get(url)
.then(({ data }) => callback(data));
},
dockerfileYml(key, callback) {
const url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
$.get(url, callback);
return axios.get(url)
.then(({ data }) => callback(data));
},
issueTemplate(namespacePath, projectPath, key, type, callback) {
......@@ -184,49 +174,48 @@ const Api = {
.replace(':type', type)
.replace(':project_path', projectPath)
.replace(':namespace_path', namespacePath);
$.ajax({
url,
dataType: 'json',
})
.done(file => callback(null, file))
.fail(callback);
return axios.get(url)
.then(({ data }) => callback(null, data))
.catch(callback);
},
users(query, options) {
const url = Api.buildUrl(this.usersPath);
return Api.wrapAjaxCall({
url,
data: Object.assign({
return axios.get(url, {
params: Object.assign({
search: query,
per_page: 20,
}, options),
dataType: 'json',
});
},
approverUsers(search, options, callback = $.noop) {
const url = Api.buildUrl('/autocomplete/users.json');
return $.ajax({
url,
data: $.extend({
return axios.get(url, {
params: Object.assign({
search,
per_page: 20,
}, options),
dataType: 'json',
}).done(callback);
}).then(({ data }) => {
callback(data);
return data;
});
},
ldap_groups(query, provider, callback) {
const url = Api.buildUrl(this.ldapGroupsPath).replace(':provider', provider);
return Api.wrapAjaxCall({
url,
data: Object.assign({
return axios.get(url, {
params: {
search: query,
per_page: 20,
active: true,
}),
dataType: 'json',
}).then(groups => callback(groups));
},
}).then(({ data }) => {
callback(data);
return data;
});
},
buildUrl(url) {
......@@ -236,21 +225,6 @@ const Api = {
}
return urlRoot + url.replace(':version', gon.api_version);
},
wrapAjaxCall(options) {
return new Promise((resolve, reject) => {
// jQuery 2 is not Promises/A+ compatible (missing catch)
$.ajax(options) // eslint-disable-line promise/catch-or-return
.then(data => resolve(data),
(jqXHR, textStatus, errorThrown) => {
const error = new Error(`${options.url}: ${errorThrown}`);
error.textStatus = textStatus;
if (jqXHR && jqXHR.responseJSON) error.responseJSON = jqXHR.responseJSON;
reject(error);
},
);
});
},
};
export default Api;
import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils';
export default class BlobViewer {
constructor() {
......@@ -127,25 +128,18 @@ export default class BlobViewer {
const viewer = viewerParam;
const url = viewer.getAttribute('data-url');
return new Promise((resolve, reject) => {
if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
resolve(viewer);
return;
return Promise.resolve(viewer);
}
viewer.setAttribute('data-loading', 'true');
$.ajax({
url,
dataType: 'JSON',
})
.fail(reject)
.done((data) => {
return axios.get(url)
.then(({ data }) => {
viewer.innerHTML = data.html;
viewer.setAttribute('data-loaded', 'true');
resolve(viewer);
});
return viewer;
});
}
}
......@@ -5,6 +5,7 @@
import { pluralize } from './lib/utils/text_utility';
import { localTimeAgo } from './lib/utils/datetime_utility';
import Pager from './pager';
import axios from './lib/utils/axios_utils';
export default (function () {
const CommitsList = {};
......@@ -43,28 +44,29 @@ export default (function () {
CommitsList.filterResults = function () {
const form = $('.commits-search-form');
const search = CommitsList.searchField.val();
if (search === CommitsList.lastSearch) return;
if (search === CommitsList.lastSearch) return Promise.resolve();
const commitsUrl = form.attr('action') + '?' + form.serialize();
CommitsList.content.fadeTo('fast', 0.5);
return $.ajax({
type: 'GET',
url: form.attr('action'),
data: form.serialize(),
complete: function () {
return CommitsList.content.fadeTo('fast', 1.0);
},
success: function (data) {
const params = form.serializeArray().reduce((acc, obj) => Object.assign(acc, {
[obj.name]: obj.value,
}), {});
return axios.get(form.attr('action'), {
params,
})
.then(({ data }) => {
CommitsList.lastSearch = search;
CommitsList.content.html(data.html);
return history.replaceState({
page: commitsUrl,
CommitsList.content.fadeTo('fast', 1.0);
// Change url so if user reload a page - search results are saved
history.replaceState({
page: commitsUrl,
}, document.title, commitsUrl);
},
error: function () {
})
.catch(() => {
CommitsList.content.fadeTo('fast', 1.0);
CommitsList.lastSearch = null;
},
dataType: 'json',
});
};
......
......@@ -71,7 +71,7 @@ export const setResizingStatus = ({ commit }, resizing) => {
export const checkCommitStatus = ({ state }) =>
service
.getBranchData(state.currentProjectId, state.currentBranchId)
.then((data) => {
.then(({ data }) => {
const { id } = data.commit;
const selectedBranch =
state.projects[state.currentProjectId].branches[state.currentBranchId];
......@@ -90,7 +90,7 @@ export const commitChanges = (
) =>
service
.commit(state.currentProjectId, payload)
.then((data) => {
.then(({ data }) => {
const { branch } = payload;
if (!data.short_id) {
flash(data.message, 'alert', document, null, false, true);
......@@ -139,8 +139,8 @@ export const commitChanges = (
})
.catch((err) => {
let errMsg = 'Error committing changes. Please try again.';
if (err.responseJSON && err.responseJSON.message) {
errMsg += ` (${stripHtml(err.responseJSON.message)})`;
if (err.response.data && err.response.data.message) {
errMsg += ` (${stripHtml(err.response.data.message)})`;
}
flash(errMsg, 'alert', document, null, false, true);
window.dispatchEvent(new Event('resize'));
......
......@@ -10,7 +10,7 @@ export const getBranchData = (
!state.projects[`${projectId}`].branches[branchId])
|| force) {
service.getBranchData(`${projectId}`, branchId)
.then((data) => {
.then(({ data }) => {
const { id } = data.commit;
commit(types.SET_BRANCH, { projectPath: `${projectId}`, branchName: branchId, branch: data });
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
......
......@@ -8,16 +8,16 @@ class UsersCache extends Cache {
}
return Api.users('', { username })
.then((users) => {
if (!users.length) {
.then(({ data }) => {
if (!data.length) {
throw new Error(`User "${username}" could not be found!`);
}
if (users.length > 1) {
if (data.length > 1) {
throw new Error(`Expected username "${username}" to be unique!`);
}
const user = users[0];
const user = data[0];
this.internalStorage[username] = user;
return user;
});
......
class Admin::GitalyServersController < Admin::ApplicationController
def index
@gitaly_servers = Gitaly::Server.all
end
end
......@@ -153,10 +153,6 @@
GitLab API
%span.pull-right
= API::API::version
%p
Gitaly
%span.pull-right
= Gitlab::GitalyClient.expected_server_version
- if Gitlab.config.pages.enabled
%p
GitLab Pages
......@@ -172,10 +168,6 @@
- else
Undefined
%p
Git
%span.pull-right
= Gitlab::Git.version
%p
Ruby
%span.pull-right
......@@ -188,6 +180,8 @@
= Gitlab::Database.adapter_name
%span.pull-right
= Gitlab::Database.version
%p
= link_to "Gitaly Servers", admin_gitaly_servers_path
.row
.col-md-4
.info-well
......
- breadcrumb_title _("Gitaly Servers")
%h3.page-title= _("Gitaly Servers")
%hr
.gitaly_servers
- if @gitaly_servers.any?
.table-holder
%table.table.responsive-table
%thead.hidden-sm.hidden-xs
%tr
%th= _("Storage")
%th= n_("Gitaly|Address")
%th= _("Server version")
%th= _("Git version")
%th= _("Up to date")
- @gitaly_servers.each do |server|
%tr
%td
= server.storage
%td
= server.address
%td
= server.server_version
%td
= server.git_binary_version
%td
= boolean_to_icon(server.up_to_date?)
- else
.empty-state
.text-center
%h4= _("No connection could be made to a Gitaly Server, please check your logs!")
---
title: Add Gitaly Servers admin dashboard
merge_request:
author:
type: added
......@@ -29,6 +29,8 @@ namespace :admin do
resource :impersonation, only: :destroy
resources :abuse_reports, only: [:index, :destroy]
resources :gitaly_servers, only: [:index]
resources :spam_logs, only: [:index, :destroy] do
member do
post :mark_as_ham
......
......@@ -79,9 +79,9 @@ export default class ApproversSelect {
query: (query) => {
const fetchGroups = this.fetchGroups(query.term);
const fetchUsers = this.fetchUsers(query.term);
return $.when(fetchGroups, fetchUsers).then((groups, users) => {
return Promise.all([fetchGroups, fetchUsers]).then(([groups, users]) => {
const data = {
results: groups[0].concat(users[0]),
results: groups.concat(users),
};
return query.callback(data);
});
......
......@@ -13,22 +13,17 @@ function AdminEmailSelect() {
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
var group_result, project_result;
group_result = Api.groups(query.term, {}, function(groups) {
return groups;
});
project_result = Api.projects(query.term, {
const groupsFetch = Api.groups(query.term, {});
const projectsFetch = Api.projects(query.term, {
order_by: 'id',
membership: false
}, function(projects) {
return projects;
});
return $.when(project_result, group_result).done(function(projects, groups) {
return Promise.all([projectsFetch, groupsFetch]).then(function([projects, groups]) {
var all, data;
all = {
id: "all"
};
data = [all].concat(groups[0], projects[0]);
data = [all].concat(groups, projects);
return query.callback({
results: data
});
......
......@@ -17,9 +17,7 @@ class Groups::EpicsController < Groups::ApplicationController
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("groups/epics/_epics")
}
render json: serializer.represent(@epics)
end
end
end
......@@ -38,6 +36,10 @@ class Groups::EpicsController < Groups::ApplicationController
private
def pagination_disabled?
request.format.json?
end
def epic
@issuable = @epic ||= @group.epics.find_by(iid: params[:epic_id] || params[:id])
......
module Gitaly
class Server
def self.all
Gitlab.config.repositories.storages.keys.map { |s| Gitaly::Server.new(s) }
end
attr_reader :storage
def initialize(storage)
@storage = storage
end
def server_version
info.server_version
end
def git_binary_version
info.git_version
end
def up_to_date?
server_version == Gitlab::GitalyClient.expected_server_version
end
def address
Gitlab::GitalyClient.address(@storage)
rescue RuntimeError => e
"Error getting the address: #{e.message}"
end
private
def info
@info ||=
begin
Gitlab::GitalyClient::ServerService.new(@storage).info
rescue GRPC::Unavailable, GRPC::GRPC::DeadlineExceeded
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '')
end
end
end
end
module Gitlab
module GitalyClient
# Meant for extraction of server data, and later maybe to perform misc task
#
# Not meant for connection logic, look in Gitlab::GitalyClient
class ServerService
def initialize(storage)
@storage = storage
end
def info
GitalyClient.call(@storage, :server_service, :server_info, Gitaly::ServerInfoRequest.new)
end
end
end
end
......@@ -145,9 +145,11 @@ module Gitlab
#
# See `Gitlab::Metrics::Transaction#add_event` for more details.
def add_event(*args)
trans = current_transaction
current_transaction&.add_event(*args)
end
trans&.add_event(*args)
def add_event_with_values(*args)
current_transaction&.add_event_with_values(*args)
end
# Returns the prefix to use for the name of a series.
......
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-12 18:31+0000\n"
"PO-Revision-Date: 2017-12-12 18:31+0000\n"
"POT-Creation-Date: 2018-01-31 09:31+0100\n"
"PO-Revision-Date: 2018-01-31 09:31+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -23,17 +23,27 @@ msgid_plural "%d commits"
msgstr[0] ""
msgstr[1] ""
msgid "%d issue"
msgid_plural "%d issues"
msgstr[0] ""
msgstr[1] ""
msgid "%d layer"
msgid_plural "%d layers"
msgstr[0] ""
msgstr[1] ""
msgid "%d merge request"
msgid_plural "%d merge requests"
msgstr[0] ""
msgstr[1] ""
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
msgstr[1] ""
msgid "%{commit_author_link} committed %{commit_timeago}"
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
msgid "%{count} participant"
......@@ -47,9 +57,6 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
......@@ -123,15 +130,39 @@ msgstr ""
msgid "Add new directory"
msgstr ""
msgid "AdminArea|Stop all jobs"
msgstr ""
msgid "AdminArea|Stop all jobs?"
msgstr ""
msgid "AdminArea|Stop jobs"
msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
msgid "Advanced"
msgstr ""
msgid "Advanced settings"
msgstr ""
msgid "All"
msgstr ""
msgid "All changes are committed"
msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
......@@ -141,6 +172,9 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
......@@ -165,9 +199,6 @@ msgstr ""
msgid "Are you sure you want to discard your changes?"
msgstr ""
msgid "Are you sure you want to leave this group?"
msgstr ""
msgid "Are you sure you want to reset registration token?"
msgstr ""
......@@ -195,13 +226,13 @@ msgstr ""
msgid "Author"
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
msgstr ""
msgid "AutoDevOps|Auto DevOps (Beta)"
......@@ -225,6 +256,9 @@ msgstr ""
msgid "Available"
msgstr ""
msgid "Avatar will be removed. Are you sure?"
msgstr ""
msgid "Billing"
msgstr ""
......@@ -434,15 +468,24 @@ msgstr ""
msgid "ChangeTypeAction|Revert"
msgstr ""
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
msgstr ""
msgid "Changelog"
msgstr ""
msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
msgstr ""
msgid "Charts"
msgstr ""
msgid "Chat"
msgstr ""
msgid "Check interval"
msgstr ""
msgid "Checking %{text} availability…"
msgstr ""
......@@ -455,6 +498,15 @@ msgstr ""
msgid "Cherry-pick this merge request"
msgstr ""
msgid "Choose File ..."
msgstr ""
msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request."
msgstr ""
msgid "Choose file..."
msgstr ""
msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all."
msgstr ""
......@@ -515,39 +567,42 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
msgid "Click to expand text"
msgstr ""
msgid "Clone repository"
msgstr ""
msgid "Close"
msgstr ""
msgid "Cluster"
msgid "Closed"
msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
msgid "Cluster"
msgstr ""
msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
msgstr ""
msgid "ClusterIntegration|API URL"
msgstr ""
msgid "ClusterIntegration|Active"
msgstr ""
msgid "ClusterIntegration|Add an existing cluster"
msgstr ""
msgid "ClusterIntegration|Add cluster"
msgstr ""
msgid "ClusterIntegration|All"
msgid "ClusterIntegration|Advanced options on this cluster's integration"
msgstr ""
msgid "ClusterIntegration|Applications"
msgstr ""
msgid "ClusterIntegration|Are you sure you want to remove this cluster's integration? This will not delete your actual cluster."
msgstr ""
msgid "ClusterIntegration|CA Certificate"
msgstr ""
......@@ -557,6 +612,9 @@ msgstr ""
msgid "ClusterIntegration|Choose how to set up cluster integration"
msgstr ""
msgid "ClusterIntegration|Choose which of your project's environments will use this cluster."
msgstr ""
msgid "ClusterIntegration|Cluster"
msgstr ""
......@@ -587,6 +645,12 @@ msgstr ""
msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
msgstr ""
msgid "ClusterIntegration|Clusters can be used to deploy applications and to provide Review Apps for this project"
msgstr ""
msgid "ClusterIntegration|Control how your cluster integrates with GitLab"
msgstr ""
msgid "ClusterIntegration|Copy API URL"
msgstr ""
......@@ -599,7 +663,7 @@ msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
msgid "ClusterIntegration|Create a new cluster on Google Kubernetes Engine right from GitLab"
msgstr ""
msgid "ClusterIntegration|Create cluster"
......@@ -611,19 +675,16 @@ msgstr ""
msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|Enter the details for your cluster"
msgstr ""
msgid "ClusterIntegration|Environment pattern"
msgid "ClusterIntegration|Environment scope"
msgstr ""
msgid "ClusterIntegration|GKE pricing"
msgid "ClusterIntegration|GitLab Integration"
msgstr ""
msgid "ClusterIntegration|GitLab Runner"
......@@ -641,18 +702,12 @@ msgstr ""
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
msgid "ClusterIntegration|Inactive"
msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
msgid "ClusterIntegration|Install"
msgstr ""
msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
msgstr ""
msgid "ClusterIntegration|Installed"
msgstr ""
......@@ -662,19 +717,22 @@ msgstr ""
msgid "ClusterIntegration|Integrate cluster automation"
msgstr ""
msgid "ClusterIntegration|Integration status"
msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
msgid "ClusterIntegration|Learn more about Clusters"
msgstr ""
msgid "ClusterIntegration|Machine type"
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
......@@ -695,12 +753,6 @@ msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
msgid "ClusterIntegration|Problem setting up the cluster"
msgstr ""
msgid "ClusterIntegration|Problem setting up the clusters list"
msgstr ""
msgid "ClusterIntegration|Project ID"
msgstr ""
......@@ -710,6 +762,9 @@ msgstr ""
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
msgid "ClusterIntegration|Prometheus"
msgstr ""
msgid "ClusterIntegration|Read our %{link_to_help_page} on cluster integration."
msgstr ""
......@@ -719,7 +774,7 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
msgid "ClusterIntegration|Remove this cluster's configuration from this project. This will not delete your actual cluster."
msgstr ""
msgid "ClusterIntegration|Request to begin installing failed"
......@@ -755,9 +810,6 @@ msgstr ""
msgid "ClusterIntegration|Something went wrong while installing %{title}"
msgstr ""
msgid "ClusterIntegration|There are no clusters to show"
msgstr ""
msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
msgstr ""
......@@ -779,6 +831,9 @@ msgstr ""
msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr ""
msgid "ClusterIntegration|check the pricing here"
msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
......@@ -797,6 +852,9 @@ msgstr ""
msgid "ClusterIntegration|properly configured"
msgstr ""
msgid "Collapse"
msgstr ""
msgid "Comments"
msgstr ""
......@@ -826,15 +884,42 @@ msgstr ""
msgid "Commits feed"
msgstr ""
msgid "Commits|An error occurred while fetching merge requests data."
msgstr ""
msgid "Commits|History"
msgstr ""
msgid "Commits|No related merge requests found"
msgstr ""
msgid "Committed by"
msgstr ""
msgid "Compare"
msgstr ""
msgid "Compare Git revisions"
msgstr ""
msgid "Compare Revisions"
msgstr ""
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
msgstr ""
msgid "CompareBranches|Compare"
msgstr ""
msgid "CompareBranches|Source"
msgstr ""
msgid "CompareBranches|Target"
msgstr ""
msgid "CompareBranches|There isn't anything to compare."
msgstr ""
msgid "Container Registry"
msgstr ""
......@@ -886,6 +971,9 @@ msgstr ""
msgid "Contributors"
msgstr ""
msgid "ContributorsPage|%{startDate} – %{endDate}"
msgstr ""
msgid "ContributorsPage|Building repository graph."
msgstr ""
......@@ -961,6 +1049,9 @@ msgstr ""
msgid "Cron syntax"
msgstr ""
msgid "Current node"
msgstr ""
msgid "Custom notification events"
msgstr ""
......@@ -970,9 +1061,6 @@ msgstr ""
msgid "Cycle Analytics"
msgstr ""
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
msgid "CycleAnalyticsStage|Code"
msgstr ""
......@@ -1029,12 +1117,21 @@ msgstr ""
msgid "Details"
msgstr ""
msgid "Diffs|No file name available"
msgstr ""
msgid "Directory name"
msgstr ""
msgid "Disable"
msgstr ""
msgid "Discard changes"
msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
msgid "Dismiss Cycle Analytics introduction box"
msgstr ""
......@@ -1077,9 +1174,15 @@ msgstr ""
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
msgid "Edit files in the editor and commit changes here"
msgstr ""
msgid "Emails"
msgstr ""
msgid "Enable"
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
......@@ -1098,9 +1201,6 @@ msgstr ""
msgid "Environments|Environments"
msgstr ""
msgid "Environments|Environments are places where code gets deployed, such as staging or production."
msgstr ""
msgid "Environments|Job"
msgstr ""
......@@ -1143,6 +1243,12 @@ msgstr ""
msgid "Error creating epic"
msgstr ""
msgid "Error fetching contributors data."
msgstr ""
msgid "Error fetching refs"
msgstr ""
msgid "Error occurred when toggling the notification subscription"
msgstr ""
......@@ -1173,6 +1279,9 @@ msgstr ""
msgid "Every week (Sundays at 4:00am)"
msgstr ""
msgid "Expand"
msgstr ""
msgid "Explore projects"
msgstr ""
......@@ -1235,10 +1344,10 @@ msgstr ""
msgid "GPG Keys"
msgstr ""
msgid "Geo Nodes"
msgid "Generate a default set of labels"
msgstr ""
msgid "GeoNodeSyncStatus|Failed"
msgid "Geo Nodes"
msgstr ""
msgid "GeoNodeSyncStatus|Node is failing or broken."
......@@ -1247,10 +1356,85 @@ msgstr ""
msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
msgstr ""
msgid "GeoNodeSyncStatus|Out of sync"
msgid "GeoNodes|Database replication lag:"
msgstr ""
msgid "GeoNodeSyncStatus|Synced"
msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
msgstr ""
msgid "GeoNodes|Does not match the primary storage configuration"
msgstr ""
msgid "GeoNodes|Failed"
msgstr ""
msgid "GeoNodes|Full"
msgstr ""
msgid "GeoNodes|GitLab version does not match the primary node version"
msgstr ""
msgid "GeoNodes|GitLab version:"
msgstr ""
msgid "GeoNodes|Health status:"
msgstr ""
msgid "GeoNodes|Last event ID processed by cursor:"
msgstr ""
msgid "GeoNodes|Last event ID seen from primary:"
msgstr ""
msgid "GeoNodes|Loading nodes"
msgstr ""
msgid "GeoNodes|Local Attachments:"
msgstr ""
msgid "GeoNodes|Local LFS objects:"
msgstr ""
msgid "GeoNodes|Local job artifacts:"
msgstr ""
msgid "GeoNodes|New node"
msgstr ""
msgid "GeoNodes|Out of sync"
msgstr ""
msgid "GeoNodes|Replication slot WAL:"
msgstr ""
msgid "GeoNodes|Replication slots:"
msgstr ""
msgid "GeoNodes|Repositories:"
msgstr ""
msgid "GeoNodes|Selective"
msgstr ""
msgid "GeoNodes|Storage config:"
msgstr ""
msgid "GeoNodes|Sync settings:"
msgstr ""
msgid "GeoNodes|Synced"
msgstr ""
msgid "GeoNodes|Unused slots"
msgstr ""
msgid "GeoNodes|Used slots"
msgstr ""
msgid "GeoNodes|Wikis:"
msgstr ""
msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
msgstr ""
msgid "Geo|File sync capacity"
......@@ -1268,9 +1452,15 @@ msgstr ""
msgid "Git storage health information has been reset"
msgstr ""
msgid "Git version"
msgstr ""
msgid "GitLab Runner section"
msgstr ""
msgid "Gitaly Servers"
msgstr ""
msgid "Go to your fork"
msgstr ""
......@@ -1316,7 +1506,7 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
msgstr ""
msgid "GroupsTree|Create a project in this group."
......@@ -1367,6 +1557,11 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
msgid "Hide value"
msgid_plural "Hide values"
msgstr[0] ""
msgstr[1] ""
msgid "History"
msgstr ""
......@@ -1393,6 +1588,9 @@ msgid_plural "Instances"
msgstr[0] ""
msgstr[1] ""
msgid "Interested parties can even contribute by pushing commits if they want to."
msgstr ""
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr ""
......@@ -1420,6 +1618,9 @@ msgstr ""
msgid "Issues"
msgstr ""
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
msgstr ""
msgid "Jan"
msgstr ""
......@@ -1447,6 +1648,9 @@ msgstr ""
msgid "Labels"
msgstr ""
msgid "Labels can be applied to issues and merge requests to categorize them."
msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
......@@ -1476,6 +1680,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
msgid "Learn more"
msgstr ""
msgid "Learn more in the"
msgstr ""
......@@ -1494,10 +1701,8 @@ msgstr ""
msgid "License"
msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
msgstr[1] ""
msgid "Loading the GitLab IDE..."
msgstr ""
msgid "Lock"
msgstr ""
......@@ -1511,6 +1716,9 @@ msgstr ""
msgid "Login"
msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
msgid "Mar"
msgstr ""
......@@ -1529,6 +1737,9 @@ msgstr ""
msgid "Members"
msgstr ""
msgid "Merge Request"
msgstr ""
msgid "Merge Requests"
msgstr ""
......@@ -1538,9 +1749,27 @@ msgstr ""
msgid "Merge request"
msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
msgid "Merged"
msgstr ""
msgid "Messages"
msgstr ""
msgid "Milestones|Delete milestone"
msgstr ""
msgid "Milestones|Delete milestone %{milestoneTitle}?"
msgstr ""
msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
msgstr ""
msgid "Milestones|Milestone %{milestoneTitle} was not found"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
......@@ -1585,6 +1814,9 @@ msgstr ""
msgid "New issue"
msgstr ""
msgid "New label"
msgstr ""
msgid "New merge request"
msgstr ""
......@@ -1603,7 +1835,13 @@ msgstr ""
msgid "New tag"
msgstr ""
msgid "No container images stored for this project. Add one by following the instructions above."
msgid "No changes"
msgstr ""
msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr ""
msgid "No file chosen"
msgstr ""
msgid "No repository"
......@@ -1681,6 +1919,12 @@ msgstr ""
msgid "Notifications"
msgstr ""
msgid "Notifications off"
msgstr ""
msgid "Notifications on"
msgstr ""
msgid "Nov"
msgstr ""
......@@ -1690,7 +1934,7 @@ msgstr ""
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgid "OK"
msgstr ""
msgid "Oct"
......@@ -1705,6 +1949,9 @@ msgstr ""
msgid "Only project members can comment."
msgstr ""
msgid "Open"
msgstr ""
msgid "Opened"
msgstr ""
......@@ -1738,9 +1985,6 @@ msgstr ""
msgid "Password"
msgstr ""
msgid "People without permission will never get a notification and won\\'t be able to comment."
msgstr ""
msgid "Pipeline"
msgstr ""
......@@ -1828,6 +2072,12 @@ msgstr ""
msgid "Pipelines for last year"
msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
msgid "Pipeline|all"
msgstr ""
......@@ -1840,12 +2090,21 @@ msgstr ""
msgid "Pipeline|with stages"
msgstr ""
msgid "Play"
msgstr ""
msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a cluster</a>, then try again."
msgstr ""
msgid "Please solve the reCAPTCHA"
msgstr ""
msgid "Preferences"
msgstr ""
msgid "Primary"
msgstr ""
msgid "Private - Project access must be granted explicitly to each user."
msgstr ""
......@@ -1906,6 +2165,15 @@ msgstr ""
msgid "Project access must be granted explicitly to each user."
msgstr ""
msgid "Project avatar"
msgstr ""
msgid "Project avatar in repository: %{link}"
msgstr ""
msgid "Project cache successfully reset."
msgstr ""
msgid "Project details"
msgstr ""
......@@ -1948,15 +2216,9 @@ msgstr ""
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
msgid "ProjectSettings|Immediately run a pipeline on the default branch"
msgstr ""
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
msgstr ""
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
......@@ -2053,6 +2315,9 @@ msgstr ""
msgid "RefSwitcher|Tags"
msgstr ""
msgid "Register / Sign In"
msgstr ""
msgid "Registry"
msgstr ""
......@@ -2077,9 +2342,18 @@ msgstr ""
msgid "Remind later"
msgstr ""
msgid "Remove"
msgstr ""
msgid "Remove avatar"
msgstr ""
msgid "Remove project"
msgstr ""
msgid "Repair authentication"
msgstr ""
msgid "Repository"
msgstr ""
......@@ -2095,6 +2369,11 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
msgstr[1] ""
msgid "Revert this commit"
msgstr ""
......@@ -2104,9 +2383,6 @@ msgstr ""
msgid "SSH Keys"
msgstr ""
msgid "Save"
msgstr ""
msgid "Save changes"
msgstr ""
......@@ -2131,9 +2407,6 @@ msgstr ""
msgid "Seconds before reseting failure information"
msgstr ""
msgid "Seconds to wait after a storage failure"
msgstr ""
msgid "Seconds to wait for a storage access attempt"
msgstr ""
......@@ -2143,6 +2416,9 @@ msgstr ""
msgid "Select a timezone"
msgstr ""
msgid "Select branch/tag"
msgstr ""
msgid "Select target branch"
msgstr ""
......@@ -2152,6 +2428,9 @@ msgstr ""
msgid "September"
msgstr ""
msgid "Server version"
msgstr ""
msgid "Service Templates"
msgstr ""
......@@ -2173,6 +2452,15 @@ msgstr ""
msgid "Settings"
msgstr ""
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
msgid "Show parent pages"
msgstr ""
......@@ -2187,9 +2475,6 @@ msgstr[1] ""
msgid "Sidebar|Change weight"
msgstr ""
msgid "Sidebar|Edit"
msgstr ""
msgid "Sidebar|No"
msgstr ""
......@@ -2208,12 +2493,18 @@ msgstr ""
msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
msgid "Something went wrong. Please try again."
msgstr ""
msgid "Sort by"
msgstr ""
......@@ -2343,10 +2634,10 @@ msgstr ""
msgid "Stopped"
msgstr ""
msgid "Subgroups"
msgid "Storage"
msgstr ""
msgid "Subscribe"
msgid "Subgroups"
msgstr ""
msgid "Switch branch/tag"
......@@ -2444,7 +2735,10 @@ msgstr ""
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
msgstr ""
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
msgstr ""
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
msgstr ""
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
......@@ -2459,10 +2753,10 @@ msgstr ""
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The number of attempts GitLab will make to access a storage."
msgid "The maximum file size allowed is 200KB."
msgstr ""
msgid "The number of failures after which GitLab will start temporarily disabling access to a storage shard on a host"
msgid "The number of attempts GitLab will make to access a storage."
msgstr ""
msgid "The number of failures of after which GitLab will completely prevent access to the storage. The number of failures can be reset in the admin interface: %{link_to_health_page} or using the %{api_documentation_link}."
......@@ -2471,9 +2765,6 @@ msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
msgstr ""
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
......@@ -2504,19 +2795,37 @@ msgstr ""
msgid "The time in seconds GitLab will try to access storage. After this time a timeout error will be raised."
msgstr ""
msgid "The time in seconds between storage checks. When a previous check did complete yet, GitLab will skip a check."
msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
msgid "There are no issues to show"
msgstr ""
msgid "There are no merge requests to show"
msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
msgid "There was an error when reseting email token."
msgstr ""
msgid "There was an error when subscribing to this label."
msgstr ""
msgid "There was an error when unsubscribing from this label."
msgstr ""
msgid "This board\\'s scope is reduced"
msgstr ""
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgid "This directory"
msgstr ""
msgid "This is a confidential issue."
......@@ -2531,12 +2840,36 @@ msgstr ""
msgid "This issue is locked."
msgstr ""
msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments"
msgstr ""
msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
msgstr ""
msgid "This job has not been triggered yet"
msgstr ""
msgid "This job has not started yet"
msgstr ""
msgid "This job is in pending state and is waiting to be picked by a runner"
msgstr ""
msgid "This job requires a manual action"
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr ""
msgid "This merge request is locked."
msgstr ""
msgid "This project"
msgstr ""
msgid "This repository"
msgstr ""
msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
msgstr ""
......@@ -2691,6 +3024,12 @@ msgstr ""
msgid "Title"
msgstr ""
msgid "ToggleButton|Toggle Status: OFF"
msgstr ""
msgid "ToggleButton|Toggle Status: ON"
msgstr ""
msgid "Total Time"
msgstr ""
......@@ -2706,9 +3045,18 @@ msgstr ""
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Trigger this manual action"
msgstr ""
msgid "Turn on Service Desk"
msgstr ""
msgid "Unable to reset project cache."
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Unlock"
msgstr ""
......@@ -2718,7 +3066,7 @@ msgstr ""
msgid "Unstar"
msgstr ""
msgid "Unsubscribe"
msgid "Up to date"
msgstr ""
msgid "Upgrade your plan to activate Advanced Global Search."
......@@ -2742,6 +3090,9 @@ msgstr ""
msgid "Upload file"
msgstr ""
msgid "Upload new avatar"
msgstr ""
msgid "UploadLink|click to upload"
msgstr ""
......@@ -2778,6 +3129,9 @@ msgstr ""
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
......@@ -2790,9 +3144,6 @@ msgstr ""
msgid "Weight"
msgstr ""
msgid "When access to a storage fails. GitLab will prevent access to the storage for the time specified here. This allows the filesystem to recover. Repositories on failing shards are temporarly unavailable"
msgstr ""
msgid "Wiki"
msgstr ""
......@@ -2913,9 +3264,15 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You can also star a label to make it a priority label."
msgstr ""
msgid "You can only add files when you are on a branch"
msgstr ""
msgid "You can only edit files when you are on a branch"
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
msgstr ""
......@@ -2955,6 +3312,9 @@ msgstr ""
msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
msgstr ""
msgid "You'll need to use different branch names to get a valid comparison."
msgstr ""
msgid "Your comment will not be visible to the public."
msgstr ""
......@@ -2973,6 +3333,30 @@ msgstr ""
msgid "by"
msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
msgid "ciReport|Failed to load ${type} report"
msgstr ""
msgid "ciReport|Fixed:"
msgstr ""
msgid "ciReport|Instances"
msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
msgid "ciReport|Loading ${type} report"
msgstr ""
msgid "ciReport|SAST:container no vulnerabilities were found"
msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
msgid "commit"
msgstr ""
......@@ -2981,12 +3365,113 @@ msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
msgid "mrWidget|Cancel automatic merge"
msgstr ""
msgid "mrWidget|Checking ability to merge automatically"
msgstr ""
msgid "mrWidget|Cherry-pick"
msgstr ""
msgid "mrWidget|Cherry-pick this merge request in a new merge request"
msgstr ""
msgid "mrWidget|Closed by"
msgstr ""
msgid "mrWidget|Merge"
msgstr ""
msgid "mrWidget|Merge failed."
msgstr ""
msgid "mrWidget|Merge locally"
msgstr ""
msgid "mrWidget|Merged by"
msgstr ""
msgid "mrWidget|Refresh"
msgstr ""
msgid "mrWidget|Refresh now"
msgstr ""
msgid "mrWidget|Refreshing now"
msgstr ""
msgid "mrWidget|Remove Source Branch"
msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
msgid "mrWidget|Resolve conflicts"
msgstr ""
msgid "mrWidget|Revert"
msgstr ""
msgid "mrWidget|Revert this merge request in a new merge request"
msgstr ""
msgid "mrWidget|Set by"
msgstr ""
msgid "mrWidget|The changes were merged into"
msgstr ""
msgid "mrWidget|The changes were not merged into"
msgstr ""
msgid "mrWidget|The changes will be merged into"
msgstr ""
msgid "mrWidget|The source branch has been removed"
msgstr ""
msgid "mrWidget|The source branch is being removed"
msgstr ""
msgid "mrWidget|The source branch will be removed"
msgstr ""
msgid "mrWidget|The source branch will not be removed"
msgstr ""
msgid "mrWidget|There are merge conflicts"
msgstr ""
msgid "mrWidget|This merge request failed to be merged automatically"
msgstr ""
msgid "mrWidget|This merge request is in the process of being merged"
msgstr ""
msgid "mrWidget|This project is archived, write access has been disabled"
msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
msgid "mrWidget|to be merged automatically when the pipeline succeeds"
msgstr ""
msgid "new merge request"
msgstr ""
msgid "notification emails"
msgstr ""
msgid "or"
msgstr ""
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
......
require 'spec_helper'
describe Admin::GitalyServersController do
describe '#index' do
before do
sign_in(create(:admin))
end
it 'shows the gitaly servers page' do
get :index
expect(response).to have_gitlab_http_status(200)
end
end
end
......@@ -76,6 +76,39 @@ describe Groups::EpicsController do
expect(response).to have_gitlab_http_status(200)
end
end
context 'when format is JSON' do
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
end
def list_epics
get :index, group_id: group, format: :json
end
it 'returns a list of epics' do
list_epics
expect(json_response).to be_an Array
end
it 'does not use pagination' do
list_epics
expect(json_response.size).to eq(2)
end
it 'returns correct epic attributes' do
list_epics
item = json_response.first
epic = Epic.find(item['id'])
expect(item['group_id']).to eq(group.id)
expect(item['start_date']).to eq(epic.start_date)
expect(item['end_date']).to eq(epic.end_date)
expect(item['web_url']).to eq(group_epic_path(group, epic))
end
end
end
describe 'GET #show' do
......
require 'spec_helper'
describe API::Jobs do
set(:project) do
create(:project, :repository, public_builds: false)
end
set(:pipeline) do
create(:ci_empty_pipeline, project: project,
sha: project.commit.id,
ref: project.default_branch)
end
let!(:job) { create(:ci_build, :success, pipeline: pipeline) }
let(:user) { create(:user) }
let(:api_user) { user }
let(:reporter) { create(:project_member, :reporter, project: project).user }
let(:cross_project_pipeline_enabled) { true }
let(:object_storage_enabled) { true }
before do
stub_licensed_features(cross_project_pipelines: cross_project_pipeline_enabled,
object_storage: object_storage_enabled)
project.add_developer(user)
end
describe 'GET /projects/:id/jobs/:job_id/artifacts' do
shared_examples 'downloads artifact' do
let(:download_headers) do
{ 'Content-Transfer-Encoding' => 'binary',
'Content-Disposition' => 'attachment; filename=ci_build_artifacts.zip' }
end
it 'returns specific job artifacts' do
expect(response).to have_gitlab_http_status(200)
expect(response.headers).to include(download_headers)
expect(response.body).to match_file(job.artifacts_file.file.file)
end
end
context 'normal authentication' do
before do
stub_artifacts_object_storage
end
context 'when job with artifacts are stored remotely' do
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: job) }
before do
job.reload
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
end
context 'authorized by job_token' do
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
before do
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts"), job_token: job.token
end
context 'user is developer' do
let(:api_user) { user }
it_behaves_like 'downloads artifact'
end
context 'when anonymous user is accessing private artifacts' do
let(:api_user) { nil }
it 'hides artifacts and rejects request' do
expect(project).to be_private
expect(response).to have_gitlab_http_status(404)
end
end
context 'feature is disabled for EES' do
let(:api_user) { user }
let(:cross_project_pipeline_enabled) { false }
it 'disallows access to the artifacts' do
expect(response).to have_gitlab_http_status(404)
end
end
end
end
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
let(:api_user) { reporter }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
before do
stub_artifacts_object_storage(licensed: :skip)
job.success
end
def get_for_ref(ref = pipeline.ref, job_name = job.name)
get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job_name
end
context 'find proper job' do
shared_examples 'a valid file' do
context 'when artifacts are stored remotely' do
let(:job) { create(:ci_build, pipeline: pipeline, user: api_user) }
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: job) }
before do
job.reload
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
end
context 'with regular branch' do
before do
pipeline.reload
pipeline.update(ref: 'master',
sha: project.commit('master').sha)
get_for_ref('master')
end
it_behaves_like 'a valid file'
end
context 'with branch name containing slash' do
before do
pipeline.reload
pipeline.update(ref: 'improve/awesome',
sha: project.commit('improve/awesome').sha)
get_for_ref('improve/awesome')
end
it_behaves_like 'a valid file'
end
context 'when using job_token to authenticate' do
before do
pipeline.reload
pipeline.update(ref: 'master',
sha: project.commit('master').sha)
get api("/projects/#{project.id}/jobs/artifacts/master/download"), job: job.name, job_token: job.token
end
context 'when user is reporter' do
it_behaves_like 'a valid file'
end
context 'when user is admin, but not member' do
let(:api_user) { create(:admin) }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
it 'does not allow to see that artfiact is present' do
expect(response).to have_gitlab_http_status(404)
end
end
end
end
end
end
require 'spec_helper'
describe API::V3::Builds do
set(:user) { create(:user) }
let(:api_user) { user }
set(:project) { create(:project, :repository, creator: user, public_builds: false) }
let!(:developer) { create(:project_member, :developer, user: user, project: project) }
let(:reporter) { create(:project_member, :reporter, project: project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
let(:build) { create(:ci_build, pipeline: pipeline) }
before do
stub_artifacts_object_storage
end
describe 'GET /projects/:id/builds/:build_id/artifacts' do
before do
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
end
context 'when job with artifacts are stored remotely' do
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: build) }
it 'returns location redirect' do
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
expect(response).to have_gitlab_http_status(302)
end
end
end
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
let(:api_user) { reporter.user }
before do
build.success
end
def path_for_ref(ref = pipeline.ref, job = build.name)
v3_api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
end
shared_examples 'a valid file' do
context 'when artifacts are stored remotely' do
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: build) }
before do
build.reload
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
end
context 'with regular branch' do
before do
pipeline.reload
pipeline.update(ref: 'master',
sha: project.commit('master').sha)
get path_for_ref('master')
end
it_behaves_like 'a valid file'
end
context 'with branch name containing slash' do
before do
pipeline.reload
pipeline.update(ref: 'improve/awesome',
sha: project.commit('improve/awesome').sha)
get path_for_ref('improve/awesome')
end
it_behaves_like 'a valid file'
end
end
end
......@@ -122,7 +122,7 @@ feature 'Project > Members > Share with Group', :js do
select2 group.id, from: '#link_group_id'
fill_in 'expires_at_groups', with: (Time.now + 4.5.days).strftime('%Y-%m-%d')
page.find('body').click
click_on 'share-with-group-tab'
find('.btn-create').click
end
......
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Api from '~/api';
describe('Api', () => {
......@@ -7,20 +9,17 @@ describe('Api', () => {
api_version: dummyApiVersion,
relative_url_root: dummyUrlRoot,
};
const dummyResponse = 'hello from outer space!';
const sendDummyResponse = () => {
const deferred = $.Deferred();
deferred.resolve(dummyResponse);
return deferred.promise();
};
let originalGon;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
originalGon = window.gon;
window.gon = Object.assign({}, dummyGon);
});
afterEach(() => {
mock.restore();
window.gon = originalGon;
});
......@@ -38,15 +37,13 @@ describe('Api', () => {
describe('group', () => {
it('fetches a group', (done) => {
const groupId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}.json`;
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
return sendDummyResponse();
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}`;
mock.onGet(expectedUrl).reply(200, {
name: 'test',
});
Api.group(groupId, (response) => {
expect(response).toBe(dummyResponse);
expect(response.name).toBe('test');
done();
});
});
......@@ -57,19 +54,13 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups.json`;
const expectedData = Object.assign({
search: query,
per_page: 20,
}, options);
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.groups(query, options, (response) => {
expect(response).toBe(dummyResponse);
expect(response.length).toBe(1);
expect(response[0].name).toBe('test');
done();
});
});
......@@ -79,19 +70,13 @@ describe('Api', () => {
it('fetches namespaces', (done) => {
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/namespaces.json`;
const expectedData = {
search: query,
per_page: 20,
};
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.namespaces(query, (response) => {
expect(response).toBe(dummyResponse);
expect(response.length).toBe(1);
expect(response[0].name).toBe('test');
done();
});
});
......@@ -103,21 +88,13 @@ describe('Api', () => {
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
window.gon.current_user_id = 1;
const expectedData = Object.assign({
search: query,
per_page: 20,
membership: true,
simple: true,
}, options);
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.projects(query, options, (response) => {
expect(response).toBe(dummyResponse);
expect(response.length).toBe(1);
expect(response[0].name).toBe('test');
done();
});
});
......@@ -126,20 +103,13 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
const expectedData = Object.assign({
search: query,
per_page: 20,
simple: true,
}, options);
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.projects(query, options, (response) => {
expect(response).toBe(dummyResponse);
expect(response.length).toBe(1);
expect(response[0].name).toBe('test');
done();
});
});
......@@ -154,16 +124,16 @@ describe('Api', () => {
const expectedData = {
label: labelData,
};
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.type).toEqual('POST');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
mock.onPost(expectedUrl).reply((config) => {
expect(config.data).toBe(JSON.stringify(expectedData));
return [200, {
name: 'test',
}];
});
Api.newLabel(namespace, project, labelData, (response) => {
expect(response).toBe(dummyResponse);
expect(response.name).toBe('test');
done();
});
});
......@@ -175,16 +145,16 @@ describe('Api', () => {
const expectedData = {
label: labelData,
};
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.type).toEqual('POST');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
mock.onPost(expectedUrl).reply((config) => {
expect(config.data).toBe(JSON.stringify(expectedData));
return [200, {
name: 'test',
}];
});
Api.newLabel(namespace, null, labelData, (response) => {
expect(response).toBe(dummyResponse);
expect(response.name).toBe('test');
done();
});
});
......@@ -195,19 +165,13 @@ describe('Api', () => {
const groupId = '123456';
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/projects.json`;
const expectedData = {
search: query,
per_page: 20,
};
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.groupProjects(groupId, query, (response) => {
expect(response).toBe(dummyResponse);
expect(response.length).toBe(1);
expect(response[0].name).toBe('test');
done();
});
});
......@@ -218,14 +182,10 @@ describe('Api', () => {
const licenseKey = "driver's license";
const data = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/licenses/${licenseKey}`;
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.data).toEqual(data);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, 'test');
Api.licenseText(licenseKey, data, (response) => {
expect(response).toBe(dummyResponse);
expect(response).toBe('test');
done();
});
});
......@@ -235,13 +195,10 @@ describe('Api', () => {
it('fetches a gitignore text', (done) => {
const gitignoreKey = 'ignore git';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/gitignores/${gitignoreKey}`;
spyOn(jQuery, 'get').and.callFake((url, callback) => {
expect(url).toEqual(expectedUrl);
callback(dummyResponse);
});
mock.onGet(expectedUrl).reply(200, 'test');
Api.gitignoreText(gitignoreKey, (response) => {
expect(response).toBe(dummyResponse);
expect(response).toBe('test');
done();
});
});
......@@ -251,13 +208,10 @@ describe('Api', () => {
it('fetches a .gitlab-ci.yml', (done) => {
const gitlabCiYmlKey = 'Y CI ML';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/gitlab_ci_ymls/${gitlabCiYmlKey}`;
spyOn(jQuery, 'get').and.callFake((url, callback) => {
expect(url).toEqual(expectedUrl);
callback(dummyResponse);
});
mock.onGet(expectedUrl).reply(200, 'test');
Api.gitlabCiYml(gitlabCiYmlKey, (response) => {
expect(response).toBe(dummyResponse);
expect(response).toBe('test');
done();
});
});
......@@ -267,13 +221,10 @@ describe('Api', () => {
it('fetches a Dockerfile', (done) => {
const dockerfileYmlKey = 'a giant whale';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/templates/dockerfiles/${dockerfileYmlKey}`;
spyOn(jQuery, 'get').and.callFake((url, callback) => {
expect(url).toEqual(expectedUrl);
callback(dummyResponse);
});
mock.onGet(expectedUrl).reply(200, 'test');
Api.dockerfileYml(dockerfileYmlKey, (response) => {
expect(response).toBe(dummyResponse);
expect(response).toBe('test');
done();
});
});
......@@ -286,14 +237,10 @@ describe('Api', () => {
const templateKey = ' template #%?.key ';
const templateType = 'template type';
const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${encodeURIComponent(templateKey)}`;
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, 'test');
Api.issueTemplate(namespace, project, templateKey, templateType, (error, response) => {
expect(error).toBe(null);
expect(response).toBe(dummyResponse);
expect(response).toBe('test');
done();
});
});
......@@ -304,20 +251,14 @@ describe('Api', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users.json`;
const expectedData = Object.assign({
search: query,
per_page: 20,
}, options);
spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl);
expect(request.dataType).toEqual('json');
expect(request.data).toEqual(expectedData);
return sendDummyResponse();
});
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.users(query, options)
.then((response) => {
expect(response).toBe(dummyResponse);
.then(({ data }) => {
expect(data.length).toBe(1);
expect(data[0].name).toBe('test');
})
.then(done)
.catch(done.fail);
......@@ -329,8 +270,11 @@ describe('Api', () => {
const query = 'query';
const provider = 'provider';
const callback = jasmine.createSpy();
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/ldap/${provider}/groups.json`;
spyOn(jQuery, 'ajax').and.callFake(() => $.Deferred().resolve());
mock.onGet(expectedUrl).reply(200, [{
name: 'test',
}]);
Api.ldap_groups(query, provider, callback)
.then((response) => {
......
/* eslint-disable no-new */
import MockAdapter from 'axios-mock-adapter';
import BlobViewer from '~/blob/viewer/index';
import axios from '~/lib/utils/axios_utils';
describe('Blob viewer', () => {
let blob;
let mock;
preloadFixtures('snippets/show.html.raw');
beforeEach(() => {
mock = new MockAdapter(axios);
loadFixtures('snippets/show.html.raw');
$('#modal-upload-blob').remove();
blob = new BlobViewer();
spyOn($, 'ajax').and.callFake(() => {
const d = $.Deferred();
d.resolve({
mock.onGet('http://test.host/snippets/1.json?viewer=rich').reply(200, {
html: '<div>testing</div>',
});
return d.promise();
mock.onGet('http://test.host/snippets/1.json?viewer=simple').reply(200, {
html: '<div>testing</div>',
});
spyOn(axios, 'get').and.callThrough();
});
afterEach(() => {
mock.restore();
location.hash = '';
});
......@@ -30,7 +37,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
expect($.ajax).toHaveBeenCalled();
expect(
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]')
.classList.contains('hidden'),
......@@ -46,7 +52,6 @@ describe('Blob viewer', () => {
new BlobViewer();
setTimeout(() => {
expect($.ajax).toHaveBeenCalled();
expect(
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]')
.classList.contains('hidden'),
......@@ -64,12 +69,8 @@ describe('Blob viewer', () => {
});
asyncClick()
.then(() => asyncClick())
.then(() => {
expect($.ajax).toHaveBeenCalled();
return asyncClick();
})
.then(() => {
expect($.ajax.calls.count()).toBe(1);
expect(
document.querySelector('.blob-viewer[data-type="simple"]').getAttribute('data-loaded'),
).toBe('true');
......@@ -122,7 +123,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
expect($.ajax).toHaveBeenCalled();
expect(
copyButton.classList.contains('disabled'),
).toBeFalsy();
......@@ -135,8 +135,6 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => {
expect($.ajax).toHaveBeenCalled();
expect(
copyButton.getAttribute('data-original-title'),
).toBe('Copy source to clipboard');
......@@ -171,14 +169,14 @@ describe('Blob viewer', () => {
it('sends AJAX request when switching to simple view', () => {
blob.switchToViewer('simple');
expect($.ajax).toHaveBeenCalled();
expect(axios.get).toHaveBeenCalled();
});
it('does not send AJAX request when switching to rich view', () => {
blob.switchToViewer('simple');
blob.switchToViewer('rich');
expect($.ajax.calls.count()).toBe(1);
expect(axios.get.calls.count()).toBe(1);
});
});
});
import 'vendor/jquery.endless-scroll';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import CommitsList from '~/commits';
describe('Commits List', () => {
......@@ -43,30 +45,47 @@ describe('Commits List', () => {
describe('on entering input', () => {
let ajaxSpy;
let mock;
beforeEach(() => {
CommitsList.init(25);
CommitsList.searchField.val('');
spyOn(history, 'replaceState').and.stub();
ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
req.success({
data: '<li>Result</li>',
mock = new MockAdapter(axios);
mock.onGet('/h5bp/html5-boilerplate/commits/master').reply(200, {
html: '<li>Result</li>',
});
ajaxSpy = spyOn(axios, 'get').and.callThrough();
});
afterEach(() => {
mock.restore();
});
it('should save the last search string', () => {
it('should save the last search string', (done) => {
CommitsList.searchField.val('GitLab');
CommitsList.filterResults();
CommitsList.filterResults()
.then(() => {
expect(ajaxSpy).toHaveBeenCalled();
expect(CommitsList.lastSearch).toEqual('GitLab');
done();
})
.catch(done.fail);
});
it('should not make ajax call if the input does not change', () => {
CommitsList.filterResults();
it('should not make ajax call if the input does not change', (done) => {
CommitsList.filterResults()
.then(() => {
expect(ajaxSpy).not.toHaveBeenCalled();
expect(CommitsList.lastSearch).toEqual('');
done();
})
.catch(done.fail);
});
});
});
......@@ -92,7 +92,9 @@ describe('UsersCache', () => {
apiSpy = (query, options) => {
expect(query).toBe('');
expect(options).toEqual({ username: dummyUsername });
return Promise.resolve([dummyUser]);
return Promise.resolve({
data: [dummyUser],
});
};
UsersCache.retrieve(dummyUsername)
......
......@@ -18,9 +18,11 @@ describe('new file modal component', () => {
}));
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
data: {
commit: {
id: '123branch',
},
},
}));
spyOn(service, 'getTreeData').and.returnValue(Promise.resolve({
......
......@@ -17,9 +17,11 @@ describe('new dropdown upload', () => {
}));
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
data: {
commit: {
id: '123branch',
},
},
}));
spyOn(service, 'getTreeData').and.returnValue(Promise.resolve({
......
......@@ -106,8 +106,10 @@ describe('RepoCommitSection', () => {
changedFiles = JSON.parse(JSON.stringify(vm.$store.getters.changedFiles));
spyOn(service, 'commit').and.returnValue(Promise.resolve({
data: {
short_id: '1',
stats: {},
},
}));
});
......
......@@ -178,7 +178,9 @@ describe('Multi-file store actions', () => {
it('calls service', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
data: {
commit: { id: '123' },
},
}));
store.dispatch('checkCommitStatus')
......@@ -192,7 +194,9 @@ describe('Multi-file store actions', () => {
it('returns true if current ref does not equal returned ID', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
data: {
commit: { id: '123' },
},
}));
store.dispatch('checkCommitStatus')
......@@ -206,7 +210,9 @@ describe('Multi-file store actions', () => {
it('returns false if current ref equals returned ID', (done) => {
spyOn(service, 'getBranchData').and.returnValue(Promise.resolve({
data: {
commit: { id: '1' },
},
}));
store.dispatch('checkCommitStatus')
......@@ -250,6 +256,7 @@ describe('Multi-file store actions', () => {
describe('success', () => {
beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({
data: {
id: '123456',
short_id: '123',
message: 'test message',
......@@ -258,6 +265,7 @@ describe('Multi-file store actions', () => {
additions: '1',
deletions: '2',
},
},
}));
});
......@@ -321,7 +329,9 @@ describe('Multi-file store actions', () => {
describe('failed', () => {
beforeEach(() => {
spyOn(service, 'commit').and.returnValue(Promise.resolve({
data: {
message: 'failed message',
},
}));
});
......
require 'spec_helper'
describe Gitaly::Server do
describe '.all' do
let(:storages) { Gitlab.config.repositories.storages }
it 'includes all storages' do
expect(storages.count).to eq(described_class.all.count)
expect(storages.keys).to eq(described_class.all.map(&:storage))
end
end
subject { described_class.all.first }
it { is_expected.to respond_to(:server_version) }
it { is_expected.to respond_to(:git_binary_version) }
it { is_expected.to respond_to(:up_to_date?) }
it { is_expected.to respond_to(:address) }
describe 'request memoization' do
context 'when requesting multiple properties', :request_store do
it 'uses memoization for the info request' do
expect do
subject.server_version
subject.up_to_date?
end.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end
end
end
......@@ -17,12 +17,8 @@ describe API::Jobs do
let(:api_user) { user }
let(:reporter) { create(:project_member, :reporter, project: project).user }
let(:guest) { create(:project_member, :guest, project: project).user }
let(:cross_project_pipeline_enabled) { true }
let(:object_storage_enabled) { true }
before do
stub_licensed_features(cross_project_pipelines: cross_project_pipeline_enabled,
object_storage: object_storage_enabled)
project.add_developer(user)
end
......@@ -30,8 +26,6 @@ describe API::Jobs do
let(:query) { Hash.new }
before do |example|
job
unless example.metadata[:skip_before_request]
get api("/projects/#{project.id}/jobs", api_user), query
end
......@@ -118,7 +112,6 @@ describe API::Jobs do
let(:query) { Hash.new }
before do
job
get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query
end
......@@ -321,10 +314,6 @@ describe API::Jobs do
end
context 'normal authentication' do
before do
stub_artifacts_object_storage
end
context 'job with artifacts' do
context 'when artifacts are stored locally' do
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
......@@ -346,21 +335,6 @@ describe API::Jobs do
end
end
context 'when artifacts are stored remotely' do
let(:job) { create(:ci_build, pipeline: pipeline) }
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: job) }
before do
job.reload
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
it 'does not return job artifacts if not uploaded' do
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
......@@ -368,38 +342,6 @@ describe API::Jobs do
end
end
end
context 'authorized by job_token' do
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
before do
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts"), job_token: job.token
end
context 'user is developer' do
let(:api_user) { user }
it_behaves_like 'downloads artifact'
end
context 'when anonymous user is accessing private artifacts' do
let(:api_user) { nil }
it 'hides artifacts and rejects request' do
expect(project).to be_private
expect(response).to have_gitlab_http_status(404)
end
end
context 'feature is disabled for EES' do
let(:api_user) { user }
let(:cross_project_pipeline_enabled) { false }
it 'disallows access to the artifacts' do
expect(response).to have_gitlab_http_status(404)
end
end
end
end
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
......@@ -407,7 +349,6 @@ describe API::Jobs do
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
before do
stub_artifacts_object_storage(licensed: :skip)
job.success
end
......@@ -474,21 +415,6 @@ describe API::Jobs do
it { expect(response).to have_gitlab_http_status(200) }
it { expect(response.headers).to include(download_headers) }
end
context 'when artifacts are stored remotely' do
let(:job) { create(:ci_build, pipeline: pipeline, user: api_user) }
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: job) }
before do
job.reload
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
end
context 'with regular branch' do
......@@ -516,29 +442,6 @@ describe API::Jobs do
it_behaves_like 'a valid file'
end
context 'when using job_token to authenticate' do
before do
pipeline.reload
pipeline.update(ref: 'master',
sha: project.commit('master').sha)
get api("/projects/#{project.id}/jobs/artifacts/master/download"), job: job.name, job_token: job.token
end
context 'when user is reporter' do
it_behaves_like 'a valid file'
end
context 'when user is admin, but not member' do
let(:api_user) { create(:admin) }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user) }
it 'does not allow to see that artfiact is present' do
expect(response).to have_gitlab_http_status(404)
end
end
end
end
end
......
......@@ -216,7 +216,6 @@ describe API::V3::Builds do
describe 'GET /projects/:id/builds/:build_id/artifacts' do
before do
stub_artifacts_object_storage
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
end
......@@ -238,17 +237,6 @@ describe API::V3::Builds do
end
end
context 'when artifacts are stored remotely' do
let(:build) { create(:ci_build, pipeline: pipeline) }
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: build) }
it 'returns location redirect' do
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
expect(response).to have_gitlab_http_status(302)
end
end
context 'unauthorized user' do
let(:api_user) { nil }
......@@ -268,7 +256,6 @@ describe API::V3::Builds do
let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
before do
stub_artifacts_object_storage
build.success
end
......@@ -334,21 +321,6 @@ describe API::V3::Builds do
it { expect(response).to have_gitlab_http_status(200) }
it { expect(response.headers).to include(download_headers) }
end
context 'when artifacts are stored remotely' do
let(:build) { create(:ci_build, pipeline: pipeline) }
let!(:artifact) { create(:ci_job_artifact, :archive, :remote_store, job: build) }
before do
build.reload
get v3_api("/projects/#{project.id}/builds/#{build.id}/artifacts", api_user)
end
it 'returns location redirect' do
expect(response).to have_gitlab_http_status(302)
end
end
end
context 'with regular branch' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment