This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.ts

327 lines
12 KiB
TypeScript

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';
/**
* A component that lets the user set up a build trigger for a public Git repository host service.
*/
@Component({
selector: 'manage-trigger-githost',
templateUrl: '/static/js/directives/ui/manage-trigger-githost/manage-trigger-githost.component.html'
})
export class ManageTriggerGithostComponent implements OnInit {
// FIXME: Use one-way data binding
@Input('=') public repository: Repository;
@Input('=') public trigger: Trigger;
@Output() public activateTrigger: EventEmitter<{config: any, pull_robot?: any}> = new EventEmitter();
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;
private repositoriesPerPage: number = 10;
private robotsPerPage: number = 10;
private namespaceTitle: string;
private namespace: any;
constructor(@Inject('ApiService') private ApiService: any,
@Inject('TableService') private TableService: any,
@Inject('TriggerService') private TriggerService: any,
@Inject('RolesService') private RolesService: any,
@Inject('$scope') private $scope: ng.IScope) {
// FIXME: Here binding methods to class context in order to pass them as arguments to $scope.$watch
this.buildOrderedNamespaces = this.buildOrderedNamespaces.bind(this);
this.loadNamespaces = this.loadNamespaces.bind(this);
this.buildOrderedRepositories = this.buildOrderedRepositories.bind(this);
this.loadRepositories = this.loadRepositories.bind(this);
this.loadRepositoryRefs = this.loadRepositoryRefs.bind(this);
this.buildOrderedRobotAccounts = this.buildOrderedRobotAccounts.bind(this);
this.loadDockerfileLocations = this.loadDockerfileLocations.bind(this);
this.checkDockerfilePath = this.checkDockerfilePath.bind(this);
}
public ngOnInit(): void {
// TODO: Replace $scope.$watch with @Output methods for child component mutations or $onChanges for parent mutations
this.$scope.$watch(() => this.trigger, this.initialSetup.bind(this));
this.$scope.$watch(() => this.repository, this.initialSetup.bind(this));
this.$scope.$watch(() => this.local.selectedNamespace, (namespace) => {
if (namespace) {
this.loadRepositories(namespace);
}
});
this.$scope.$watch(() => this.local.selectedRepository, (repository) => {
if (repository) {
this.loadRepositoryRefs(repository);
this.loadDockerfileLocations(repository);
}
});
this.$scope.$watch(() => this.local.dockerfilePath, (path) => {
if (path && this.local.selectedRepository) {
this.setPossibleContexts(path);
this.checkDockerfilePath(this.local.selectedRepository, path, this.local.dockerContext);
}
});
this.$scope.$watch(() => this.local.dockerContext, (context) => {
if (context && this.local.selectedRepository) {
this.checkDockerfilePath(this.local.selectedRepository, this.local.dockerfilePath, context);
}
});
this.$scope.$watch(() => this.local.namespaceOptions.predicate, this.buildOrderedNamespaces);
this.$scope.$watch(() => this.local.namespaceOptions.reverse, this.buildOrderedNamespaces);
this.$scope.$watch(() => this.local.namespaceOptions.filter, this.buildOrderedNamespaces);
this.$scope.$watch(() => this.local.repositoryOptions.predicate, this.buildOrderedRepositories);
this.$scope.$watch(() => this.local.repositoryOptions.reverse, this.buildOrderedRepositories);
this.$scope.$watch(() => this.local.repositoryOptions.filter, this.buildOrderedRepositories);
this.$scope.$watch(() => this.local.repositoryOptions.hideStale, this.buildOrderedRepositories);
this.$scope.$watch(() => this.local.robotOptions.predicate, this.buildOrderedRobotAccounts);
this.$scope.$watch(() => this.local.robotOptions.reverse, this.buildOrderedRobotAccounts);
this.$scope.$watch(() => this.local.robotOptions.filter, this.buildOrderedRobotAccounts);
}
private initialSetup(): void {
if (!this.repository || !this.trigger) { return; }
if (this.namespaceTitle) {
// Already setup.
return;
}
this.config = this.trigger['config'] || {};
this.namespaceTitle = 'organization';
this.local.selectedNamespace = null;
this.loadNamespaces();
}
public getTriggerIcon(): any {
return this.TriggerService.getIcon(this.trigger.service);
}
public createTrigger(): void {
var config: any = {
build_source: this.local.selectedRepository.full_name,
dockerfile_path: this.local.dockerfilePath,
context: this.local.dockerContext
};
if (this.local.triggerOptions['hasBranchTagFilter'] && this.local.triggerOptions['branchTagFilter']) {
config['branchtag_regex'] = this.local.triggerOptions['branchTagFilter'];
}
const activate = () => {
this.activateTrigger.emit({config: config, pull_robot: this.local.robotAccount});
};
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.
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();
}
}
private buildOrderedNamespaces(): void {
if (!this.local.namespaces) {
return;
}
var namespaces: Namespace[] = this.local.namespaces || [];
this.local.orderedNamespaces = this.TableService.buildOrderedItems(namespaces,
this.local.namespaceOptions,
['id'],
['score']);
this.local.maxScore = 0;
namespaces.forEach((namespace) => {
this.local.maxScore = Math.max(namespace.score, this.local.maxScore);
});
}
private loadNamespaces(): void {
this.local.namespaces = null;
this.local.selectedNamespace = null;
this.local.orderedNamespaces = null;
this.local.selectedRepository = null;
this.local.orderedRepositories = null;
var params = {
'repository': this.repository.namespace + '/' + this.repository.name,
'trigger_uuid': this.trigger.id
};
this.ApiService.listTriggerBuildSourceNamespaces(null, params)
.then((resp) => {
this.local.namespaces = resp['namespaces'];
this.local.repositories = null;
this.buildOrderedNamespaces();
}, this.ApiService.errorDisplay('Could not retrieve the list of ' + this.namespaceTitle));
}
private buildOrderedRepositories(): void {
if (!this.local.repositories) {
return;
}
var repositories = this.local.repositories || [];
repositories.forEach((repository) => {
repository['last_updated_datetime'] = new Date(repository['last_updated'] * 1000);
});
if (this.local.repositoryOptions.hideStale) {
var existingRepositories = repositories;
repositories = repositories.filter((repository) => {
var older_date = moment(repository['last_updated_datetime']).add(1, 'months');
return !moment().isAfter(older_date);
});
if (existingRepositories.length > 0 && repositories.length == 0) {
repositories = existingRepositories;
}
}
this.local.orderedRepositories = this.TableService.buildOrderedItems(repositories,
this.local.repositoryOptions,
['name', 'description'],
[]);
}
private loadRepositories(namespace: any): void {
this.local.repositories = null;
this.local.selectedRepository = null;
this.local.repositoryRefs = null;
this.local.triggerOptions = {
'hasBranchTagFilter': false
};
this.local.orderedRepositories = null;
var params = {
'repository': this.repository.namespace + '/' + this.repository.name,
'trigger_uuid': this.trigger.id
};
var data = {
'namespace': namespace.id
};
this.ApiService.listTriggerBuildSources(data, params).then((resp) => {
if (namespace == this.local.selectedNamespace) {
this.local.repositories = resp['sources'];
this.buildOrderedRepositories();
}
}, this.ApiService.errorDisplay('Could not retrieve repositories'));
}
private loadRepositoryRefs(repository: any): void {
this.local.repositoryRefs = null;
this.local.triggerOptions = {
'hasBranchTagFilter': false
};
var params = {
'repository': this.repository.namespace + '/' + this.repository.name,
'trigger_uuid': this.trigger.id,
'field_name': 'refs'
};
var config = {
'build_source': repository.full_name
};
this.ApiService.listTriggerFieldValues(config, params).then((resp) => {
if (repository == this.local.selectedRepository) {
this.local.repositoryRefs = resp['values'];
this.local.repositoryFullRefs = resp['values'].map((ref) => {
var kind = ref.kind == 'branch' ? 'heads' : 'tags';
var icon = ref.kind == 'branch' ? 'fa-code-fork' : 'fa-tag';
return {
'value': kind + '/' + ref.name,
'icon': icon,
'title': ref.name
};
});
}
}, this.ApiService.errorDisplay('Could not retrieve repository refs'));
}
private loadDockerfileLocations(repository: any): void {
this.local.dockerfilePath = null;
this.local.dockerContext = null;
var params = {
'repository': this.repository.namespace + '/' + this.repository.name,
'trigger_uuid': this.trigger.id
};
var config = {
'build_source': repository.full_name
};
this.ApiService.listBuildTriggerSubdirs(config, params)
.then((resp) => {
if (repository == this.local.selectedRepository) {
this.local.dockerfileLocations = resp;
}
}, this.ApiService.errorDisplay('Could not retrieve Dockerfile locations'));
}
private buildOrderedRobotAccounts(): void {
if (!this.local.triggerAnalysis || !this.local.triggerAnalysis.robots) {
return;
}
var robots = this.local.triggerAnalysis.robots;
this.local.orderedRobotAccounts = this.TableService.buildOrderedItems(robots,
this.local.robotOptions,
['name'],
[]);
}
private checkDockerfilePath(repository: any, path: string, context: string): void {
this.local.triggerAnalysis = null;
this.local.robotAccount = null;
var params = {
'repository': this.repository.namespace + '/' + this.repository.name,
'trigger_uuid': this.trigger.id
};
var config = {
'build_source': repository.full_name,
'dockerfile_path': path.substr(1),
'context': context
};
var data = {
'config': config
};
this.ApiService.analyzeBuildTrigger(data, params)
.then((resp) => {
this.local.triggerAnalysis = resp;
this.buildOrderedRobotAccounts();
}, this.ApiService.errorDisplay('Could not analyze trigger'));
}
private setPossibleContexts(path){
if(this.local.dockerfileLocations.contextMap){
this.local.contexts = this.local.dockerfileLocations.contextMap[path] || [];
}
}
}