UNPKG

abstruse

Version:
351 lines (313 loc) 13.1 kB
import { Component, OnInit, OnDestroy, Inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; import { ApiService } from '../../services/api.service'; import { TimeService } from '../../services/time.service'; import { AuthService } from '../../services/auth.service'; import { SocketService } from '../../services/socket.service'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import { format, distanceInWordsToNow, distanceInWordsStrict } from 'date-fns'; import * as Clipboard from 'clipboard'; @Component({ selector: 'app-job', templateUrl: 'app-job.component.html' }) export class AppJobComponent implements OnInit, OnDestroy { loading: boolean; termSub: Subscription; sub: Subscription; id: number; job: any; jobRun: any; terminalReady: boolean; terminalOptions: { size: 'small' | 'large' }; terminalInput: any; timeWords: string; previousRuntime: number; processing: boolean; sshd: string; vnc: string; tag: string = null; userData: any; userId: string | null; committerAvatar: string; authorAvatar: string; nameAuthor: string; nameCommitter: string; timerSubscription: any = null; currentTime: number; commitMessage: string; dateTime: string; dateTimeToNow: string; debug = false; constructor( private socketService: SocketService, private apiService: ApiService, private timeService: TimeService, private authService: AuthService, private route: ActivatedRoute, @Inject(DOCUMENT) private document: any, private titleService: Title ) { this.currentTime = new Date().getTime(); this.loading = true; this.terminalOptions = { size: 'large' }; this.id = null; this.sshd = null; this.vnc = null; } ngOnInit() { this.userData = this.authService.getData(); this.userId = this.userData && this.userData.id || null; this.id = this.route.snapshot.params.id; this.termSub = this.socketService.outputEvents .subscribe(event => { if (event.type === 'data' || event.type === 'exit' || event.type === 'container' || event.type === 'jobLog') { if (Number(event.job_id) === Number(this.id) || event.type === 'jobLog') { this.terminalInput = event.data; } } else if (event.type === 'job stopped' && event.data === this.id) { this.processing = false; } else if (event.type === 'job restarted' && event.data === this.id) { this.processing = false; } else if (event.type === 'exposed ports') { const portData = event.data && event.data.info || null; if (portData && portData['22/tcp']) { const port = portData['22/tcp'][0].HostPort; this.sshd = `${document.location.hostname}:${port}`; } if (portData && portData['5900/tcp']) { const port = portData['5900/tcp'][0].HostPort; this.vnc = `${document.location.hostname}:${port}`; } } else if (event.type === 'debug') { const debug = event.data || 'false'; this.debug = debug === 'true'; } }); this.socketService.emit({ type: 'subscribeToJobOutput', data: { jobId: this.id } }); this.sub = this.socketService.outputEvents .pipe( filter(event => event.type === 'process'), filter(event => Number(event.job_id) === Number(this.id)) ) .subscribe(event => { if (!this.jobRun) { return; } if (event.data === 'job started') { this.jobRun.status = 'running'; this.jobRun.end_time = null; this.jobRun.start_time = event.additionalData; } else if (event.data === 'job succeded') { this.jobRun.status = 'success'; this.jobRun.end_time = event.additionalData; this.previousRuntime = this.jobRun.end_time - this.jobRun.start_time; } else if (event.data === 'job failed') { this.jobRun.status = 'failed'; this.jobRun.end_time = event.additionalData; this.previousRuntime = this.jobRun.end_time - this.jobRun.start_time; } this.setFavicon(); }); this.apiService.getJob(this.id, this.userId).subscribe(job => { this.job = job; this.setData(); if (this.job.build.data.ref && this.job.build.data.ref.startsWith('refs/tags/')) { this.tag = this.job.build.data.ref.replace('refs/tags/', ''); } this.jobRun = job.runs[job.runs.length - 1]; this.terminalInput = this.jobRun.log; this.timeWords = distanceInWordsToNow(job.build.created_at); this.setFavicon(); this.loading = false; const lastRun = job.runs && job.runs[job.runs.length - 1].end_time ? job.runs[job.runs.length - 1] : job.runs[job.runs.length - 2]; if (lastRun) { this.previousRuntime = lastRun.end_time - lastRun.start_time; } }); const clipboard = new Clipboard('.code-copy'); } ngOnDestroy() { if (this.termSub) { this.termSub.unsubscribe(); } if (this.sub) { this.sub.unsubscribe(); } if (this.timerSubscription) { this.timerSubscription.unsubscribe(); } if (this.document.getElementById('favicon')) { this.document.getElementById('favicon').setAttribute('href', 'assets/images/favicon.png'); } this.titleService.setTitle('Abstruse CI'); } setFavicon(): void { let favicon; switch (this.jobRun.status) { case 'queued': favicon = 'assets/images/favicon-queued.png'; break; case 'failed': favicon = 'assets/images/favicon-error.png'; break; case 'running': favicon = 'assets/images/favicon-running.png'; break; case 'success': favicon = 'assets/images/favicon-success.png'; break; default: favicon = 'assets/images/favicon.png'; break; } const name = this.job.build.repository.full_name; const status = this.jobRun.status; this.titleService.setTitle(`${name} - ${status}`); if (this.document.getElementById('favicon')) { this.document.getElementById('favicon').setAttribute('href', favicon); } } restartJob(e: MouseEvent): void { e.preventDefault(); e.stopPropagation(); this.processing = true; this.sshd = null; this.vnc = null; this.debug = false; this.socketService.emit({ type: 'restartJob', data: { jobId: this.id } }); this.terminalInput = { clear: true }; } stopJob(e: MouseEvent): void { e.preventDefault(); e.stopPropagation(); this.processing = true; this.sshd = null; this.vnc = null; this.debug = false; this.socketService.emit({ type: 'stopJob', data: { jobId: this.id } }); } debugMode(e: MouseEvent): void { e.preventDefault(); e.stopPropagation(); this.debug = !this.debug; this.socketService.emit({ type: 'debugJob', data: { jobId: this.id, debug: this.debug } }); } terminalOutput(e: any): void { if (e === 'ready') { this.terminalReady = true; } } setData(): void { const data = this.job.build.data; this.dateTime = data.pull_request && data.pull_request.updated_at || data.commit && data.commit.author && data.commit.author.date || data.commits && data.commits[data.commits.length - 1] && data.commits[data.commits.length - 1].timestamp || data.head_commit && data.head_commit.timestamp || null; if (this.job.build.repository.repository_provider === 'github') { if (this.job.build.data.commit) { this.commitMessage = this.job.build.data.commit.message; } else if (this.job.build.data.commits && this.job.build.data.commits.length > 0) { const len = this.job.build.data.commits.length - 1; this.commitMessage = this.job.build.data.commits[len].message; } else if (this.job.build.data.pull_request && this.job.build.data.pull_request.title) { this.commitMessage = this.job.build.data.pull_request.title; } else if (this.job.build.data.head_commit) { this.commitMessage = this.job.build.data.head_commit.message; } if (this.job.build.data.sha) { const buildData = this.job.build.data; this.committerAvatar = buildData.committer.avatar_url; this.nameCommitter = buildData.commit.committer.name; this.authorAvatar = buildData.author.avatar_url; this.nameAuthor = buildData.commit.author.name; } else if (this.job.build.data.head_commit) { const commit = this.job.build.data.head_commit; this.committerAvatar = this.job.build.data.sender.avatar_url; this.nameAuthor = this.job.build.data.head_commit.author.name; this.nameCommitter = this.job.build.data.head_commit.committer.name; if (commit.author.username !== commit.committer.username) { this.nameCommitter = commit.committer.name; this.apiService.getGithubUserData(commit.author.username).subscribe((evt: any) => { if (evt.status === 200) { const body = JSON.parse(evt._body); this.authorAvatar = body.avatar_url; } }); } else { this.authorAvatar = this.committerAvatar; this.nameCommitter = this.nameAuthor; } } else if (this.job.build.data.pull_request) { this.authorAvatar = this.job.build.data.sender.avatar_url; this.committerAvatar = this.authorAvatar; this.apiService.getGithubUserData(this.job.build.data.sender.login).subscribe((evt: any) => { if (evt.status === 200) { const body = JSON.parse(evt._body); this.nameAuthor = body.name; } }); this.apiService.getGithubUserData(this.job.build.data.pull_request.user.login).subscribe((evt: any) => { if (evt.status === 200) { const body = JSON.parse(evt._body); this.nameCommitter = body.name; } }); } } else if (this.job.build.repository.repository_provider === 'bitbucket') { // bitbucket if (this.job.build.data.actor) { this.authorAvatar = this.job.build.data.actor.links.avatar.href; this.nameAuthor = this.job.build.data.actor.display_name; } if (this.job.build.data.push) { this.commitMessage = this.job.build.data.push.changes[0].commits[0].message; this.dateTime = this.job.build.data.push.changes[0].commits[0].date; this.committerAvatar = this.job.build.data.push.changes[0].commits[0].author.user.links.avatar.href; this.nameCommitter = this.job.build.data.push.changes[0].commits[0].author.user.display_name; } else if (this.job.build.data.pullrequest) { this.commitMessage = data.pullrequest.description; this.dateTime = data.pullrequest.updated_on; this.committerAvatar = data.pullrequest.author.links.avatar.href; this.nameAuthor = data.pullrequest.author.display_name; this.nameCommitter = this.nameAuthor; } } else if (this.job.build.repository.repository_provider === 'gitlab') { // gitlab if (data.commit) { this.dateTime = data.commit.created_at; this.commitMessage = data.commit.message; this.nameCommitter = data.commit.committer_name; this.nameAuthor = data.commit.author_name; this.apiService.customGet(this.job.build.repository.api_url + '/users', { username: this.job.build.repository.user_login }).subscribe(userData => { this.authorAvatar = userData[0].avatar_url; }); } else if (data.user_avatar) { this.authorAvatar = data.user_avatar; this.commitMessage = data.commits[0].message; this.dateTime = data.commits[0].timestamp; this.committerAvatar = this.authorAvatar; this.nameAuthor = data.user_name; this.nameCommitter = data.commits[0].author.name; } else if (data.object_attributes) { this.authorAvatar = data.user.avatar_url; this.commitMessage = data.object_attributes.last_commit.message; this.dateTime = data.object_attributes.last_commit.timestamp; this.committerAvatar = this.authorAvatar; this.nameAuthor = data.user.name; this.nameCommitter = data.object_attributes.last_commit.author.name; } } else if (this.job.build.repository.repository_provider === 'gogs') { // gogs if (data.sender && data.pusher) { this.authorAvatar = data.pusher.avatar_url; this.nameAuthor = data.pusher.username; this.commitMessage = data.commits[0].message; this.dateTime = data.commits[0].timestamp; this.committerAvatar = data.sender.avatar_url; this.nameCommitter = data.sender.username; } } this.timerSubscription = this.timeService.getCurrentTime().subscribe(time => { this.currentTime = time; this.dateTimeToNow = distanceInWordsToNow(this.dateTime); }); } }