import axios from "axios" ; import { Artifact , CircleCI , CircleCIOptions , GitType , BuildWithSteps } from "circleci-api" ; import { safelyFetchEnvs } from "../lib/envs" ; const { CIRCLE_TOKEN } = safelyFetchEnvs ( [ "CIRCLE_TOKEN" ] ) ; interface PullRequest { head_sha : string ; url : string ; } interface BuildWithStepsExtended extends BuildWithSteps { pull_requests : PullRequest [ ] ; } interface FetchArtifactParams { jobName : string ; artifactName : string ; buildNum ? : number ; branchName ? : string ; } export class Circle { private owner : string ; private repo : string ; private api : CircleCI ; constructor ( { owner , repo } ) { this . owner = owner ; this . repo = repo ; const options = { token : CIRCLE_TOKEN , vcs : { type : GitType . GITHUB , owner , repo } } ; this . api = new CircleCI ( options ) ; } async getPullRequest ( buildNum ) { let build ; try { build = ( await this . api . build ( buildNum ) ) as BuildWithStepsExtended ; } catch ( error ) { console . error ( `Failed to get circle build details for job #${ buildNum } of ${ this . owner }/${ this . repo }` ) ; throw error ; } if ( build . pull_requests . length > 0 && build . branch !== "master" ) { const pr = build . pull_requests [ 0 ] . url ; console . log ( "Related pull request:" , pr ) ; return pr ; } return null ; } param branch return async getLatestArtifacts ( branch = "master" ) { try { const result = await this . api . latestArtifacts ( { branch , filter : "successful" } ) ; console . log ( `Found ${ result . length } artifacts` ) ; return result ; } catch ( error ) { console . log ( "No build artifacts found" , error ) ; } return [ ] ; } async fetchArtifact ( { jobName , artifactName , buildNum , branchName = "master" } ) { let latestBuild ; let artifact ; if ( ! buildNum ) { try { latestBuild = ( await this . api . buildsFor ( branchName , { filter : "successful" , limit : 10 } ) ) . filter ( build => build . workflows && build . workflows . some ( workflow => workflow . job_name === jobName ) ) [ 0 ] ; } catch ( error ) { console . error ( `Failed to find latest master ${ jobName } job` ) ; throw error ; } } try { if ( buildNum || latestBuild ) { let targetArtifact = ( await this . api . artifacts ( buildNum || latestBuild . build_num ! ) ) . filter ( artifact => artifact . path . includes ( artifactName ! ) ) [ 0 ] ; if ( targetArtifact && targetArtifact . url ) { artifact = ( await axios . get ( targetArtifact . url ) ) . data ; } } } catch ( error ) { const branchText = buildNum ? "" : `latest ${ branchName } ` ; const buildText = buildNum ? `#${ buildNum } ` : "" ; console . error ( `Found ${ branchText }job ${ buildText }but failed to fetch artifact` ) ; throw error ; } return artifact ; } }