Commit b6c4889b authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-01-09

# Conflicts:
#	app/views/admin/application_settings/_form.html.haml
#	db/migrate/20160301174731_add_fingerprint_index.rb
#	db/schema.rb
#	doc/administration/operations/fast_ssh_key_lookup.md
#	doc/administration/operations/index.md

[ci skip]
parents e72ee845 65b04860
......@@ -105,9 +105,13 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight] is a great place to start. Issues with a lower weight (1 or 2) are deemed suitable for beginners.
These issues will be of reasonable size and challenge, for anyone to start
contributing to GitLab.
If you want to contribute to GitLab [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight]
is a great place to start. Issues with a lower weight (1 or 2) are deemed
suitable for beginners. These issues will be of reasonable size and challenge,
for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to
learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel
please consider we favor
[asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication. Thanks for your contribution!
## Workflow labels
......
......@@ -73,6 +73,10 @@ gem 'net-ldap'
# Git Wiki
# Required manually in config/initializers/gollum.rb to control load order
gem 'gollum-lib', '~> 4.2', require: false
# Before updating this gem, check if
# https://github.com/gollum/rugged_adapter/pull/28 has been merged.
# If it has, then remove the monkey patch for tree_entry in config/initializers/gollum.rb
gem 'gollum-rugged_adapter', '~> 0.4.4', require: false
# Language detection
......@@ -81,7 +85,7 @@ gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
gem 'grape', '~> 1.0'
gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
# Disable strong_params so that Mash does not respond to :permitted?
gem 'hashie-forbidden_attributes'
......
......@@ -680,7 +680,7 @@ GEM
rack (>= 0.4)
rack-attack (4.4.1)
rack
rack-cors (0.4.0)
rack-cors (1.0.2)
rack-oauth2 (1.2.3)
activesupport (>= 2.3)
attr_required (>= 0.0.5)
......@@ -1171,7 +1171,7 @@ DEPENDENCIES
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0)
rack-cors (~> 1.0.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
rails (= 4.2.10)
......@@ -1251,4 +1251,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.16.0
1.16.1
......@@ -7,6 +7,7 @@ import installGlEmojiElement from './gl_emoji';
import './quick_submit';
import './requires_input';
import './toggler_behavior';
import '../preview_markdown';
installGlEmojiElement();
initCopyAsGFM();
......
......@@ -197,7 +197,7 @@ export default {
<li
class="board-list-count text-center"
v-if="showCount"
data-id="-1">
data-issue-id="-1">
<loading-icon
v-show="list.loadingMore"
......
......@@ -57,7 +57,6 @@ import GfmAutoComplete from './gfm_auto_complete';
import ShortcutsBlob from './shortcuts_blob';
import SigninTabsMemoizer from './signin_tabs_memoizer';
import Star from './star';
import Todos from './todos';
import TreeView from './tree';
import UsagePing from './usage_ping';
import UsernameValidator from './username_validator';
......@@ -123,6 +122,7 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
}
const fail = () => Flash('Error loading dynamic module');
const callDefault = m => m.default();
path = page.split(':');
shortcut_handler = null;
......@@ -240,7 +240,7 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
projectSelect();
break;
case 'dashboard:todos:index':
new Todos();
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
break;
case 'dashboard:projects:index':
case 'dashboard:projects:starred':
......@@ -607,7 +607,7 @@ import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line
new CILintEditor();
break;
case 'users:show':
import('./pages/users/show').then(m => m.default()).catch(fail);
import('./pages/users/show').then(callDefault).catch(fail);
break;
case 'admin:conversational_development_index:show':
new UserCallout();
......
......@@ -46,7 +46,6 @@ import LazyLoader from './lazy_loader';
import './line_highlighter';
import initLogoAnimation from './logo';
import './milestone_select';
import './preview_markdown';
import './projects_dropdown';
import './render_gfm';
import initBreadcrumbs from './breadcrumb';
......
import Todos from './todos';
export default () => new Todos();
/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
import { visitUrl } from './lib/utils/url_utility';
import UsersSelect from './users_select';
import { isMetaClick } from './lib/utils/common_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import UsersSelect from '~/users_select';
import { isMetaClick } from '~/lib/utils/common_utils';
export default class Todos {
constructor() {
......
......@@ -6,16 +6,16 @@ document.addEventListener('DOMContentLoaded', () => {
const data = {
labels: chartScope.labels,
datasets: [{
fillColor: '#7f8fa4',
strokeColor: '#7f8fa4',
pointColor: '#7f8fa4',
fillColor: '#707070',
strokeColor: '#707070',
pointColor: '#707070',
pointStrokeColor: '#EEE',
data: chartScope.totalValues,
},
{
fillColor: '#44aa22',
strokeColor: '#44aa22',
pointColor: '#44aa22',
fillColor: '#1aaa55',
strokeColor: '#1aaa55',
pointColor: '#1aaa55',
pointStrokeColor: '#fff',
data: chartScope.successValues,
},
......
This diff is collapsed.
......@@ -28,7 +28,9 @@
.dropdown-menu,
.dropdown-menu-nav {
@include set-visible;
min-height: 40px;
min-height: $dropdown-min-height;
max-height: $dropdown-max-height;
overflow: auto;
@media (max-width: $screen-xs-max) {
width: 100%;
......
......@@ -260,7 +260,7 @@
}
.filtered-search-input-dropdown-menu {
max-height: 260px;
max-height: $dropdown-max-height;
max-width: 280px;
overflow: auto;
......
......@@ -106,10 +106,6 @@ body {
}
}
.layout-page > .content-wrapper {
min-height: calc(100vh - #{$header-height});
}
.with-performance-bar .layout-page {
margin-top: $header-height + $performance-bar-height;
}
......
......@@ -341,7 +341,8 @@ $regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-San
* Dropdowns
*/
$dropdown-width: 300px;
$dropdown-max-height: 215px;
$dropdown-min-height: 40px;
$dropdown-max-height: 312px;
$dropdown-vertical-offset: 4px;
$dropdown-link-color: #555;
$dropdown-link-hover-bg: $row-hover;
......
......@@ -651,15 +651,13 @@
min-width: 0;
}
.diff-changed-file-name,
.diff-changed-file-path {
.diff-changed-file-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.diff-changed-file-path {
direction: rtl;
color: $gl-text-color-tertiary;
}
......
......@@ -75,7 +75,7 @@
}
.dropdown-menu {
max-height: 250px;
max-height: $dropdown-max-height;
overflow-y: auto;
}
......@@ -1222,3 +1222,11 @@ a.linked-pipeline-mini-item {
font-weight: $gl-font-weight-normal;
line-height: 1.5;
}
.legend-all {
color: $gl-text-color-secondary;
}
.legend-success {
color: $green-500;
}
......@@ -330,13 +330,6 @@
}
}
.project-repo-buttons {
.project-action-button .dropdown-menu {
max-height: 250px;
overflow-y: auto;
}
}
.split-one {
display: inline-table;
margin-right: 12px;
......
......@@ -226,4 +226,12 @@ module DiffHelper
diffs.overflow?
end
def diff_file_path_text(diff_file, max: 60)
path = diff_file.new_path
return path unless path.size > max && max > 3
"...#{path[-(max - 3)..-1]}"
end
end
......@@ -27,7 +27,7 @@ class PagesDomain < ActiveRecord::Base
def url
return unless domain
if certificate
if certificate.present?
"https://#{domain}"
else
"http://#{domain}"
......
......@@ -828,6 +828,7 @@
if you have configured your OpenSSH server to use the
AuthorizedKeysCommand. Click on the help icon for more details.
= link_to icon('question-circle'), help_page_path('administration/operations/fast_ssh_key_lookup')
<<<<<<< HEAD
- if Gitlab.com? || Rails.env.development?
%fieldset
%legend Slack application
......@@ -864,6 +865,8 @@
.help-block
The amount of seconds after which a request to get a secondary node
status will time out.
=======
>>>>>>> upstream/master
%fieldset
%legend User and IP Rate Limits
......
.top-area
.nav-block
%ul.nav-links
= nav_link(html_options: { class: ("active" unless params[:personal].present?) }) do
= link_to s_('DashboardProjects|All'), dashboard_projects_path
......
!!! 5
%html.devise-layout-html
= render "layouts/head"
%body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } }
%body.ui_indigo.login-page.application.navless{ data: { page: body_data_page } }
.page-wrap
= render "layouts/header/empty"
.login-page-broadcast
......
!!! 5
%html{ lang: "en" }
= render "layouts/head"
%body.ui_charcoal.login-page.application.navless
%body.ui_indigo.login-page.application.navless
= render "layouts/header/empty"
= render "layouts/broadcast"
.container.navless-container
......
......@@ -25,7 +25,7 @@
= sprite_icon(diff_file_changed_icon(diff_file), size: 16, css_class: "#{diff_file_changed_icon_color(diff_file)} diff-file-changed-icon append-right-8")
%span.diff-changed-file-content.append-right-8
%strong.diff-changed-file-name= diff_file.blob.name
%span.diff-changed-file-path.prepend-top-5= diff_file.new_path
%span.diff-changed-file-path.prepend-top-5= diff_file_path_text(diff_file)
%span.diff-changed-stats
%span.cgreen<
+#{diff_file.added_lines}
......
......@@ -4,11 +4,11 @@
%h4= _("Pipelines charts")
%p
&nbsp;
%span.cgreen
%span.legend-success
= icon("circle")
= s_("Pipeline|success")
&nbsp;
%span.cgray
%span.legend-all
= icon("circle")
= s_("Pipeline|all")
......
---
title: Generate HTTP URLs for custom Pages domains when appropriate
merge_request: 16279
author:
type: fixed
---
title: "Issue board: fix for dragging an issue to the very bottom in long lists"
merge_request: 16250
author: David Kuri
type: fixed
\ No newline at end of file
---
title: Substitute deprecated ui_charcoal with new default ui_indigo
merge_request: 16271
author: Takuya Noguchi
type: fixed
---
title: Fixed chanages dropdown ellipsis positioning
merge_request:
author:
type: fixed
---
title: Fix dashboard projects nav links height
merge_request: 16204
author: George Tsiolis
type: fixed
---
title: Fixing bug when wiki last version
merge_request: 16197
author:
type: fixed
---
title: Added option to disable commits stats in the commit endpoint
merge_request: 16309
author:
type: added
---
title: Backport fast database lookup of SSH authorized_keys from EE
merge_request: 16014
author:
type: added
---
title: Save user ID and username in Grape API log (api_json.log)
merge_request:
author:
type: changed
......@@ -36,6 +36,26 @@ module Gollum
end
end
end
module Git
class Git
def tree_entry(commit, path)
pathname = Pathname.new(path)
tmp_entry = nil
pathname.each_filename do |dir|
tmp_entry = if tmp_entry.nil?
commit.tree[dir]
else
@repo.lookup(tmp_entry[:oid])[dir]
end
return nil unless tmp_entry
end
tmp_entry
end
end
end
end
Rails.application.configure do
......
'use strict';
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
......@@ -193,15 +194,34 @@ var config = {
if (chunk.name) {
return chunk.name;
}
return chunk.mapModules((m) => {
const moduleNames = [];
function collectModuleNames(m) {
// handle ConcatenatedModule which does not have resource nor context set
if (m.modules) {
m.modules.forEach(collectModuleNames);
return;
}
const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages');
if (m.resource.indexOf(pagesBase) === 0) {
return path.relative(pagesBase, m.resource)
moduleNames.push(path.relative(pagesBase, m.resource)
.replace(/\/index\.[a-z]+$/, '')
.replace(/\//g, '__');
.replace(/\//g, '__'));
} else {
moduleNames.push(path.relative(m.context, m.resource));
}
return path.relative(m.context, m.resource);
}).join('_');
}
chunk.forEachModule(collectModuleNames);
const hash = crypto.createHash('sha256')
.update(moduleNames.join('_'))
.digest('hex');
return `${moduleNames[0]}-${hash.substr(0, 6)}`;
}),
// create cacheable common library bundle for all vue chunks
......
......@@ -2,6 +2,11 @@
class AddFingerprintIndex < ActiveRecord::Migration
disable_ddl_transaction!
<<<<<<< HEAD
=======
DOWNTIME = false
>>>>>>> upstream/master
# https://gitlab.com/gitlab-org/gitlab-ee/issues/764
def change
args = [:keys, :fingerprint]
......
......@@ -15,8 +15,6 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
end
def up
merge_requests = MergeRequest.where("id IN (#{updatable_merge_requests_union_sql})").reorder(:id)
say 'Scheduling `PopulateMergeRequestMetricsWithEventsData` jobs'
# It will update around 4_000_000 records in batches of 10_000 merge
# requests (running between 10 minutes) and should take around 66 hours to complete.
......@@ -25,7 +23,7 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
#
# More information about the updates in `PopulateMergeRequestMetricsWithEventsData` class.
#
merge_requests.each_batch(of: BATCH_SIZE) do |relation, index|
MergeRequest.all.each_batch(of: BATCH_SIZE) do |relation, index|
range = relation.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * 10.minutes, MIGRATION, range)
......@@ -37,32 +35,4 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
execute "update merge_request_metrics set latest_closed_by_id = null"
execute "update merge_request_metrics set merged_by_id = null"
end
private
# On staging:
# Planning time: 0.682 ms
# Execution time: 22033.158 ms
#
def updatable_merge_requests_union_sql
metrics_not_exists_clause =
'NOT EXISTS (SELECT 1 FROM merge_request_metrics WHERE merge_request_metrics.merge_request_id = merge_requests.id)'
without_metrics_data = <<-SQL.strip_heredoc
merge_request_metrics.merged_by_id IS NULL OR
merge_request_metrics.latest_closed_by_id IS NULL OR
merge_request_metrics.latest_closed_at IS NULL
SQL
mrs_without_metrics_record = MergeRequest
.where(metrics_not_exists_clause)
.select(:id)
mrs_without_events_data = MergeRequest
.joins('INNER JOIN merge_request_metrics ON merge_requests.id = merge_request_metrics.merge_request_id')
.where(without_metrics_data)
.select(:id)
Gitlab::SQL::Union.new([mrs_without_metrics_record, mrs_without_events_data]).to_sql
end
end
......@@ -177,7 +177,11 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.integer "gitaly_timeout_default", default: 55, null: false
t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false
<<<<<<< HEAD
t.boolean "mirror_available", default: true, null: false
=======
t.boolean "authorized_keys_enabled", default: true, null: false
>>>>>>> upstream/master
end
create_table "approvals", force: :cascade do |t|
......
......@@ -19,6 +19,7 @@ instructions will break installations using older versions of OpenSSH, such as
those included with CentOS 6 as of September 2017. If you want to use this
feature for CentOS 6, follow [the instructions on how to build and install a custom OpenSSH package](#compiling-a-custom-version-of-openssh-for-centos-6) before continuing.
<<<<<<< HEAD
## Fast lookup is required for GitLab Geo
......@@ -33,12 +34,15 @@ secondary nodes, but note that the `Write to "authorized keys" file` checkbox
only needs to be unchecked on the primary node since it will be reflected
automatically on the secondary if database replication is working.
=======
>>>>>>> upstream/master
## Setting up fast lookup via GitLab Shell
GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup
to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to
check whether the user is authorized to access GitLab.
<<<<<<< HEAD
Create the directory `/opt/gitlab-shell` first:
```bash
......@@ -67,6 +71,14 @@ are using Omnibus Docker:
```
AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
=======
Add the following to your `sshd_config` file. This is usuaully located at
`/etc/ssh/sshd_config`, but it will be `/assets/sshd_config` if you're using
Omnibus Docker:
```
AuthorizedKeysCommand /opt/embedded/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k
>>>>>>> upstream/master
AuthorizedKeysCommandUser git
```
......@@ -84,7 +96,11 @@ Confirm that SSH is working by removing your user's SSH key in the UI, adding a
new one, and attempting to pull a repo.
> **Warning:** Do not disable writes until SSH is confirmed to be working
<<<<<<< HEAD
perfectly because the file will quickly become out-of-date.
=======
perfectly, because the file will quickly become out-of-date.
>>>>>>> upstream/master
In the case of lookup failures (which are not uncommon), the `authorized_keys`
file will still be scanned. So git SSH performance will still be slow for many
......
......@@ -13,6 +13,9 @@ by GitLab to another file system or another server.
that to prioritize important jobs.
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md): Configure Sidekiq MemoryKiller
to restart Sidekiq.
<<<<<<< HEAD
- **(EES/EEP)** [Extra Sidekiq operations](extra_sidekiq_processes.md): Configure an extra set of Sidekiq processes to ensure certain queues always have dedicated workers, no matter the amount of jobs that need to be processed.
=======
>>>>>>> upstream/master
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
- [Speed up SSH operations](fast_ssh_key_lookup.md): Authorize SSH users via a fast, indexed lookup to the GitLab database.
......@@ -159,6 +159,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
| `sha` | string | yes | The commit hash or name of a repository branch or tag |
| `stats` | boolean | no | Include commit stats. Default is true |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master
......
......@@ -113,7 +113,7 @@ GET /projects/:id/repository/archive
Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `sha` (optional) - The commit SHA to download defaults to the tip of the default branch
- `sha` (optional) - The commit SHA to download. A tag, branch reference or sha can be used. This defaults to the tip of the default branch if not specified
## Compare branches, tags or commits
......
......@@ -181,7 +181,7 @@ before_script:
## Assuming you created the SSH_KNOWN_HOSTS variable, uncomment the
## following two lines.
##
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts'
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
##
......
......@@ -133,8 +133,6 @@ Usage: /etc/init.d/postgresql {start|stop|restart|reload|force-reload|status} [v
### Log locations of the services
Note: `/home/git/` is shorthand for `/home/git`.
gitlabhq (includes Unicorn and Sidekiq logs)
- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `githost.log` and `unicorn.stderr.log` normally.
......
......@@ -127,7 +127,7 @@ type:
If you're working on the GitLab EE repository, the entry will be added to
`changelogs/unreleased-ee/` instead.
#### Arguments
### Arguments
| Argument | Shorthand | Purpose |
| ----------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
......
......@@ -216,7 +216,7 @@ If you want a line or set of lines to be ignored by the linter, you can use
```scss
// This lint rule is disabled because the class name comes from a gem.
// scss-lint:disable SelectorFormat
.ui_charcoal {
.ui_indigo {
background-color: #333;
}
// scss-lint:enable SelectorFormat
......
......@@ -15,7 +15,7 @@ request introducing these changes must be accompanied by the documentation
(either updating existing ones or creating new ones). This is also valid when
changes are introduced to the UI.
The one resposible for writing the first piece of documentation is the developer who
The one responsible for writing the first piece of documentation is the developer who
wrote the code. It's the job of the Product Manager to ensure all features are
shipped with its docs, whether is a small or big change. At the pace GitLab evolves,
this is the only way to keep the docs up-to-date. If you have any questions about it,
......@@ -31,7 +31,7 @@ Every major feature (regardless if present in GitLab Community or Enterprise edi
should present, at the beginning of the document, two main sections: **overview** and
**use cases**. Every GitLab EE-only feature should also contain these sections.
**Overview**: at the name suggests, the goal here is to provide an overview of the feature.
**Overview**: as the name suggests, the goal here is to provide an overview of the feature.
Describe what is it, what it does, why it is important/cool/nice-to-have,
what problem it solves, and what you can do with this feature that you couldn't
do before.
......
......@@ -47,4 +47,8 @@ Irker accepts channel names of the form `chan` and `#chan`, both for the
case, `Aorimn` is treated as a nick and no more as a channel name.
Irker can also join password-protected channels. Users need to append
`?key=thesecretpassword` to the chan name.
`?key=thesecretpassword` to the chan name. When using this feature remember to
**not** put the `#` sign in front of the channel name; failing to do so will
result on irker joining a channel literally named `#chan?key=password` henceforth
leaking the channel key through the `/whois` IRC command (depending on IRC server
configuration). This is due to a long standing irker bug.
......@@ -79,6 +79,12 @@ Below are described the supported events.
Triggered when you push to the repository except when pushing tags.
> **Note:** When more than 20 commits are pushed at once, the `commits` web hook
attribute will only contain the first 20 for performance reasons. Loading
detailed commit data is expensive. Note that despite only 20 commits being
present in the `commits` attribute, the `total_commits_count` attribute will
contain the actual total.
**Request header**:
```
......
......@@ -13,7 +13,8 @@ module API
formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new,
include: [
GrapeLogging::Loggers::FilterParameters.new,
GrapeLogging::Loggers::ClientEnv.new
GrapeLogging::Loggers::ClientEnv.new,
Gitlab::GrapeLogging::Loggers::UserLogger.new
]
allow_access_with_scope :api
......
......@@ -82,13 +82,14 @@ module API
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
optional :stats, type: Boolean, default: true, desc: 'Include commit stats'
end
get ':id/repository/commits/:sha', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit
present commit, with: Entities::CommitDetail
present commit, with: Entities::CommitDetail, stats: params[:stats]
end
desc 'Get the diff for a specific commit of a project' do
......
......@@ -307,7 +307,7 @@ module API
end
class CommitDetail < Commit
expose :stats, using: Entities::CommitStats
expose :stats, using: Entities::CommitStats, if: :stats
expose :status
expose :last_pipeline, using: 'API::Entities::PipelineBasic'
end
......
......@@ -8,6 +8,7 @@ module API
SUDO_HEADER = "HTTP_SUDO".freeze
SUDO_PARAM = :sudo
API_USER_ENV = 'gitlab.api.user'.freeze
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
......@@ -51,10 +52,16 @@ module API
validate_access_token!(scopes: scopes_registered_for_endpoint) unless sudo?
save_current_user_in_env(@current_user) if @current_user
@current_user
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def save_current_user_in_env(user)
env[API_USER_ENV] = { user_id: user.id, username: user.username }
end
def sudo?
initial_current_user != current_user
end
......
......@@ -71,13 +71,14 @@ module API
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
optional :stats, type: Boolean, default: true, desc: 'Include commit stats'
end
get ":id/repository/commits/:sha", requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit
present commit, with: ::API::Entities::CommitDetail
present commit, with: ::API::Entities::CommitDetail, stats: params[:stats]
end
desc 'Get the diff for a specific commit of a project' do
......
......@@ -43,8 +43,11 @@ module Gitlab
GitalyClient.call(@storage, :repository_service, :apply_gitattributes, request)
end
def fetch_remote(remote, ssh_auth: nil, forced: false, no_tags: false)
request = Gitaly::FetchRemoteRequest.new(repository: @gitaly_repo, remote: remote, force: forced, no_tags: no_tags)
def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:)
request = Gitaly::FetchRemoteRequest.new(
repository: @gitaly_repo, remote: remote, force: forced,
no_tags: no_tags, timeout: timeout
)
if ssh_auth&.ssh_import?
if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present?
......
# This grape_logging module (https://github.com/aserafin/grape_logging) makes it
# possible to log the user who performed the Grape API action by retrieving
# the user context from the request environment.
module Gitlab
module GrapeLogging
module Loggers
class UserLogger < ::GrapeLogging::Loggers::Base
def parameters(request, _)
params = request.env[::API::Helpers::API_USER_ENV]
return {} unless params
params.slice(:user_id, :username)
end
end
end
end
end
......@@ -128,7 +128,7 @@ module Gitlab
def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false)
gitaly_migrate(:fetch_remote) do |is_enabled|
if is_enabled
repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout)
else
storage_path = Gitlab.config.repositories.storages[repository.storage]["path"]
local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
......
......@@ -15,7 +15,6 @@
"dependencies": {
"autosize": "^4.0.0",
"axios": "^0.17.1",
"axios-mock-adapter": "^1.10.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.2",
"babel-loader": "^7.1.2",
......@@ -91,6 +90,7 @@
},
"devDependencies": {
"@gitlab-org/gitlab-svgs": "^1.5.0",
"axios-mock-adapter": "^1.10.0",
"babel-plugin-istanbul": "^4.1.5",
"eslint": "^3.10.1",
"eslint-config-airbnb-base": "^10.0.1",
......
......@@ -266,4 +266,14 @@ describe DiffHelper do
end
end
end
context '#diff_file_path_text' do
it 'returns full path by default' do
expect(diff_file_path_text(diff_file)).to eq(diff_file.new_path)
end
it 'returns truncated path' do
expect(diff_file_path_text(diff_file, max: 10)).to eq("...open.rb")
end
end
end
require 'spec_helper'
describe 'gollum' do
let(:project) { create(:project) }
let(:user) { project.owner }
let(:wiki) { ProjectWiki.new(project, user) }
let(:gollum_wiki) { Gollum::Wiki.new(wiki.repository.path) }
before do
create_page(page_name, 'content1')
end
after do
destroy_page(page_name)
end
context 'with simple paths' do
let(:page_name) { 'page1' }
it 'returns the entry hash if it matches the file name' do
expect(tree_entry(page_name)).not_to be_nil
end
it 'returns nil if the path does not fit completely' do
expect(tree_entry("foo/#{page_name}")).to be_nil
end
end
context 'with complex paths' do
let(:page_name) { '/foo/bar/page2' }
it 'returns the entry hash if it matches the file name' do
expect(tree_entry(page_name)).not_to be_nil
end
it 'returns nil if the path does not fit completely' do
expect(tree_entry("foo1/bar/page2")).to be_nil
expect(tree_entry("foo/bar1/page2")).to be_nil
end
end
def tree_entry(name)
gollum_wiki.repo.git.tree_entry(wiki_commits[0].commit, name + '.md')
end
def wiki_commits
gollum_wiki.repo.commits
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "test commit")
end
def create_page(name, content)
wiki.wiki.write_page(name, :markdown, content, commit_details)
end
def destroy_page(name)
page = wiki.find_page(name).page
wiki.delete_page(page, "test commit")
end
end
......@@ -154,6 +154,18 @@ describe('Board list component', () => {
});
});
it('sets data attribute with invalid id', (done) => {
component.showCount = true;
Vue.nextTick(() => {
expect(
component.$el.querySelector('.board-list-count').getAttribute('data-issue-id'),
).toBe('-1');
done();
});
});
it('shows how many more issues to load', (done) => {
component.showCount = true;
component.list.issuesSize = 20;
......
......@@ -19,17 +19,24 @@ import IssuablesHelper from '~/helpers/issuables_helper';
$('input[type=checkbox]').attr('checked', true)[0].dispatchEvent(changeEvent);
return expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
});
return it('submits an ajax request on tasklist:changed', function() {
spyOn(jQuery, 'ajax').and.callFake(function(req) {
it('submits an ajax request on tasklist:changed', (done) => {
spyOn(jQuery, 'ajax').and.callFake((req) => {
expect(req.type).toBe('PATCH');
expect(req.url).toBe(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`);
return expect(req.data.merge_request.description).not.toBe(null);
expect(req.data.merge_request.description).not.toBe(null);
done();
});
return $('.js-task-list-field').trigger('tasklist:changed');
$('.js-task-list-field').trigger('tasklist:changed');
});
});
describe('class constructor', () => {
beforeEach(() => {
spyOn(jQuery, 'ajax').and.stub();
});
it('calls .initCloseReopenReport', () => {
spyOn(IssuablesHelper, 'initCloseReopenReport');
......
import * as urlUtils from '~/lib/utils/url_utility';
import Todos from '~/todos';
import Todos from '~/pages/dashboard/todos/index/todos';
import '~/lib/utils/common_utils';
describe('Todos', () => {
......
......@@ -32,7 +32,7 @@ describe('Pagination component', () => {
change: spy,
});
expect(component.$el.innerHTML).not.toBeDefined();
expect(component.$el.childNodes.length).toEqual(0);
});
describe('prev button', () => {
......
......@@ -14,7 +14,7 @@ describe Gitlab::Regex do
it { is_expected.not_to match('?gitlab') }
end
describe '.environment_slug_regex' do
describe '.environment_name_regex' do
subject { described_class.environment_name_regex }
it { is_expected.to match('foo') }
......@@ -24,6 +24,7 @@ describe Gitlab::Regex do
it { is_expected.to match('foo.1') }
it { is_expected.not_to match('9&foo') }
it { is_expected.not_to match('foo-^') }
it { is_expected.not_to match('!!()()') }
end
describe '.environment_slug_regex' do
......
......@@ -4,6 +4,7 @@ require 'stringio'
describe Gitlab::Shell do
set(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:gitlab_shell) { described_class.new }
let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
let(:gitlab_projects) { double('gitlab_projects') }
......@@ -401,17 +402,6 @@ describe Gitlab::Shell do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
describe '#add_key' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
)
gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
end
end
describe '#add_repository' do
shared_examples '#add_repository' do
let(:repository_storage) { 'default' }
......@@ -506,8 +496,6 @@ describe Gitlab::Shell do
end
shared_examples 'fetch_remote' do |gitaly_on|
let(:repository) { project.repository }
def fetch_remote(ssh_auth = nil)
gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth)
end
......@@ -630,6 +618,23 @@ describe Gitlab::Shell do
describe '#fetch_remote gitaly' do
it_should_behave_like 'fetch_remote', true
context 'gitaly call' do
let(:remote_name) { 'remote-name' }
let(:ssh_auth) { double(:ssh_auth) }
subject do
gitlab_shell.fetch_remote(repository.raw_repository, remote_name,
forced: true, no_tags: true, ssh_auth: ssh_auth)
end
it 'passes the correct params to the gitaly service' do
expect(repository.gitaly_repository_client).to receive(:fetch_remote)
.with(remote_name, ssh_auth: ssh_auth, forced: true, no_tags: true, timeout: timeout)
subject
end
end
end
describe '#import_repository' do
......
......@@ -68,7 +68,7 @@ describe PagesDomain do
subject { domain.url }
context 'without the certificate' do
let(:domain) { build(:pages_domain) }
let(:domain) { build(:pages_domain, certificate: '') }
it { is_expected.to eq('http://my.domain.com') }
end
......
......@@ -512,6 +512,31 @@ describe API::Commits do
end
end
context 'when stat param' do
let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}" }
it 'is not present return stats by default' do
get api(route, user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to include 'stats'
end
it "is false it does not include stats" do
get api(route, user), stats: false
expect(response).to have_gitlab_http_status(200)
expect(json_response).not_to include 'stats'
end
it "is true it includes stats" do
get api(route, user), stats: true
expect(response).to have_gitlab_http_status(200)
expect(json_response).to include 'stats'
end
end
context 'when unauthenticated', 'and project is public' do
let(:project) { create(:project, :public, :repository) }
......
......@@ -71,6 +71,12 @@ describe API::Helpers do
end
it { is_expected.to eq(user) }
it 'sets the environment with data of the current user' do
subject
expect(env[API::Helpers::API_USER_ENV]).to eq({ user_id: subject.id, username: subject.username })
end
end
context "HEAD request" do
......
......@@ -403,6 +403,33 @@ describe API::V3::Commits do
expect(response).to have_gitlab_http_status(200)
expect(json_response['status']).to eq("created")
end
context 'when stat param' do
let(:project_id) { project.id }
let(:commit_id) { project.repository.commit.id }
let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}" }
it 'is not present return stats by default' do
get v3_api(route, user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to include 'stats'
end
it "is false it does not include stats" do
get v3_api(route, user), stats: false
expect(response).to have_gitlab_http_status(200)
expect(json_response).not_to include 'stats'
end
it "is true it includes stats" do
get v3_api(route, user), stats: true
expect(response).to have_gitlab_http_status(200)
expect(json_response).to include 'stats'
end
end
end
context "unauthorized user" 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