Commit ad30e6eb authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-03-14

# Conflicts:
#	app/assets/stylesheets/pages/merge_requests.scss
#	spec/models/ci/build_spec.rb

[ci skip]
parents f3c32e8c 8467a796
......@@ -312,7 +312,7 @@ group :metrics do
end
group :development do
gem 'foreman', '~> 0.78.0'
gem 'foreman', '~> 0.84.0'
gem 'brakeman', '~> 3.6.0', require: false
gem 'letter_opener_web', '~> 1.3.0'
......
......@@ -290,7 +290,7 @@ GEM
nokogiri (>= 1.5.11, < 2.0.0)
font-awesome-rails (4.7.0.1)
railties (>= 3.2, < 5.1)
foreman (0.78.0)
foreman (0.84.0)
thor (~> 0.19.1)
formatador (0.2.5)
fuubar (2.2.0)
......@@ -1090,7 +1090,7 @@ DEPENDENCIES
fog-openstack (~> 0.1)
fog-rackspace (~> 0.1.1)
font-awesome-rails (~> 4.7)
foreman (~> 0.78.0)
foreman (~> 0.84.0)
fuubar (~> 2.2.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.3)
......
......@@ -132,9 +132,8 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
matcher(flag, subtext) {
const relevantText = subtext.trim().split(/\s/).pop();
const regexp = new RegExp(`(?:[^${glRegexp.unicodeLetters}0-9:]|\n|^):([^:]*)$`, 'gi');
const match = regexp.exec(relevantText);
const match = regexp.exec(subtext);
return match && match.length ? match[1] : null;
},
......
<script>
import timeagoMixin from '../../vue_shared/mixins/timeago';
import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
import { visitUrl } from '../../lib/utils/url_utility';
import createFlash from '../../flash';
import MemoryUsage from './memory_usage.vue';
import StatusIcon from './mr_widget_status_icon.vue';
import MRWidgetService from '../services/mr_widget_service';
export default {
name: 'Deployment',
components: {
LoadingButton,
MemoryUsage,
StatusIcon,
},
directives: {
tooltip,
},
mixins: [
timeagoMixin,
],
props: {
deployment: {
type: Object,
required: true,
},
},
data() {
return {
isStopping: false,
};
},
computed: {
deployTimeago() {
return this.timeFormated(this.deployment.deployed_at);
},
hasExternalUrls() {
return !!(this.deployment.external_url && this.deployment.external_url_formatted);
},
hasDeploymentTime() {
return !!(this.deployment.deployed_at && this.deployment.deployed_at_formatted);
},
hasDeploymentMeta() {
return !!(this.deployment.url && this.deployment.name);
},
hasMetrics() {
return !!(this.deployment.metrics_url);
},
},
methods: {
stopEnvironment() {
const msg = 'Are you sure you want to stop this environment?';
const isConfirmed = confirm(msg); // eslint-disable-line
if (isConfirmed) {
this.isStopping = true;
MRWidgetService.stopEnvironment(this.deployment.stop_url)
.then(res => res.data)
.then((data) => {
if (data.redirect_url) {
visitUrl(data.redirect_url);
}
this.isStopping = false;
})
.catch(() => {
createFlash('Something went wrong while stopping this environment. Please try again.');
this.isStopping = false;
});
}
},
},
};
</script>
<template>
<div class="mr-widget-heading deploy-heading">
<div class="ci-widget media">
<div class="ci-status-icon ci-status-icon-success">
<span class="js-icon-link icon-link">
<status-icon status="success" />
</span>
</div>
<div class="media-body">
<div class="deploy-body">
<template v-if="hasDeploymentMeta">
<span>
Deployed to
</span>
<a
:href="deployment.url"
target="_blank"
rel="noopener noreferrer nofollow"
class="deploy-link js-deploy-meta"
>
{{ deployment.name }}
</a>
</template>
<template v-if="hasExternalUrls">
<span>
on
</span>
<a
:href="deployment.external_url"
target="_blank"
rel="noopener noreferrer nofollow"
class="deploy-link js-deploy-url"
>
<i
class="fa fa-external-link"
aria-hidden="true"
>
</i>
{{ deployment.external_url_formatted }}
</a>
</template>
<span
v-if="hasDeploymentTime"
v-tooltip
:title="deployment.deployed_at_formatted"
class="js-deploy-time"
>
{{ deployTimeago }}
</span>
<loading-button
v-if="deployment.stop_url"
container-class="btn btn-default btn-xs prepend-left-default"
label="Stop environment"
:loading="isStopping"
@click="stopEnvironment"
/>
</div>
<memory-usage
v-if="hasMetrics"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
/>
</div>
</div>
</div>
</template>
import { getTimeago } from '~/lib/utils/datetime_utility';
import { visitUrl } from '../../lib/utils/url_utility';
import Flash from '../../flash';
import MemoryUsage from './memory_usage.vue';
import StatusIcon from './mr_widget_status_icon.vue';
import MRWidgetService from '../services/mr_widget_service';
export default {
name: 'MRWidgetDeployment',
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
},
components: {
MemoryUsage,
StatusIcon,
},
methods: {
formatDate(date) {
return getTimeago().format(date);
},
hasExternalUrls(deployment = {}) {
return deployment.external_url && deployment.external_url_formatted;
},
hasDeploymentTime(deployment = {}) {
return deployment.deployed_at && deployment.deployed_at_formatted;
},
hasDeploymentMeta(deployment = {}) {
return deployment.url && deployment.name;
},
stopEnvironment(deployment) {
const msg = 'Are you sure you want to stop this environment?';
const isConfirmed = confirm(msg); // eslint-disable-line
if (isConfirmed) {
MRWidgetService.stopEnvironment(deployment.stop_url)
.then(res => res.data)
.then((data) => {
if (data.redirect_url) {
visitUrl(data.redirect_url);
}
})
.catch(() => {
new Flash('Something went wrong while stopping this environment. Please try again.'); // eslint-disable-line
});
}
},
},
template: `
<div class="mr-widget-heading deploy-heading">
<div v-for="deployment in mr.deployments">
<div class="ci-widget media">
<div class="ci-status-icon ci-status-icon-success">
<span class="js-icon-link icon-link">
<status-icon status="success" />
</span>
</div>
<div class="media-body space-children">
<span>
<span
v-if="hasDeploymentMeta(deployment)">
Deployed to
</span>
<a
v-if="hasDeploymentMeta(deployment)"
:href="deployment.url"
target="_blank"
rel="noopener noreferrer nofollow"
class="js-deploy-meta inline">
{{deployment.name}}
</a>
<span
v-if="hasExternalUrls(deployment)">
on
</span>
<a
v-if="hasExternalUrls(deployment)"
:href="deployment.external_url"
target="_blank"
rel="noopener noreferrer nofollow"
class="js-deploy-url inline">
<i
class="fa fa-external-link"
aria-hidden="true" />
{{deployment.external_url_formatted}}
</a>
<span
v-if="hasDeploymentTime(deployment)"
:data-title="deployment.deployed_at_formatted"
class="js-deploy-time"
data-toggle="tooltip"
data-placement="top">
{{formatDate(deployment.deployed_at)}}
</span>
</span>
<button
type="button"
v-if="deployment.stop_url"
@click="stopEnvironment(deployment)"
class="btn btn-default btn-xs">
Stop environment
</button>
<memory-usage
v-if="deployment.metrics_url"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
/>
</div>
</div>
</div>
</div>
`,
};
......@@ -14,7 +14,7 @@ export { default as SmartInterval } from '~/smart_interval';
export { default as WidgetHeader } from './components/mr_widget_header.vue';
export { default as WidgetMergeHelp } from './components/mr_widget_merge_help.vue';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as WidgetDeployment } from './components/mr_widget_deployment';
export { default as Deployment } from './components/deployment.vue';
export { default as WidgetMaintainerEdit } from './components/mr_widget_maintainer_edit.vue';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue';
export { default as MergedState } from './components/states/mr_widget_merged.vue';
......
......@@ -5,7 +5,7 @@ import {
WidgetHeader,
WidgetMergeHelp,
WidgetPipeline,
WidgetDeployment,
Deployment,
WidgetMaintainerEdit,
WidgetRelatedLinks,
MergedState,
......@@ -67,9 +67,6 @@ export default {
shouldRenderRelatedLinks() {
return !!this.mr.relatedLinks && !this.mr.isNothingToMergeState;
},
shouldRenderDeployments() {
return this.mr.deployments.length;
},
shouldRenderSourceBranchRemovalStatus() {
return !this.mr.canRemoveSourceBranch && this.mr.shouldRemoveSourceBranch &&
(!this.mr.isNothingToMergeState && !this.mr.isMergedState);
......@@ -217,7 +214,7 @@ export default {
'mr-widget-header': WidgetHeader,
'mr-widget-merge-help': WidgetMergeHelp,
'mr-widget-pipeline': WidgetPipeline,
'mr-widget-deployment': WidgetDeployment,
Deployment,
'mr-widget-maintainer-edit': WidgetMaintainerEdit,
'mr-widget-related-links': WidgetRelatedLinks,
'mr-widget-merged': MergedState,
......@@ -251,10 +248,11 @@ export default {
:ci-status="mr.ciStatus"
:has-ci="mr.hasCI"
/>
<mr-widget-deployment
v-if="shouldRenderDeployments"
:mr="mr"
:service="service" />
<deployment
v-for="deployment in mr.deployments"
:key="deployment.id"
:deployment="deployment"
/>
<div class="mr-widget-section">
<component
:is="componentName"
......
......@@ -768,6 +768,8 @@
}
.mr-memory-usage {
width: 100%;
p.usage-info-loading .usage-info-load-spinner {
margin-right: 10px;
font-size: 16px;
......@@ -778,8 +780,42 @@
margin-right: -5px;
}
<<<<<<< HEAD
.mr-widget-icon {
font-size: 22px;
margin: 0 10px 0 0;
=======
.deploy-heading {
.media-body {
min-width: 0;
}
}
.deploy-body {
display: flex;
flex-wrap: wrap;
@media (min-width: $screen-xs) {
flex-wrap: nowrap;
white-space: nowrap;
}
> *:not(:last-child) {
margin-right: .3em;
}
}
.deploy-link {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 100px;
max-width: 150px;
@media (min-width: $screen-xs) {
min-width: 0;
max-width: 100%;
}
>>>>>>> upstream/master
}
......@@ -1097,7 +1097,7 @@ class Project < ActiveRecord::Base
# Forked import is handled asynchronously
return if forked? && !force
if gitlab_shell.add_repository(repository_storage, disk_path)
if gitlab_shell.create_repository(repository_storage, disk_path)
repository.after_create
true
else
......
......@@ -183,7 +183,7 @@ class ProjectWiki
private
def create_repo!(raw_repository)
gitlab_shell.add_repository(project.repository_storage, disk_path)
gitlab_shell.create_repository(project.repository_storage, disk_path)
raise CouldNotCreateWikiError unless raw_repository.exists?
......
---
title: Update foreman from 0.78.0 to 0.84.0
merge_request: 17690
author: Takuya Noguchi
type: other
---
title: Hide emoji popup after multiple spaces
merge_request:
author: Jan Beckmann
type: fixed
......@@ -189,6 +189,7 @@ for a real-world example of this exploit.
```sh
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart
```
1. Verify that everything is configured correctly:
......
Feature: Project Graph
Background:
Given I sign in as a user
And I own project "Shop"
@javascript
Scenario: I should see project graphs
When I visit project "Shop" graph page
Then page should have graphs
@javascript
Scenario: I should see project languages & commits graphs on commits graph url
When I visit project "Shop" commits graph page
Then page should have commits graphs
Then page should have languages graphs
@javascript
Scenario: I should see project ci graphs
Given project "Shop" has CI enabled
When I visit project "Shop" CI graph page
Then page should have CI graphs
@javascript
Scenario: I should see project languages & commits graphs on language graph url
When I visit project "Shop" languages graph page
Then page should have languages graphs
Then page should have commits graphs
@javascript
Scenario: I should see project languages & commits graphs on charts url
When I visit project "Shop" chart page
Then page should have languages graphs
Then page should have commits graphs
Feature: Project Redirects
Background:
Given public project "Community"
And private project "Enterprise"
Scenario: I visit public project page
When I visit project "Community" page
Then I should see project "Community" home page
Scenario: I visit private project page
When I visit project "Enterprise" page
Then I should be redirected to sign in page
Scenario: I visit a non-existent project page
When I visit project "CommunityDoesNotExist" page
Then I should be redirected to sign in page
Scenario: I visit a non-existent project page as user
Given I sign in as a user
When I visit project "CommunityDoesNotExist" page
Then page status code should be 404
Scenario: I visit unauthorized project page as user
Given I sign in as a user
When I visit project "Enterprise" page
Then page status code should be 404
Scenario: I visit a public project without signing in
When I visit project "Community" page
And I should see project "Community" home page
And I click on "Sign In"
And Authenticate
Then I should be redirected to "Community" page
Scenario: I visit private project page without signing in
When I visit project "Enterprise" page
And I get redirected to signin page where I sign in
Then I should be redirected to "Enterprise" page
class Spinach::Features::ProjectGraph < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
step 'page should have graphs' do
expect(page).to have_selector ".stat-graph"
end
When 'I visit project "Shop" graph page' do
visit project_graph_path(project, "master")
end
step 'I visit project "Shop" commits graph page' do
visit commits_project_graph_path(project, "master")
end
step 'I visit project "Shop" languages graph page' do
visit languages_project_graph_path(project, "master")
end
step 'I visit project "Shop" chart page' do
visit charts_project_graph_path(project, "master")
end
step 'page should have languages graphs' do
expect(page).to have_content /Ruby 66.* %/
expect(page).to have_content /JavaScript 22.* %/
end
step 'page should have commits graphs' do
expect(page).to have_content "Commit statistics for master"
expect(page).to have_content "Commits per day of month"
end
step 'I visit project "Shop" CI graph page' do
visit ci_project_graph_path(project, 'master')
end
step 'page should have CI graphs' do
expect(page).to have_content 'Overall'
expect(page).to have_content 'Pipelines for last week'
expect(page).to have_content 'Pipelines for last month'
expect(page).to have_content 'Pipelines for last year'
expect(page).to have_content 'Commit duration in minutes for last 30 commits'
end
def project
@project ||= Project.find_by(name: "Shop")
end
end
class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedProject
step 'public project "Community"' do
create(:project, :public, name: 'Community')
end
step 'private project "Enterprise"' do
create(:project, :private, name: 'Enterprise')
end
step 'I visit project "Community" page' do
project = Project.find_by(name: 'Community')
visit project_path(project)
end
step 'I should see project "Community" home page' do
Gitlab.config.gitlab.should_receive(:host).and_return("www.example.com")
page.within '.breadcrumbs .breadcrumb-item-text' do
expect(page).to have_content 'Community'
end
end
step 'I visit project "Enterprise" page' do
project = Project.find_by(name: 'Enterprise')
visit project_path(project)
end
step 'I visit project "CommunityDoesNotExist" page' do
project = Project.find_by(name: 'Community')
visit project_path(project) + 'DoesNotExist'
end
step 'I click on "Sign In"' do
first(:link, "Sign in").click
end
step 'Authenticate' do
admin = create(:admin)
fill_in "user_login", with: admin.email
fill_in "user_password", with: admin.password
click_button "Sign in"
Thread.current[:current_user] = admin
end
step 'I should be redirected to "Community" page' do
project = Project.find_by(name: 'Community')
expect(current_path).to eq "/#{project.full_path}"
expect(status_code).to eq 200
end
step 'I get redirected to signin page where I sign in' do
admin = create(:admin)
fill_in "user_login", with: admin.email
fill_in "user_password", with: admin.password
click_button "Sign in"
Thread.current[:current_user] = admin
end
step 'I should be redirected to "Enterprise" page' do
project = Project.find_by(name: 'Enterprise')
expect(current_path).to eq "/#{project.full_path}"
expect(status_code).to eq 200
end
end
......@@ -69,13 +69,14 @@ module Gitlab
# name - project disk path
#
# Ex.
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
# create_repository("/path/to/storage", "gitlab/gitlab-ci")
#
def add_repository(storage, name)
def create_repository(storage, name)
relative_path = name.dup
relative_path << '.git' unless relative_path.end_with?('.git')
gitaly_migrate(:create_repository) do |is_enabled|
gitaly_migrate(:create_repository,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
repository = Gitlab::Git::Repository.new(storage, relative_path, '')
repository.gitaly_repository_client.create_repository
......@@ -85,7 +86,7 @@ module Gitlab
Gitlab::Git::Repository.create(repo_path, bare: true, symlink_hooks_to: gitlab_shell_hooks_path)
end
end
rescue => err
rescue => err # Once the Rugged codes gets removes this can be improved
Rails.logger.error("Failed to add repository #{storage}/#{name}: #{err}")
false
end
......@@ -487,8 +488,8 @@ module Gitlab
Gitlab.config.gitlab_shell.git_timeout
end
def gitaly_migrate(method, &block)
Gitlab::GitalyClient.migrate(method, &block)
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
Gitlab::GitalyClient.migrate(method, status: status, &block)
rescue GRPC::NotFound, GRPC::BadStatus => e
# Old Popen code returns [Error, output] to the caller, so we
# need to do the same here...
......
......@@ -69,7 +69,7 @@ namespace :gitlab do
if File.exist?(path_to_repo)
print '-'
else
if Gitlab::Shell.new.add_repository(project.repository_storage,
if Gitlab::Shell.new.create_repository(project.repository_storage,
project.disk_path)
print '.'
else
......
......@@ -22,7 +22,7 @@ describe 'Merge request > User sees deployment widget', :js do
wait_for_requests
expect(page).to have_content("Deployed to #{environment.name}")
expect(find('.js-deploy-time')['data-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
expect(find('.js-deploy-time')['data-original-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
end
context 'with stop action' do
......
require 'spec_helper'
describe 'Project Graph', :js do
let(:user) { create :user }
let(:project) { create(:project, :repository, namespace: user.namespace) }
before do
project.add_master(user)
sign_in(user)
end
shared_examples 'page should have commits graphs' do
it 'renders commits' do
expect(page).to have_content('Commit statistics for master')
expect(page).to have_content('Commits per day of month')
end
end
shared_examples 'page should have languages graphs' do
it 'renders languages' do
expect(page).to have_content(/Ruby 66.* %/)
expect(page).to have_content(/JavaScript 22.* %/)
end
end
it 'renders graphs' do
visit project_graph_path(project, 'master')
expect(page).to have_selector('.stat-graph', visible: false)
end
context 'commits graph' do
before do
visit commits_project_graph_path(project, 'master')
end
it_behaves_like 'page should have commits graphs'
it_behaves_like 'page should have languages graphs'
end
context 'languages graph' do
before do
visit languages_project_graph_path(project, 'master')
end
it_behaves_like 'page should have commits graphs'
it_behaves_like 'page should have languages graphs'
end
context 'charts graph' do
before do
visit charts_project_graph_path(project, 'master')
end
it_behaves_like 'page should have commits graphs'
it_behaves_like 'page should have languages graphs'
end
context 'when CI enabled' do
before do
project.enable_ci
visit ci_project_graph_path(project, 'master')
end
it 'renders CI graphs' do
expect(page).to have_content 'Overall'
expect(page).to have_content 'Pipelines for last week'
expect(page).to have_content 'Pipelines for last month'
expect(page).to have_content 'Pipelines for last year'
expect(page).to have_content 'Commit duration in minutes for last 30 commits'
end
end
end
require 'spec_helper'
describe 'Project redirects' do
let(:user) { create :user }
let(:public_project) { create :project, :public }
let(:private_project) { create :project, :private }
before do
allow(Gitlab.config.gitlab).to receive(:host).and_return('www.example.com')
end
it 'shows public project page' do
visit project_path(public_project)
page.within '.breadcrumbs .breadcrumb-item-text' do
expect(page).to have_content(public_project.name)
end
end
it 'redirects to sign in page when project is private' do
visit project_path(private_project)
expect(current_path).to eq(new_user_session_path)
end
it 'redirects to sign in page when project does not exist' do
visit project_path(build(:project, :public))
expect(current_path).to eq(new_user_session_path)
end
it 'redirects to public project page after signing in' do
visit project_path(public_project)
first(:link, 'Sign in').click
fill_in 'user_login', with: user.email
fill_in 'user_password', with: user.password
click_button 'Sign in'
expect(status_code).to eq(200)
expect(current_path).to eq("/#{public_project.full_path}")
end
it 'redirects to private project page after sign in' do
visit project_path(private_project)
owner = private_project.owner
fill_in 'user_login', with: owner.email
fill_in 'user_password', with: owner.password
click_button 'Sign in'
expect(status_code).to eq(200)
expect(current_path).to eq("/#{private_project.full_path}")
end
context 'when signed in' do
before do
sign_in(user)
end
it 'returns 404 status when project does not exist' do
visit project_path(build(:project, :public))
expect(status_code).to eq(404)
end
it 'returns 404 when project is private' do
visit project_path(private_project)
expect(status_code).to eq(404)
end
end
end
import Vue from 'vue';
import * as urlUtils from '~/lib/utils/url_utility';
import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment';
import deploymentComponent from '~/vue_merge_request_widget/components/deployment.vue';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
import { getTimeago } from '~/lib/utils/datetime_utility';
const deploymentMockData = [
{
id: 15,
name: 'review/diplo',
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
external_url: 'http://diplo.',
external_url_formatted: 'diplo.',
deployed_at: '2017-03-22T22:44:42.258Z',
deployed_at_formatted: 'Mar 22, 2017 10:44pm',
},
];
const deploymentMockData = {
id: 15,
name: 'review/diplo',
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
external_url: 'http://diplo.',
external_url_formatted: 'diplo.',
deployed_at: '2017-03-22T22:44:42.258Z',
deployed_at_formatted: 'Mar 22, 2017 10:44pm',
};
const createComponent = () => {
const Component = Vue.extend(deploymentComponent);
const mr = {
deployments: deploymentMockData,
};
const service = {};
return new Component({
el: document.createElement('div'),
propsData: { mr, service },
propsData: { deployment: { ...deploymentMockData } },
});
};
describe('MRWidgetDeployment', () => {
describe('props', () => {
it('should have props', () => {
const { mr, service } = deploymentComponent.props;
expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy();
describe('Deployment component', () => {
let vm;
expect(service.type instanceof Object).toBeTruthy();
expect(service.required).toBeTruthy();
});
beforeEach(() => {
vm = createComponent();
});
describe('methods', () => {
let vm = createComponent();
const deployment = deploymentMockData[0];
afterEach(() => {
vm.$destroy();
});
describe('formatDate', () => {
it('should work', () => {
const readable = getTimeago().format(deployment.deployed_at);
expect(vm.formatDate(deployment.deployed_at)).toEqual(readable);
describe('computed', () => {
describe('deployTimeago', () => {
it('return formatted date', () => {
const readable = getTimeago().format(deploymentMockData.deployed_at);
expect(vm.deployTimeago).toEqual(readable);
});
});
describe('hasExternalUrls', () => {
it('should return true', () => {
expect(vm.hasExternalUrls(deployment)).toBeTruthy();
expect(vm.hasExternalUrls).toEqual(true);
});
it('should return false when deployment has no external_url_formatted', () => {
vm.deployment.external_url_formatted = null;
expect(vm.hasExternalUrls).toEqual(false);
});
it('should return false when there is not enough information', () => {
expect(vm.hasExternalUrls()).toBeFalsy();
expect(vm.hasExternalUrls({ external_url: 'Diplo' })).toBeFalsy();
expect(vm.hasExternalUrls({ external_url_formatted: 'Diplo' })).toBeFalsy();
it('should return false when deployment has no external_url', () => {
vm.deployment.external_url = null;
expect(vm.hasExternalUrls).toEqual(false);
});
});
describe('hasDeploymentTime', () => {
it('should return true', () => {
expect(vm.hasDeploymentTime(deployment)).toBeTruthy();
expect(vm.hasDeploymentTime).toEqual(true);
});
it('should return false when there is not enough information', () => {
expect(vm.hasDeploymentTime()).toBeFalsy();
expect(vm.hasDeploymentTime({ deployed_at: 'Diplo' })).toBeFalsy();
expect(vm.hasDeploymentTime({ deployed_at_formatted: 'Diplo' })).toBeFalsy();
it('should return false when deployment has no deployed_at', () => {
vm.deployment.deployed_at = null;
expect(vm.hasDeploymentTime).toEqual(false);
});
it('should return false when deployment has no deployed_at_formatted', () => {
vm.deployment.deployed_at_formatted = null;
expect(vm.hasDeploymentTime).toEqual(false);
});
});
describe('hasDeploymentMeta', () => {
it('should return true', () => {
expect(vm.hasDeploymentMeta(deployment)).toBeTruthy();
expect(vm.hasDeploymentMeta).toEqual(true);
});
it('should return false when deployment has no url', () => {
vm.deployment.url = null;
expect(vm.hasDeploymentMeta).toEqual(false);
});
it('should return false when there is not enough information', () => {
expect(vm.hasDeploymentMeta()).toBeFalsy();
expect(vm.hasDeploymentMeta({ url: 'Diplo' })).toBeFalsy();
expect(vm.hasDeploymentMeta({ name: 'Diplo' })).toBeFalsy();
it('should return false when deployment has no name', () => {
vm.deployment.name = null;
expect(vm.hasDeploymentMeta).toEqual(false);
});
});
});
describe('methods', () => {
describe('stopEnvironment', () => {
const url = '/foo/bar';
const returnPromise = () => new Promise((resolve) => {
......@@ -131,49 +140,33 @@ describe('MRWidgetDeployment', () => {
});
describe('template', () => {
let vm;
let el;
const [deployment] = deploymentMockData;
beforeEach(() => {
vm = createComponent(deploymentMockData);
el = vm.$el;
});
it('should render template elements correctly', () => {
expect(el.classList.contains('mr-widget-heading')).toBeTruthy();
expect(el.querySelector('.js-icon-link')).toBeDefined();
expect(el.querySelector('.js-deploy-meta').getAttribute('href')).toEqual(deployment.url);
expect(el.querySelector('.js-deploy-meta').innerText).toContain(deployment.name);
expect(el.querySelector('.js-deploy-url').getAttribute('href')).toEqual(deployment.external_url);
expect(el.querySelector('.js-deploy-url').innerText).toContain(deployment.external_url_formatted);
expect(el.querySelector('.js-deploy-time').innerText).toContain(vm.formatDate(deployment.deployed_at));
expect(el.querySelector('.js-mr-memory-usage')).toBeDefined();
expect(el.querySelector('button')).toBeDefined();
it('renders deployment name', () => {
expect(el.querySelector('.js-deploy-meta').getAttribute('href')).toEqual(deploymentMockData.url);
expect(el.querySelector('.js-deploy-meta').innerText).toContain(deploymentMockData.name);
});
it('should list multiple deployments', (done) => {
vm.mr.deployments.push(deployment);
vm.mr.deployments.push(deployment);
it('renders external URL', () => {
expect(el.querySelector('.js-deploy-url').getAttribute('href')).toEqual(deploymentMockData.external_url);
expect(el.querySelector('.js-deploy-url').innerText).toContain(deploymentMockData.external_url_formatted);
});
Vue.nextTick(() => {
expect(el.querySelectorAll('.ci-widget').length).toEqual(3);
expect(el.querySelectorAll('.js-mr-memory-usage').length).toEqual(3);
done();
});
it('renders stop button', () => {
expect(el.querySelector('.btn')).not.toBeNull();
});
it('should not have some elements when there is not enough data', (done) => {
vm.mr.deployments = [{}];
it('renders deployment time', () => {
expect(el.querySelector('.js-deploy-time').innerText).toContain(vm.deployTimeago);
});
Vue.nextTick(() => {
expect(el.querySelectorAll('.js-deploy-meta').length).toEqual(0);
expect(el.querySelectorAll('.js-deploy-url').length).toEqual(0);
expect(el.querySelectorAll('.js-deploy-time').length).toEqual(0);
expect(el.querySelectorAll('.js-mr-memory-usage').length).toEqual(0);
expect(el.querySelectorAll('.button').length).toEqual(0);
done();
});
it('renders metrics component', () => {
expect(el.querySelector('.js-mr-memory-usage')).not.toBeNull();
});
});
});
......@@ -123,17 +123,6 @@ describe('mrWidgetOptions', () => {
expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
});
});
describe('shouldRenderDeployments', () => {
it('should return false for the initial data', () => {
expect(vm.shouldRenderDeployments).toBeFalsy();
});
it('should return true if there is deployments', () => {
vm.mr.deployments.push({}, {});
expect(vm.shouldRenderDeployments).toBeTruthy();
});
});
});
describe('methods', () => {
......@@ -189,16 +178,16 @@ describe('mrWidgetOptions', () => {
describe('fetchDeployments', () => {
it('should fetch deployments', (done) => {
spyOn(vm.service, 'fetchDeployments').and.returnValue(returnPromise([{ deployment: 1 }]));
spyOn(vm.service, 'fetchDeployments').and.returnValue(returnPromise([{ id: 1 }]));
vm.fetchDeployments();
setTimeout(() => {
expect(vm.service.fetchDeployments).toHaveBeenCalled();
expect(vm.mr.deployments.length).toEqual(1);
expect(vm.mr.deployments[0].deployment).toEqual(1);
expect(vm.mr.deployments[0].id).toBe(1);
done();
}, 333);
});
});
});
......@@ -368,34 +357,6 @@ describe('mrWidgetOptions', () => {
});
});
describe('components', () => {
it('should register all components', () => {
const comps = mrWidgetOptions.components;
expect(comps['mr-widget-header']).toBeDefined();
expect(comps['mr-widget-merge-help']).toBeDefined();
expect(comps['mr-widget-pipeline']).toBeDefined();
expect(comps['mr-widget-deployment']).toBeDefined();
expect(comps['mr-widget-related-links']).toBeDefined();
expect(comps['mr-widget-merged']).toBeDefined();
expect(comps['mr-widget-closed']).toBeDefined();
expect(comps['mr-widget-merging']).toBeDefined();
expect(comps['mr-widget-failed-to-merge']).toBeDefined();
expect(comps['mr-widget-wip']).toBeDefined();
expect(comps['mr-widget-archived']).toBeDefined();
expect(comps['mr-widget-conflicts']).toBeDefined();
expect(comps['mr-widget-nothing-to-merge']).toBeDefined();
expect(comps['mr-widget-not-allowed']).toBeDefined();
expect(comps['mr-widget-missing-branch']).toBeDefined();
expect(comps['mr-widget-ready-to-merge']).toBeDefined();
expect(comps['mr-widget-checking']).toBeDefined();
expect(comps['mr-widget-unresolved-discussions']).toBeDefined();
expect(comps['mr-widget-pipeline-blocked']).toBeDefined();
expect(comps['mr-widget-pipeline-failed']).toBeDefined();
expect(comps['mr-widget-merge-when-pipeline-succeeds']).toBeDefined();
expect(comps['mr-widget-maintainer-edit']).toBeDefined();
});
});
describe('rendering relatedLinks', () => {
beforeEach((done) => {
vm.mr.relatedLinks = {
......@@ -454,4 +415,34 @@ describe('mrWidgetOptions', () => {
});
});
});
describe('rendering deployments', () => {
const deploymentMockData = {
id: 15,
name: 'review/diplo',
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
external_url: 'http://diplo.',
external_url_formatted: 'diplo.',
deployed_at: '2017-03-22T22:44:42.258Z',
deployed_at_formatted: 'Mar 22, 2017 10:44pm',
};
beforeEach((done) => {
vm.mr.deployments.push({
...deploymentMockData,
}, {
...deploymentMockData,
id: deploymentMockData.id + 1,
});
vm.$nextTick(done);
});
it('renders multiple deployments', () => {
expect(vm.$el.querySelectorAll('.deploy-heading').length).toBe(2);
});
});
});
......@@ -61,7 +61,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do
let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
before do
gitlab_shell.add_repository(repository_storage, hashed_path)
gitlab_shell.create_repository(repository_storage, hashed_path)
repository = Rugged::Repository.new(repo_path)
repository.config['gitlab.fullpath'] = 'to/repo'
end
......
......@@ -681,7 +681,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
subject { new_repository.fetch_repository_as_mirror(repository) }
before do
Gitlab::Shell.new.add_repository('default', 'my_project')
Gitlab::Shell.new.create_repository('default', 'my_project')
end
after do
......
......@@ -20,7 +20,7 @@ describe Gitlab::Shell do
it { is_expected.to respond_to :add_key }
it { is_expected.to respond_to :remove_key }
it { is_expected.to respond_to :add_repository }
it { is_expected.to respond_to :create_repository }
it { is_expected.to respond_to :remove_repository }
it { is_expected.to respond_to :fork_repository }
......@@ -402,8 +402,8 @@ describe Gitlab::Shell do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
describe '#add_repository' do
shared_examples '#add_repository' do
describe '#create_repository' do
shared_examples '#create_repository' do
let(:repository_storage) { 'default' }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
let(:repo_name) { 'project/path' }
......@@ -414,7 +414,7 @@ describe Gitlab::Shell do
end
it 'creates a repository' do
expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_truthy
expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_truthy
expect(File.stat(created_path).mode & 0o777).to eq(0o770)
......@@ -426,19 +426,19 @@ describe Gitlab::Shell do
it 'returns false when the command fails' do
FileUtils.mkdir_p(File.dirname(created_path))
# This file will block the creation of the repo's .git directory. That
# should cause #add_repository to fail.
# should cause #create_repository to fail.
FileUtils.touch(created_path)
expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_falsy
expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_falsy
end
end
context 'with gitaly' do
it_behaves_like '#add_repository'
it_behaves_like '#create_repository'
end
context 'without gitaly', :skip_gitaly_mock do
it_behaves_like '#add_repository'
it_behaves_like '#create_repository'
end
end
......
......@@ -1917,7 +1917,11 @@ describe Ci::Build do
allow_any_instance_of(Project)
.to receive(:predefined_variables) { [project_pre_var] }
<<<<<<< HEAD
allow_any_instance_of(EE::Project)
=======
allow_any_instance_of(Project)
>>>>>>> upstream/master
.to receive(:secret_variables_for)
.with(ref: 'master', environment: nil) do
[create(:ci_variable, key: 'secret', value: 'value')]
......
......@@ -1511,7 +1511,7 @@ describe Project do
context 'using a regular repository' do
it 'creates the repository' do
expect(shell).to receive(:add_repository)
expect(shell).to receive(:create_repository)
.with(project.repository_storage, project.disk_path)
.and_return(true)
......@@ -1521,7 +1521,7 @@ describe Project do
end
it 'adds an error if the repository could not be created' do
expect(shell).to receive(:add_repository)
expect(shell).to receive(:create_repository)
.with(project.repository_storage, project.disk_path)
.and_return(false)
......@@ -1535,7 +1535,7 @@ describe Project do
context 'using a forked repository' do
it 'does nothing' do
expect(project).to receive(:forked?).and_return(true)
expect(shell).not_to receive(:add_repository)
expect(shell).not_to receive(:create_repository)
project.create_repository
end
......@@ -1554,7 +1554,7 @@ describe Project do
allow(project).to receive(:repository_exists?)
.and_return(false)
allow(shell).to receive(:add_repository)
allow(shell).to receive(:create_repository)
.with(project.repository_storage_path, project.disk_path)
.and_return(true)
......@@ -1578,7 +1578,7 @@ describe Project do
allow(project).to receive(:repository_exists?)
.and_return(false)
expect(shell).to receive(:add_repository)
expect(shell).to receive(:create_repository)
.with(project.repository_storage, project.disk_path)
.and_return(true)
......
......@@ -82,7 +82,7 @@ describe ProjectWiki do
# Create a fresh project which will not have a wiki
project_wiki = described_class.new(create(:project), user)
gitlab_shell = double(:gitlab_shell)
allow(gitlab_shell).to receive(:add_repository)
allow(gitlab_shell).to receive(:create_repository)
allow(project_wiki).to receive(:gitlab_shell).and_return(gitlab_shell)
expect { project_wiki.send(:wiki) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
......
......@@ -164,7 +164,7 @@ describe Projects::CreateService, '#execute' do
context 'with legacy storage' do
before do
gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
gitlab_shell.create_repository(repository_storage, "#{user.namespace.full_path}/existing")
end
after do
......@@ -200,7 +200,7 @@ describe Projects::CreateService, '#execute' do
end
before do
gitlab_shell.add_repository(repository_storage, hashed_path)
gitlab_shell.create_repository(repository_storage, hashed_path)
end
after do
......
......@@ -108,7 +108,7 @@ describe Projects::ForkService do
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do
gitlab_shell.add_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}")
gitlab_shell.create_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}")
end
after do
......
......@@ -151,7 +151,7 @@ describe Projects::TransferService do
before do
group.add_owner(user)
unless gitlab_shell.add_repository(repository_storage, "#{group.full_path}/#{project.path}")
unless gitlab_shell.create_repository(repository_storage, "#{group.full_path}/#{project.path}")
raise 'failed to add repository'
end
......
......@@ -197,7 +197,7 @@ describe Projects::UpdateService, '#execute' do
let(:project) { create(:project, :legacy_storage, :repository, creator: user, namespace: user.namespace) }
before do
gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
gitlab_shell.create_repository(repository_storage, "#{user.namespace.full_path}/existing")
end
after do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment