Commit 9f80a23a authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee-2017-09-22' into 'master'

CE upstream: Friday

See merge request gitlab-org/gitlab-ee!2999
parents 3cca7d4d 4d8f758e
9.6.0-pre
10.1.0-pre
......@@ -3,6 +3,7 @@
import '../lib/utils/url_utility';
import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf';
function toggleLoading($el, $icon, loading) {
if (loading) {
......@@ -36,9 +37,7 @@ export default class BlobFileDropzone {
maxFiles: 1,
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
},
headers: csrf.headers,
init: function () {
this.on('addedfile', function () {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
......
......@@ -11,14 +11,22 @@
function ImageFile(file) {
this.file = file;
this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
// Determine if old and new file has same dimensions, if not show 'two-up' view
return function(deletedWidth, deletedHeight) {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
if (width === deletedWidth && height === deletedHeight) {
return _this.initViewModes();
} else {
return _this.initView('two-up');
}
_this.initViewModes();
// Load two-up view after images are loaded
// so that we can display the correct width and height information
const images = $('.two-up.view img', _this.file);
let loadedCount = 0;
images.on('load', () => {
loadedCount += 1;
if (loadedCount === images.length) {
_this.initView('two-up');
}
});
});
};
})(this));
......
......@@ -2,6 +2,7 @@
/* global Dropzone */
import _ from 'underscore';
import './preview_markdown';
import csrf from './lib/utils/csrf';
window.DropzoneInput = (function() {
function DropzoneInput(form) {
......@@ -50,9 +51,7 @@ window.DropzoneInput = (function() {
paramName: 'file',
maxFilesize: maxFileSize,
uploadMultiple: false,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
headers: csrf.headers,
previewContainer: false,
processing: function() {
return $('.div-dropzone-alert').alert('close');
......@@ -260,9 +259,7 @@ window.DropzoneInput = (function() {
dataType: 'json',
processData: false,
contentType: false,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
headers: csrf.headers,
beforeSend: function() {
showSpinner();
return closeAlertMessage();
......
/*
This module provides easy access to the CSRF token and caches
it for re-use. It also exposes some values commonly used in relation
to the CSRF token (header key and headers object).
If you need to refresh the csrfToken for some reason, just call `init` and
then use the accessors as you would normally.
If you need to compose a headers object, use the spread operator:
```
headers: {
...csrf.headers,
someOtherHeader: '12345',
}
```
*/
const csrf = {
init() {
const tokenEl = document.querySelector('meta[name=csrf-token]');
if (tokenEl !== null) {
this.csrfToken = tokenEl.getAttribute('content');
} else {
this.csrfToken = null;
}
},
get token() {
return this.csrfToken;
},
get headerKey() {
return 'X-CSRF-Token';
},
get headers() {
if (this.csrfToken !== null) {
return {
[this.headerKey]: this.token,
};
}
return {};
},
};
csrf.init();
// use our cached token for any $.rails-generated AJAX requests
if ($.rails) {
$.rails.csrfToken = () => csrf.token;
}
export default csrf;
......@@ -2,6 +2,7 @@
/* global Flash, Autosave */
import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore';
import autosize from 'vendor/autosize';
import '../../autosave';
import TaskList from '../../task_list';
import * as constants from '../constants';
......@@ -96,6 +97,8 @@
methods: {
...mapActions([
'saveNote',
'stopPolling',
'restartPolling',
'removePlaceholderNotes',
]),
setIsSubmitButtonDisabled(note, isSubmitting) {
......@@ -124,10 +127,14 @@
}
this.isSubmitting = true;
this.note = ''; // Empty textarea while being requested. Repopulate in catch
this.resizeTextarea();
this.stopPolling();
this.saveNote(noteData)
.then((res) => {
this.isSubmitting = false;
this.restartPolling();
if (res.errors) {
if (res.errors.commands_only) {
this.discard();
......@@ -174,6 +181,8 @@
if (shouldClear) {
this.note = '';
this.resizeTextarea();
this.$refs.markdownField.previewMarkdown = false;
}
// reset autostave
......@@ -205,6 +214,11 @@
selector: '.notes',
});
},
resizeTextarea() {
this.$nextTick(() => {
autosize.update(this.$refs.textarea);
});
},
},
mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery.
......@@ -247,7 +261,8 @@
:markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"
:is-confidential-issue="isConfidentialIssue">
:is-confidential-issue="isConfidentialIssue"
ref="markdownField">
<textarea
id="note-body"
name="note[note]"
......
......@@ -187,6 +187,14 @@ export const poll = ({ commit, state, getters }) => {
});
};
export const stopPolling = () => {
eTagPoll.stop();
};
export const restartPolling = () => {
eTagPoll.restart();
};
export const fetchData = ({ commit, state, getters }) => {
const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt };
......
......@@ -5,15 +5,19 @@ import * as constants from '../constants';
export default {
[types.ADD_NEW_NOTE](state, note) {
const { discussion_id, type } = note;
const noteData = {
expanded: true,
id: discussion_id,
individual_note: !(type === constants.DISCUSSION_NOTE),
notes: [note],
reply_id: discussion_id,
};
state.notes.push(noteData);
const [exists] = state.notes.filter(n => n.id === note.discussion_id);
if (!exists) {
const noteData = {
expanded: true,
id: discussion_id,
individual_note: !(type === constants.DISCUSSION_NOTE),
notes: [note],
reply_id: discussion_id,
};
state.notes.push(noteData);
}
},
[types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) {
......
import Vue from 'vue';
import VueResource from 'vue-resource';
import csrf from '../lib/utils/csrf';
Vue.use(VueResource);
......@@ -18,9 +19,7 @@ Vue.http.interceptors.push((request, next) => {
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination
// and polling.
Vue.http.interceptors.push((request, next) => {
if ($.rails) {
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
}
request.headers.set(csrf.headerKey, csrf.token);
next((response) => {
// Headers object has a `forEach` property that iterates through all values.
......
......@@ -3,8 +3,13 @@ class HelpController < ApplicationController
layout 'help'
# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
def index
@help_index = File.read(Rails.root.join('doc', 'README.md'))
# Remove YAML frontmatter so that it doesn't look weird
@help_index = File.read(Rails.root.join('doc', 'README.md')).sub(YAML_FRONT_MATTER_REGEXP, '')
# Prefix Markdown links with `help/` unless they are external links
# See http://rubular.com/r/X3baHTbPO2
......@@ -22,7 +27,8 @@ class HelpController < ApplicationController
path = File.join(Rails.root, 'doc', "#{@path}.md")
if File.exist?(path)
@markdown = File.read(path)
# Remove YAML frontmatter so that it doesn't look weird
@markdown = File.read(path).gsub(YAML_FRONT_MATTER_REGEXP, '')
render 'show.html.haml'
else
......
......@@ -176,13 +176,15 @@ module CommitsHelper
end
end
def view_file_button(commit_sha, diff_new_path, project)
def view_file_button(commit_sha, diff_new_path, project, replaced: false)
title = replaced ? _('View replaced file @ ') : _('View file @ ')
link_to(
project_blob_path(project,
tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file'
) do
raw('View file @ ') + content_tag(:span, Commit.truncate_sha(commit_sha),
raw(title) + content_tag(:span, Commit.truncate_sha(commit_sha),
class: 'commit-sha')
end
end
......
- environment = local_assigns.fetch(:environment, nil)
- file_hash = hexdigest(diff_file.file_path)
- image_diff = diff_file.rich_viewer && diff_file.rich_viewer.partial_name == 'image'
- image_replaced = diff_file.old_content_sha && diff_file.old_content_sha != diff_file.content_sha
.diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_file.content_sha) }
.js-file-title.file-title-flex-parent
.file-header-content
......@@ -17,6 +20,9 @@
= edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path,
blob: blob, link_opts: link_opts)
- if image_diff && image_replaced
= view_file_button(diff_file.old_content_sha, diff_file.old_path, project, replaced: true)
= view_file_button(diff_file.content_sha, diff_file.file_path, project)
= view_on_environment_button(diff_file.content_sha, diff_file.file_path, environment) if environment
......
......@@ -15,8 +15,7 @@
.two-up.view
%span.wrap
.frame.deleted
%a{ href: project_blob_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) }
= image_tag(old_blob_raw_path, alt: diff_file.old_path)
= image_tag(old_blob_raw_path, alt: diff_file.old_path)
%p.image-info.hide
%span.meta-filesize= number_to_human_size(old_blob.size)
|
......@@ -27,8 +26,7 @@
%span.meta-height
%span.wrap
.frame.added
%a{ href: project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.new_path)) }
= image_tag(blob_raw_path, alt: diff_file.new_path)
= image_tag(blob_raw_path, alt: diff_file.new_path)
%p.image-info.hide
%span.meta-filesize= number_to_human_size(blob.size)
|
......
......@@ -43,4 +43,4 @@
"empty-state-svg" => image_path('illustrations/issues.svg'),
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":project-id" => @project.try(:id) }
":project-id" => @project.id }
---
title: Add view replaced file link for image diffs
merge_request:
author:
type: changed
---
title: Correctly detect multiple issue URLs after 'Closes...' in MR descriptions
merge_request:
author:
type: fixed
---
title: Display full pre-receive and post-receive hook output in GitLab UI
merge_request: 14222
author: Robin Bobbitt
type: fixed
---
title: Force two up view to load by default for image diffs
merge_request:
author:
type: fixed
---
title: Replace the 'project/service.feature' spinach test with an rspec analog
merge_request: 14432
author: Vitaliy @blackst0ne Klachkov
type: other
---
title: Removed two legacy config options
merge_request:
author: Daniel Voogsgerd
type: deprecated
......@@ -681,12 +681,6 @@ production: &base
# Use the default values unless you really know what you are doing
git:
bin_path: /usr/bin/git
# The next value is the maximum memory size grit can use
# Given in number of bytes per git object (e.g. a commit)
# This value can be increased if you have very large commits
max_size: 20971520 # 20.megabytes
# Git timeout to read a commit, in seconds
timeout: 10
## Webpack settings
# If enabled, this will tell rails to serve frontend assets from the webpack-dev-server running
......
......@@ -149,31 +149,19 @@ helm install --name gitlab --set baseDomain=gitlab.io,baseIP=1.1.1.1,gitlab=ee,g
## Updating GitLab using the Helm Chart
Once your GitLab Chart is installed, configuration changes and chart updates
should we done using `helm upgrade`
should we done using `helm upgrade`:
```bash
helm upgrade -f <CONFIG_VALUES_FILE> <RELEASE-NAME> gitlab/gitlab
helm upgrade -f values.yaml gitlab gitlab/gitlab-omnibus
```
where:
- `<CONFIG_VALUES_FILE>` is the path to values file containing your custom
[configuration] (#configuring-and-installing-gitlab).
- `<RELEASE-NAME>` is the name you gave the chart when installing it.
In the [Install section](#installing-gitlab-using-the-helm-chart) we called it `gitlab`.
## Uninstalling GitLab using the Helm Chart
To uninstall the GitLab Chart, run the following:
```bash
helm delete <RELEASE-NAME>
helm delete gitlab
```
where:
- `<RELEASE-NAME>` is the name you gave the chart when installing it.
In the [Install section](#installing) we called it `gitlab`.
[kube-srv]: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
[storageclass]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#storageclasses
Feature: Project Services
Background:
Given I sign in as a user
And I own project "Shop"
Scenario: I should see project services
When I visit project "Shop" services page
Then I should see list of available services
Scenario: Activate hipchat service
When I visit project "Shop" services page
And I click hipchat service link
And I fill hipchat settings
Then I should see the Hipchat success message
Scenario: Activate hipchat service with custom server
When I visit project "Shop" services page
And I click hipchat service link
And I fill hipchat settings with custom server
Then I should see the Hipchat success message
Scenario: Activate pivotaltracker service
When I visit project "Shop" services page
And I click pivotaltracker service link
And I fill pivotaltracker settings
Then I should see the Pivotaltracker success message
Scenario: Activate Flowdock service
When I visit project "Shop" services page
And I click Flowdock service link
And I fill Flowdock settings
Then I should see the Flowdock success message
Scenario: Activate Assembla service
When I visit project "Shop" services page
And I click Assembla service link
And I fill Assembla settings
Then I should see the Assembla success message
Scenario: Activate Slack notifications service
When I visit project "Shop" services page
And I click Slack notifications service link
And I fill Slack notifications settings
Then I should see the Slack notifications success message
Scenario: Activate Pushover service
When I visit project "Shop" services page
And I click Pushover service link
And I fill Pushover settings
Then I should see the Pushover success message
Scenario: Activate email on push service
When I visit project "Shop" services page
And I click email on push service link
And I fill email on push settings
Then I should see the Emails on push success message
Scenario: Activate JIRA service
When I visit project "Shop" services page
And I click jira service link
And I fill jira settings
Then I should see the JIRA success message
Scenario: Activate Irker (IRC Gateway) service
When I visit project "Shop" services page
And I click Irker service link
And I fill Irker settings
Then I should see the Irker success message
Scenario: Activate Atlassian Bamboo CI service
When I visit project "Shop" services page
And I click Atlassian Bamboo CI service link
And I fill Atlassian Bamboo CI settings
Then I should see the Bamboo success message
And I should see empty field Change Password
Scenario: Activate jetBrains TeamCity CI service
When I visit project "Shop" services page
And I click jetBrains TeamCity CI service link
And I fill jetBrains TeamCity CI settings
Then I should see the JetBrains success message
Scenario: Activate Asana service
When I visit project "Shop" services page
And I click Asana service link
And I fill Asana settings
Then I should see the Asana success message
......@@ -139,7 +139,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'The diff links to both the previous and current image' do
links = page.all('.two-up span div a')
links = page.all('.file-actions a')
expect(links[0]['href']).to match %r{blob/#{sample_image_commit.old_blob_id}}
expect(links[1]['href']).to match %r{blob/#{sample_image_commit.new_blob_id}}
end
......
class Spinach::Features::ProjectServices < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
step 'I visit project "Shop" services page' do
visit project_settings_integrations_path(@project)
end
step 'I should see list of available services' do
expect(page).to have_content 'Project services'
expect(page).to have_content 'Campfire'
expect(page).to have_content 'HipChat'
expect(page).to have_content 'Assembla'
expect(page).to have_content 'Pushover'
expect(page).to have_content 'Atlassian Bamboo'
expect(page).to have_content 'JetBrains TeamCity'
expect(page).to have_content 'Asana'
expect(page).to have_content 'Irker (IRC gateway)'
end
step 'I should see service settings saved' do
expect(find_field('Active').value).to eq '1'
end
step 'I click hipchat service link' do
click_link 'HipChat'
end
step 'I fill hipchat settings' do
check 'Active'
fill_in 'Room', with: 'gitlab'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see the Hipchat success message' do
expect(page).to have_content 'HipChat activated.'
end
step 'I fill hipchat settings with custom server' do
check 'Active'
fill_in 'Room', with: 'gitlab_custom'
fill_in 'Token', with: 'secretCustom'
fill_in 'Server', with: 'https://chat.example.com'
click_button 'Save'
end
step 'I click pivotaltracker service link' do
click_link 'PivotalTracker'
end
step 'I fill pivotaltracker settings' do
check 'Active'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see the Pivotaltracker success message' do
expect(page).to have_content 'PivotalTracker activated.'
end
step 'I click Flowdock service link' do
click_link 'Flowdock'
end
step 'I fill Flowdock settings' do
check 'Active'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see the Flowdock success message' do
expect(page).to have_content 'Flowdock activated.'
end
step 'I click Assembla service link' do
click_link 'Assembla'
end
step 'I fill Assembla settings' do
check 'Active'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see the Assembla success message' do
expect(page).to have_content 'Assembla activated.'
end
step 'I click Asana service link' do
click_link 'Asana'
end
step 'I fill Asana settings' do
check 'Active'
fill_in 'Api key', with: 'verySecret'
fill_in 'Restrict to branch', with: 'master'
click_button 'Save'
end
step 'I should see the Asana success message' do
expect(page).to have_content 'Asana activated.'
end
step 'I click email on push service link' do
click_link 'Emails on push'
end
step 'I fill email on push settings' do
check 'Active'
fill_in 'Recipients', with: 'qa@company.name'
click_button 'Save'
end
step 'I should see the Emails on push success message' do
expect(page).to have_content 'Emails on push activated.'
end
step 'I click Irker service link' do
click_link 'Irker (IRC gateway)'
end
step 'I fill Irker settings' do
check 'Active'
fill_in 'Recipients', with: 'irc://chat.freenode.net/#commits'
check 'Colorize messages'
click_button 'Save'
end
step 'I should see the Irker success message' do
expect(page).to have_content 'Irker (IRC gateway) activated.'
end
step 'I click Slack notifications service link' do
click_link 'Slack notifications'
end
step 'I fill Slack notifications settings' do
check 'Active'
fill_in 'Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685'
click_button 'Save'
end
step 'I should see the Slack notifications success message' do
expect(page).to have_content 'Slack notifications activated.'
end
step 'I click Pushover service link' do
click_link 'Pushover'
end
step 'I fill Pushover settings' do
check 'Active'
fill_in 'Api key', with: 'verySecret'
fill_in 'User key', with: 'verySecret'
fill_in 'Device', with: 'myDevice'
select 'High Priority', from: 'Priority'
select 'Bike', from: 'Sound'
click_button 'Save'
end
step 'I should see the Pushover success message' do
expect(page).to have_content 'Pushover activated.'
end
step 'I click jira service link' do
click_link 'JIRA'
end
step 'I fill jira settings' do
check 'Active'
fill_in 'Web URL', with: 'http://jira.example'
fill_in 'JIRA API URL', with: 'http://jira.example/api'
fill_in 'Username', with: 'gitlab'
fill_in 'Password', with: 'gitlab'
click_button 'Save'
end
step 'I should see the JIRA success message' do
expect(page).to have_content 'JIRA activated.'
end
step 'I click Atlassian Bamboo CI service link' do
click_link 'Atlassian Bamboo CI'
end
step 'I fill Atlassian Bamboo CI settings' do
check 'Active'
fill_in 'Bamboo url', with: 'http://bamboo.example.com'
fill_in 'Build key', with: 'KEY'
fill_in 'Username', with: 'user'
fill_in 'Password', with: 'verySecret'
click_button 'Save'
end
step 'I should see the Bamboo success message' do
expect(page).to have_content 'Atlassian Bamboo CI activated.'
end
step 'I should see empty field Change Password' do
click_link 'Atlassian Bamboo CI'
expect(find_field('Enter new password').value).to be_nil
end
step 'I click JetBrains TeamCity CI service link' do
click_link 'JetBrains TeamCity CI'
end
step 'I fill JetBrains TeamCity CI settings' do
check 'Active'
fill_in 'Teamcity url', with: 'http://teamcity.example.com'
fill_in 'Build type', with: 'GitlabTest_Build'
fill_in 'Username', with: 'user'
fill_in 'Password', with: 'verySecret'
click_button 'Save'
end
step 'I should see the JetBrains success message' do
expect(page).to have_content 'JetBrains TeamCity CI activated.'
end
end
......@@ -79,7 +79,7 @@ module Backup
# - 1495527122_gitlab_backup.tar
# - 1495527068_2017_05_23_gitlab_backup.tar
# - 1495527097_2017_05_23_9.3.0-pre_gitlab_backup.tar
next unless file =~ /^(\d{10})(?:_\d{4}_\d{2}_\d{2}(_\d+\.\d+\.\d+((-|\.)(pre|rc\d))?)?)?_gitlab_backup\.tar$/
next unless file =~ /^(\d{10})(?:_\d{4}_\d{2}_\d{2}(_\d+\.\d+\.\d+((-|\.)(pre|rc\d))?(-ee)?)?)?_gitlab_backup\.tar$/
timestamp = $1.to_i
......
module Gitlab
class ClosingIssueExtractor
ISSUE_CLOSING_REGEX = begin
link_pattern = URI.regexp(%w(http https))
link_pattern = Banzai::Filter::AutolinkFilter::LINK_PATTERN
pattern = Gitlab.config.gitlab.issue_closing_pattern
pattern = pattern.sub('%{issue_ref}', "(?:(?:#{link_pattern})|(?:#{Issue.reference_pattern}))")
......
......@@ -83,13 +83,14 @@ module Gitlab
def call_update_hook(gl_id, oldrev, newrev, ref)
Dir.chdir(repo_path) do
stdout, stderr, status = Open3.capture3({ 'GL_ID' => gl_id }, path, ref, oldrev, newrev)
[status.success?, stderr.presence || stdout]
[status.success?, (stderr.presence || stdout).gsub(/\R/, "<br>").html_safe]
end
end
def retrieve_error_message(stderr, stdout)
err_message = stderr.gets
err_message.blank? ? stdout.gets : err_message
err_message = stderr.read
err_message = err_message.blank? ? stdout.read : err_message
err_message.gsub(/\R/, "<br>").html_safe
end
end
end
......
......@@ -58,11 +58,11 @@ module Gitlab
end
def repository_storages
@repository_storage ||= storages_paths.keys
storages_paths.keys
end
def storages_paths
@storage_paths ||= Gitlab.config.repositories.storages
Gitlab.config.repositories.storages
end
def exec_with_timeout(cmd_args, *args, &block)
......
......@@ -62,13 +62,43 @@ feature 'Diff file viewer', :js do
end
context 'Image file' do
before do
visit_commit('2f63565e7aac07bcdadb654e253078b727143ec4')
context 'Replaced' do
before do
visit_commit('2f63565e7aac07bcdadb654e253078b727143ec4')
end
it 'shows a rendered image' do
within('.diff-file[id="e986451b8f7397b617dbb6fffcb5539328c56921"]') do
expect(page).to have_css('img[alt="files/images/6049019_460s.jpg"]')
end
end
it 'shows view replaced and view file links' do
expect(page.all('.file-actions a').length).to eq 2
expect(page.all('.file-actions a')[0]).to have_content 'View replaced file @'
expect(page.all('.file-actions a')[1]).to have_content 'View file @'
end
end
context 'Added' do
before do
visit_commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9')
end
it 'shows view file link' do
expect(page.all('.file-actions a').length).to eq 1
expect(page.all('.file-actions a')[0]).to have_content 'View file @'
end
end
it 'shows a rendered image' do
within('.diff-file[id="e986451b8f7397b617dbb6fffcb5539328c56921"]') do
expect(page).to have_css('img[alt="files/images/6049019_460s.jpg"]')
context 'Deleted' do
before do
visit_commit('7fd7a459706ee87be6f855fd98ce8c552b15529a')
end
it 'shows view file link' do
expect(page.all('.file-actions a').length).to eq 1
expect(page.all('.file-actions a')[0]).to have_content 'View file @'
end
end
end
......
require 'spec_helper'
feature 'Projects > Slack service > Setup events' do
let(:user) { create(:user) }
let(:service) { SlackService.new }
let(:project) { create(:project, slack_service: service) }
background do
service.fields
service.update_attributes(push_channel: 1, issue_channel: 2, merge_request_channel: 3, note_channel: 4, tag_push_channel: 5, pipeline_channel: 6, wiki_page_channel: 7)
project.team << [user, :master]
sign_in(user)
end
scenario 'user can filter events by channel' do
visit edit_project_service_path(project, service)
expect(page.find_field("service_push_channel").value).to have_content '1'
expect(page.find_field("service_issue_channel").value).to have_content '2'
expect(page.find_field("service_merge_request_channel").value).to have_content '3'
expect(page.find_field("service_note_channel").value).to have_content '4'
expect(page.find_field("service_tag_push_channel").value).to have_content '5'
expect(page.find_field("service_pipeline_channel").value).to have_content '6'
expect(page.find_field("service_wiki_page_channel").value).to have_content '7'
end
end
require 'spec_helper'
describe 'User activates Asana' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Asana')
end
it 'activates service' do
check('Active')
fill_in('Api key', with: 'verySecret')
fill_in('Restrict to branch', with: 'verySecret')
click_button('Save')
expect(page).to have_content('Asana activated.')
end
end
require 'spec_helper'
describe 'User activates Assembla' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Assembla')
end
it 'activates service' do
check('Active')
fill_in('Token', with: 'verySecret')
click_button('Save')
expect(page).to have_content('Assembla activated.')
end
end
require 'spec_helper'
describe 'User activates Atlassian Bamboo CI' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Atlassian Bamboo CI')
end
it 'activates service' do
check('Active')
fill_in('Bamboo url', with: 'http://bamboo.example.com')
fill_in('Build key', with: 'KEY')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
click_button('Save')
expect(page).to have_content('Atlassian Bamboo CI activated.')
# Password field should not be filled in.
click_link('Atlassian Bamboo CI')
expect(find_field('Enter new password').value).to be_nil
end
end
require 'spec_helper'
describe 'User activates Emails on push' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Emails on push')
end
it 'activates service' do
check('Active')
fill_in('Recipients', with: 'qa@company.name')
click_button('Save')
expect(page).to have_content('Emails on push activated.')
end
end
require 'spec_helper'
describe 'User activates Flowdock' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Flowdock')
end
it 'activates service' do
check('Active')
fill_in('Token', with: 'verySecret')
click_button('Save')
expect(page).to have_content('Flowdock activated.')
end
end
require 'spec_helper'
describe 'User activates HipChat' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('HipChat')
end
context 'with standart settings' do
it 'activates service' do
check('Active')
fill_in('Room', with: 'gitlab')
fill_in('Token', with: 'verySecret')
click_button('Save')
expect(page).to have_content('HipChat activated.')
end
end
context 'with custom settings' do
it 'activates service' do
check('Active')
fill_in('Room', with: 'gitlab_custom')
fill_in('Token', with: 'secretCustom')
fill_in('Server', with: 'https://chat.example.com')
click_button('Save')
expect(page).to have_content('HipChat activated.')
end
end
end
require 'spec_helper'
describe 'User activates Irker (IRC gateway)' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Irker (IRC gateway)')
end
it 'activates service' do
check('Active')
check('Colorize messages')
fill_in('Recipients', with: 'irc://chat.freenode.net/#commits')
click_button('Save')
expect(page).to have_content('Irker (IRC gateway) activated.')
end
end
require 'spec_helper'
describe 'User activates JetBrains TeamCity CI' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('JetBrains TeamCity CI')
end
it 'activates service' do
check('Active')
fill_in('Teamcity url', with: 'http://teamcity.example.com')
fill_in('Build type', with: 'GitlabTest_Build')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
click_button('Save')
expect(page).to have_content('JetBrains TeamCity CI activated.')
end
end
require 'spec_helper'
feature 'Setup Jira service', :js do
describe 'User activates Jira', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:service) { project.create_jira_service }
......
require 'spec_helper'
describe 'User activates PivotalTracker' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('PivotalTracker')
end
it 'activates service' do
check('Active')
fill_in('Token', with: 'verySecret')
click_button('Save')
expect(page).to have_content('PivotalTracker activated.')
end
end
require 'spec_helper'
describe 'User activates Pushover' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
click_link('Pushover')
end
it 'activates service' do
check('Active')
fill_in('Api key', with: 'verySecret')
fill_in('User key', with: 'verySecret')
fill_in('Device', with: 'myDevice')
select('High Priority', from: 'Priority')
select('Bike', from: 'Sound')
click_button('Save')
expect(page).to have_content('Pushover activated.')
end
end
require 'spec_helper'
describe 'User activates Slack notifications' do
let(:user) { create(:user) }
let(:service) { SlackService.new }
let(:project) { create(:project, slack_service: service) }
before do
project.add_master(user)
sign_in(user)
end
context 'when service is not configured yet' do
before do
visit(project_settings_integrations_path(project))
click_link('Slack notifications')
end
it 'activates service' do
check('Active')
fill_in('Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685')
click_button('Save')
expect(page).to have_content('Slack notifications activated.')
end
end
context 'when service is already configured' do
before do
service.fields
service.update_attributes(
push_channel: 1,
issue_channel: 2,
merge_request_channel: 3,
note_channel: 4,
tag_push_channel: 5,
pipeline_channel: 6,
wiki_page_channel: 7)
visit(edit_project_service_path(project, service))
end
it 'filters events by channel' do
expect(page.find_field('service_push_channel').value).to have_content('1')
expect(page.find_field('service_issue_channel').value).to have_content('2')
expect(page.find_field('service_merge_request_channel').value).to have_content('3')
expect(page.find_field('service_note_channel').value).to have_content('4')
expect(page.find_field('service_tag_push_channel').value).to have_content('5')
expect(page.find_field('service_pipeline_channel').value).to have_content('6')
expect(page.find_field('service_wiki_page_channel').value).to have_content('7')
end
end
end
require 'spec_helper'
describe 'User views services' do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.add_master(user)
sign_in(user)
visit(project_settings_integrations_path(project))
end
it 'shows the list of available services' do
expect(page).to have_content('Project services')
expect(page).to have_content('Campfire')
expect(page).to have_content('HipChat')
expect(page).to have_content('Assembla')
expect(page).to have_content('Pushover')
expect(page).to have_content('Atlassian Bamboo')
expect(page).to have_content('JetBrains TeamCity')
expect(page).to have_content('Asana')
expect(page).to have_content('Irker (IRC gateway)')
end
end
import csrf from '~/lib/utils/csrf';
describe('csrf', () => {
beforeEach(() => {
this.tokenKey = 'X-CSRF-Token';
this.token = 'pH1cvjnP9grx2oKlhWEDvUZnJ8x2eXsIs1qzyHkF3DugSG5yTxR76CWeEZRhML2D1IeVB7NEW0t5l/axE4iJpQ==';
});
it('returns the correct headerKey', () => {
expect(csrf.headerKey).toBe(this.tokenKey);
});
describe('when csrf token is in the DOM', () => {
beforeEach(() => {
setFixtures(`
<meta name="csrf-token" content="${this.token}">
`);
csrf.init();
});
it('returns the csrf token', () => {
expect(csrf.token).toBe(this.token);
});
it('returns the csrf headers object', () => {
expect(csrf.headers[this.tokenKey]).toBe(this.token);
});
});
describe('when csrf token is not in the DOM', () => {
beforeEach(() => {
setFixtures(`
<meta name="some-other-token">
`);
csrf.init();
});
it('returns null for token', () => {
expect(csrf.token).toBeNull();
});
it('returns empty object for headers', () => {
expect(typeof csrf.headers).toBe('object');
expect(Object.keys(csrf.headers).length).toBe(0);
});
});
});
import Vue from 'vue';
import autosize from 'vendor/autosize';
import store from '~/notes/stores';
import issueCommentForm from '~/notes/components/issue_comment_form.vue';
import { loggedOutIssueData, notesDataMock, userDataMock, issueDataMock } from '../mock_data';
......@@ -55,6 +56,19 @@ describe('issue_comment_form component', () => {
expect(vm.$el.querySelector(`a[href="${quickActionsDocsPath}"]`).textContent.trim()).toEqual('quick actions');
});
it('should resize textarea after note discarded', (done) => {
spyOn(autosize, 'update');
spyOn(vm, 'discard').and.callThrough();
vm.note = 'foo';
vm.discard();
Vue.nextTick(() => {
expect(autosize.update).toHaveBeenCalled();
done();
});
});
describe('edit mode', () => {
it('should enter edit mode when arrow up is pressed', () => {
spyOn(vm, 'editCurrentUserLastNote').and.callThrough();
......
import * as actions from '~/notes/stores/actions';
import testAction from './helpers';
import { discussionMock, notesDataMock, userDataMock, issueDataMock, individualNote } from '../mock_data';
......
......@@ -3,19 +3,31 @@ import { note, discussionMock, notesDataMock, userDataMock, issueDataMock, indiv
describe('Mutation Notes Store', () => {
describe('ADD_NEW_NOTE', () => {
it('should add a new note to an array of notes', () => {
const state = { notes: [] };
let state;
let noteData;
beforeEach(() => {
state = { notes: [] };
noteData = {
expanded: true,
id: note.discussion_id,
individual_note: true,
notes: [note],
reply_id: note.discussion_id,
};
mutations.ADD_NEW_NOTE(state, note);
});
it('should add a new note to an array of notes', () => {
expect(state).toEqual({
notes: [{
expanded: true,
id: note.discussion_id,
individual_note: true,
notes: [note],
reply_id: note.discussion_id,
}],
notes: [noteData],
});
expect(state.notes.length).toBe(1);
});
it('should not add the same note to the notes array', () => {
mutations.ADD_NEW_NOTE(state, note);
expect(state.notes.length).toBe(1);
});
});
......
......@@ -28,6 +28,7 @@ describe Backup::Manager do
'1451520000_2015_12_31_4.5.6_gitlab_backup.tar',
'1451520000_2015_12_31_4.5.6-pre_gitlab_backup.tar',
'1451520000_2015_12_31_4.5.6-rc1_gitlab_backup.tar',
'1451520000_2015_12_31_4.5.6-pre-ee_gitlab_backup.tar',
'1451510000_2015_12_30_gitlab_backup.tar',
'1450742400_2015_12_22_gitlab_backup.tar',
'1449878400_gitlab_backup.tar',
......@@ -114,14 +115,18 @@ describe Backup::Manager do
expect(FileUtils).to have_received(:rm).with(files[3])
end
it 'removes matching files with a human-readable non-versioned timestamp' do
it 'removes matching files with a human-readable versioned timestamp with tagged EE' do
expect(FileUtils).to have_received(:rm).with(files[4])
end
it 'removes matching files with a human-readable non-versioned timestamp' do
expect(FileUtils).to have_received(:rm).with(files[5])
expect(FileUtils).to have_received(:rm).with(files[6])
end
it 'removes matching files without a human-readable timestamp' do
expect(FileUtils).to have_received(:rm).with(files[6])
expect(FileUtils).to have_received(:rm).with(files[7])
expect(FileUtils).to have_received(:rm).with(files[8])
end
it 'does not remove files that are not old enough' do
......@@ -129,11 +134,11 @@ describe Backup::Manager do
end
it 'does not remove non-matching files' do
expect(FileUtils).not_to have_received(:rm).with(files[8])
expect(FileUtils).not_to have_received(:rm).with(files[9])
end
it 'prints a done message' do
expect(progress).to have_received(:puts).with('done. (7 removed)')
expect(progress).to have_received(:puts).with('done. (8 removed)')
end
end
......@@ -153,10 +158,11 @@ describe Backup::Manager do
expect(FileUtils).to have_received(:rm).with(files[5])
expect(FileUtils).to have_received(:rm).with(files[6])
expect(FileUtils).to have_received(:rm).with(files[7])
expect(FileUtils).to have_received(:rm).with(files[8])
end
it 'sets the correct removed count' do
expect(progress).to have_received(:puts).with('done. (6 removed)')
expect(progress).to have_received(:puts).with('done. (7 removed)')
end
it 'prints the error from file that could not be removed' do
......
......@@ -347,10 +347,10 @@ describe Gitlab::ClosingIssueExtractor do
end
it "fetches cross-project URL references" do
message = "Closes #{urls.project_issue_url(issue2.project, issue2)} and #{reference}"
message = "Closes #{urls.project_issue_url(issue2.project, issue2)}, #{reference} and #{urls.project_issue_url(other_issue.project, other_issue)}"
expect(subject.closed_by_message(message))
.to match_array([issue, issue2])
.to match_array([issue, issue2, other_issue])
end
it "ignores invalid cross-project URL references" do
......
......@@ -28,6 +28,7 @@ describe Gitlab::Git::Hook do
f.write(<<-HOOK)
echo 'regular message from the hook'
echo 'error message from the hook' 1>&2
echo 'error message from the hook line 2' 1>&2
exit 1
HOOK
end
......@@ -73,7 +74,7 @@ describe Gitlab::Git::Hook do
status, errors = hook.trigger(gl_id, blank, blank, ref)
expect(status).to be false
expect(errors).to eq("error message from the hook\n")
expect(errors).to eq("error message from the hook<br>error message from the hook line 2<br>")
end
end
end
......
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