Skip to content

Commit

Permalink
feat: add retry to check (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
levibostian committed Nov 20, 2023
1 parent 3e80783 commit 5e36ab8
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 16 deletions.
9 changes: 7 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@ const program = new Command()
.requiredOption('--package-manager <name>', 'npm')
.requiredOption('--package-name <name>', 'react')
.requiredOption('--package-version <name>', '1.0.0')
.option('--max-retries <number>', 'retry checking every few seconds until max retries is reached. If max is reached, return false', undefined)
.parse();

(async () => {
const {
packageManager,
packageName,
packageVersion
packageVersion,
maxRetries
} = program.opts()

console.log(`Checking if ${packageName}@${packageVersion} is deployed on ${packageManager}...`)
if (maxRetries) {
console.log(`Will retry ${maxRetries} times`)
}

const isItDeployedResult = await isItDeployed({
packageManager,
packageName,
packageVersion
})
}, maxRetries)

if (!isItDeployedResult) {
console.log('its not')
Expand Down
22 changes: 8 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { NpmPackageManager } from "./packageManagers/npm";
import { CocoapodsPackageManager } from "./packageManagers/cocoapods";
import { MavenPackageManager } from "./packageManagers/maven";
import { PackageManager, getPackageManager } from "./packageManagers";
import { runCheckIsItDeployed } from "./runner";

export const isItDeployed = (args: { packageManager: 'npm' | 'cocoapods' | 'maven', packageName: string, packageVersion: string }) => {
switch (args.packageManager) {
case 'npm':
return NpmPackageManager.doesItExist(args)
case 'cocoapods':
return CocoapodsPackageManager.doesItExist(args)
case 'maven':
return MavenPackageManager.doesItExist(args)
default:
throw new Error('Package manager not supported');
}
export const isItDeployed = (args: { packageManager: 'npm' | 'cocoapods' | 'maven', packageName: string, packageVersion: string }, opts?: { maxRetries: number | undefined }) => {
const packageManager: PackageManager | undefined = getPackageManager(args.packageManager)

if (!packageManager) throw new Error('Package manager not supported');

return runCheckIsItDeployed({ packageManager, packageName: args.packageName, packageVersion: args.packageVersion }, { maxRetries: opts?.maxRetries, secondsBetweenRetries: 5 })
}
15 changes: 15 additions & 0 deletions src/packageManagers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import { CocoapodsPackageManager } from "./cocoapods"
import { MavenPackageManager } from "./maven"
import { NpmPackageManager } from "./npm"

export const getPackageManager = (packageManager: string): PackageManager | undefined => {
switch (packageManager) {
case 'npm':
return NpmPackageManager
case 'cocoapods':
return CocoapodsPackageManager
case 'maven':
return MavenPackageManager
}

return undefined
}

export interface PackageManager {
doesItExist: (args: { packageName: string, packageVersion: string }) => Promise<boolean>
Expand Down
37 changes: 37 additions & 0 deletions src/runner.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { PackageManager } from './packageManagers';
import { runCheckIsItDeployed } from './runner';

describe('runCheckIsItDeployed', () => {
let mockPackageManager: PackageManager
beforeEach(() => {
mockPackageManager = {
doesItExist: jest.fn()
}
})

it('should return true if the package exists', async() => {
mockPackageManager.doesItExist = jest.fn().mockResolvedValue(true)

const result = await runCheckIsItDeployed({ packageManager: mockPackageManager, packageName: 'test', packageVersion: '1.0.0' }, { maxRetries: 0, secondsBetweenRetries: 1 })

expect(result).toBe(true)
})

describe('retries', () => {
it('should retry if the first check fails. it should return true after retry', async() => {
mockPackageManager.doesItExist = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true)

const result = await runCheckIsItDeployed({ packageManager: mockPackageManager, packageName: 'test', packageVersion: '1.0.0' }, { maxRetries: 2, secondsBetweenRetries: 0.1 })

expect(result).toBe(true)
})

it('should return false if the package does not exist after retries', async() => {
mockPackageManager.doesItExist = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(false)

const result = await runCheckIsItDeployed({ packageManager: mockPackageManager, packageName: 'test', packageVersion: '1.0.0' }, { maxRetries: 2, secondsBetweenRetries: 0.1 })

expect(result).toBe(false)
})
})
})
26 changes: 26 additions & 0 deletions src/runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { PackageManager } from "./packageManagers/index.js";
import { Sleeper } from "./util/sleeper";

export const runCheckIsItDeployed = async(args: { packageManager: PackageManager, packageName: string, packageVersion: string }, retryOptions: { maxRetries: number | undefined, secondsBetweenRetries: number }): Promise<boolean> => {
let maxRetries = 0
if (retryOptions.maxRetries) maxRetries = retryOptions.maxRetries
const sleeper = new Sleeper({ maxNumberSleeps: maxRetries, secondsForEachSleep: retryOptions.secondsBetweenRetries })

const theLoop = async(): Promise<boolean> => {
const doesItExist = await args.packageManager.doesItExist({ packageName: args.packageName, packageVersion: args.packageVersion })

if (doesItExist) return true

try {
await sleeper.sleep()

return theLoop()
} catch (error) {
// out of retries
return false
}
}

return theLoop()
}

26 changes: 26 additions & 0 deletions src/util/sleeper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Sleeper } from './sleeper'

describe('sleep', () => {
it('should sleep for expected amount of time', async() => {
let sleeper = new Sleeper({ maxNumberSleeps: 3, secondsForEachSleep: 0.25 })

const startTime = Date.now()
await sleeper.sleep()
await sleeper.sleep()
await sleeper.sleep()
const endTime = Date.now()
const totalSecondsRun = (endTime - startTime) / 1000

expect(totalSecondsRun).toBeGreaterThanOrEqual(0.5)
expect(totalSecondsRun).toBeLessThan(1)
})

it('should reject when run out of sleeps', async() => {
let sleeper = new Sleeper({ maxNumberSleeps: 1, secondsForEachSleep: 0.1 })

await sleeper.sleep() // success

// this next try should reject
await expect(sleeper.sleep()).rejects.toBeUndefined()
})
})
20 changes: 20 additions & 0 deletions src/util/sleeper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export class Sleeper {
maxNumberSleeps: number
secondsForEachSleep: number

constructor(args: { maxNumberSleeps: number, secondsForEachSleep: number }) {
this.maxNumberSleeps = args.maxNumberSleeps
this.secondsForEachSleep = args.secondsForEachSleep
}

async sleep(): Promise<void> {
if (this.maxNumberSleeps === 0) return Promise.reject()

this.maxNumberSleeps = this.maxNumberSleeps - 1

await new Promise(resolve => setTimeout(resolve, this.secondsForEachSleep * 1000)); // sleep

return
}

}

0 comments on commit 5e36ab8

Please sign in to comment.