ci(docs-infra): add explicit return types to methods

This commit is contained in:
Pete Bacon Darwin 2018-08-10 11:10:22 +01:00
parent 36c4c8daa9
commit d604ef7cf0
14 changed files with 59 additions and 46 deletions

View File

@ -24,7 +24,7 @@ export class BuildCleaner {
}
// Methods - Public
public async cleanUp() {
public async cleanUp(): Promise<void> {
try {
this.logger.log('Cleaning up builds and downloads');
const openPrs = await this.getOpenPrNumbers();
@ -38,17 +38,17 @@ export class BuildCleaner {
}
}
public async cleanBuilds(openPrs: number[]) {
public async cleanBuilds(openPrs: number[]): Promise<void> {
const existingBuilds = await this.getExistingBuildNumbers();
await this.removeUnnecessaryBuilds(existingBuilds, openPrs);
}
public async cleanDownloads(openPrs: number[]) {
public async cleanDownloads(openPrs: number[]): Promise<void> {
const existingDownloads = await this.getExistingDownloads();
await this.removeUnnecessaryDownloads(existingDownloads, openPrs);
}
public getExistingBuildNumbers() {
public getExistingBuildNumbers(): Promise<number[]> {
return new Promise<number[]>((resolve, reject) => {
fs.readdir(this.buildsDir, (err, files) => {
if (err) {
@ -65,14 +65,14 @@ export class BuildCleaner {
});
}
public async getOpenPrNumbers() {
public async getOpenPrNumbers(): Promise<number[]> {
const api = new GithubApi(this.githubToken);
const githubPullRequests = new GithubPullRequests(api, this.githubOrg, this.githubRepo);
const prs = await githubPullRequests.fetchAll('open');
return prs.map(pr => pr.number);
}
public removeDir(dir: string) {
public removeDir(dir: string): void {
try {
if (shell.test('-d', dir)) {
shell.chmod('-R', 'a+w', dir);
@ -83,7 +83,7 @@ export class BuildCleaner {
}
}
public removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]) {
public removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]): void {
const toRemove = existingBuildNumbers.filter(num => !openPrNumbers.includes(num));
this.logger.log(`Existing builds: ${existingBuildNumbers.length}`);
@ -100,7 +100,7 @@ export class BuildCleaner {
forEach(dir => this.removeDir(dir));
}
public getExistingDownloads() {
public getExistingDownloads(): Promise<string[]> {
const artifactFile = path.basename(this.artifactPath);
return new Promise<string[]>((resolve, reject) => {
fs.readdir(this.downloadsDir, (err, files) => {
@ -113,7 +113,7 @@ export class BuildCleaner {
});
}
public removeUnnecessaryDownloads(existingDownloads: string[], openPrNumbers: number[]) {
public removeUnnecessaryDownloads(existingDownloads: string[], openPrNumbers: number[]): void {
const toRemove = existingDownloads.filter(filePath => {
const {pr} = getPrInfoFromDownloadPath(filePath);
return !openPrNumbers.includes(pr);

View File

@ -13,7 +13,7 @@ import {BuildCleaner} from './build-cleaner';
_main();
// Functions
function _main() {
function _main(): void {
const buildCleaner = new BuildCleaner(
AIO_BUILDS_DIR,
AIO_GITHUB_ORGANIZATION,

View File

@ -55,7 +55,7 @@ export class CircleCiApi {
* @param buildNumber The CircleCI build number that generated the artifact.
* @returns A promise to the info about the build
*/
public async getBuildInfo(buildNumber: number) {
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}`);
@ -73,7 +73,7 @@ export class CircleCiApi {
* @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) {
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}`);

View File

@ -56,7 +56,7 @@ export class GithubApi {
}
// Methods - Protected
protected buildPath(pathname: string, params?: RequestParamsOrNull) {
protected buildPath(pathname: string, params?: RequestParamsOrNull): string {
if (params == null) {
return pathname;
}
@ -67,7 +67,7 @@ export class GithubApi {
return `${pathname}${joiner}${search}`;
}
protected request<T>(method: string, path: string, data: any = null) {
protected request<T>(method: string, path: string, data: any = null): Promise<T> {
return new Promise<T>((resolve, reject) => {
const options = {
headers: {...this.requestHeaders},
@ -101,7 +101,7 @@ export class GithubApi {
});
}
protected serializeSearchParams(params: RequestParams) {
protected serializeSearchParams(params: RequestParams): string {
return Object.keys(params).
filter(key => params[key] != null).
map(key => `${key}=${encodeURIComponent(String(params[key]))}`).

View File

@ -38,7 +38,7 @@ export class GithubPullRequests {
* @param body The body of the comment to post.
* @returns A promise that resolves when the comment has been posted.
*/
public addComment(pr: number, body: string) {
public addComment(pr: number, body: string): Promise<any> {
assert(pr > 0, `Invalid PR number: ${pr}`);
assert(!!body, `Invalid or empty comment body: ${body}`);
return this.api.post<any>(`/repos/${this.repoSlug}/issues/${pr}/comments`, null, {body});
@ -49,7 +49,7 @@ export class GithubPullRequests {
* @param pr The number of the PR for which to request info.
* @returns A promise that is resolves with information about the specified PR.
*/
public fetch(pr: number) {
public fetch(pr: number): Promise<PullRequest> {
assert(pr > 0, `Invalid PR number: ${pr}`);
// Using the `/issues/` URL, because the `/pulls/` one does not provide labels.
return this.api.get<PullRequest>(`/repos/${this.repoSlug}/issues/${pr}`);
@ -60,7 +60,7 @@ export class GithubPullRequests {
* @param state Only retrieve PRs that have this state.
* @returns A promise that is resolved with information about the requested PRs.
*/
public fetchAll(state: PullRequestState = 'all') {
public fetchAll(state: PullRequestState = 'all'): Promise<PullRequest[]> {
const pathname = `/repos/${this.repoSlug}/pulls`;
const params = {state};
@ -72,7 +72,7 @@ export class GithubPullRequests {
* @param pr The number of the PR for which to request files.
* @returns A promise that resolves to an array of file information
*/
public fetchFiles(pr: number) {
public fetchFiles(pr: number): Promise<FileInfo[]> {
assert(pr > 0, `Invalid PR number: ${pr}`);
return this.api.get<FileInfo[]>(`/repos/${this.repoSlug}/pulls/${pr}/files`);
}

View File

@ -24,7 +24,7 @@ export class GithubTeams {
* Request information about all the organisation's teams in GitHub.
* @returns A promise that is resolved with information about the teams.
*/
public fetchAll() {
public fetchAll(): Promise<Team[]> {
return this.api.getPaginated<Team>(`/orgs/${this.githubOrg}/teams`);
}
@ -34,7 +34,7 @@ export class GithubTeams {
* @param teamIds The team to check for the username.
* @returns a Promise that resolves to `true` if the username is a member of the team.
*/
public async isMemberById(username: string, teamIds: number[]) {
public async isMemberById(username: string, teamIds: number[]): Promise<boolean> {
const getMembership = async (teamId: number) => {
try {
@ -60,7 +60,7 @@ export class GithubTeams {
* @param teamSlugs A collection of slugs that represent the teams to check for the the username.
* @returns a Promise that resolves to `true` if the usernane is a member of at least one of the specified teams.
*/
public async isMemberBySlug(username: string, teamSlugs: string[]) {
public async isMemberBySlug(username: string, teamSlugs: string[]): Promise<boolean> {
try {
const teams = await this.fetchAll();
const teamIds = teams.filter(team => teamSlugs.includes(team.slug)).map(team => team.id);

View File

@ -119,7 +119,7 @@ export class BuildCreator extends EventEmitter {
});
}
protected getCandidatePrDirs(pr: number, isPublic: boolean) {
protected getCandidatePrDirs(pr: number, isPublic: boolean): {oldPrDir: string, newPrDir: string} {
const hiddenPrDir = path.join(this.buildsDir, HIDDEN_DIR_PREFIX + pr);
const publicPrDir = path.join(this.buildsDir, `${pr}`);

View File

@ -30,7 +30,7 @@ export class BuildRetriever {
* @param buildNum The number of the build for which to retrieve the info.
* @returns The Github org, repo, PR and latest SHA for the specified build.
*/
public async getGithubInfo(buildNum: number) {
public async getGithubInfo(buildNum: number): Promise<GithubInfo> {
const buildInfo = await this.api.getBuildInfo(buildNum);
const githubInfo: GithubInfo = {
org: buildInfo.username,
@ -50,7 +50,7 @@ export class BuildRetriever {
* @param artifactPath the path on CircleCI where the artifact was stored.
* @returns A promise to the file path where the downloaded file was stored.
*/
public async downloadBuildArtifact(buildNum: number, pr: number, sha: string, artifactPath: string) {
public async downloadBuildArtifact(buildNum: number, pr: number, sha: string, artifactPath: string): Promise<string> {
try {
const outPath = computeArtifactDownloadPath(this.downloadDir, pr, sha, artifactPath);
const downloadExists = await new Promise(resolve => fs.exists(outPath, exists => resolve(exists)));
@ -73,7 +73,7 @@ export class BuildRetriever {
}
}
function getPrfromBranch(branch: string) {
function getPrfromBranch(branch: string): number {
// CircleCI only exposes PR numbers via the `branch` field :-(
const match = /^pull\/(\d+)$/.exec(branch);
if (!match) {

View File

@ -24,7 +24,7 @@ export class BuildVerifier {
* @param pr The number of the PR to check
* @param significantFilePattern A regex that selects files that are significant.
*/
public async getSignificantFilesChanged(pr: number, significantFilePattern: RegExp) {
public async getSignificantFilesChanged(pr: number, significantFilePattern: RegExp): Promise<boolean> {
const files = await this.prs.fetchFiles(pr);
return files.some(file => significantFilePattern.test(file.filename));
}
@ -40,7 +40,7 @@ export class BuildVerifier {
(await this.teams.isMemberBySlug(prInfo.user.login, this.allowedTeamSlugs));
}
protected hasLabel(prInfo: PullRequest, label: string) {
protected hasLabel(prInfo: PullRequest, label: string): boolean {
return prInfo.labels.some(labelObj => labelObj.name === label);
}
}

View File

@ -21,7 +21,7 @@ import {UploadServerFactory} from './upload-server-factory';
_main();
// Functions
function _main() {
function _main(): void {
UploadServerFactory
.create({
buildArtifactPath: AIO_ARTIFACT_PATH,

View File

@ -156,7 +156,7 @@ export class UploadServerFactory {
return middleware;
}
public static createBuildCreator(prs: GithubPullRequests, buildsDir: string, domainName: string) {
public static createBuildCreator(prs: GithubPullRequests, buildsDir: string, domainName: string): BuildCreator {
const buildCreator = new BuildCreator(buildsDir);
const postPreviewsComment = (pr: number, shas: string[]) => {
const body = shas.

View File

@ -7,7 +7,7 @@ import {UploadError} from './upload-error';
* @param res The response to configure as an error.
* @param err The error that needs to be reported.
*/
export async function respondWithError(res: express.Response, err: any) {
export async function respondWithError(res: express.Response, err: any): Promise<void> {
if (!(err instanceof UploadError)) {
err = new UploadError(500, String((err && err.message) || err));
}

View File

@ -42,7 +42,7 @@ class Helper {
}
// Methods - Public
public cleanUp() {
public cleanUp(): void {
while (this.cleanUpFns.length) {
// Clean-up fns remove themselves from the list.
this.cleanUpFns[0]();
@ -66,7 +66,7 @@ class Helper {
}
}
public createDummyBuild(pr: number, sha: string, isPublic = true, force = false, legacy = false) {
public createDummyBuild(pr: number, sha: string, isPublic = true, force = false, legacy = false): CleanUpFn {
const prDir = this.getPrDir(pr, isPublic);
const shaDir = this.getShaDir(prDir, sha, legacy);
const idxPath = path.join(shaDir, 'index.html');
@ -101,7 +101,7 @@ class Helper {
});
}
public runForAllSupportedSchemes(suiteFactory: TestSuiteFactory) {
public runForAllSupportedSchemes(suiteFactory: TestSuiteFactory): void {
Object.keys(this.portPerScheme).forEach(scheme => suiteFactory(scheme, this.portPerScheme[scheme]));
}
@ -137,13 +137,13 @@ class Helper {
}
public writeBuildFile(pr: number, sha: string, relFilePath: string, content: string, isPublic = true,
legacy = false) {
legacy = false): void {
const shaDir = this.getShaDir(this.getPrDir(pr, isPublic), sha, legacy);
const absFilePath = path.join(shaDir, relFilePath);
this.writeFile(absFilePath, {content}, true);
}
public writeFile(filePath: string, {content, size}: FileSpecs, force = false) {
public writeFile(filePath: string, {content, size}: FileSpecs, force = false): void {
if (!force && fs.existsSync(filePath)) {
throw new Error(`Refusing to overwrite existing file '${filePath}'.`);
}
@ -206,7 +206,18 @@ export function makeCurl(baseUrl: string) {
};
}
export function payload(buildNum: number) {
export interface PayloadData {
data: {
payload: {
build_num: number,
build_parameters: {
CIRCLE_JOB: string;
};
};
};
}
export function payload(buildNum: number): PayloadData {
return {
data: {
payload: {

View File

@ -6,7 +6,7 @@ import {computeShortSha} from '../common/utils';
import {SHA} from './constants';
import {helper} from './helper';
function checkFile(filePath: string, remove: boolean) {
function checkFile(filePath: string, remove: boolean): boolean {
const exists = existsSync(filePath);
if (exists && remove) {
// if we expected the file to exist then we remove it to prevent leftover file errors
@ -15,7 +15,7 @@ function checkFile(filePath: string, remove: boolean) {
return exists;
}
function getArtifactPath(prNum: number, sha: string = SHA) {
function getArtifactPath(prNum: number, sha: string = SHA): string {
return `${AIO_DOWNLOADS_DIR}/${prNum}-${computeShortSha(sha)}-aio-snapshot.tgz`;
}
@ -35,8 +35,8 @@ function checkFiles(prNum: number, isPublic: boolean, sha: string, isLegacy: boo
return { existingFiles, missingFiles };
}
class ToExistAsAFile {
public compare(actual: string, remove = true) {
class ToExistAsAFile implements jasmine.CustomMatcher {
public compare(actual: string, remove = true): jasmine.CustomMatcherResult {
const pass = checkFile(actual, remove);
return {
message: `Expected file at "${actual}" ${pass ? 'not' : ''} to exist`,
@ -45,8 +45,8 @@ class ToExistAsAFile {
}
}
class ToExistAsAnArtifact {
public compare(actual: {prNum: number, sha?: string}, remove = true) {
class ToExistAsAnArtifact implements jasmine.CustomMatcher {
public compare(actual: {prNum: number, sha?: string}, remove = true): jasmine.CustomMatcherResult {
const { prNum, sha = SHA } = actual;
const filePath = getArtifactPath(prNum, sha);
const pass = checkFile(filePath, remove);
@ -57,8 +57,9 @@ class ToExistAsAnArtifact {
}
}
class ToExistAsABuild {
public compare(actual: {prNum: number, isPublic?: boolean, sha?: string, isLegacy?: boolean}, remove = true) {
class ToExistAsABuild implements jasmine.CustomMatcher {
public compare(actual: {prNum: number, isPublic?: boolean, sha?: string, isLegacy?: boolean}, remove = true):
jasmine.CustomMatcherResult {
const {prNum, isPublic = true, sha = SHA, isLegacy = false} = actual;
const {missingFiles} = checkFiles(prNum, isPublic, sha, isLegacy, remove);
return {
@ -67,7 +68,8 @@ class ToExistAsABuild {
pass: missingFiles.length === 0,
};
}
public negativeCompare(actual: {prNum: number, isPublic?: boolean, sha?: string, isLegacy?: boolean}) {
public negativeCompare(actual: {prNum: number, isPublic?: boolean, sha?: string, isLegacy?: boolean}):
jasmine.CustomMatcherResult {
const {prNum, isPublic = true, sha = SHA, isLegacy = false} = actual;
const { existingFiles } = checkFiles(prNum, isPublic, sha, isLegacy, false);
return {