import { window , commands , StatusBarAlignment , StatusBarItem , workspace , extensions } from 'vscode' ; import path = require ( 'path' ) ; import fs = require ( 'fs' ) ; var Travis = require ( 'travis-ci' ) ; var Git = require ( 'git-rev-2' ) ; export default class TravisStatusIndicator { private _travis ; private _statusBarItem : StatusBarItem ; private _useProxy : boolean = false ; private _proxyData = { host : null , port : null } ; private _statusPollingTimeout = null ; private _statusPolling : boolean = workspace . getConfiguration ( 'travis' ) . get < boolean > ( 'statusPolling' ) ; private _statusPollingInterval : number = workspace . getConfiguration ( 'travis' ) . get < number > ( 'statusPollingInterval' ) ; constructor ( ) { workspace . onDidChangeConfiguration ( this . updateStatusPollingConfiguration . bind ( this ) ) ; } public updateStatus ( ) { if ( ! this . _statusBarItem ) { this . _statusBarItem = window . createStatusBarItem ( StatusBarAlignment . Left ) ; this . _statusBarItem . command = 'extension.updateTravis' ; } this . _statusBarItem . text = 'Travis CI $(sync)' ; this . _statusBarItem . tooltip = 'Fetching Travis CI status for this project...' ; if ( this . isTravisProject ( ) ) { let userRepo = this . getUserRepo ( ) ; if ( ! userRepo || userRepo . length < 2 || userRepo [ 0 ] . length === 0 || userRepo [ 1 ] . length === 0 ) { this . displayError ( 'Fetching Travis CI build status failed: Could not detect username and repository' ) ; } let [ username , repoName ] = userRepo ; Git . branch ( workspace . rootPath , ( err1 , currentActiveBranch ) => { Git . long ( workspace . rootPath , ( err2 , currentCommitSha ) => { this . getTravis ( ) . repos ( username , repoName ) . branches ( currentActiveBranch ) . get ( ( branchError , branchResponse ) => { if ( ! branchError && branchResponse . commit . sha === currentCommitSha ) { let started = new Date ( branchResponse . branch . started_at ) ; let state = branchResponse . branch . state ; let buildNumber = branchResponse . branch . number ; let durationInSeconds = branchResponse . branch . duration ; this . show ( durationInSeconds , state , buildNumber , started , currentCommitSha . substr ( 0 , 7 ) ) ; } else { this . getTravis ( ) . repos ( username , repoName ) . get ( ( repoError , repoResponse ) => { if ( repoError ) return this . displayError ( `Travis could not find ${ userRepo [ 0 ] }/${ userRepo [ 1 ] }` ) ; if ( ! repoResponse || ! repoResponse . repo ) return this . displayError ( 'Travis CI could not find your repository.' ) ; if ( repoResponse . repo . last_build_number === null ) return this . displayError ( 'Travis found your repository, but it never ran a test.' ) ; let started = new Date ( repoResponse . repo . last_build_started_at ) ; let state = repoResponse . repo . last_build_state ; let buildNumber = repoResponse . repo . last_build_number ; let durationInSeconds = repoResponse . repo . last_build_duration ; this . show ( durationInSeconds , state , buildNumber , started , 'master' ) ; } ) ; } } ) ; } ) ; } ) ; } if ( this . _statusPolling === true ) { this . _statusPollingTimeout = setTimeout ( this . updateStatus . bind ( this ) , this . _statusPollingInterval * 1000 ) ; } } private show ( buildDuration , state , buildNumber , started , identifier ? ) { let duration = Math . round ( buildDuration / 60 ) . toString ( ) ; duration += ( duration === '1' ) ? ' minute' : ' minutes' ; let timeInfo = `Started: ${ started . toLocaleDateString ( ) }\nDuration: ${ duration }` ; switch ( state ) { case 'passed' : return this . displaySuccess ( `Build ${ buildNumber } has passed.\n${ timeInfo }` , identifier ) ; case 'started' : return this . displayRunning ( `Build ${ buildNumber } has started.\n${ timeInfo }` , identifier ) ; case 'running' : return this . displayRunning ( `Build ${ buildNumber } is currently running.\n${ timeInfo }` , identifier ) ; case 'failed' : return this . displayFailure ( `Build ${ buildNumber } failed.\n${ timeInfo }` , identifier ) ; default : return this . displayRunning ( `Build ${ buildNumber } has ${ state }. \n${ timeInfo }` , identifier ) ; } } public openInTravis ( ) { if ( ! workspace || ! workspace . rootPath || ! this . isTravisProject ( ) ) return ; let open = require ( 'open' ) ; let repo = this . getUserRepo ( ) ; let base = "https://travis-ci" ; if ( workspace . getConfiguration ( 'travis' ) [ 'pro' ] ) { base += '.com/' ; } else { base += '.org/' ; } if ( repo && repo . length === 2 ) { return open ( `${ base }${ repo [ 0 ] }/${ repo [ 1 ] }` ) ; } } public isTravisProject ( ) { if ( ! workspace || ! workspace . rootPath ) return false ; let conf = path . join ( workspace . rootPath , '.travis.yml' ) ; try { return fs . statSync ( conf ) . isFile ( ) ; } catch ( err ) { return false ; } } public getUserRepo ( ) { if ( ! workspace || ! workspace . rootPath ) return null ; let fSettings = this . getUserRepoFromSettings ( ) ; let fTravis = this . getUserRepoFromTravis ( ) ; let user = ( fSettings && fSettings . length > 0 && fSettings [ 0 ] ) ? fSettings [ 0 ] : fTravis [ 0 ] ; let repo = ( fSettings && fSettings . length > 1 && fSettings [ 1 ] ) ? fSettings [ 1 ] : fTravis [ 1 ] ; return [ user , repo ] ; } private displayError ( err , identifier ? ) { this . setupStatusBarItem ( err , 'stop' , identifier ) ; } private displaySuccess ( text , identifier ? ) { this . setupStatusBarItem ( text , 'check' , identifier ) ; } private displayFailure ( text , identifier ? ) { this . setupStatusBarItem ( text , 'x' , identifier ) ; } private displayRunning ( text , identifier ? ) { this . setupStatusBarItem ( text , 'clock' , identifier ) ; } private setupStatusBarItem ( tooltip , icon , identifier ? ) { if ( ! this . _statusBarItem ) { this . _statusBarItem = window . createStatusBarItem ( StatusBarAlignment . Left ) ; } this . _statusBarItem . text = identifier ? `Travis CI ${ identifier } $(${ icon })` : `Travis CI $(${ icon })` ; this . _statusBarItem . tooltip = tooltip ; this . _statusBarItem . show ( ) ; } private getUserRepoFromSettings ( ) { if ( ! workspace || ! workspace . rootPath ) return null ; let settingsFile = path . join ( workspace . rootPath , '.vscode' , 'settings.json' ) ; try { let settings = JSON . parse ( fs . readFileSync ( settingsFile , 'utf8' ) ) ; if ( settings ) { let repo = settings [ 'travis.repository' ] ; let user = settings [ 'travis.username' ] ; return [ user , repo ] ; } else { return [ '' , '' ] ; } } catch ( e ) { return [ '' , '' ] ; } } private getUserRepoFromTravis ( ) { let ini = require ( 'ini' ) ; let configFile = path . join ( workspace . rootPath , '.git' , 'config' ) ; try { let config = ini . parse ( fs . readFileSync ( configFile , 'utf-8' ) ) ; let origin = config [ 'remote "origin"' ] ; if ( origin && origin . url ) { let repo = origin . url . replace ( /^(.*\/\/)?[^\/:]+[\/:]/ , '' ) ; let combo = repo ; if ( repo . substr ( repo . length - 4 ) === '.git' ) { combo = repo . substr ( 0 , repo . length - 4 ) ; } let split = combo . split ( '/' ) ; return ( split && split . length > 1 ) ? split : [ '' , '' ] ; } } catch ( err ) { return [ '' , '' ] ; } } private updateStatusPollingConfiguration ( ) { let statusPolling = workspace . getConfiguration ( 'travis' ) . get < boolean > ( 'statusPolling' ) ; let statusPollingInterval = workspace . getConfiguration ( 'travis' ) . get < number > ( 'statusPollingInterval' ) ; if ( statusPolling !== this . _statusPolling || statusPollingInterval !== this . _statusPollingInterval ) { clearTimeout ( this . _statusPollingTimeout ) ; this . _statusPolling = statusPolling ; this . _statusPollingInterval = statusPollingInterval ; if ( statusPolling === true ) { this . updateStatus ( ) ; } } } private getTravis ( ) { if ( this . _travis == null ) { this . _travis = new Travis ( { version : '2.0.0' , pro : workspace . getConfiguration ( 'travis' ) [ 'pro' ] } ) ; } if ( workspace . getConfiguration ( 'travis' ) [ 'github_oauth_token' ] != "" ) { this . _travis . authenticate ( { github_token : workspace . getConfiguration ( 'travis' ) [ 'github_oauth_token' ] } , function ( err ) { } ) ; } else if ( workspace . getConfiguration ( 'travis' ) [ 'github_user' ] != "" && workspace . getConfiguration ( 'travis' ) [ 'github_password' ] != "" ) { this . _travis . authenticate ( { username : workspace . getConfiguration ( 'travis' ) [ 'github_user' ] , password : workspace . getConfiguration ( 'travis' ) [ 'github_password' ] } , function ( err ) { } ) ; } return this . _travis ; } dispose ( ) { this . _statusBarItem . dispose ( ) ; } }