Commit 7a66cd68 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'deploy-keys-load-async' into 'master'

Deploy keys load async

Closes #29667

See merge request !10973
parents 97a9a38b 136baeda
<script>
import eventHub from '../eventhub';
export default {
data() {
return {
isLoading: false,
};
},
props: {
deployKey: {
type: Object,
required: true,
},
type: {
type: String,
required: true,
},
btnCssClass: {
type: String,
required: false,
default: 'btn-default',
},
},
methods: {
doAction() {
this.isLoading = true;
eventHub.$emit(`${this.type}.key`, this.deployKey);
},
},
computed: {
text() {
return `${this.type.charAt(0).toUpperCase()}${this.type.slice(1)}`;
},
},
};
</script>
<template>
<button
class="btn btn-sm prepend-left-10"
:class="[{ disabled: isLoading }, btnCssClass]"
:disabled="isLoading"
@click="doAction">
{{ text }}
<i
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="Loading">
</i>
</button>
</template>
<script>
/* global Flash */
import eventHub from '../eventhub';
import DeployKeysService from '../service';
import DeployKeysStore from '../store';
import keysPanel from './keys_panel.vue';
export default {
data() {
return {
isLoading: false,
store: new DeployKeysStore(),
};
},
props: {
endpoint: {
type: String,
required: true,
},
},
computed: {
hasKeys() {
return Object.keys(this.keys).length;
},
keys() {
return this.store.keys;
},
},
components: {
keysPanel,
},
methods: {
fetchKeys() {
this.isLoading = true;
this.service.getKeys()
.then((data) => {
this.isLoading = false;
this.store.keys = data;
})
.catch(() => new Flash('Error getting deploy keys'));
},
enableKey(deployKey) {
this.service.enableKey(deployKey.id)
.then(() => this.fetchKeys())
.catch(() => new Flash('Error enabling deploy key'));
},
disableKey(deployKey) {
// eslint-disable-next-line no-alert
if (confirm('You are going to remove this deploy key. Are you sure?')) {
this.service.disableKey(deployKey.id)
.then(() => this.fetchKeys())
.catch(() => new Flash('Error removing deploy key'));
}
},
},
created() {
this.service = new DeployKeysService(this.endpoint);
eventHub.$on('enable.key', this.enableKey);
eventHub.$on('remove.key', this.disableKey);
eventHub.$on('disable.key', this.disableKey);
},
mounted() {
this.fetchKeys();
},
beforeDestroy() {
eventHub.$off('enable.key', this.enableKey);
eventHub.$off('remove.key', this.disableKey);
eventHub.$off('disable.key', this.disableKey);
},
};
</script>
<template>
<div class="col-lg-9 col-lg-offset-3 append-bottom-default deploy-keys">
<div
class="text-center"
v-if="isLoading && !hasKeys">
<i
class="fa fa-spinner fa-spin fa-2x"
aria-hidden="true"
aria-label="Loading deploy keys">
</i>
</div>
<div v-else-if="hasKeys">
<keys-panel
title="Enabled deploy keys for this project"
:keys="keys.enabled_keys"
:store="store" />
<keys-panel
title="Deploy keys from projects you have access to"
:keys="keys.available_project_keys"
:store="store" />
<keys-panel
v-if="keys.public_keys.length"
title="Public deploy keys available to any project"
:keys="keys.public_keys"
:store="store" />
</div>
</div>
</template>
<script>
import actionBtn from './action_btn.vue';
export default {
props: {
deployKey: {
type: Object,
required: true,
},
store: {
type: Object,
required: true,
},
},
components: {
actionBtn,
},
computed: {
timeagoDate() {
return gl.utils.getTimeago().format(this.deployKey.created_at);
},
},
methods: {
isEnabled(id) {
return this.store.findEnabledKey(id) !== undefined;
},
},
};
</script>
<template>
<div>
<div class="pull-left append-right-10 hidden-xs">
<i
aria-hidden="true"
class="fa fa-key key-icon">
</i>
</div>
<div class="deploy-key-content key-list-item-info">
<strong class="title">
{{ deployKey.title }}
</strong>
<div class="description">
{{ deployKey.fingerprint }}
</div>
<div
v-if="deployKey.can_push"
class="write-access-allowed">
Write access allowed
</div>
</div>
<div class="deploy-key-content prepend-left-default deploy-key-projects">
<a
v-for="project in deployKey.projects"
class="label deploy-project-label"
:href="project.full_path">
{{ project.full_name }}
</a>
</div>
<div class="deploy-key-content">
<span class="key-created-at">
created {{ timeagoDate }}
</span>
<action-btn
v-if="!isEnabled(deployKey.id)"
:deploy-key="deployKey"
type="enable"/>
<action-btn
v-else-if="deployKey.destroyed_when_orphaned && deployKey.almost_orphaned"
:deploy-key="deployKey"
btn-css-class="btn-warning"
type="remove" />
<action-btn
v-else
:deploy-key="deployKey"
btn-css-class="btn-warning"
type="disable" />
</div>
</div>
</template>
<script>
import key from './key.vue';
export default {
props: {
title: {
type: String,
required: true,
},
keys: {
type: Array,
required: true,
},
showHelpBox: {
type: Boolean,
required: false,
default: true,
},
store: {
type: Object,
required: true,
},
},
components: {
key,
},
};
</script>
<template>
<div class="deploy-keys-panel">
<h5>
{{ title }}
({{ keys.length }})
</h5>
<ul class="well-list"
v-if="keys.length">
<li
v-for="deployKey in keys"
:key="deployKey.id">
<key
:deploy-key="deployKey"
:store="store" />
</li>
</ul>
<div
class="settings-message text-center"
v-else-if="showHelpBox">
No deploy keys found. Create one with the form above.
</div>
</div>
</template>
import Vue from 'vue';
export default new Vue();
import Vue from 'vue';
import deployKeysApp from './components/app.vue';
document.addEventListener('DOMContentLoaded', () => new Vue({
el: document.getElementById('js-deploy-keys'),
data() {
return {
endpoint: this.$options.el.dataset.endpoint,
};
},
components: {
deployKeysApp,
},
render(createElement) {
return createElement('deploy-keys-app', {
props: {
endpoint: this.endpoint,
},
});
},
}));
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);
export default class DeployKeysService {
constructor(endpoint) {
this.endpoint = endpoint;
this.resource = Vue.resource(`${this.endpoint}{/id}`, {}, {
enable: {
method: 'PUT',
url: `${this.endpoint}{/id}/enable`,
},
disable: {
method: 'PUT',
url: `${this.endpoint}{/id}/disable`,
},
});
}
getKeys() {
return this.resource.get()
.then(response => response.json());
}
enableKey(id) {
return this.resource.enable({ id }, {});
}
disableKey(id) {
return this.resource.disable({ id }, {});
}
}
export default class DeployKeysStore {
constructor() {
this.keys = {};
}
findEnabledKey(id) {
return this.keys.enabled_keys.find(key => key.id === id);
}
}
......@@ -8,7 +8,12 @@ class Projects::DeployKeysController < Projects::ApplicationController
layout "project_settings"
def index
redirect_to_repository_settings(@project)
respond_to do |format|
format.html { redirect_to_repository_settings(@project) }
format.json do
render json: Projects::Settings::DeployKeysPresenter.new(@project, current_user: current_user).as_json
end
end
end
def new
......@@ -19,7 +24,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
@key = DeployKey.new(deploy_key_params.merge(user: current_user))
unless @key.valid? && @project.deploy_keys << @key
flash[:alert] = @key.errors.full_messages.join(', ').html_safe
flash[:alert] = @key.errors.full_messages.join(', ').html_safe
end
redirect_to_repository_settings(@project)
end
......@@ -27,7 +32,10 @@ class Projects::DeployKeysController < Projects::ApplicationController
def enable
Projects::EnableDeployKeyService.new(@project, current_user, params).execute
redirect_to_repository_settings(@project)
respond_to do |format|
format.html { redirect_to_repository_settings(@project) }
format.json { head :ok }
end
end
def disable
......@@ -35,7 +43,11 @@ class Projects::DeployKeysController < Projects::ApplicationController
return render_404 unless deploy_key_project
deploy_key_project.destroy!
redirect_to_repository_settings(@project)
respond_to do |format|
format.html { redirect_to_repository_settings(@project) }
format.json { head :ok }
end
end
protected
......
......@@ -48,6 +48,17 @@ module Projects
available_public_keys.any?
end
def as_json
serializer = DeployKeySerializer.new
opts = { user: current_user }
{
enabled_keys: serializer.represent(enabled_keys, opts),
available_project_keys: serializer.represent(available_project_keys, opts),
public_keys: serializer.represent(available_public_keys, opts)
}
end
def to_partial_path
'projects/deploy_keys/index'
end
......
class DeployKeyEntity < Grape::Entity
expose :id
expose :user_id
expose :title
expose :fingerprint
expose :can_push
expose :destroyed_when_orphaned?, as: :destroyed_when_orphaned
expose :almost_orphaned?, as: :almost_orphaned
expose :created_at
expose :updated_at
expose :projects, using: ProjectEntity do |deploy_key|
deploy_key.projects.select { |project| options[:user].can?(:read_project, project) }
end
end
class DeployKeySerializer < BaseSerializer
entity DeployKeyEntity
end
class ProjectEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :name
expose :full_path do |project|
namespace_project_path(project.namespace, project)
end
expose :full_name do |project|
project.full_name
end
end
......@@ -10,25 +10,4 @@
= render @deploy_keys.form_partial_path
.col-lg-9.col-lg-offset-3
%hr
.col-lg-9.col-lg-offset-3.append-bottom-default.deploy-keys
%h5.prepend-top-0
Enabled deploy keys for this project (#{@deploy_keys.enabled_keys_size})
- if @deploy_keys.any_keys_enabled?
%ul.well-list
= render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.enabled_keys, as: :deploy_key
- else
.settings-message.text-center
No deploy keys found. Create one with the form above.
%h5.prepend-top-default
Deploy keys from projects you have access to (#{@deploy_keys.available_project_keys_size})
- if @deploy_keys.any_available_project_keys_enabled?
%ul.well-list
= render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.available_project_keys, as: :deploy_key
- else
.settings-message.text-center
No deploy keys from your projects could be found. Create one with the form above or add existing one below.
- if @deploy_keys.any_available_public_keys_enabled?
%h5.prepend-top-default
Public deploy keys available to any project (#{@deploy_keys.available_public_keys_size})
%ul.well-list
= render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.available_public_keys, as: :deploy_key
#js-deploy-keys{ data: { endpoint: namespace_project_deploy_keys_path } }
- page_title "Repository"
= render "projects/settings/head"
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('deploy_keys')
= render @deploy_keys
= render "projects/protected_branches/index"
= render "projects/protected_tags/index"
---
title: Deploy keys load are loaded async
merge_request:
author:
......@@ -26,6 +26,7 @@ var config = {
common_d3: ['d3'],
cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js',
commit_pipelines: './commit/pipelines/pipelines_bundle.js',
deploy_keys: './deploy_keys/index.js',
diff_notes: './diff_notes/diff_notes_bundle.js',
environments: './environments/environments_bundle.js',
environments_folder: './environments/folder/environments_folder_bundle.js',
......@@ -122,6 +123,7 @@ var config = {
'boards',
'commit_pipelines',
'cycle_analytics',
'deploy_keys',
'diff_notes',
'environments',
'environments_folder',
......
......@@ -3,28 +3,33 @@ Feature: Project Deploy Keys
Given I sign in as a user
And I own project "Shop"
@javascript
Scenario: I should see deploy keys list
Given project has deploy key
When I visit project deploy keys page
Then I should see project deploy key
@javascript
Scenario: I should see project deploy keys
Given other projects have deploy keys
When I visit project deploy keys page
Then I should see other project deploy key
And I should only see the same deploy key once
@javascript
Scenario: I should see public deploy keys
Given public deploy key exists
When I visit project deploy keys page
Then I should see public deploy key
@javascript
Scenario: I add new deploy key
Given I visit project deploy keys page
And I submit new deploy key
Then I should be on deploy keys page
And I should see newly created deploy key
@javascript
Scenario: I attach other project deploy key to project
Given other projects have deploy keys
And I visit project deploy keys page
......@@ -32,6 +37,7 @@ Feature: Project Deploy Keys
Then I should be on deploy keys page
And I should see newly created deploy key
@javascript
Scenario: I attach public deploy key to project
Given public deploy key exists
And I visit project deploy keys page
......
......@@ -8,19 +8,19 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
end
step 'I should see project deploy key' do
page.within '.deploy-keys' do
page.within(find('.deploy-keys')) do
expect(page).to have_content deploy_key.title
end
end
step 'I should see other project deploy key' do
page.within '.deploy-keys' do
page.within(find('.deploy-keys')) do
expect(page).to have_content other_deploy_key.title
end
end
step 'I should see public deploy key' do
page.within '.deploy-keys' do
page.within(find('.deploy-keys')) do
expect(page).to have_content public_deploy_key.title
end
end
......@@ -40,7 +40,8 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
end
step 'I should see newly created deploy key' do
page.within '.deploy-keys' do
@project.reload
page.within(find('.deploy-keys')) do
expect(page).to have_content(deploy_key.title)
end
end
......@@ -56,7 +57,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
end
step 'I should only see the same deploy key once' do
page.within '.deploy-keys' do
page.within(find('.deploy-keys')) do
expect(page).to have_selector('ul li', count: 1)
end
end
......@@ -66,8 +67,9 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
end
step 'I click attach deploy key' do
page.within '.deploy-keys' do
click_link 'Enable'
page.within(find('.deploy-keys')) do
click_button 'Enable'
expect(page).not_to have_selector('.fa-spinner')
end
end
......
require 'spec_helper'
describe Projects::DeployKeysController do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
project.team << [user, :master]
sign_in(user)
end
describe 'GET index' do
let(:params) do
{ namespace_id: project.namespace, project_id: project }
end
context 'when html requested' do
it 'redirects to blob' do
get :index, params
expect(response).to redirect_to(namespace_project_settings_repository_path(params))
end
end
context 'when json requested' do
let(:project2) { create(:empty_project, :internal)}
let(:project_private) { create(:empty_project, :private)}
let(:deploy_key_internal) do
create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com')
end
let(:deploy_key_actual) do
create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNd/UJWhPrpb+b/G5oL109y57yKuCxE+WUGJGYaj7WQKsYRJmLYh1mgjrl+KVyfsWpq4ylOxIfFSnN9xBBFN8mlb0Fma5DC7YsSsibJr3MZ19ZNBprwNcdogET7aW9I0In7Wu5f2KqI6e5W/spJHCy4JVxzVMUvk6Myab0LnJ2iQ== dummy@gitlab.com')
end
let!(:deploy_key_public) { create(:deploy_key, public: true) }
let!(:deploy_keys_project_internal) do
create(:deploy_keys_project, project: project2, deploy_key: deploy_key_internal)
end
let!(:deploy_keys_actual_project) do
create(:deploy_keys_project, project: project, deploy_key: deploy_key_actual)
end
let!(:deploy_keys_project_private) do
create(:deploy_keys_project, project: project_private, deploy_key: create(:another_deploy_key))
end
before do
project2.team << [user, :developer]
end
it 'returns json in a correct format' do
get :index, params.merge(format: :json)
json = JSON.parse(response.body)
expect(json.keys).to match_array(%w(enabled_keys available_project_keys public_keys))
expect(json['enabled_keys'].count).to eq(1)
expect(json['available_project_keys'].count).to eq(1)
expect(json['public_keys'].count).to eq(1)
end
end
end
end
require 'spec_helper'
describe 'Project deploy keys', feature: true do
describe 'Project deploy keys', :js, :feature do
let(:user) { create(:user) }
let(:project) { create(:project_empty_repo) }
......@@ -17,9 +17,13 @@ describe 'Project deploy keys', feature: true do
it 'removes association between project and deploy key' do
visit namespace_project_settings_repository_path(project.namespace, project)
page.within '.deploy-keys' do
expect { click_on 'Remove' }
.to change { project.deploy_keys.count }.by(-1)
page.within(find('.deploy-keys')) do
expect(page).to have_selector('.deploy-keys li', count: 1)
click_on 'Remove'
expect(page).not_to have_selector('.fa-spinner', count: 0)
expect(page).to have_selector('.deploy-keys li', count: 0)
end
end
end
......
import Vue from 'vue';
import eventHub from '~/deploy_keys/eventhub';
import actionBtn from '~/deploy_keys/components/action_btn.vue';
describe('Deploy keys action btn', () => {
const data = getJSONFixture('deploy_keys/keys.json');
const deployKey = data.enabled_keys[0];
let vm;
beforeEach((done) => {
const ActionBtnComponent = Vue.extend(actionBtn);
vm = new ActionBtnComponent({
propsData: {
deployKey,
type: 'enable',
},
}).$mount();
setTimeout(done);
});
it('renders the type as uppercase', () => {
expect(
vm.$el.textContent.trim(),
).toBe('Enable');
});
it('sends eventHub event with btn type', (done) => {
spyOn(eventHub, '$emit');
vm.$el.click();
setTimeout(() => {
expect(
eventHub.$emit,
).toHaveBeenCalledWith('enable.key', deployKey);
done();
});
});
it('shows loading spinner after click', (done) => {
vm.$el.click();
setTimeout(() => {
expect(
vm.$el.querySelector('.fa'),
).toBeDefined();
done();
});
});
it('disables button after click', (done) => {
vm.$el.click();
setTimeout(() => {
expect(
vm.$el.classList.contains('disabled'),
).toBeTruthy();
expect(
vm.$el.getAttribute('disabled'),
).toBe('disabled');
done();
});
});
});
import Vue from 'vue';
import eventHub from '~/deploy_keys/eventhub';
import deployKeysApp from '~/deploy_keys/components/app.vue';
describe('Deploy keys app component', () => {
const data = getJSONFixture('deploy_keys/keys.json');
let vm;
const deployKeysResponse = (request, next) => {
next(request.respondWith(JSON.stringify(data), {
status: 200,
}));
};
beforeEach((done) => {
const Component = Vue.extend(deployKeysApp);
Vue.http.interceptors.push(deployKeysResponse);
vm = new Component({
propsData: {
endpoint: '/test',
},
}).$mount();
setTimeout(done);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, deployKeysResponse);
});
it('renders loading icon', (done) => {
vm.store.keys = {};
vm.isLoading = false;
Vue.nextTick(() => {
expect(
vm.$el.querySelectorAll('.deploy-keys-panel').length,
).toBe(0);
expect(
vm.$el.querySelector('.fa-spinner'),
).toBeDefined();
done();
});
});
it('renders keys panels', () => {
expect(
vm.$el.querySelectorAll('.deploy-keys-panel').length,
).toBe(3);
});
it('does not render key panels when keys object is empty', (done) => {
vm.store.keys = {};
Vue.nextTick(() => {
expect(
vm.$el.querySelectorAll('.deploy-keys-panel').length,
).toBe(0);
done();
});
});
it('does not render public panel when empty', (done) => {
vm.store.keys.public_keys = [];
Vue.nextTick(() => {
expect(
vm.$el.querySelectorAll('.deploy-keys-panel').length,
).toBe(2);
done();
});
});
it('re-fetches deploy keys when enabling a key', (done) => {
const key = data.public_keys[0];
spyOn(vm.service, 'getKeys');
spyOn(vm.service, 'enableKey').and.callFake(() => new Promise((resolve) => {
resolve();
setTimeout(() => {
expect(vm.service.getKeys).toHaveBeenCalled();
done();
});
}));
eventHub.$emit('enable.key', key);
expect(vm.service.enableKey).toHaveBeenCalledWith(key.id);
});
it('re-fetches deploy keys when disabling a key', (done) => {
const key = data.public_keys[0];
spyOn(window, 'confirm').and.returnValue(true);
spyOn(vm.service, 'getKeys');
spyOn(vm.service, 'disableKey').and.callFake(() => new Promise((resolve) => {
resolve();
setTimeout(() => {
expect(vm.service.getKeys).toHaveBeenCalled();
done();
});
}));
eventHub.$emit('disable.key', key);
expect(vm.service.disableKey).toHaveBeenCalledWith(key.id);
});
it('calls disableKey when removing a key', (done) => {
const key = data.public_keys[0];
spyOn(window, 'confirm').and.returnValue(true);
spyOn(vm.service, 'getKeys');
spyOn(vm.service, 'disableKey').and.callFake(() => new Promise((resolve) => {
resolve();
setTimeout(() => {
expect(vm.service.getKeys).toHaveBeenCalled();
done();
});
}));
eventHub.$emit('remove.key', key);
expect(vm.service.disableKey).toHaveBeenCalledWith(key.id);
});
it('hasKeys returns true when there are keys', () => {
expect(vm.hasKeys).toEqual(3);
});
});
import Vue from 'vue';
import DeployKeysStore from '~/deploy_keys/store';
import key from '~/deploy_keys/components/key.vue';
describe('Deploy keys key', () => {
let vm;
const KeyComponent = Vue.extend(key);
const data = getJSONFixture('deploy_keys/keys.json');
const createComponent = (deployKey) => {
const store = new DeployKeysStore();
store.keys = data;
vm = new KeyComponent({
propsData: {
deployKey,
store,
},
}).$mount();
};
describe('enabled key', () => {
const deployKey = data.enabled_keys[0];
beforeEach((done) => {
createComponent(deployKey);
setTimeout(done);
});
it('renders the keys title', () => {
expect(
vm.$el.querySelector('.title').textContent.trim(),
).toContain('My title');
});
it('renders human friendly formatted created date', () => {
expect(
vm.$el.querySelector('.key-created-at').textContent.trim(),
).toBe(`created ${gl.utils.getTimeago().format(deployKey.created_at)}`);
});
it('shows remove button', () => {
expect(
vm.$el.querySelector('.btn').textContent.trim(),
).toBe('Remove');
});
it('shows write access text when key has write access', (done) => {
vm.deployKey.can_push = true;
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.write-access-allowed'),
).not.toBeNull();
expect(
vm.$el.querySelector('.write-access-allowed').textContent.trim(),
).toBe('Write access allowed');
done();
});
});
});
describe('public keys', () => {
const deployKey = data.public_keys[0];
beforeEach((done) => {
createComponent(deployKey);
setTimeout(done);
});
it('shows enable button', () => {
expect(
vm.$el.querySelector('.btn').textContent.trim(),
).toBe('Enable');
});
it('shows disable button when key is enabled', (done) => {
vm.store.keys.enabled_keys.push(deployKey);
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.btn').textContent.trim(),
).toBe('Disable');
done();
});
});
});
});
import Vue from 'vue';
import DeployKeysStore from '~/deploy_keys/store';
import deployKeysPanel from '~/deploy_keys/components/keys_panel.vue';
describe('Deploy keys panel', () => {
const data = getJSONFixture('deploy_keys/keys.json');
let vm;
beforeEach((done) => {
const DeployKeysPanelComponent = Vue.extend(deployKeysPanel);
const store = new DeployKeysStore();
store.keys = data;
vm = new DeployKeysPanelComponent({
propsData: {
title: 'test',
keys: data.enabled_keys,
showHelpBox: true,
store,
},
}).$mount();
setTimeout(done);
});
it('renders the title with keys count', () => {
expect(
vm.$el.querySelector('h5').textContent.trim(),
).toContain('test');
expect(
vm.$el.querySelector('h5').textContent.trim(),
).toContain(`(${vm.keys.length})`);
});
it('renders list of keys', () => {
expect(
vm.$el.querySelectorAll('li').length,
).toBe(vm.keys.length);
});
it('renders help box if keys are empty', (done) => {
vm.keys = [];
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.settings-message'),
).toBeDefined();
expect(
vm.$el.querySelector('.settings-message').textContent.trim(),
).toBe('No deploy keys found. Create one with the form above.');
done();
});
});
it('does not render help box if keys are empty & showHelpBox is false', (done) => {
vm.keys = [];
vm.showHelpBox = false;
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.settings-message'),
).toBeNull();
done();
});
});
});
require 'spec_helper'
describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') }
let(:project2) { create(:empty_project, :internal)}
before(:all) do
clean_frontend_fixtures('deploy_keys/')
end
before(:each) do
sign_in(admin)
end
render_views
it 'deploy_keys/keys.json' do |example|
create(:deploy_key, public: true)
project_key = create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com')
internal_key = create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNd/UJWhPrpb+b/G5oL109y57yKuCxE+WUGJGYaj7WQKsYRJmLYh1mgjrl+KVyfsWpq4ylOxIfFSnN9xBBFN8mlb0Fma5DC7YsSsibJr3MZ19ZNBprwNcdogET7aW9I0In7Wu5f2KqI6e5W/spJHCy4JVxzVMUvk6Myab0LnJ2iQ== dummy@gitlab.com')
create(:deploy_keys_project, project: project, deploy_key: project_key)
create(:deploy_keys_project, project: project2, deploy_key: internal_key)
get :index,
namespace_id: project.namespace.to_param,
project_id: project,
format: :json
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
end
require 'spec_helper'
describe DeployKeyEntity do
include RequestAwareEntity
let(:user) { create(:user) }
let(:project) { create(:empty_project, :internal)}
let(:project_private) { create(:empty_project, :private)}
let(:deploy_key) { create(:deploy_key) }
let!(:deploy_key_internal) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) }
let!(:deploy_key_private) { create(:deploy_keys_project, project: project_private, deploy_key: deploy_key) }
let(:entity) { described_class.new(deploy_key, user: user) }
it 'returns deploy keys with projects a user can read' do
expected_result = {
id: deploy_key.id,
user_id: deploy_key.user_id,
title: deploy_key.title,
fingerprint: deploy_key.fingerprint,
can_push: deploy_key.can_push,
destroyed_when_orphaned: true,
almost_orphaned: false,
created_at: deploy_key.created_at,
updated_at: deploy_key.updated_at,
projects: [
{
id: project.id,
name: project.name,
full_path: namespace_project_path(project.namespace, project),
full_name: project.full_name
}
]
}
expect(entity.as_json).to eq(expected_result)
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