91 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
// Imports
 | 
						|
import fetch from 'node-fetch';
 | 
						|
import {assertNotMissingOrEmpty} from './utils';
 | 
						|
 | 
						|
// Constants
 | 
						|
const CIRCLE_CI_API_URL = 'https://circleci.com/api/v1.1/project/github';
 | 
						|
 | 
						|
// Interfaces - Types
 | 
						|
export interface ArtifactInfo {
 | 
						|
  path: string;
 | 
						|
  pretty_path: string;
 | 
						|
  node_index: number;
 | 
						|
  url: string;
 | 
						|
}
 | 
						|
 | 
						|
export type ArtifactResponse = ArtifactInfo[];
 | 
						|
 | 
						|
export interface BuildInfo {
 | 
						|
  reponame: string;
 | 
						|
  failed: boolean;
 | 
						|
  branch: string;
 | 
						|
  username: string;
 | 
						|
  build_num: number;
 | 
						|
  has_artifacts: boolean;
 | 
						|
  outcome: string; // e.g. 'success'
 | 
						|
  vcs_revision: string; // HEAD SHA
 | 
						|
  // there are other fields but they are not used in this code
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * A Helper that can interact with the CircleCI API.
 | 
						|
 */
 | 
						|
export class CircleCiApi {
 | 
						|
 | 
						|
  private tokenParam = `circle-token=${this.circleCiToken}`;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Construct a helper that can interact with the CircleCI REST API.
 | 
						|
   * @param githubOrg The Github organisation whose repos we want to access in CircleCI (e.g. angular).
 | 
						|
   * @param githubRepo The Github repo whose builds we want to access in CircleCI (e.g. angular).
 | 
						|
   * @param circleCiToken The CircleCI API access token (secret).
 | 
						|
   */
 | 
						|
  constructor(
 | 
						|
    private githubOrg: string,
 | 
						|
    private githubRepo: string,
 | 
						|
    private circleCiToken: string,
 | 
						|
  ) {
 | 
						|
    assertNotMissingOrEmpty('githubOrg', githubOrg);
 | 
						|
    assertNotMissingOrEmpty('githubRepo', githubRepo);
 | 
						|
    assertNotMissingOrEmpty('circleCiToken', circleCiToken);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the info for a build from the CircleCI API
 | 
						|
   * @param buildNumber The CircleCI build number that generated the artifact.
 | 
						|
   * @returns A promise to the info about the build
 | 
						|
   */
 | 
						|
  public async getBuildInfo(buildNumber: number): Promise<BuildInfo> {
 | 
						|
    try {
 | 
						|
      const baseUrl = `${CIRCLE_CI_API_URL}/${this.githubOrg}/${this.githubRepo}/${buildNumber}`;
 | 
						|
      const response = await fetch(`${baseUrl}?${this.tokenParam}`);
 | 
						|
      if (response.status !== 200) {
 | 
						|
        throw new Error(`${baseUrl}: ${response.status} - ${response.statusText}`);
 | 
						|
      }
 | 
						|
      return response.json();
 | 
						|
    } catch (error) {
 | 
						|
        throw new Error(`CircleCI build info request failed (${error.message})`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Query the CircleCI API to get a URL for a specified artifact from a specified build.
 | 
						|
   * @param artifactPath The path, within the build to the artifact.
 | 
						|
   * @returns A promise to the URL that can be requested to download the actual build artifact file.
 | 
						|
   */
 | 
						|
  public async getBuildArtifactUrl(buildNumber: number, artifactPath: string): Promise<string> {
 | 
						|
    const baseUrl = `${CIRCLE_CI_API_URL}/${this.githubOrg}/${this.githubRepo}/${buildNumber}`;
 | 
						|
    try {
 | 
						|
      const response = await fetch(`${baseUrl}/artifacts?${this.tokenParam}`);
 | 
						|
      const artifacts = await response.json() as ArtifactResponse;
 | 
						|
      const artifact = artifacts.find(item => item.path === artifactPath);
 | 
						|
      if (!artifact) {
 | 
						|
        throw new Error(`Missing artifact (${artifactPath}) for CircleCI build: ${buildNumber}`);
 | 
						|
      }
 | 
						|
      return artifact.url;
 | 
						|
    } catch (error) {
 | 
						|
      throw new Error(`CircleCI artifact URL request failed (${error.message})`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |