Fix Trigger Setup Robot Permissions for Private Base (#2543)
This commit is contained in:
parent
2f757faa40
commit
581d7c67a7
5 changed files with 210 additions and 91 deletions
|
@ -356,7 +356,10 @@
|
|||
total-count="$ctrl.local.orderedRobotAccounts.entries.length"
|
||||
current-page="$ctrl.local.robotOptions.page"
|
||||
page-size="$ctrl.robotsPerPage"></span>
|
||||
<input class="form-control" type="text" ng-model="$ctrl.local.robotOptions.filter" placeholder="Filter robot accounts...">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
ng-model="$ctrl.local.robotOptions.filter"
|
||||
placeholder="Filter robot accounts...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
import { ManageTriggerGithostComponent, Local, Trigger } from './manage-trigger-githost.component';
|
||||
import { ManageTriggerGithostComponent } from './manage-trigger-githost.component';
|
||||
import { Local, Trigger, Repository } from '../../../types/common.types';
|
||||
import { Mock } from 'ts-mocks';
|
||||
import Spy = jasmine.Spy;
|
||||
|
||||
|
||||
describe("ManageTriggerGithostComponent", () => {
|
||||
var component: ManageTriggerGithostComponent;
|
||||
var apiServiceMock: any;
|
||||
var tableServiceMock: any;
|
||||
var triggerServiceMock: any;
|
||||
var rolesServiceMock: any;
|
||||
var apiServiceMock: Mock<any>;
|
||||
var tableServiceMock: Mock<any>;
|
||||
var triggerServiceMock: Mock<any>;
|
||||
var rolesServiceMock: Mock<any>;
|
||||
var repository: any;
|
||||
var trigger: Trigger;
|
||||
var $scope: ng.IScope;
|
||||
var $scopeMock: Mock<ng.IScope>;
|
||||
|
||||
beforeEach(inject(($injector: ng.auto.IInjectorService) => {
|
||||
apiServiceMock = jasmine.createSpyObj('apiServiceMock', ['listTriggerBuildSourceNamespaces']);
|
||||
tableServiceMock = jasmine.createSpyObj('tableServiceMock', ['buildOrderedItems']);
|
||||
triggerServiceMock = jasmine.createSpyObj('triggerServiceMock', ['getIcon']);
|
||||
rolesServiceMock = jasmine.createSpyObj('rolesServiceMock', ['setRepositoryRole']);
|
||||
$scope = $injector.get('$rootScope');
|
||||
component = new ManageTriggerGithostComponent(apiServiceMock,
|
||||
tableServiceMock,
|
||||
triggerServiceMock,
|
||||
rolesServiceMock,
|
||||
$scope);
|
||||
apiServiceMock = new Mock<any>();
|
||||
tableServiceMock = new Mock<any>();
|
||||
triggerServiceMock = new Mock<any>();
|
||||
rolesServiceMock = new Mock<any>();
|
||||
$scopeMock = new Mock<ng.IScope>();
|
||||
component = new ManageTriggerGithostComponent(apiServiceMock.Object,
|
||||
tableServiceMock.Object,
|
||||
triggerServiceMock.Object,
|
||||
rolesServiceMock.Object,
|
||||
$scopeMock.Object);
|
||||
trigger = {service: "serviceMock", id: 1};
|
||||
component.trigger = trigger;
|
||||
}));
|
||||
|
@ -36,14 +39,75 @@ describe("ManageTriggerGithostComponent", () => {
|
|||
|
||||
describe("getTriggerIcon", () => {
|
||||
|
||||
it("calls trigger service to get icon", () => {
|
||||
component.getTriggerIcon();
|
||||
beforeEach(() => {
|
||||
triggerServiceMock.setup(mock => mock.getIcon).is((service: any) => null);
|
||||
});
|
||||
|
||||
expect(triggerServiceMock.getIcon.calls.argsFor(0)[0]).toEqual(component.trigger.service);
|
||||
it("calls trigger service to get icon", () => {
|
||||
const icon: any = component.getTriggerIcon();
|
||||
|
||||
expect((<Spy>triggerServiceMock.Object.getIcon).calls.argsFor(0)[0]).toEqual(component.trigger.service);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createTrigger", () => {
|
||||
// TODO
|
||||
|
||||
beforeEach(() => {
|
||||
component.local.selectedRepository = new Mock<Repository>().Object;
|
||||
component.local.selectedRepository.full_name = "someorg/some-repository";
|
||||
component.local.dockerfilePath = "/Dockerfile";
|
||||
component.local.dockerContext = "/";
|
||||
component.local.triggerOptions = {};
|
||||
component.local.triggerAnalysis = {};
|
||||
rolesServiceMock.setup(mock => mock.setRepositoryRole).is((repo, role, entityKind, entityName, callback) => {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
|
||||
it("calls roles service to grant read access to selected robot if robot is required and cannot read", (done) => {
|
||||
component.local.triggerAnalysis = {status: 'requiresrobot', name: 'privatebase', namespace: 'someorg'};
|
||||
component.local.robotAccount = {can_read: false, is_robot: true, kind: 'user', name: 'test-robot'};
|
||||
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[0]).toEqual({
|
||||
name: component.local.triggerAnalysis.name,
|
||||
namespace: component.local.triggerAnalysis.namespace,
|
||||
});
|
||||
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[1]).toEqual('read');
|
||||
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[2]).toEqual('robot');
|
||||
done();
|
||||
});
|
||||
|
||||
component.createTrigger();
|
||||
});
|
||||
|
||||
it("does not call roles service if robot is required but already has read access", (done) => {
|
||||
component.local.robotAccount = {can_read: true, is_robot: true, kind: 'user', name: 'test-robot'};
|
||||
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||
expect((<Spy>rolesServiceMock.Object.setRepositoryRole)).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
component.createTrigger();
|
||||
});
|
||||
|
||||
it("does not call roles service if robot is not required", (done) => {
|
||||
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||
expect((<Spy>rolesServiceMock.Object.setRepositoryRole)).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
component.createTrigger();
|
||||
});
|
||||
|
||||
it("emits output event with config and pull robot", (done) => {
|
||||
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||
expect(event.config.build_source).toEqual(component.local.selectedRepository.full_name);
|
||||
expect(event.config.dockerfile_path).toEqual(component.local.dockerfilePath);
|
||||
expect(event.config.context).toEqual(component.local.dockerContext);
|
||||
done();
|
||||
});
|
||||
|
||||
component.createTrigger();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,5 +1,6 @@
|
|||
import { Input, Output, Component, Inject, EventEmitter, OnInit } from 'ng-metadata/core';
|
||||
import * as moment from 'moment';
|
||||
import { Local, Trigger, Repository, Namespace } from '../../../types/common.types';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -12,30 +13,14 @@ import * as moment from 'moment';
|
|||
export class ManageTriggerGithostComponent implements OnInit {
|
||||
|
||||
// FIXME: Use one-way data binding
|
||||
@Input('=') public repository: any;
|
||||
@Input('=') public repository: Repository;
|
||||
@Input('=') public trigger: Trigger;
|
||||
@Output() public activateTrigger: EventEmitter<{config: any, pull_robot?: any}> = new EventEmitter();
|
||||
private config: any;
|
||||
private local: any = {
|
||||
namespaceOptions: {
|
||||
filter: '',
|
||||
predicate: 'score',
|
||||
reverse: false,
|
||||
page: 0
|
||||
},
|
||||
repositoryOptions: {
|
||||
filter: '',
|
||||
predicate: 'score',
|
||||
reverse: false,
|
||||
page: 0,
|
||||
hideStale: true
|
||||
},
|
||||
robotOptions: {
|
||||
filter: '',
|
||||
predicate: 'score',
|
||||
reverse: false,
|
||||
page: 0
|
||||
}
|
||||
public config: any;
|
||||
public local: Local = {
|
||||
namespaceOptions: {filter: '', predicate: 'score', reverse: false, page: 0},
|
||||
repositoryOptions: {filter: '', predicate: 'score', reverse: false, page: 0, hideStale: true},
|
||||
robotOptions: {filter: '', predicate: 'score', reverse: false, page: 0},
|
||||
};
|
||||
private currentState: any | null;
|
||||
private namespacesPerPage: number = 10;
|
||||
|
@ -128,23 +113,21 @@ export class ManageTriggerGithostComponent implements OnInit {
|
|||
context: this.local.dockerContext
|
||||
};
|
||||
|
||||
if (this.local.triggerOptions.hasBranchTagFilter &&
|
||||
this.local.triggerOptions.branchTagFilter) {
|
||||
config['branchtag_regex'] = this.local.triggerOptions.branchTagFilter;
|
||||
if (this.local.triggerOptions['hasBranchTagFilter'] && this.local.triggerOptions['branchTagFilter']) {
|
||||
config['branchtag_regex'] = this.local.triggerOptions['branchTagFilter'];
|
||||
}
|
||||
|
||||
var activate = () => {
|
||||
const activate = () => {
|
||||
this.activateTrigger.emit({config: config, pull_robot: this.local.robotAccount});
|
||||
};
|
||||
|
||||
if (this.local.robotAccount && this.local.triggerAnalysis.status == 'requiresrobot') {
|
||||
if (this.local.triggerAnalysis.status == 'requiresrobot' && this.local.robotAccount) {
|
||||
if (this.local.robotAccount.can_read) {
|
||||
activate();
|
||||
} else {
|
||||
// Add read permission onto the base repository for the robot and then activate the
|
||||
// trigger.
|
||||
var robot_name = this.local.robotAccount.name;
|
||||
this.RolesService.setRepositoryRole(this.repository, 'read', 'robot', robot_name, activate);
|
||||
// Add read permission onto the base repository for the robot and then activate the trigger.
|
||||
const baseRepo: any = {name: this.local.triggerAnalysis.name, namespace: this.local.triggerAnalysis.namespace};
|
||||
this.RolesService.setRepositoryRole(baseRepo, 'read', 'robot', this.local.robotAccount.name, activate);
|
||||
}
|
||||
} else {
|
||||
activate();
|
||||
|
@ -156,7 +139,7 @@ export class ManageTriggerGithostComponent implements OnInit {
|
|||
return;
|
||||
}
|
||||
|
||||
var namespaces = this.local.namespaces || [];
|
||||
var namespaces: Namespace[] = this.local.namespaces || [];
|
||||
this.local.orderedNamespaces = this.TableService.buildOrderedItems(namespaces,
|
||||
this.local.namespaceOptions,
|
||||
['id'],
|
||||
|
@ -305,9 +288,9 @@ export class ManageTriggerGithostComponent implements OnInit {
|
|||
|
||||
var robots = this.local.triggerAnalysis.robots;
|
||||
this.local.orderedRobotAccounts = this.TableService.buildOrderedItems(robots,
|
||||
this.local.robotOptions,
|
||||
['name'],
|
||||
[]);
|
||||
this.local.robotOptions,
|
||||
['name'],
|
||||
[]);
|
||||
}
|
||||
|
||||
private checkDockerfilePath(repository: any, path: string, context: string): void {
|
||||
|
@ -342,38 +325,3 @@ export class ManageTriggerGithostComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A type representing local application data.
|
||||
*/
|
||||
export type Local = {
|
||||
namespaceOptions: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
};
|
||||
repositoryOptions: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
hideStale: boolean;
|
||||
};
|
||||
robotOptions: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A type representing a trigger.
|
||||
*/
|
||||
export type Trigger = {
|
||||
id: number;
|
||||
service: any;
|
||||
};
|
104
static/js/types/common.types.ts
Normal file
104
static/js/types/common.types.ts
Normal file
|
@ -0,0 +1,104 @@
|
|||
import { ViewArray } from '../services/view-array/view-array';
|
||||
|
||||
|
||||
/**
|
||||
* A type representing local application data.
|
||||
*/
|
||||
export type Local = {
|
||||
contexts?: string[];
|
||||
dockerContext?: string;
|
||||
dockerfileLocations?: any;
|
||||
dockerfilePath?: string;
|
||||
hasValidContextLocation?: boolean;
|
||||
hasValidDockerfilePath?: boolean;
|
||||
maxScore?: number;
|
||||
namespaceOptions?: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
};
|
||||
namespaces?: Namespace[];
|
||||
orderedNamespaces?: ViewArray;
|
||||
orderedRepositories?: ViewArray;
|
||||
orderedRobotAccounts?: ViewArray;
|
||||
repositories?: Repository[];
|
||||
repositoryFullRefs?: {
|
||||
icon: string;
|
||||
title: string;
|
||||
value: string;
|
||||
}[];
|
||||
repositoryOptions?: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
hideStale: boolean;
|
||||
};
|
||||
repositoryRefs?: {
|
||||
kind: string;
|
||||
name: string;
|
||||
}[];
|
||||
robotAccount?: RobotAccount;
|
||||
robotOptions?: {
|
||||
filter: string;
|
||||
predicate: string;
|
||||
reverse: boolean;
|
||||
page: number;
|
||||
};
|
||||
selectedNamespace?: Namespace;
|
||||
selectedRepository?: Repository;
|
||||
triggerAnalysis?: any;
|
||||
triggerOptions?: {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A type representing a robot account.
|
||||
*/
|
||||
export type RobotAccount = {
|
||||
can_read: boolean;
|
||||
is_robot: boolean;
|
||||
kind: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A type representing a Git repository.
|
||||
*/
|
||||
export type Repository = {
|
||||
description: string;
|
||||
full_name: string;
|
||||
has_admin_permissions: boolean;
|
||||
last_updated: number;
|
||||
last_updated_datetime: Date;
|
||||
name: string;
|
||||
private: boolean;
|
||||
url: string;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A type representing a repository namespace.
|
||||
*/
|
||||
export type Namespace = {
|
||||
avatar_url: string;
|
||||
id: string;
|
||||
personal: boolean;
|
||||
score: number;
|
||||
title: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A type representing a trigger.
|
||||
*/
|
||||
export type Trigger = {
|
||||
id: number;
|
||||
service: any;
|
||||
};
|
Binary file not shown.
Reference in a new issue