Commit 0bf399f5 authored by Lin Jen-Shin (godfat)'s avatar Lin Jen-Shin (godfat)

Merge branch 'ce_upstream' into 'master'

CE upstream

Closes #2709, gitaly#654, and gitlab-ce#36417

See merge request gitlab-org/gitlab-ee!3159
parents 732750de 35de9283
...@@ -414,7 +414,7 @@ group :ed25519 do ...@@ -414,7 +414,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.41.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.42.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
......
...@@ -297,7 +297,7 @@ GEM ...@@ -297,7 +297,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly-proto (0.41.0) gitaly-proto (0.42.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -349,7 +349,9 @@ GEM ...@@ -349,7 +349,9 @@ GEM
mime-types (~> 3.0) mime-types (~> 3.0)
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.0) retriable (>= 2.0, < 4.0)
google-protobuf (3.4.0.2) google-protobuf (3.4.1.1)
googleapis-common-protos-types (1.0.0)
google-protobuf (~> 3.0)
googleauth (0.5.3) googleauth (0.5.3)
faraday (~> 0.12) faraday (~> 0.12)
jwt (~> 1.4) jwt (~> 1.4)
...@@ -376,8 +378,9 @@ GEM ...@@ -376,8 +378,9 @@ GEM
rake rake
grape_logging (1.7.0) grape_logging (1.7.0)
grape grape
grpc (1.6.0) grpc (1.6.6)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (~> 0.5.1) googleauth (~> 0.5.1)
gssapi (1.2.0) gssapi (1.2.0)
ffi (>= 1.0.1) ffi (>= 1.0.1)
...@@ -1062,7 +1065,7 @@ DEPENDENCIES ...@@ -1062,7 +1065,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.41.0) gitaly-proto (~> 0.42.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
......
...@@ -7,7 +7,7 @@ class BoardService { ...@@ -7,7 +7,7 @@ class BoardService {
this.boards = Vue.resource(`${boardsEndpoint}{/id}.json`, {}, { this.boards = Vue.resource(`${boardsEndpoint}{/id}.json`, {}, {
issues: { issues: {
method: 'GET', method: 'GET',
url: `${gon.relative_url_root}/boards/${boardId}/issues.json`, url: `${gon.relative_url_root}/-/boards/${boardId}/issues.json`,
} }
}); });
this.lists = Vue.resource(`${listsEndpoint}{/id}`, {}, { this.lists = Vue.resource(`${listsEndpoint}{/id}`, {}, {
...@@ -16,7 +16,7 @@ class BoardService { ...@@ -16,7 +16,7 @@ class BoardService {
url: `${listsEndpoint}/generate.json` url: `${listsEndpoint}/generate.json`
} }
}); });
this.issue = Vue.resource(`${gon.relative_url_root}/boards/${boardId}/issues{/id}`, {}); this.issue = Vue.resource(`${gon.relative_url_root}/-/boards/${boardId}/issues{/id}`, {});
this.issues = Vue.resource(`${listsEndpoint}{/id}/issues`, {}, { this.issues = Vue.resource(`${listsEndpoint}{/id}/issues`, {}, {
bulkUpdate: { bulkUpdate: {
method: 'POST', method: 'POST',
......
...@@ -40,6 +40,10 @@ const createFlashEl = (message, type, isInContentWrapper = false) => ` ...@@ -40,6 +40,10 @@ const createFlashEl = (message, type, isInContentWrapper = false) => `
</div> </div>
`; `;
const removeFlashClickListener = (flashEl, fadeTransition) => {
flashEl.parentNode.addEventListener('click', () => hideFlash(flashEl, fadeTransition));
};
/* /*
* Flash banner supports different types of Flash configurations * Flash banner supports different types of Flash configurations
* along with ability to provide actionConfig which can be used to show * along with ability to provide actionConfig which can be used to show
...@@ -70,7 +74,7 @@ const createFlash = function createFlash( ...@@ -70,7 +74,7 @@ const createFlash = function createFlash(
flashContainer.innerHTML = createFlashEl(message, type, isInContentWrapper); flashContainer.innerHTML = createFlashEl(message, type, isInContentWrapper);
const flashEl = flashContainer.querySelector(`.flash-${type}`); const flashEl = flashContainer.querySelector(`.flash-${type}`);
flashEl.addEventListener('click', () => hideFlash(flashEl, fadeTransition)); removeFlashClickListener(flashEl, fadeTransition);
if (actionConfig) { if (actionConfig) {
flashEl.innerHTML += createAction(actionConfig); flashEl.innerHTML += createAction(actionConfig);
...@@ -90,5 +94,6 @@ export { ...@@ -90,5 +94,6 @@ export {
createFlashEl, createFlashEl,
createAction, createAction,
hideFlash, hideFlash,
removeFlashClickListener,
}; };
window.Flash = createFlash; window.Flash = createFlash;
...@@ -43,16 +43,6 @@ ...@@ -43,16 +43,6 @@
type: 'link', type: 'link',
}); });
} }
if (this.job.retry_path) {
actions.push({
label: 'Retry',
path: this.job.retry_path,
cssClass: 'js-retry-button btn btn-inverted-secondary visible-md-block visible-lg-block',
type: 'ujs-link',
});
}
return actions; return actions;
}, },
}, },
......
...@@ -403,7 +403,11 @@ export const setCiStatusFavicon = (pageUrl) => { ...@@ -403,7 +403,11 @@ export const setCiStatusFavicon = (pageUrl) => {
}); });
}; };
export const spriteIcon = icon => `<svg><use xlink:href="${gon.sprite_icons}#${icon}" /></svg>`; export const spriteIcon = (icon, className = '') => {
const classAttribute = className.length > 0 ? `class="${className}"` : '';
return `<svg ${classAttribute}><use xlink:href="${gon.sprite_icons}#${icon}" /></svg>`;
};
export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`;
......
...@@ -54,7 +54,7 @@ import './diff'; ...@@ -54,7 +54,7 @@ import './diff';
import './dropzone_input'; import './dropzone_input';
import './due_date_select'; import './due_date_select';
import './files_comment_button'; import './files_comment_button';
import Flash from './flash'; import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown'; import './gl_dropdown';
import './gl_field_error'; import './gl_field_error';
import './gl_field_errors'; import './gl_field_errors';
...@@ -344,4 +344,9 @@ $(function () { ...@@ -344,4 +344,9 @@ $(function () {
* EE specific scripts * EE specific scripts
*/ */
$('#modal-upload-trial-license').modal('show'); $('#modal-upload-trial-license').modal('show');
const flashContainer = document.querySelector('.flash-container');
if (flashContainer && flashContainer.children.length) {
removeFlashClickListener(flashContainer.children[0]);
}
}); });
...@@ -22,7 +22,8 @@ const RepoEditor = { ...@@ -22,7 +22,8 @@ const RepoEditor = {
const monacoInstance = Helper.monaco.editor.create(this.$el, { const monacoInstance = Helper.monaco.editor.create(this.$el, {
model: null, model: null,
readOnly: false, readOnly: false,
contextmenu: false, contextmenu: true,
scrollBeyondLastLine: false,
}); });
Helper.monacoInstance = monacoInstance; Helper.monacoInstance = monacoInstance;
......
...@@ -838,6 +838,7 @@ ...@@ -838,6 +838,7 @@
a { a {
padding: 8px 40px; padding: 8px 40px;
&.is-indeterminate::before,
&.is-active::before { &.is-active::before {
left: 16px; left: 16px;
} }
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
border: 0; border: 0;
} }
&.file-holder-bottom-radius {
border-radius: 0 0 $border-radius-small $border-radius-small;
}
&.readme-holder { &.readme-holder {
margin: $gl-padding 0; margin: $gl-padding 0;
......
...@@ -234,6 +234,7 @@ $container-text-max-width: 540px; ...@@ -234,6 +234,7 @@ $container-text-max-width: 540px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$error-exclamation-point: $red-500; $error-exclamation-point: $red-500;
$border-radius-default: 4px; $border-radius-default: 4px;
$border-radius-small: 2px;
$settings-icon-size: 18px; $settings-icon-size: 18px;
$provider-btn-not-active-color: $blue-500; $provider-btn-not-active-color: $blue-500;
$link-underline-blue: $blue-500; $link-underline-blue: $blue-500;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
border-right: 1px solid $border-color; border-right: 1px solid $border-color;
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
border-bottom: none; border-bottom: none;
border-radius: 2px; border-radius: $border-radius-small $border-radius-small 0 0;
background: $gray-normal; background: $gray-normal;
} }
......
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
} }
.right-sidebar { .right-sidebar {
a, a:not(.btn-retry),
.btn-link { .btn-link {
color: inherit; color: inherit;
} }
...@@ -459,7 +459,7 @@ ...@@ -459,7 +459,7 @@
} }
} }
a { a:not(.btn-retry) {
&:hover { &:hover {
color: $md-link-color; color: $md-link-color;
text-decoration: none; text-decoration: none;
......
...@@ -7,6 +7,9 @@ module Gcp ...@@ -7,6 +7,9 @@ module Gcp
belongs_to :user belongs_to :user
belongs_to :service belongs_to :service
scope :enabled, -> { where(enabled: true) }
scope :disabled, -> { where(enabled: false) }
default_value_for :gcp_cluster_zone, 'us-central1-a' default_value_for :gcp_cluster_zone, 'us-central1-a'
default_value_for :gcp_cluster_size, 3 default_value_for :gcp_cluster_size, 3
default_value_for :gcp_machine_type, 'n1-standard-4' default_value_for :gcp_machine_type, 'n1-standard-4'
......
...@@ -404,7 +404,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -404,7 +404,7 @@ class MergeRequest < ActiveRecord::Base
end end
def merge_ongoing? def merge_ongoing?
!!merge_jid && !merged? !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid)
end end
def closed_without_fork? def closed_without_fork?
......
...@@ -28,6 +28,8 @@ module Ci ...@@ -28,6 +28,8 @@ module Ci
attributes.push([:user, current_user]) attributes.push([:user, current_user])
build.retried = true
Ci::Build.transaction do Ci::Build.transaction do
# mark all other builds of that name as retried # mark all other builds of that name as retried
build.pipeline.builds.latest build.pipeline.builds.latest
......
...@@ -3,7 +3,7 @@ module MergeRequests ...@@ -3,7 +3,7 @@ module MergeRequests
# Adds a todo to the parent merge_request when a CI build fails # Adds a todo to the parent merge_request when a CI build fails
# #
def execute(commit_status) def execute(commit_status)
return if commit_status.allow_failure? return if commit_status.allow_failure? || commit_status.retried?
commit_status_merge_requests(commit_status) do |merge_request| commit_status_merge_requests(commit_status) do |merge_request|
todo_service.merge_request_build_failed(merge_request) todo_service.merge_request_build_failed(merge_request)
......
...@@ -15,10 +15,6 @@ ...@@ -15,10 +15,6 @@
%tr %tr
%th %th
%th Global Shortcuts %th Global Shortcuts
%tr
%td.shortcut
.key n
%td Main Navigation
%tr %tr
%td.shortcut %td.shortcut
.key s .key s
......
- action = current_action?(:edit) || current_action?(:update) ? 'edit' : 'create' - action = current_action?(:edit) || current_action?(:update) ? 'edit' : 'create'
.file-holder.file.append-bottom-default .file-holder-bottom-radius.file-holder.file.append-bottom-default
.js-file-title.file-title.clearfix{ data: { current_action: action } } .js-file-title.file-title.clearfix{ data: { current_action: action } }
.editor-ref .editor-ref
= icon('code-fork') = icon('code-fork')
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
.sidebar-container .sidebar-container
.blocks-container .blocks-container
.block .block
%strong %strong.prepend-top-10
= @build.name = @build.name
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry", retry_namespace_project_job_path(@project.namespace, @project, @build), class: 'js-retry-button pull-right btn btn-inverted-secondary btn-retry visible-md-block visible-lg-block', method: :post
%a.gutter-toggle.pull-right.visible-xs-block.visible-sm-block.js-sidebar-build-toggle{ href: "#", 'aria-label': 'Toggle Sidebar', role: 'button' } %a.gutter-toggle.pull-right.visible-xs-block.visible-sm-block.js-sidebar-build-toggle{ href: "#", 'aria-label': 'Toggle Sidebar', role: 'button' }
= icon('angle-double-right') = icon('angle-double-right')
......
...@@ -54,6 +54,10 @@ ...@@ -54,6 +54,10 @@
= f.label :visibility_level, class: 'label-light' do #the label here seems wrong = f.label :visibility_level, class: 'label-light' do #the label here seems wrong
Import project from Import project from
.import-buttons .import-buttons
- if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body' } }
= link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do
= icon('gitlab', text: 'GitLab export')
%div %div
- if github_import_enabled? - if github_import_enabled?
= link_to new_import_github_path, class: 'btn import_github' do = link_to new_import_github_path, class: 'btn import_github' do
...@@ -87,10 +91,6 @@ ...@@ -87,10 +91,6 @@
- if git_import_enabled? - if git_import_enabled?
%button.btn.js-toggle-button.import_git{ type: "button" } %button.btn.js-toggle-button.import_git{ type: "button" }
= icon('git', text: 'Repo by URL') = icon('git', text: 'Repo by URL')
- if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body' } }
= link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do
= icon('gitlab', text: 'GitLab export')
.col-lg-12 .col-lg-12
.js-toggle-content.hide.toggle-import-form .js-toggle-content.hide.toggle-import-form
%hr %hr
......
...@@ -28,6 +28,7 @@ class ChangelogOptionParser ...@@ -28,6 +28,7 @@ class ChangelogOptionParser
Type.new('deprecated', 'New deprecation'), Type.new('deprecated', 'New deprecation'),
Type.new('removed', 'Feature removal'), Type.new('removed', 'Feature removal'),
Type.new('security', 'Security fix'), Type.new('security', 'Security fix'),
Type.new('performance', 'Performance improvement'),
Type.new('other', 'Other') Type.new('other', 'Other')
].freeze ].freeze
TYPES_OFFSET = 1 TYPES_OFFSET = 1
......
---
title: Move retry button in job page to sidebar
merge_request:
author:
type: fixed
---
title: Replace WikiPage::CreateService calls with wiki_page factory in specs
merge_request: 14850
author: Jacopo Beschi @jacopo-beschi
type: changed
---
title: Removed extra border radius from .file-editor and .file-holder when editing
a file
merge_request: 14803
author: Rachel Pipkin
type: fixed
---
title: Don't create build failed todos when the job is automatically retried
merge_request:
author:
type: fixed
---
title: Make usage ping scheduling more robust
merge_request:
author:
type: fixed
---
title: Make "merge ongoing" check more consistent
merge_request:
author:
type: fixed
---
title: 14830 Move GitLab export option to top of import list when creating a new project
merge_request:
author:
type: changed
---
title: Fix diff parser so it tolerates to diff special markers in the content
merge_request:
author:
type: fixed
---
title: Allow boards as top level route
merge_request:
author:
type: fixed
---
title: Fix 404 errors in API caused when the branch name had a dot
merge_request: 14462
author: gvieira37
type: fixed
---
title: Fix alignment for indeterminate marker in dropdowns
merge_request: 14809
author:
type: fixed
---
title: Add Performance improvement as category on the changelog
merge_request:
author:
type: performance
...@@ -138,12 +138,14 @@ class Settings < Settingslogic ...@@ -138,12 +138,14 @@ class Settings < Settingslogic
URI.parse(url_without_path).host URI.parse(url_without_path).host
end end
# Random cron time every Sunday to load balance usage pings # Runs every minute in a random ten-minute period on Sundays, to balance the
def cron_random_weekly_time # load on the server receiving these pings. The usage ping is safe to run
# multiple times because of a 24 hour exclusive lock.
def cron_for_usage_ping
hour = rand(24) hour = rand(24)
minute = rand(60) minute = rand(6)
"#{minute} #{hour} * * 0" "#{minute}0-#{minute}9 #{hour} * * 0"
end end
end end
end end
...@@ -473,7 +475,7 @@ Settings.cron_jobs['stuck_import_jobs_worker'] ||= Settingslogic.new({}) ...@@ -473,7 +475,7 @@ Settings.cron_jobs['stuck_import_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_import_jobs_worker']['cron'] ||= '15 * * * *' Settings.cron_jobs['stuck_import_jobs_worker']['cron'] ||= '15 * * * *'
Settings.cron_jobs['stuck_import_jobs_worker']['job_class'] = 'StuckImportJobsWorker' Settings.cron_jobs['stuck_import_jobs_worker']['job_class'] = 'StuckImportJobsWorker'
Settings.cron_jobs['gitlab_usage_ping_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['gitlab_usage_ping_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['gitlab_usage_ping_worker']['cron'] ||= Settings.__send__(:cron_random_weekly_time) Settings.cron_jobs['gitlab_usage_ping_worker']['cron'] ||= Settings.__send__(:cron_for_usage_ping)
Settings.cron_jobs['gitlab_usage_ping_worker']['job_class'] = 'GitlabUsagePingWorker' Settings.cron_jobs['gitlab_usage_ping_worker']['job_class'] = 'GitlabUsagePingWorker'
Settings.cron_jobs['schedule_update_user_activity_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['schedule_update_user_activity_worker'] ||= Settingslogic.new({})
......
...@@ -59,6 +59,19 @@ Rails.application.routes.draw do ...@@ -59,6 +59,19 @@ Rails.application.routes.draw do
get 'readiness' => 'health#readiness' get 'readiness' => 'health#readiness'
resources :metrics, only: [:index] resources :metrics, only: [:index]
mount Peek::Railtie => '/peek' mount Peek::Railtie => '/peek'
# Boards resources shared between group and projects
resources :boards, only: [] do
resources :lists, module: :boards, only: [:index, :create, :update, :destroy] do
collection do
post :generate
end
resources :issues, only: [:index, :create, :update]
end
resources :issues, module: :boards, only: [:index, :update]
end
end end
# Koding route # Koding route
...@@ -89,19 +102,6 @@ Rails.application.routes.draw do ...@@ -89,19 +102,6 @@ Rails.application.routes.draw do
# Notification settings # Notification settings
resources :notification_settings, only: [:create, :update] resources :notification_settings, only: [:create, :update]
# Boards resources shared between group and projects
resources :boards do
resources :lists, module: :boards, only: [:index, :create, :update, :destroy] do
collection do
post :generate
end
resources :issues, only: [:index, :create, :update]
end
resources :issues, module: :boards, only: [:index, :update]
end
draw :google_api draw :google_api
draw :import draw :import
draw :uploads draw :uploads
......
...@@ -248,7 +248,7 @@ var config = { ...@@ -248,7 +248,7 @@ var config = {
from: path.join(ROOT_PATH, `node_modules/monaco-editor/${IS_PRODUCTION ? 'min' : 'dev'}/vs`), from: path.join(ROOT_PATH, `node_modules/monaco-editor/${IS_PRODUCTION ? 'min' : 'dev'}/vs`),
to: 'monaco-editor/vs', to: 'monaco-editor/vs',
transform: function(content, path) { transform: function(content, path) {
if (/\.js$/.test(path) && !/worker/i.test(path)) { if (/\.js$/.test(path) && !/worker/i.test(path) && !/typescript/i.test(path)) {
return ( return (
'(function(){\n' + '(function(){\n' +
'var define = this.define, require = this.require;\n' + 'var define = this.define, require = this.require;\n' +
......
...@@ -85,7 +85,7 @@ GET /projects/:id/repository/blobs/:sha ...@@ -85,7 +85,7 @@ GET /projects/:id/repository/blobs/:sha
Parameters: Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user - `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `sha` (required) - The commit or branch name - `sha` (required) - The blob SHA
## Raw blob content ## Raw blob content
......
...@@ -102,7 +102,7 @@ PUT /application/settings ...@@ -102,7 +102,7 @@ PUT /application/settings
| `gravatar_enabled` | boolean | no | Enable Gravatar | | `gravatar_enabled` | boolean | no | Enable Gravatar |
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help | | `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help |
| `help_page_support_url` | string | no | Alternate support URL for help page | | `help_page_support_url` | string | no | Alternate support URL for help page |
| `help_text` | string | no | GitLab server administrator information | | `help_text` | string | no | GitLab server administrator information
| `home_page_url` | string | no | Redirect to this URL when not logged in | | `home_page_url` | string | no | Redirect to this URL when not logged in |
| `housekeeping_bitmaps_enabled` | boolean | no | Enable Git pack file bitmap creation | | `housekeeping_bitmaps_enabled` | boolean | no | Enable Git pack file bitmap creation |
| `housekeeping_enabled` | boolean | no | Enable or disable git housekeeping | | `housekeeping_enabled` | boolean | no | Enable or disable git housekeeping |
...@@ -146,8 +146,7 @@ PUT /application/settings ...@@ -146,8 +146,7 @@ PUT /application/settings
| `sentry_enabled` | boolean | no | Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here: https://getsentry.com | | `sentry_enabled` | boolean | no | Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here: https://getsentry.com |
| `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes | | `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes |
| `shared_runners_enabled` | true | no | Enable shared runners for new projects | | `shared_runners_enabled` | true | no | Enable shared runners for new projects |
| `shared_runners_minutes` | integer | yes (if `shared_runners_enabled` is true) | Set the maximum number of pipeline minutes that a group can use on shared Runners per month. | | `shared_runners_minutes` | integer | yes (if `shared_runners_enabled` is true) | Set the maximum number of pipeline minutes that a group can use on shared Runners per month. | `shared_runners_text` | string | no | Shared runners text |
| `shared_runners_text` | string | no | Shared runners text |
| `sidekiq_throttling_enabled` | boolean | no | Enable Sidekiq Job Throttling | | `sidekiq_throttling_enabled` | boolean | no | Enable Sidekiq Job Throttling |
| `sidekiq_throttling_factor` | decimal | yes (if `sidekiq_throttling_enabled` is true) | The factor by which the queues should be throttled. A value between 0.0 and 1.0, exclusive. | | `sidekiq_throttling_factor` | decimal | yes (if `sidekiq_throttling_enabled` is true) | The factor by which the queues should be throttled. A value between 0.0 and 1.0, exclusive. |
| `sidekiq_throttling_queues` | array of strings | yes (if `sidekiq_throttling_enabled` is true) | Choose which queues you wish to throttle | | `sidekiq_throttling_queues` | array of strings | yes (if `sidekiq_throttling_enabled` is true) | Choose which queues you wish to throttle |
...@@ -156,8 +155,7 @@ PUT /application/settings ...@@ -156,8 +155,7 @@ PUT /application/settings
| `slack_app_enabled` | boolean | no | Enable Slack ap | | `slack_app_enabled` | boolean | no | Enable Slack ap |
| `slack_app_id` | string | yes (if `slack_app_enabled` is true) | The app id of the Slack-app | | `slack_app_id` | string | yes (if `slack_app_enabled` is true) | The app id of the Slack-app |
| `slack_app_secret` | string | yes (if `slack_app_enabled` is true) | The app secret of the Slack-app | | `slack_app_secret` | string | yes (if `slack_app_enabled` is true) | The app secret of the Slack-app |
| `slack_app_verification_token` | string | yes (if `slack_app_enabled` is true) | The verification token of the Slack-app | | `slack_app_verification_token` | string | yes (if `slack_app_enabled` is true) | The verification token of the Slack-app | `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time. |
| `two_factor_grace_period` | integer | no | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication | | `two_factor_grace_period` | integer | no | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication |
| `unique_ips_limit_enabled` | boolean | no | Limit sign in from multiple ips | | `unique_ips_limit_enabled` | boolean | no | Limit sign in from multiple ips |
| `unique_ips_limit_per_user` | integer | yes (if `unique_ips_limit_enabled` is true) | Maximum number of ips per user | | `unique_ips_limit_per_user` | integer | yes (if `unique_ips_limit_enabled` is true) | Maximum number of ips per user |
......
...@@ -42,7 +42,7 @@ digging into specific reference guides. ...@@ -42,7 +42,7 @@ digging into specific reference guides.
- **The permissions model** - Learn about the access levels a user can have for - **The permissions model** - Learn about the access levels a user can have for
performing certain CI actions performing certain CI actions
- [User permissions](../user/permissions.md#gitlab-ci) - [User permissions](../user/permissions.md#gitlab-ci)
- [Jobs permissions](../user/permissions.md#jobs-permissions) - [Job permissions](../user/permissions.md#job-permissions)
## Auto DevOps ## Auto DevOps
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
[Project Templates](https://gitlab.com/gitlab-org/project-templates): [Project Templates](https://gitlab.com/gitlab-org/project-templates):
this will kickstart your repository code and CI automatically. this will kickstart your repository code and CI automatically.
Otherwise, if you have a project in a different repository, you can [import it] by Otherwise, if you have a project in a different repository, you can [import it] by
clicking an **Import project from** button provided this is enabled in clicking on the **Import project** tab, provided this is enabled in
your GitLab instance. Ask your administrator if not. your GitLab instance. Ask your administrator if not.
1. Provide the following information: 1. Provide the following information:
......
...@@ -123,8 +123,8 @@ Existing users using GitLab with MySQL/MariaDB are advised to ...@@ -123,8 +123,8 @@ Existing users using GitLab with MySQL/MariaDB are advised to
### PostgreSQL Requirements ### PostgreSQL Requirements
As of GitLab 9.3, PostgreSQL 9.2 or newer is required, and earlier versions are As of GitLab 10.0, PostgreSQL 9.6 or newer is required, and earlier versions are
not supported. We highly recommend users to use at least PostgreSQL 9.6 as this not supported. We highly recommend users to use PostgreSQL 9.6 as this
is the PostgreSQL version used for development and testing. is the PostgreSQL version used for development and testing.
Users using PostgreSQL must ensure the `pg_trgm` extension is loaded into every Users using PostgreSQL must ensure the `pg_trgm` extension is loaded into every
......
...@@ -19,7 +19,7 @@ When not specified, the default issue closing pattern as shown below will be ...@@ -19,7 +19,7 @@ When not specified, the default issue closing pattern as shown below will be
used: used:
```bash ```bash
((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+) ((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)
``` ```
Note that `%{issue_ref}` is a complex regular expression defined inside GitLab's Note that `%{issue_ref}` is a complex regular expression defined inside GitLab's
...@@ -34,6 +34,7 @@ This translates to the following keywords: ...@@ -34,6 +34,7 @@ This translates to the following keywords:
- Close, Closes, Closed, Closing, close, closes, closed, closing - Close, Closes, Closed, Closing, close, closes, closed, closing
- Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing - Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing
- Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving - Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving
- Implement, Implements, Implemented, Implementing, implement, implements, implemented, implementing
--- ---
......
...@@ -4,6 +4,10 @@ module API ...@@ -4,6 +4,10 @@ module API
LOG_FILENAME = Rails.root.join("log", "api_json.log") LOG_FILENAME = Rails.root.join("log", "api_json.log")
NO_SLASH_URL_PART_REGEX = %r{[^/]+}
PROJECT_ENDPOINT_REQUIREMENTS = { id: NO_SLASH_URL_PART_REGEX }.freeze
COMMIT_ENDPOINT_REQUIREMENTS = PROJECT_ENDPOINT_REQUIREMENTS.merge(sha: NO_SLASH_URL_PART_REGEX).freeze
use GrapeLogging::Middleware::RequestLogger, use GrapeLogging::Middleware::RequestLogger,
logger: Logger.new(LOG_FILENAME), logger: Logger.new(LOG_FILENAME),
formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new, formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new,
...@@ -105,9 +109,6 @@ module API ...@@ -105,9 +109,6 @@ module API
helpers ::API::Helpers helpers ::API::Helpers
helpers ::API::Helpers::CommonHelpers helpers ::API::Helpers::CommonHelpers
NO_SLASH_URL_PART_REGEX = %r{[^/]+}
PROJECT_ENDPOINT_REQUIREMENTS = { id: NO_SLASH_URL_PART_REGEX }.freeze
# Keep in alphabetical order # Keep in alphabetical order
mount ::API::AccessRequests mount ::API::AccessRequests
mount ::API::AwardEmoji mount ::API::AwardEmoji
......
...@@ -4,8 +4,6 @@ module API ...@@ -4,8 +4,6 @@ module API
class Commits < Grape::API class Commits < Grape::API
include PaginationParams include PaginationParams
COMMIT_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(sha: API::NO_SLASH_URL_PART_REGEX)
before { authorize! :download_code, user_project } before { authorize! :download_code, user_project }
params do params do
...@@ -85,7 +83,7 @@ module API ...@@ -85,7 +83,7 @@ module API
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ':id/repository/commits/:sha', requirements: COMMIT_ENDPOINT_REQUIREMENTS do get ':id/repository/commits/:sha', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -99,7 +97,7 @@ module API ...@@ -99,7 +97,7 @@ module API
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ':id/repository/commits/:sha/diff', requirements: COMMIT_ENDPOINT_REQUIREMENTS do get ':id/repository/commits/:sha/diff', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -115,7 +113,7 @@ module API ...@@ -115,7 +113,7 @@ module API
use :pagination use :pagination
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ':id/repository/commits/:sha/comments', requirements: COMMIT_ENDPOINT_REQUIREMENTS do get ':id/repository/commits/:sha/comments', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -132,7 +130,7 @@ module API ...@@ -132,7 +130,7 @@ module API
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
requires :branch, type: String, desc: 'The name of the branch' requires :branch, type: String, desc: 'The name of the branch'
end end
post ':id/repository/commits/:sha/cherry_pick', requirements: COMMIT_ENDPOINT_REQUIREMENTS do post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
authorize! :push_code, user_project authorize! :push_code, user_project
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
...@@ -169,7 +167,7 @@ module API ...@@ -169,7 +167,7 @@ module API
requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line' requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line'
end end
end end
post ':id/repository/commits/:sha/comments', requirements: COMMIT_ENDPOINT_REQUIREMENTS do post ':id/repository/commits/:sha/comments', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
......
...@@ -57,7 +57,7 @@ module API ...@@ -57,7 +57,7 @@ module API
desc 'Get raw blob contents from the repository' desc 'Get raw blob contents from the repository'
params do params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit hash'
end end
get ':id/repository/blobs/:sha/raw' do get ':id/repository/blobs/:sha/raw' do
assign_blob_vars! assign_blob_vars!
...@@ -67,7 +67,7 @@ module API ...@@ -67,7 +67,7 @@ module API
desc 'Get a blob from the repository' desc 'Get a blob from the repository'
params do params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit hash'
end end
get ':id/repository/blobs/:sha' do get ':id/repository/blobs/:sha' do
assign_blob_vars! assign_blob_vars!
......
...@@ -8,7 +8,7 @@ module API ...@@ -8,7 +8,7 @@ module API
params do params do
requires :id, type: String, desc: 'The ID of a project' requires :id, type: String, desc: 'The ID of a project'
end end
resource :projects do resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
helpers do helpers do
params :optional_scope do params :optional_scope do
optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show', optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
......
...@@ -11,7 +11,7 @@ module API ...@@ -11,7 +11,7 @@ module API
params do params do
requires :id, type: String, desc: 'The ID of a project' requires :id, type: String, desc: 'The ID of a project'
end end
resource :projects, requirements: { id: %r{[^/]+} } do resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository commits' do desc 'Get a project repository commits' do
success ::API::Entities::Commit success ::API::Entities::Commit
end end
...@@ -72,7 +72,7 @@ module API ...@@ -72,7 +72,7 @@ module API
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ":id/repository/commits/:sha" do get ":id/repository/commits/:sha", requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit not_found! "Commit" unless commit
...@@ -86,7 +86,7 @@ module API ...@@ -86,7 +86,7 @@ module API
params do params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ":id/repository/commits/:sha/diff" do get ":id/repository/commits/:sha/diff", requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit not_found! "Commit" unless commit
...@@ -102,7 +102,7 @@ module API ...@@ -102,7 +102,7 @@ module API
use :pagination use :pagination
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end end
get ':id/repository/commits/:sha/comments' do get ':id/repository/commits/:sha/comments', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -119,7 +119,7 @@ module API ...@@ -119,7 +119,7 @@ module API
requires :sha, type: String, desc: 'A commit sha to be cherry picked' requires :sha, type: String, desc: 'A commit sha to be cherry picked'
requires :branch, type: String, desc: 'The name of the branch' requires :branch, type: String, desc: 'The name of the branch'
end end
post ':id/repository/commits/:sha/cherry_pick' do post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
authorize! :push_code, user_project authorize! :push_code, user_project
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
...@@ -156,7 +156,7 @@ module API ...@@ -156,7 +156,7 @@ module API
requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line' requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line'
end end
end end
post ':id/repository/commits/:sha/comments' do post ':id/repository/commits/:sha/comments', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
......
...@@ -8,7 +8,7 @@ module API ...@@ -8,7 +8,7 @@ module API
params do params do
requires :id, type: String, desc: 'The ID of a project' requires :id, type: String, desc: 'The ID of a project'
end end
resource :projects, requirements: { id: %r{[^/]+} } do resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
helpers do helpers do
def handle_project_member_errors(errors) def handle_project_member_errors(errors)
if errors[:project_access].any? if errors[:project_access].any?
...@@ -43,7 +43,7 @@ module API ...@@ -43,7 +43,7 @@ module API
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit, branch name, or tag name'
requires :filepath, type: String, desc: 'The path to the file to display' requires :filepath, type: String, desc: 'The path to the file to display'
end end
get [":id/repository/blobs/:sha", ":id/repository/commits/:sha/blob"] do get [":id/repository/blobs/:sha", ":id/repository/commits/:sha/blob"], requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
repo = user_project.repository repo = user_project.repository
commit = repo.commit(params[:sha]) commit = repo.commit(params[:sha])
not_found! "Commit" unless commit not_found! "Commit" unless commit
...@@ -56,7 +56,7 @@ module API ...@@ -56,7 +56,7 @@ module API
params do params do
requires :sha, type: String, desc: 'The commit, branch name, or tag name' requires :sha, type: String, desc: 'The commit, branch name, or tag name'
end end
get ':id/repository/raw_blobs/:sha' do get ':id/repository/raw_blobs/:sha', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
repo = user_project.repository repo = user_project.repository
begin begin
blob = Gitlab::Git::Blob.raw(repo, params[:sha]) blob = Gitlab::Git::Blob.raw(repo, params[:sha])
......
...@@ -17,7 +17,9 @@ module Gitlab ...@@ -17,7 +17,9 @@ module Gitlab
# without having to instantiate all the others that come after it. # without having to instantiate all the others that come after it.
Enumerator.new do |yielder| Enumerator.new do |yielder|
@lines.each do |line| @lines.each do |line|
next if filename?(line) # We're expecting a filename parameter only in a meta-part of the diff content
# when type is defined then we're already in a content-part
next if filename?(line) && type.nil?
full_line = line.delete("\n") full_line = line.delete("\n")
......
...@@ -3,9 +3,17 @@ module Gitlab ...@@ -3,9 +3,17 @@ module Gitlab
class OperationService class OperationService
include Gitlab::Git::Popen include Gitlab::Git::Popen
WithBranchResult = Struct.new(:newrev, :repo_created, :branch_created) do BranchUpdate = Struct.new(:newrev, :repo_created, :branch_created) do
alias_method :repo_created?, :repo_created alias_method :repo_created?, :repo_created
alias_method :branch_created?, :branch_created alias_method :branch_created?, :branch_created
def self.from_gitaly(branch_update)
new(
branch_update.commit_id,
branch_update.repo_created,
branch_update.branch_created
)
end
end end
attr_reader :user, :repository attr_reader :user, :repository
...@@ -117,7 +125,7 @@ module Gitlab ...@@ -117,7 +125,7 @@ module Gitlab
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
update_ref_in_hooks(ref, newrev, oldrev) update_ref_in_hooks(ref, newrev, oldrev)
WithBranchResult.new(newrev, was_empty, was_empty || Gitlab::Git.blank_ref?(oldrev)) BranchUpdate.new(newrev, was_empty, was_empty || Gitlab::Git.blank_ref?(oldrev))
end end
def find_oldrev_from_branch(newrev, branch) def find_oldrev_from_branch(newrev, branch)
......
...@@ -704,7 +704,17 @@ module Gitlab ...@@ -704,7 +704,17 @@ module Gitlab
tags.find { |tag| tag.name == name } tags.find { |tag| tag.name == name }
end end
def merge(user, source_sha, target_branch, message) def merge(user, source_sha, target_branch, message, &block)
gitaly_migrate(:operation_user_merge_branch) do |is_enabled|
if is_enabled
gitaly_operation_client.user_merge_branch(user, source_sha, target_branch, message, &block)
else
rugged_merge(user, source_sha, target_branch, message, &block)
end
end
end
def rugged_merge(user, source_sha, target_branch, message)
committer = Gitlab::Git.committer_hash(email: user.email, name: user.name) committer = Gitlab::Git.committer_hash(email: user.email, name: user.name)
OperationService.new(user, self).with_branch(target_branch) do |start_commit| OperationService.new(user, self).with_branch(target_branch) do |start_commit|
......
...@@ -70,15 +70,27 @@ module Gitlab ...@@ -70,15 +70,27 @@ module Gitlab
# All Gitaly RPC call sites should use GitalyClient.call. This method # All Gitaly RPC call sites should use GitalyClient.call. This method
# makes sure that per-request authentication headers are set. # makes sure that per-request authentication headers are set.
#
# This method optionally takes a block which receives the keyword
# arguments hash 'kwargs' that will be passed to gRPC. This allows the
# caller to modify or augment the keyword arguments. The block must
# return a hash.
#
# For example:
#
# GitalyClient.call(storage, service, rpc, request) do |kwargs|
# kwargs.merge(deadline: Time.now + 10)
# end
#
def self.call(storage, service, rpc, request) def self.call(storage, service, rpc, request)
enforce_gitaly_request_limits(:call) enforce_gitaly_request_limits(:call)
metadata = request_metadata(storage) kwargs = request_kwargs(storage)
metadata = yield(metadata) if block_given? kwargs = yield(kwargs) if block_given?
stub(service, storage).__send__(rpc, request, metadata) # rubocop:disable GitlabSecurity/PublicSend stub(service, storage).__send__(rpc, request, kwargs) # rubocop:disable GitlabSecurity/PublicSend
end end
def self.request_metadata(storage) def self.request_kwargs(storage)
encoded_token = Base64.strict_encode64(token(storage).to_s) encoded_token = Base64.strict_encode64(token(storage).to_s)
metadata = { metadata = {
'authorization' => "Bearer #{encoded_token}", 'authorization' => "Bearer #{encoded_token}",
......
...@@ -74,6 +74,37 @@ module Gitlab ...@@ -74,6 +74,37 @@ module Gitlab
raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error
end end
end end
def user_merge_branch(user, source_sha, target_branch, message)
request_enum = QueueEnumerator.new
response_enum = GitalyClient.call(
@repository.storage,
:operation_service,
:user_merge_branch,
request_enum.each
)
request_enum.push(
Gitaly::UserMergeBranchRequest.new(
repository: @gitaly_repo,
user: Util.gitaly_user(user),
commit_id: source_sha,
branch: GitalyClient.encode(target_branch),
message: GitalyClient.encode(message)
)
)
yield response_enum.next.commit_id
request_enum.push(Gitaly::UserMergeBranchRequest.new(apply: true))
branch_update = response_enum.next.branch_update
raise Gitlab::Git::CommitError.new('failed to apply merge to branch') unless branch_update.commit_id.present?
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(branch_update)
ensure
request_enum.close
end
end end
end end
end end
module Gitlab
module GitalyClient
class QueueEnumerator
def initialize
@queue = Queue.new
end
def push(elem)
@queue << elem
end
def close
push(:close)
end
def each
return enum_for(:each) unless block_given?
loop do
elem = @queue.pop
break if elem == :close
yield elem
end
end
end
end
end
...@@ -26,7 +26,6 @@ module Gitlab ...@@ -26,7 +26,6 @@ module Gitlab
apple-touch-icon.png apple-touch-icon.png
assets assets
autocomplete autocomplete
boards
ci ci
dashboard dashboard
deploy.html deploy.html
......
...@@ -51,6 +51,13 @@ module Gitlab ...@@ -51,6 +51,13 @@ module Gitlab
self.num_running(job_ids).zero? self.num_running(job_ids).zero?
end end
# Returns true if the given job is running
#
# job_id - The Sidekiq job ID to check.
def self.running?(job_id)
num_running([job_id]) > 0
end
# Returns the number of jobs that are running. # Returns the number of jobs that are running.
# #
# job_ids - The Sidekiq job IDs to check. # job_ids - The Sidekiq job IDs to check.
......
...@@ -45,6 +45,7 @@ module Gitlab ...@@ -45,6 +45,7 @@ module Gitlab
usage_data usage_data
end end
# rubocop:disable Metrics/AbcSize
def system_usage_data def system_usage_data
{ {
counts: { counts: {
...@@ -64,6 +65,8 @@ module Gitlab ...@@ -64,6 +65,8 @@ module Gitlab
environments: ::Environment.count, environments: ::Environment.count,
gcp_clusters: ::Gcp::Cluster.count, gcp_clusters: ::Gcp::Cluster.count,
geo_nodes: GeoNode.count, geo_nodes: GeoNode.count,
gcp_clusters_enabled: ::Gcp::Cluster.enabled.count,
gcp_clusters_disabled: ::Gcp::Cluster.disabled.count,
in_review_folder: ::Environment.in_review_folder.count, in_review_folder: ::Environment.in_review_folder.count,
groups: Group.count, groups: Group.count,
issues: Issue.count, issues: Issue.count,
......
...@@ -18,6 +18,7 @@ module QA ...@@ -18,6 +18,7 @@ module QA
# Support files # Support files
# #
autoload :Actable, 'qa/scenario/actable' autoload :Actable, 'qa/scenario/actable'
autoload :Entrypoint, 'qa/scenario/entrypoint'
autoload :Template, 'qa/scenario/template' autoload :Template, 'qa/scenario/template'
## ##
...@@ -25,6 +26,10 @@ module QA ...@@ -25,6 +26,10 @@ module QA
# #
module Test module Test
autoload :Instance, 'qa/scenario/test/instance' autoload :Instance, 'qa/scenario/test/instance'
module Integration
autoload :Mattermost, 'qa/scenario/test/integration/mattermost'
end
end end
## ##
......
module QA
module Scenario
##
# Base class for running the suite against any GitLab instance,
# including staging and on-premises installation.
#
class Entrypoint < Template
def self.tags(*tags)
@tags = tags
end
def self.get_tags
@tags
end
def perform(address, *files)
Specs::Config.perform do |specs|
specs.address = address
end
##
# Perform before hooks, which are different for CE and EE
#
Runtime::Release.perform_before_hooks
Specs::Runner.perform do |specs|
specs.rspec(
tty: true,
tags: self.class.get_tags,
files: files.any? ? files : 'qa/specs/features'
)
end
end
end
end
end
...@@ -5,21 +5,8 @@ module QA ...@@ -5,21 +5,8 @@ module QA
# Run test suite against any GitLab instance, # Run test suite against any GitLab instance,
# including staging and on-premises installation. # including staging and on-premises installation.
# #
class Instance < Scenario::Template class Instance < Entrypoint
def perform(address, *files) tags :core
Specs::Config.perform do |specs|
specs.address = address
end
##
# Perform before hooks, which are different for CE and EE
#
Runtime::Release.perform_before_hooks
Specs::Runner.perform do |specs|
specs.rspec('--tty', files.any? ? files : 'qa/specs/features')
end
end
end end
end end
end end
......
module QA
module Scenario
module Test
module Integration
##
# Run test suite against any GitLab instance where mattermost is enabled,
# including staging and on-premises installation.
#
class Mattermost < Scenario::Entrypoint
tags :core, :mattermost
end
end
end
end
end
module QA module QA
feature 'standard root login' do feature 'standard root login', :core do
scenario 'user logs in using credentials' do scenario 'user logs in using credentials' do
Page::Main::Entry.act { sign_in_using_credentials } Page::Main::Entry.act { sign_in_using_credentials }
......
module QA
feature 'create a new group', :mattermost do
scenario 'creating a group with a mattermost team' do
Page::Main::Entry.act { sign_in_using_credentials }
Page::Main::Menu.act { go_to_groups }
Page::Dashboard::Groups.perform do |page|
page.go_to_new_group
expect(page).to have_content(
/Create a Mattermost team for this group/
)
end
end
end
end
module QA module QA
feature 'create a new project' do feature 'create a new project', :core do
scenario 'user creates a new project' do scenario 'user creates a new project' do
Page::Main::Entry.act { sign_in_using_credentials } Page::Main::Entry.act { sign_in_using_credentials }
......
module QA module QA
feature 'clone code from the repository' do feature 'clone code from the repository', :core do
context 'with regular account over http' do context 'with regular account over http' do
given(:location) do given(:location) do
Page::Project::Show.act do Page::Project::Show.act do
......
module QA module QA
feature 'push code to repository' do feature 'push code to repository', :core do
context 'with regular account over http' do context 'with regular account over http' do
scenario 'user pushes code to the repository' do scenario 'user pushes code to the repository' do
Page::Main::Entry.act { sign_in_using_credentials } Page::Main::Entry.act { sign_in_using_credentials }
......
...@@ -5,7 +5,14 @@ module QA ...@@ -5,7 +5,14 @@ module QA
class Runner class Runner
include Scenario::Actable include Scenario::Actable
def rspec(*args) def rspec(tty: false, tags: [], files: ['qa/specs/features'])
args = []
args << '--tty' if tty
tags.to_a.each do |tag|
args << ['-t', tag.to_s]
end
args << files
RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status| RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status|
abort if status.nonzero? abort if status.nonzero?
end end
......
...@@ -84,7 +84,7 @@ describe 'bin/changelog' do ...@@ -84,7 +84,7 @@ describe 'bin/changelog' do
expect do expect do
expect do expect do
expect { described_class.read_type }.to raise_error(SystemExit) expect { described_class.read_type }.to raise_error(SystemExit)
end.to output("Invalid category index, please select an index between 1 and 7\n").to_stderr end.to output("Invalid category index, please select an index between 1 and 8\n").to_stderr
end.to output.to_stdout end.to output.to_stdout
end end
end end
......
...@@ -14,7 +14,6 @@ feature 'Projects > Wiki > User previews markdown changes', :js do ...@@ -14,7 +14,6 @@ feature 'Projects > Wiki > User previews markdown changes', :js do
background do background do
project.team << [user, :master] project.team << [user, :master]
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
sign_in(user) sign_in(user)
......
...@@ -3,9 +3,7 @@ require 'spec_helper' ...@@ -3,9 +3,7 @@ require 'spec_helper'
feature 'Wiki shortcuts', :js do feature 'Wiki shortcuts', :js do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace) }
let(:wiki_page) do let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' }) }
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
end
before do before do
sign_in(user) sign_in(user)
......
...@@ -3,14 +3,7 @@ require 'spec_helper' ...@@ -3,14 +3,7 @@ require 'spec_helper'
describe 'Projects > Wiki > User views Git access wiki page' do describe 'Projects > Wiki > User views Git access wiki page' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:wiki_page) do let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' }) }
WikiPages::CreateService.new(
project,
user,
title: 'home',
content: '[some link](other-page)'
).execute
end
before do before do
sign_in(user) sign_in(user)
......
...@@ -18,12 +18,7 @@ describe 'Projects > Wiki > User views wiki in project page' do ...@@ -18,12 +18,7 @@ describe 'Projects > Wiki > User views wiki in project page' do
context 'when wiki homepage contains a link' do context 'when wiki homepage contains a link' do
before do before do
WikiPages::CreateService.new( create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: '[some link](other-page)' })
project,
user,
title: 'home',
content: '[some link](other-page)'
).execute
end end
it 'displays the correct URL for the link' do it 'displays the correct URL for the link' do
......
No preview for this file type
...@@ -2,6 +2,7 @@ import flash, { ...@@ -2,6 +2,7 @@ import flash, {
createFlashEl, createFlashEl,
createAction, createAction,
hideFlash, hideFlash,
removeFlashClickListener,
} from '~/flash'; } from '~/flash';
describe('Flash', () => { describe('Flash', () => {
...@@ -266,4 +267,24 @@ describe('Flash', () => { ...@@ -266,4 +267,24 @@ describe('Flash', () => {
}); });
}); });
}); });
describe('removeFlashClickListener', () => {
beforeEach(() => {
document.body.innerHTML += '<div class="flash-container"><div class="flash"></div></div>';
});
it('removes global flash on click', (done) => {
const flashEl = document.querySelector('.flash');
removeFlashClickListener(flashEl, false);
flashEl.parentNode.click();
setTimeout(() => {
expect(document.querySelector('.flash')).toBeNull();
done();
});
});
});
}); });
...@@ -30,7 +30,6 @@ describe('Job details header', () => { ...@@ -30,7 +30,6 @@ describe('Job details header', () => {
email: 'foo@bar.com', email: 'foo@bar.com',
avatar_url: 'link', avatar_url: 'link',
}, },
retry_path: 'path',
new_issue_path: 'path', new_issue_path: 'path',
}, },
isLoading: false, isLoading: false,
...@@ -49,12 +48,6 @@ describe('Job details header', () => { ...@@ -49,12 +48,6 @@ describe('Job details header', () => {
).toEqual('failed Job #123 triggered 3 weeks ago by Foo'); ).toEqual('failed Job #123 triggered 3 weeks ago by Foo');
}); });
it('should render retry link', () => {
expect(
vm.$el.querySelector('.js-retry-button').getAttribute('href'),
).toEqual(props.job.retry_path);
});
it('should render new issue link', () => { it('should render new issue link', () => {
expect( expect(
vm.$el.querySelector('.js-new-issue').getAttribute('href'), vm.$el.querySelector('.js-new-issue').getAttribute('href'),
......
...@@ -474,7 +474,11 @@ describe('common_utils', () => { ...@@ -474,7 +474,11 @@ describe('common_utils', () => {
}); });
it('should return the svg for a linked icon', () => { it('should return the svg for a linked icon', () => {
expect(gl.utils.spriteIcon('test')).toEqual('<svg><use xlink:href="icons.svg#test" /></svg>'); expect(gl.utils.spriteIcon('test')).toEqual('<svg ><use xlink:href="icons.svg#test" /></svg>');
});
it('should set svg className when passed', () => {
expect(gl.utils.spriteIcon('test', 'fa fa-test')).toEqual('<svg class="fa fa-test"><use xlink:href="icons.svg#test" /></svg>');
}); });
}); });
}); });
......
...@@ -143,4 +143,21 @@ eos ...@@ -143,4 +143,21 @@ eos
it { expect(parser.parse([])).to eq([]) } it { expect(parser.parse([])).to eq([]) }
it { expect(parser.parse(nil)).to eq([]) } it { expect(parser.parse(nil)).to eq([]) }
end end
describe 'tolerates special diff markers in a content' do
it "counts lines correctly" do
diff = <<~END
--- a/test
+++ b/test
@@ -1,2 +1,2 @@
+ipsum
+++ b
-ipsum
END
lines = parser.parse(diff.lines).to_a
expect(lines.size).to eq(3)
end
end
end end
...@@ -1525,6 +1525,45 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1525,6 +1525,45 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
describe '#merge' do
let(:repository) do
Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
let(:source_sha) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' }
let(:user) { build(:user) }
let(:target_branch) { 'test-merge-target-branch' }
before do
repository.create_branch(target_branch, '6d394385cf567f80a8fd85055db1ab4c5295806f')
end
after do
FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
ensure_seeds
end
shared_examples '#merge' do
it 'can perform a merge' do
merge_commit_id = nil
result = repository.merge(user, source_sha, target_branch, 'Test merge') do |commit_id|
merge_commit_id = commit_id
end
expect(result.newrev).to eq(merge_commit_id)
expect(result.repo_created).to eq(false)
expect(result.branch_created).to eq(false)
end
end
context 'with gitaly' do
it_behaves_like '#merge'
end
context 'without gitaly', :skip_gitaly_mock do
it_behaves_like '#merge'
end
end
def create_remote_branch(repository, remote_name, branch_name, source_branch_name) def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name } source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged rugged = repository.rugged
......
...@@ -39,6 +39,18 @@ describe Gitlab::SidekiqStatus do ...@@ -39,6 +39,18 @@ describe Gitlab::SidekiqStatus do
end end
end end
describe '.running?', :clean_gitlab_redis_shared_state do
it 'returns true if job is running' do
described_class.set('123')
expect(described_class.running?('123')).to be(true)
end
it 'returns false if job is not found' do
expect(described_class.running?('123')).to be(false)
end
end
describe '.num_running', :clean_gitlab_redis_shared_state do describe '.num_running', :clean_gitlab_redis_shared_state do
it 'returns 0 if all jobs have been completed' do it 'returns 0 if all jobs have been completed' do
expect(described_class.num_running(%w(123))).to eq(0) expect(described_class.num_running(%w(123))).to eq(0)
......
...@@ -73,6 +73,8 @@ describe Gitlab::UsageData do ...@@ -73,6 +73,8 @@ describe Gitlab::UsageData do
environments environments
gcp_clusters gcp_clusters
geo_nodes geo_nodes
gcp_clusters_enabled
gcp_clusters_disabled
in_review_folder in_review_folder
groups groups
issues issues
......
...@@ -37,7 +37,7 @@ describe BlobViewer::Readme do ...@@ -37,7 +37,7 @@ describe BlobViewer::Readme do
context 'when the wiki is not empty' do context 'when the wiki is not empty' do
before do before do
WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' })
end end
it 'returns nil' do it 'returns nil' do
......
...@@ -1762,19 +1762,34 @@ describe Ci::Build do ...@@ -1762,19 +1762,34 @@ describe Ci::Build do
end end
describe 'state transition when build fails' do describe 'state transition when build fails' do
let(:service) { MergeRequests::AddTodoWhenBuildFailsService.new(project, user) }
before do
allow(MergeRequests::AddTodoWhenBuildFailsService).to receive(:new).and_return(service)
allow(service).to receive(:close)
end
context 'when build is configured to be retried' do context 'when build is configured to be retried' do
subject { create(:ci_build, :running, options: { retry: 3 }) } subject { create(:ci_build, :running, options: { retry: 3 }, project: project, user: user) }
it 'retries builds and assigns a same user to it' do it 'retries build and assigns the same user to it' do
expect(described_class).to receive(:retry) expect(described_class).to receive(:retry)
.with(subject, subject.user) .with(subject, user)
subject.drop!
end
it 'does not try to create a todo' do
project.add_developer(user)
expect(service).not_to receive(:commit_status_merge_requests)
subject.drop! subject.drop!
end end
end end
context 'when build is not configured to be retried' do context 'when build is not configured to be retried' do
subject { create(:ci_build, :running) } subject { create(:ci_build, :running, project: project, user: user) }
it 'does not retry build' do it 'does not retry build' do
expect(described_class).not_to receive(:retry) expect(described_class).not_to receive(:retry)
...@@ -1789,6 +1804,14 @@ describe Ci::Build do ...@@ -1789,6 +1804,14 @@ describe Ci::Build do
subject.drop! subject.drop!
end end
it 'creates a todo' do
project.add_developer(user)
expect(service).to receive(:commit_status_merge_requests)
subject.drop!
end
end end
end end
end end
...@@ -7,6 +7,30 @@ describe Gcp::Cluster do ...@@ -7,6 +7,30 @@ describe Gcp::Cluster do
it { is_expected.to validate_presence_of(:gcp_cluster_zone) } it { is_expected.to validate_presence_of(:gcp_cluster_zone) }
describe '.enabled' do
subject { described_class.enabled }
let!(:cluster) { create(:gcp_cluster, enabled: true) }
before do
create(:gcp_cluster, enabled: false)
end
it { is_expected.to contain_exactly(cluster) }
end
describe '.disabled' do
subject { described_class.disabled }
let!(:cluster) { create(:gcp_cluster, enabled: false) }
before do
create(:gcp_cluster, enabled: true)
end
it { is_expected.to contain_exactly(cluster) }
end
describe '#default_value_for' do describe '#default_value_for' do
let(:cluster) { described_class.new } let(:cluster) { described_class.new }
......
...@@ -1887,11 +1887,31 @@ describe MergeRequest do ...@@ -1887,11 +1887,31 @@ describe MergeRequest do
end end
describe '#merge_ongoing?' do describe '#merge_ongoing?' do
it 'returns true when merge_id is present and MR is not merged' do it 'returns true when merge_id, MR is not merged and it has no running job' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo') merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo')
allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { true }
expect(merge_request.merge_ongoing?).to be(true) expect(merge_request.merge_ongoing?).to be(true)
end end
it 'returns false when merge_jid is nil' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: nil)
expect(merge_request.merge_ongoing?).to be(false)
end
it 'returns false if MR is merged' do
merge_request = build_stubbed(:merge_request, state: :merged, merge_jid: 'foo')
expect(merge_request.merge_ongoing?).to be(false)
end
it 'returns false if there is no merge job running' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo')
allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { false }
expect(merge_request.merge_ongoing?).to be(false)
end
end end
describe "#closed_without_fork?" do describe "#closed_without_fork?" do
......
...@@ -108,12 +108,8 @@ describe MicrosoftTeamsService do ...@@ -108,12 +108,8 @@ describe MicrosoftTeamsService do
message: "user created page: Awesome wiki_page" message: "user created page: Awesome wiki_page"
} }
end end
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) }
let(:wiki_page_sample_data) do let(:wiki_page_sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
service = WikiPages::CreateService.new(project, user, opts)
wiki_page = service.execute
Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create')
end
it "calls Microsoft Teams API" do it "calls Microsoft Teams API" do
chat_service.execute(wiki_page_sample_data) chat_service.execute(wiki_page_sample_data)
......
...@@ -1286,6 +1286,7 @@ describe Repository do ...@@ -1286,6 +1286,7 @@ describe Repository do
let(:message) { 'Test \r\n\r\n message' } let(:message) { 'Test \r\n\r\n message' }
shared_examples '#merge' do
it 'merges the code and returns the commit id' do it 'merges the code and returns the commit id' do
expect(merge_commit).to be_present expect(merge_commit).to be_present
expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
...@@ -1302,6 +1303,15 @@ describe Repository do ...@@ -1302,6 +1303,15 @@ describe Repository do
expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r")) expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r"))
end end
end
context 'with gitaly' do
it_behaves_like '#merge'
end
context 'without gitaly', :skip_gitaly_mock do
it_behaves_like '#merge'
end
def merge(repository, user, merge_request, message) def merge(repository, user, merge_request, message)
repository.merge(user, merge_request.diff_head_sha, merge_request, message) repository.merge(user, merge_request.diff_head_sha, merge_request, message)
......
...@@ -97,10 +97,11 @@ describe API::V3::Repositories do ...@@ -97,10 +97,11 @@ describe API::V3::Repositories do
end end
end end
{ [
'blobs/:sha' => 'blobs/master', ['blobs/:sha', 'blobs/master'],
'commits/:sha/blob' => 'commits/master/blob' ['blobs/:sha', 'blobs/v1.1.0'],
}.each do |desc_path, example_path| ['commits/:sha/blob', 'commits/master/blob']
].each do |desc_path, example_path|
describe "GET /projects/:id/repository/#{desc_path}" do describe "GET /projects/:id/repository/#{desc_path}" do
let(:route) { "/projects/#{project.id}/repository/#{example_path}?filepath=README.md" } let(:route) { "/projects/#{project.id}/repository/#{example_path}?filepath=README.md" }
shared_examples_for 'repository blob' do shared_examples_for 'repository blob' do
...@@ -110,7 +111,7 @@ describe API::V3::Repositories do ...@@ -110,7 +111,7 @@ describe API::V3::Repositories do
end end
context 'when sha does not exist' do context 'when sha does not exist' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get v3_api(route.sub('master', 'invalid_branch_name'), current_user) } let(:request) { get v3_api("/projects/#{project.id}/repository/#{desc_path.sub(':sha', 'invalid_branch_name')}?filepath=README.md", current_user) }
let(:message) { '404 Commit Not Found' } let(:message) { '404 Commit Not Found' }
end end
end end
......
...@@ -161,8 +161,9 @@ describe Ci::RetryBuildService do ...@@ -161,8 +161,9 @@ describe Ci::RetryBuildService do
expect(new_build).to be_created expect(new_build).to be_created
end end
it 'does mark old build as retried' do it 'does mark old build as retried in the database and on the instance' do
expect(new_build).to be_latest expect(new_build).to be_latest
expect(build).to be_retried
expect(build.reload).to be_retried expect(build.reload).to be_retried
end end
end end
......
...@@ -52,6 +52,11 @@ describe Projects::UpdatePagesService do ...@@ -52,6 +52,11 @@ describe Projects::UpdatePagesService do
expect(project.pages_deployed?).to be_falsey expect(project.pages_deployed?).to be_falsey
expect(execute).to eq(:success) expect(execute).to eq(:success)
expect(project.pages_deployed?).to be_truthy expect(project.pages_deployed?).to be_truthy
# Check that all expected files are extracted
%w[index.html zero .hidden/file].each do |filename|
expect(File.exist?(File.join(project.public_pages_path, filename))).to be_truthy
end
end end
it 'limits pages size' do it 'limits pages size' do
......
...@@ -76,8 +76,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do ...@@ -76,8 +76,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
message: "user created page: Awesome wiki_page" message: "user created page: Awesome wiki_page"
} }
wiki_page_service = WikiPages::CreateService.new(project, user, opts) @wiki_page = create(:wiki_page, wiki: project.wiki, attrs: opts)
@wiki_page = wiki_page_service.execute
@wiki_page_sample_data = Gitlab::DataBuilder::WikiPage.build(@wiki_page, user, 'create') @wiki_page_sample_data = Gitlab::DataBuilder::WikiPage.build(@wiki_page, user, 'create')
end end
......
...@@ -4148,9 +4148,9 @@ moment@2.x: ...@@ -4148,9 +4148,9 @@ moment@2.x:
version "2.17.1" version "2.17.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82"
monaco-editor@0.8.3: monaco-editor@0.10.0:
version "0.8.3" version "0.10.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.8.3.tgz#523bdf2d1524db2c2dfc3cae0a7b6edc48d6dea6" resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.10.0.tgz#6604932585fe9c1f993f000a503d0d20fbe5896a"
mousetrap@^1.4.6: mousetrap@^1.4.6:
version "1.4.6" version "1.4.6"
...@@ -6405,9 +6405,9 @@ vue@^2.2.6: ...@@ -6405,9 +6405,9 @@ vue@^2.2.6:
version "2.2.6" version "2.2.6"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.2.6.tgz#451714b394dd6d4eae7b773c40c2034a59621aed" resolved "https://registry.yarnpkg.com/vue/-/vue-2.2.6.tgz#451714b394dd6d4eae7b773c40c2034a59621aed"
vuex@^2.3.1: vuex@^3.0.0:
version "2.3.1" version "3.0.0"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-2.3.1.tgz#cde8e997c1f9957719bc7dea154f9aa691d981a6" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.0.tgz#98b4b5c4954b1c1c1f5b29fa0476a23580315814"
watchpack@^1.4.0: watchpack@^1.4.0:
version "1.4.0" version "1.4.0"
......
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