Commit 687a6c08 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into ce-to-ee-tue

parents 8ae9b485 19dd138c
......@@ -13,9 +13,11 @@
},
"plugins": [
"filenames",
"import"
"import",
"html"
],
"settings": {
"html/html-extensions": [".html", ".html.raw", ".vue"],
"import/resolver": {
"webpack": {
"config": "./config/webpack.config.js"
......
......@@ -90,6 +90,8 @@ window.Build = (function () {
success: ((log) => {
const $buildContainer = $('.js-build-output');
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`);
if (log.state) {
this.state = log.state;
}
......
......@@ -4,8 +4,8 @@ import PipelinesTableComponent from '../../vue_shared/components/pipelines_table
import PipelinesService from '../../vue_pipelines_index/services/pipelines_service';
import PipelineStore from '../../vue_pipelines_index/stores/pipelines_store';
import eventHub from '../../vue_pipelines_index/event_hub';
import EmptyState from '../../vue_pipelines_index/components/empty_state';
import ErrorState from '../../vue_pipelines_index/components/error_state';
import EmptyState from '../../vue_pipelines_index/components/empty_state.vue';
import ErrorState from '../../vue_pipelines_index/components/error_state.vue';
import '../../lib/utils/common_utils';
import '../../vue_shared/vue_resource_interceptor';
import Poll from '../../lib/utils/poll';
......
<script>
/* eslint-disable no-new, no-alert */
/* global Flash */
import '~/flash';
......@@ -65,29 +66,31 @@ export default {
this.isLoading = true;
this.service.postAction(this.endpoint)
.then(() => {
this.isLoading = false;
eventHub.$emit('refreshPipelines');
})
.catch(() => {
this.isLoading = false;
new Flash('An error occured while making the request.');
});
.then(() => {
this.isLoading = false;
eventHub.$emit('refreshPipelines');
})
.catch(() => {
this.isLoading = false;
new Flash('An error occured while making the request.');
});
},
},
template: `
<button
type="button"
@click="onClick"
:class="buttonClass"
:title="title"
:aria-label="title"
data-container="body"
data-placement="top"
:disabled="isLoading">
<i :class="iconClass" aria-hidden="true"/>
<i class="fa fa-spinner fa-spin" aria-hidden="true" v-if="isLoading" />
</button>
`,
};
</script>
<template>
<button
type="button"
@click="onClick"
:class="buttonClass"
:title="title"
:aria-label="title"
data-container="body"
data-placement="top"
:disabled="isLoading"
>
<i :class="iconClass" aria-hidden="true"></i>
<i class="fa fa-spinner fa-spin" aria-hidden="true" v-if="isLoading"></i>
</button>
</template>
import pipelinesEmptyStateSVG from 'empty_states/icons/_pipelines_empty.svg';
export default {
props: {
helpPagePath: {
type: String,
required: true,
},
},
template: `
<div class="row empty-state">
<div class="col-xs-12">
<div class="svg-content">
${pipelinesEmptyStateSVG}
</div>
</div>
<div class="col-xs-12 text-center">
<div class="text-content">
<h4>Build with confidence</h4>
<p>
Continous Integration can help catch bugs by running your tests automatically,
while Continuous Deployment can help you deliver code to your product environment.
</p>
<a :href="helpPagePath" class="btn btn-info">
Get started with Pipelines
</a>
</div>
</div>
</div>
`,
};
<script>
import pipelinesEmptyStateSVG from 'empty_states/icons/_pipelines_empty.svg';
export default {
props: {
helpPagePath: {
type: String,
required: true,
},
},
data: () => ({ pipelinesEmptyStateSVG }),
};
</script>
<template>
<div class="row empty-state">
<div class="col-xs-12">
<div class="svg-content" v-html="pipelinesEmptyStateSVG" />
</div>
<div class="col-xs-12 text-center">
<div class="text-content">
<h4>Build with confidence</h4>
<p>
Continous Integration can help catch bugs by running your tests automatically,
while Continuous Deployment can help you deliver code to your product environment.
</p>
<a :href="helpPagePath" class="btn btn-info">
Get started with Pipelines
</a>
</div>
</div>
</div>
</template>
import pipelinesErrorStateSVG from 'empty_states/icons/_pipelines_failed.svg';
export default {
template: `
<div class="row empty-state js-pipelines-error-state">
<div class="col-xs-12">
<div class="svg-content">
${pipelinesErrorStateSVG}
</div>
</div>
<div class="col-xs-12 text-center">
<div class="text-content">
<h4>The API failed to fetch the pipelines.</h4>
</div>
</div>
</div>
`,
};
<script>
import pipelinesErrorStateSVG from 'empty_states/icons/_pipelines_failed.svg';
export default {
data: () => ({ pipelinesErrorStateSVG }),
};
</script>
<template>
<div class="row empty-state js-pipelines-error-state">
<div class="col-xs-12">
<div class="svg-content" v-html="pipelinesErrorStateSVG" />
</div>
<div class="col-xs-12 text-center">
<div class="text-content">
<h4>The API failed to fetch the pipelines.</h4>
</div>
</div>
</div>
</template>
......@@ -4,8 +4,8 @@ import PipelinesService from './services/pipelines_service';
import eventHub from './event_hub';
import PipelinesTableComponent from '../vue_shared/components/pipelines_table';
import TablePaginationComponent from '../vue_shared/components/table_pagination';
import EmptyState from './components/empty_state';
import ErrorState from './components/error_state';
import EmptyState from './components/empty_state.vue';
import ErrorState from './components/error_state.vue';
import NavigationTabs from './components/navigation_tabs';
import NavigationControls from './components/nav_controls';
import Poll from '../lib/utils/poll';
......
/* eslint-disable no-param-reassign */
import AsyncButtonComponent from '../../vue_pipelines_index/components/async_button';
import AsyncButtonComponent from '../../vue_pipelines_index/components/async_button.vue';
import PipelinesActionsComponent from '../../vue_pipelines_index/components/pipelines_actions';
import PipelinesArtifactsComponent from '../../vue_pipelines_index/components/pipelines_artifacts';
import PipelinesStatusComponent from '../../vue_pipelines_index/components/status';
......
......@@ -118,6 +118,10 @@ module BlobHelper
blob && blob.text? && !blob.lfs_pointer? && !blob.only_display_raw?
end
def blob_rendered_as_text?(blob)
blob_text_viewable?(blob) && blob.to_partial_path(@project) == 'text'
end
def blob_size(blob)
if blob.lfs_pointer?
blob.lfs_size
......
......@@ -42,12 +42,16 @@ class Blob < SimpleDelegator
size && truncated?
end
def extension
extname.downcase.delete('.')
end
def svg?
text? && language && language.name == 'SVG'
end
def pdf?
name && File.extname(name) == '.pdf'
extension == 'pdf'
end
def ipython_notebook?
......@@ -55,11 +59,15 @@ class Blob < SimpleDelegator
end
def sketch?
binary? && extname.downcase.delete('.') == 'sketch'
binary? && extension == 'sketch'
end
def stl?
extname.downcase.delete('.') == 'stl'
extension == 'stl'
end
def markup?
text? && Gitlab::MarkupHelper.markup?(name)
end
def size_within_svg_limits?
......@@ -77,8 +85,10 @@ class Blob < SimpleDelegator
else
'text'
end
elsif image? || svg?
elsif image?
'image'
elsif svg?
'svg'
elsif pdf?
'pdf'
elsif ipython_notebook?
......@@ -87,8 +97,18 @@ class Blob < SimpleDelegator
'sketch'
elsif stl?
'stl'
elsif markup?
if only_display_raw?
'too_large'
else
'markup'
end
elsif text?
'text'
if only_display_raw?
'too_large'
else
'text'
end
else
'download'
end
......
......@@ -414,8 +414,6 @@ class Repository
# Runs code after a repository has been forked/imported.
def after_import
expire_content_cache
expire_tags_cache
expire_branches_cache
end
# Runs code after a new commit has been pushed.
......
......@@ -662,6 +662,7 @@
The multiplier can also have a decimal value.
The default value (1) is a reasonable choice for the majority of GitLab
installations. Set to 0 to completely disable polling.
= link_to icon('question-circle'), help_page_path('administration/polling')
- if Gitlab::Geo.license_allows?
%fieldset
......
......@@ -2,7 +2,7 @@
Project #{@project.name} was exported successfully.
%p
The project export can be downloaded from:
= link_to download_export_namespace_project_url(@project.namespace, @project), rel: 'nofollow', download: '', do
= link_to download_export_namespace_project_url(@project.namespace, @project), rel: 'nofollow', download: '' do
= @project.name_with_namespace + " export"
%p
The download link will expire in 24 hours.
......@@ -33,4 +33,10 @@
= link_to 'Fork', fork_path, method: :post, class: 'btn btn-grouped btn-inverted btn-new'
%button.js-cancel-fork-suggestion.btn.btn-grouped{ type: 'button' }
Cancel
= render blob.to_partial_path(@project), blob: blob
- if blob.empty?
.file-content.code
.nothing-here-block
Empty file
- else
= render blob.to_partial_path(@project), blob: blob
......@@ -13,7 +13,7 @@
.file-actions.hidden-xs
.btn-group{ role: "group" }<
= copy_blob_content_button(blob) if !blame && blob_text_viewable?(blob)
= copy_blob_content_button(blob) if !blame && blob_rendered_as_text?(blob)
= open_raw_file_button(namespace_project_raw_path(@project.namespace, @project, @id))
= view_on_environment_button(@commit.sha, @path, @environment) if @environment
......
.file-content.image_file
- if blob.svg?
- if blob.size_within_svg_limits?
-# We need to scrub SVG but we cannot do so in the RawController: it would
-# be wrong/strange if RawController modified the data.
- blob.load_all_data!(@repository)
- blob = sanitize_svg(blob)
%img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}", alt: "#{blob.name}" }
- else
.nothing-here-block
The SVG could not be displayed as it is too large, you can
#{link_to('view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank', rel: 'noopener noreferrer')}
instead.
- else
%img{ src: namespace_project_raw_path(@project.namespace, @project, tree_join(@commit.id, blob.path)), alt: "#{blob.name}" }
%img{ src: namespace_project_raw_path(@project.namespace, @project, @id), alt: blob.name }
- blob.load_all_data!(@repository)
.file-content.wiki
= render_markup(blob.name, blob.data)
- if blob.size_within_svg_limits?
-# We need to scrub SVG but we cannot do so in the RawController: it would
-# be wrong/strange if RawController modified the data.
- blob.load_all_data!(@repository)
- blob = sanitize_svg(blob)
.file-content.image_file
%img{ src: "data:#{blob.mime_type};base64,#{Base64.encode64(blob.data)}", alt: blob.name }
- else
= render 'too_large'
- if blob.only_display_raw?
.file-content.code
.nothing-here-block
File too large, you can
= succeed '.' do
= link_to 'view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank', rel: 'noopener noreferrer'
- else
- blob.load_all_data!(@repository)
- if blob.empty?
.file-content.code
.nothing-here-block Empty file
- else
- if markup?(blob.name)
.file-content.wiki
= render_markup(blob.name, blob.data)
- else
= render 'shared/file_highlight', blob: blob, repository: @repository
- blob.load_all_data!(@repository)
= render 'shared/file_highlight', blob: blob, repository: @repository
.file-content.code
.nothing-here-block
The file could not be displayed as it is too large, you can
#{link_to('view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank', rel: 'noopener noreferrer')}
instead.
......@@ -16,7 +16,7 @@
= render "home_panel"
- if current_user && can?(current_user, :download_code, @project)
%nav.project-stats.limit-container-width{ class: container_class }
%nav.project-stats{ class: container_class }
%ul.nav
%li
= link_to project_files_path(@project) do
......@@ -77,11 +77,11 @@
Set up auto deploy
- if @repository.commit
.limit-container-width{ class: container_class }
%div{ class: container_class }
.project-last-commit
= render 'projects/last_commit', commit: @repository.commit, ref: current_ref, project: @project
.limit-container-width{ class: container_class }
%div{ class: container_class }
- if @project.archived?
.text-warning.center.prepend-top-20
%p
......
---
title: Disable invalid service templates
merge_request:
author:
---
title: Keep webpack-dev-server process functional across branch changes
merge_request: 10581
author:
---
title: add support for .vue templates
merge_request: 10517
author:
---
title: Fix redundant cache expiration in Repository
merge_request: 10575
author: blackst0ne
---
title: Add spec for schema.rb
merge_request: 10580
author: blackst0ne
......@@ -344,3 +344,57 @@
:why: https://github.com/nodeca/pako/blob/master/LICENSE
:versions: []
:when: 2017-04-05 10:43:45.897720000 Z
- - :approve
- caniuse-db
- :who: Mike Greiling
:why: https://github.com/Fyrd/caniuse/blob/master/LICENSE
:versions: []
:when: 2017-04-07 16:05:14.185549000 Z
- - :approve
- domelementtype
- :who: Mike Greiling
:why: https://github.com/fb55/domelementtype/blob/master/LICENSE
:versions: []
:when: 2017-04-07 16:19:17.992640000 Z
- - :approve
- domhandler
- :who: Mike Greiling
:why: https://github.com/fb55/domhandler/blob/master/LICENSE
:versions: []
:when: 2017-04-07 16:19:19.628953000 Z
- - :approve
- domutils
- :who: Mike Greiling
:why: https://github.com/fb55/domutils/blob/master/LICENSE
:versions: []
:when: 2017-04-07 16:19:21.159356000 Z
- - :approve
- entities
- :who: Mike Greiling
:why: https://github.com/fb55/entities/blob/master/LICENSE
:versions: []
:when: 2017-04-07 16:19:23.900571000 Z
- - :approve
- ansi-html
- :who: Mike Greiling
:why: https://github.com/Tjatse/ansi-html/blob/master/LICENSE
:versions: []
:when: 2017-04-10 05:42:12.898178000 Z
- - :approve
- map-stream
- :who: Mike Greiling
:why: https://github.com/dominictarr/map-stream/blob/master/LICENCE
:versions: []
:when: 2017-04-10 06:27:52.269085000 Z
- - :approve
- pause-stream
- :who: Mike Greiling
:why: https://github.com/dominictarr/pause-stream/blob/master/LICENSE
:versions: []
:when: 2017-04-10 06:28:39.825894000 Z
- - :approve
- undefsafe
- :who: Mike Greiling
:why: https://github.com/remy/undefsafe/blob/master/LICENSE
:versions: []
:when: 2017-04-10 06:30:00.002555000 Z
......@@ -6,6 +6,7 @@ var webpack = require('webpack');
var StatsPlugin = require('stats-webpack-plugin');
var CompressionPlugin = require('compression-webpack-plugin');
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
var ROOT_PATH = path.resolve(__dirname, '..');
var IS_PRODUCTION = process.env.NODE_ENV === 'production';
......@@ -68,13 +69,18 @@ var config = {
{
test: /\.js$/,
exclude: /(node_modules|vendor\/assets)/,
loader: 'babel-loader'
loader: 'babel-loader',
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.svg$/,
use: 'raw-loader'
}, {
test: /\.(worker.js|pdf)$/,
loader: 'raw-loader',
},
{
test: /\.(worker\.js|pdf)$/,
exclude: /node_modules/,
loader: 'file-loader',
},
......@@ -187,6 +193,10 @@ if (IS_DEV_SERVER) {
inline: DEV_SERVER_LIVERELOAD
};
config.output.publicPath = '//localhost:' + DEV_SERVER_PORT + config.output.publicPath;
config.plugins.push(
// watch node_modules for changes if we encounter a missing module compile error
new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules'))
);
}
if (WEBPACK_REPORT) {
......
......@@ -69,6 +69,7 @@ All technical content published by GitLab lives in the documentation, including:
- [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE.
- [Monitoring uptime](user/admin_area/monitoring/health_check.md) Check the server status using the health check endpoint.
- [Operations](administration/operations.md) Keeping GitLab up and running.
- [Polling](administration/polling.md) Configure how often the GitLab UI polls for updates
- [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects.
- [Reply by email](administration/reply_by_email.md) Allow users to comment on issues and merge requests by replying to notification emails.
- [Repository checks](administration/repository_checks.md) Periodic Git repository checks.
......
# Polling configuration
The GitLab UI polls for updates for different resources (issue notes, issue
titles, pipeline statuses, etc.) on a schedule appropriate to the resource.
In "Application settings -> Real-time features" you can configure "Polling
interval multiplier". This multiplier is applied to all resources at once,
and decimal values are supported. For the sake of the examples below, we will
say that issue notes poll every 2 seconds, and issue titles poll every 5
seconds; these are _not_ the actual values.
- 1 is the default, and recommended for most installations. (Issue notes poll
every 2 seconds, and issue titles poll every 5 seconds.)
- 0 will disable UI polling completely. (On the next poll, clients will stop
polling for updates.)
- A value greater than 1 will slow polling down. If you see issues with
database load from lots of clients polling for updates, increasing the
multiplier from 1 can be a good compromise, rather than disabling polling
completely. (For example: If this is set to 2, then issue notes poll every 4
seconds, and issue titles poll every 10 seconds.)
- A value between 0 and 1 will make the UI poll more frequently (so updates
will show in other sessions faster), but is **not recommended**. 1 should be
fast enough. (For example, if this is set to 0.5, then issue notes poll every
1 second, and issue titles poll every 2.5 seconds.)
......@@ -12,8 +12,8 @@ Thus, we must strike a balance between sending requests and the feeling of realt
Use the following rules when creating realtime solutions.
1. The server will tell you how much to poll by sending `Poll-Interval` in the header.
Use that as your polling interval. This way it is easy for system administrators to change the
polling rate.
Use that as your polling interval. This way it is [easy for system administrators to change the
polling rate](../../administration/polling.md).
A `Poll-Interval: -1` means you should disable polling, and this must be implemented.
1. A response with HTTP status `4XX` or `5XX` should disable polling as well.
1. Use a common library for polling.
......
......@@ -51,5 +51,6 @@ request path. By doing this we avoid query parameter ordering problems and make
route matching easier.
For more information see:
- [`Poll-Interval` header](fe_guide/performance.md#realtime-components)
- [RFC 7232](https://tools.ietf.org/html/rfc7232)
- [ETag proposal](https://gitlab.com/gitlab-org/gitlab-ce/issues/26926)
......@@ -20,8 +20,8 @@ the hardware requirements.
- [Docker](https://docs.gitlab.com/omnibus/docker/) - Install GitLab using Docker.
- [Installation on Google Cloud Platform](google_cloud_platform/index.md) - Install
GitLab on Google Cloud Platform using our official image.
- [Digital Ocean and Docker](digitaloceandocker.md) - Install GitLab quickly
on DigitalOcean using Docker.
- Testing only! [DigitalOcean and Docker Machine](digitaloceandocker.md) -
Quickly test any version of GitLab on DigitalOcean using Docker Machine.
## Database
......
# Digital Ocean and Docker
# Digital Ocean and Docker Machine test environment
## Warning. This guide is for quickly testing different versions of GitLab and
## not recommended for ease of future upgrades or keeping the data you create.
## Initial setup
......
......@@ -143,7 +143,7 @@ into the password field.
To disable two-factor authentication on your account (for example, if you
have lost your code generation device) you can:
* [Use a saved recovery code](#use-a-saved-recovery-code)
* [Generate new recovery codes using SSH](#generate-new-recovery-codes-using-SSH)
* [Generate new recovery codes using SSH](#generate-new-recovery-codes-using-ssh)
* [Ask a GitLab administrator to disable two-factor authentication on your account](#ask-a-gitlab-administrator-to-disable-two-factor-authentication-on-your-account)
### Use a saved recovery code
......
......@@ -323,6 +323,5 @@ Merging only when needed prevents creating merge commits in your feature branch
## References
- [Sketch file](https://www.dropbox.com/s/58dvsj5votbwrzv/git_flows.sketch?dl=0) with vectors of images in this article
- [Git Flow by Vincent Driessen](http://nvie.com/posts/a-successful-git-branching-model/)
- [Blog post with responses](https://about.gitlab.com/2014/09/29/gitlab-flow/)
\ No newline at end of file
......@@ -111,7 +111,7 @@ There are four kinds of filters you can use on your Todos dashboard.
| Type | Filter by issue or merge request |
| Action | Filter by the action that triggered the Todo |
You can also filter by more than one of these at the same time.
You can also filter by more than one of these at the same time. The possible Actions are `Any Action`, `Assigned`, `Mentioned`, `Added`, `Pipelines`, and `Directly Addressed`, [as described above](#what-triggers-a-todo).
[ce-2817]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2817
[ce-7926]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7926
......@@ -53,6 +53,7 @@ module API
]
end
<<<<<<< HEAD
def log_user_activity(actor)
commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS
......@@ -62,6 +63,11 @@ module API
def parse_env
return {} if params[:env].blank?
=======
def parse_env
return {} if params[:env].blank?
>>>>>>> 19dd138cdd4e551759a2163f5357ae2fc9f73b99
JSON.parse(params[:env])
rescue JSON::ParserError
{}
......
......@@ -3,23 +3,42 @@ module Banzai
class MergeRequestParser < BaseParser
self.reference_type = :merge_request
def nodes_visible_to_user(user, nodes)
merge_requests = merge_requests_for_nodes(nodes)
nodes.select do |node|
merge_request = merge_requests[node]
merge_request && can?(user, :read_merge_request, merge_request.project)
end
end
def referenced_by(nodes)
merge_requests = merge_requests_for_nodes(nodes)
nodes.map { |node| merge_requests[node] }.compact.uniq
end
def merge_requests_for_nodes(nodes)
@merge_requests_for_nodes ||= grouped_objects_for_nodes(
nodes,
MergeRequest.all,
MergeRequest.includes(
:author,
:assignee,
{
# These associations are primarily used for checking permissions.
# Eager loading these ensures we don't end up running dozens of
# queries in this process.
target_project: [
{ namespace: :owner },
{ group: [:owners, :group_members] },
:invited_groups,
:project_members
]
}),
self.class.data_attribute
)
end
def references_relation
MergeRequest.includes(:author, :assignee, :target_project)
end
private
def can_read_reference?(user, ref_project)
can?(user, :read_merge_request, ref_project)
end
end
end
end
module Gitlab
module EtagCaching
class Middleware
RESERVED_WORDS = NamespaceValidator::WILDCARD_ROUTES.map { |word| "/#{word}/" }.join('|')
ROUTES = [
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z),
name: 'issue_notes'
},
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/issues/\d+/rendered_title\z),
name: 'issue_title'
},
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/pipelines\.json\z),
name: 'project_pipelines'
},
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/commit/\s+/pipelines\.json\z),
name: 'commit_pipelines'
},
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/merge_requests/new\.json\z),
name: 'new_merge_request_pipelines'
},
{
regexp: %r(^(?!.*(#{RESERVED_WORDS})).*/merge_requests/\d+/pipelines\.json\z),
name: 'merge_request_pipelines'
}
].freeze
def initialize(app)
@app = app
end
def call(env)
route = match_current_route(env)
route = Gitlab::EtagCaching::Router.match(env)
return @app.call(env) unless route
track_event(:etag_caching_middleware_used, route)
......@@ -55,10 +27,6 @@ module Gitlab
private
def match_current_route(env)
ROUTES.find { |route| route[:regexp].match(env['PATH_INFO']) }
end
def get_etag(env)
cache_key = env['PATH_INFO']
store = Gitlab::EtagCaching::Store.new
......@@ -95,7 +63,7 @@ module Gitlab
end
def track_event(name, route)
Gitlab::Metrics.add_event(name, endpoint: route[:name])
Gitlab::Metrics.add_event(name, endpoint: route.name)
end
end
end
......
module Gitlab
module EtagCaching
class Router
Route = Struct.new(:regexp, :name)
RESERVED_WORDS = NamespaceValidator::WILDCARD_ROUTES.map { |word| "/#{word}/" }.join('|')
ROUTES = [
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z),
'issue_notes'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/issues/\d+/rendered_title\z),
'issue_title'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/commit/\S+/pipelines\.json\z),
'commit_pipelines'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/merge_requests/new\.json\z),
'new_merge_request_pipelines'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/merge_requests/\d+/pipelines\.json\z),
'merge_request_pipelines'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS})).*/pipelines\.json\z),
'project_pipelines'
)
].freeze
def self.match(env)
ROUTES.find { |route| route.regexp.match(env['PATH_INFO']) }
end
end
end
end
{
"private": true,
"scripts": {
"dev-server": "webpack-dev-server --config config/webpack.config.js",
"eslint": "eslint --max-warnings 0 --ext .js .",
"eslint-fix": "eslint --max-warnings 0 --ext .js --fix .",
"eslint-report": "eslint --max-warnings 0 --ext .js --format html --output-file ./eslint-report.html .",
"dev-server": "nodemon --watch config/webpack.config.js -- ./node_modules/.bin/webpack-dev-server --config config/webpack.config.js",
"eslint": "eslint --max-warnings 0 --ext .js,.vue .",
"eslint-fix": "eslint --max-warnings 0 --ext .js,.vue --fix .",
"eslint-report": "eslint --max-warnings 0 --ext .js,.vue --format html --output-file ./eslint-report.html .",
"karma": "karma start config/karma.config.js --single-run",
"karma-coverage": "BABEL_ENV=coverage karma start config/karma.config.js --single-run",
"karma-start": "karma start config/karma.config.js",
......@@ -21,10 +21,12 @@
"clipboard": "^1.6.1",
"compression-webpack-plugin": "^0.3.2",
"core-js": "^2.4.1",
"css-loader": "^0.28.0",
"d3": "^3.5.11",
"document-register-element": "^1.3.0",
"dropzone": "^4.2.0",
"emoji-unicode-version": "^0.2.1",
"eslint-plugin-html": "^2.0.1",
"file-loader": "^0.11.1",
"jquery": "^2.2.1",
"jquery-ujs": "^1.2.1",
......@@ -35,6 +37,7 @@
"pikaday": "^1.5.1",
"raphael": "^2.2.7",
"raw-loader": "^0.5.1",
"react-dev-utils": "^0.5.2",
"select2": "3.5.2-browserify",
"stats-webpack-plugin": "^0.4.3",
"three": "^0.84.0",
......@@ -43,8 +46,10 @@
"timeago.js": "^2.0.5",
"underscore": "^1.8.3",
"visibilityjs": "^1.2.4",
"vue": "^2.2.4",
"vue": "^2.2.6",
"vue-loader": "^11.3.4",
"vue-resource": "^0.9.3",
"vue-template-compiler": "^2.2.6",
"webpack": "^2.3.3",
"webpack-bundle-analyzer": "^2.3.0"
},
......@@ -66,6 +71,7 @@
"karma-phantomjs-launcher": "^1.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.2",
"nodemon": "^1.11.0",
"webpack-dev-server": "^2.4.2"
}
}
\ No newline at end of file
......@@ -98,9 +98,9 @@ describe('Build', () => {
jasmine.clock().tick(4001);
expect($.ajax.calls.count()).toBe(2);
expect($.ajax.calls.count()).toBe(3);
args = $.ajax.calls.argsFor(1)[0];
args = $.ajax.calls.argsFor(2)[0];
expect(args.url).toBe(`${BUILD_URL}/trace.json`);
expect(args.dataType).toBe('json');
expect(args.data.state).toBe('newstate');
......@@ -133,7 +133,7 @@ describe('Build', () => {
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
jasmine.clock().tick(4001);
args = $.ajax.calls.argsFor(1)[0];
args = $.ajax.calls.argsFor(2)[0];
args.success.call($, {
html: '<span>Different</span>',
status: 'running',
......
import Vue from 'vue';
import asyncButtonComp from '~/vue_pipelines_index/components/async_button';
import asyncButtonComp from '~/vue_pipelines_index/components/async_button.vue';
describe('Pipelines Async Button', () => {
let component;
......
import Vue from 'vue';
import emptyStateComp from '~/vue_pipelines_index/components/empty_state';
import emptyStateComp from '~/vue_pipelines_index/components/empty_state.vue';
describe('Pipelines Empty State', () => {
let component;
......
import Vue from 'vue';
import errorStateComp from '~/vue_pipelines_index/components/error_state';
import errorStateComp from '~/vue_pipelines_index/components/error_state.vue';
describe('Pipelines Error State', () => {
let component;
......
require 'spec_helper'
describe Gitlab::EtagCaching::Router do
it 'matches issue notes endpoint' do
env = build_env(
'/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'issue_notes'
end
it 'matches issue title endpoint' do
env = build_env(
'/my-group/my-project/issues/123/rendered_title'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'issue_title'
end
it 'matches project pipelines endpoint' do
env = build_env(
'/my-group/my-project/pipelines.json'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'project_pipelines'
end
it 'matches commit pipelines endpoint' do
env = build_env(
'/my-group/my-project/commit/aa8260d253a53f73f6c26c734c72fdd600f6e6d4/pipelines.json'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'commit_pipelines'
end
it 'matches new merge request pipelines endpoint' do
env = build_env(
'/my-group/my-project/merge_requests/new.json'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'new_merge_request_pipelines'
end
it 'matches merge request pipelines endpoint' do
env = build_env(
'/my-group/my-project/merge_requests/234/pipelines.json'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'merge_request_pipelines'
end
it 'does not match blob with confusing name' do
env = build_env(
'/my-group/my-project/blob/master/pipelines.json'
)
result = described_class.match(env)
expect(result).to be_blank
end
def build_env(path)
{ 'PATH_INFO' => path }
end
end
require 'spec_helper'
# Check consistency of db/schema.rb version, migrations' timestamps, and the latest migration timestamp
# stored in the database's schema_migrations table.
describe ActiveRecord::Schema do
let(:latest_migration_timestamp) do
migrations = Dir[Rails.root.join('db', 'migrate', '*'), Rails.root.join('db', 'post_migrate', '*')]
migrations.map { |migration| File.basename(migration).split('_').first.to_i }.max
end
it '> schema version equals last migration timestamp' do
defined_schema_version = File.open(Rails.root.join('db', 'schema.rb')) do |file|
file.find { |line| line =~ /ActiveRecord::Schema.define/ }
end.match(/(\d+)/)[0].to_i
expect(defined_schema_version).to eq(latest_migration_timestamp)
end
it '> schema version should equal the latest migration timestamp stored in schema_migrations table' do
expect(latest_migration_timestamp).to eq(ActiveRecord::Migrator.current_version.to_i)
end
end
......@@ -55,13 +55,13 @@ describe Blob do
describe '#pdf?' do
it 'is falsey when file extension is not .pdf' do
git_blob = double(name: 'git_blob.txt')
git_blob = Gitlab::Git::Blob.new(name: 'git_blob.txt')
expect(described_class.decorate(git_blob)).not_to be_pdf
end
it 'is truthy when file extension is .pdf' do
git_blob = double(name: 'git_blob.pdf')
git_blob = Gitlab::Git::Blob.new(name: 'git_blob.pdf')
expect(described_class.decorate(git_blob)).to be_pdf
end
......@@ -140,7 +140,7 @@ describe Blob do
stl?: false
)
described_class.decorate(double).tap do |blob|
described_class.decorate(Gitlab::Git::Blob.new({})).tap do |blob|
allow(blob).to receive_messages(overrides)
end
end
......@@ -158,7 +158,7 @@ describe Blob do
it 'handles SVGs' do
blob = stubbed_blob(text?: true, svg?: true)
expect(blob.to_partial_path(project)).to eq 'image'
expect(blob.to_partial_path(project)).to eq 'svg'
end
it 'handles images' do
......@@ -167,7 +167,7 @@ describe Blob do
end
it 'handles text' do
blob = stubbed_blob(text?: true)
blob = stubbed_blob(text?: true, name: 'test.txt')
expect(blob.to_partial_path(project)).to eq 'text'
end
......
......@@ -1309,8 +1309,6 @@ describe Repository, models: true do
describe '#after_import' do
it 'flushes and builds the cache' do
expect(repository).to receive(:expire_content_cache)
expect(repository).to receive(:expire_tags_cache)
expect(repository).to receive(:expire_branches_cache)
repository.after_import
end
......
......@@ -222,6 +222,22 @@ describe API::Internal, api: true do
end
end
context 'with env passed as a JSON' do
it 'sets env in RequestStore' do
expect(Gitlab::Git::Env).to receive(:set).with({
'GIT_OBJECT_DIRECTORY' => 'foo',
'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
})
push(key, project.wiki, env: {
GIT_OBJECT_DIRECTORY: 'foo',
GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar'
}.to_json)
expect(response).to have_http_status(200)
end
end
context "git push with project.wiki" do
it 'responds with success' do
push(key, project.wiki)
......
......@@ -1216,6 +1216,22 @@ describe NotificationService, services: true do
should_not_email(@u_disabled)
end
end
describe '#project_exported' do
it do
notification.project_exported(project, @u_disabled)
should_only_email(@u_disabled)
end
end
describe '#project_not_exported' do
it do
notification.project_not_exported(project, @u_disabled, ['error'])
should_only_email(@u_disabled)
end
end
end
describe 'GroupMember' do
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment