diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..19c7bdb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +16 \ No newline at end of file diff --git a/lib/utils/builds.ts b/lib/utils/builds.ts index 4f10e59..525cb74 100644 --- a/lib/utils/builds.ts +++ b/lib/utils/builds.ts @@ -4,6 +4,25 @@ import * as times from './times'; const defaultBuildDir = path.join(__dirname, '../..'); +export async function getAllDownloadedSlugs(cwd = defaultBuildDir) { + let allDownloadedSlugs = []; + const pathToCache = path.join(cwd, '.data'); + + const allHosts = await fs.readDir(pathToCache); + + await Promise.all(allHosts.map(async host => { + const allUsers = await fs.readDir(path.join(pathToCache, host)); + await Promise.all(allUsers.map(async user => { + const allRepos = await fs.readDir(path.join(pathToCache, host, user)); + allRepos.forEach(repo => { + allDownloadedSlugs.push(`${host}:${user}/${repo}`); + }); + })) + })); + + return allDownloadedSlugs; +} + export async function getBuildDir(cwd = defaultBuildDir, host, user, repo) { const buildsDir = path.join(cwd, '.data', host, user, repo, 'builds'); await fs.mkdirp(buildsDir); @@ -86,6 +105,7 @@ export async function getLastDownloadedBuildNumber(buildsDir) { } module.exports = { + getAllDownloadedSlugs, getBuildDir, getHistory, getLastDownloadedBuildNumber, diff --git a/lib/utils/sanitize.ts b/lib/utils/sanitize.ts index 02002e8..e482cf9 100644 --- a/lib/utils/sanitize.ts +++ b/lib/utils/sanitize.ts @@ -1,4 +1,8 @@ import inquirer from 'inquirer'; +import { SUPPORTED_COMMANDS } from '../../index'; +import { InvalidInputError } from '../error'; +import { getAllDownloadedSlugs } from './builds'; +import flatten from 'lodash.flatten'; const getHost = { name: 'host', @@ -29,15 +33,35 @@ const getUser = { const getRepo = { name: 'repo', type: 'input', - message: 'Enter the repo name', + message: 'Enter the repository name', }; +const getSlug = (choices) => ({ + name: 'slug', + type: 'list', + message: 'Select the repo:', + choices +}) + export async function sanitizeInput(input): Promise<[Array, string]> { if (/(.*):(.*)\/(.*)/.test(input[0])) { return [input[0].match(/(.*):(.*)\/(.*)/).slice(1), input[1]]; } - const { host, user, repo } = await inquirer.prompt([getHost, getUser, getRepo]); + if (input[0] === 'download') { + const { host, user, repo } = await inquirer.prompt([getHost, getUser, getRepo]); + + return [[host, user, repo], input[0]]; + } - return [[host, user, repo], input[0]]; + if (SUPPORTED_COMMANDS.indexOf(input[0]) !== -1) { + const downloadedSlugs = await getAllDownloadedSlugs(); + const { slug } = await inquirer.prompt([getSlug(downloadedSlugs)]); + + if (/(.*):(.*)\/(.*)/.test(slug)) { + return [slug.match(/(.*):(.*)\/(.*)/).slice(1), input[0]]; + } + } + + throw new InvalidInputError(`Invalid input. Please run build-stats --help to documention for the tool.`, input); } diff --git a/lib/utils/tests/builds.test.ts b/lib/utils/tests/builds.test.ts index dfe3abb..8480065 100644 --- a/lib/utils/tests/builds.test.ts +++ b/lib/utils/tests/builds.test.ts @@ -2,12 +2,53 @@ import fixtures from 'fixturez'; import * as builds from '../builds'; const f = fixtures(__dirname); +test('builds.getAllDownloadsSlugs', async () => { + const cwd = f.copy('with-builds'); + const downloadedSlugs = await builds.getAllDownloadedSlugs(cwd); + expect(downloadedSlugs.length).toBe(2); + expect(downloadedSlugs).toEqual(expect.arrayContaining([ + 'bitbucket:atlassian/build-stats', + 'travis:boltpkg/bolt' + ])); +}); + test('builds.getBuildDir()', async () => { let cwd = f.copy('testRepo'); let dirPath = await builds.getBuildDir(cwd, 'bitbucket', 'test', 'test-repo'); expect(dirPath).toMatch(/testRepo\/\.data\/bitbucket\/test\/test-repo\/builds/); }); -test.todo('builds.getHistory()'); -test.todo('builds.findLongest()'); -test.todo('builds.toTimeRanges()'); +test('builds.getHistory()',async () => { + const cwd = f.copy('with-builds'); + const history = await builds.getHistory(cwd, 'bitbucket', 'atlassian', 'build-stats', { + branch: '*', + result: '*' + }); + expect(history.length).toBe(10); +}); +test('builds.findLongest()',async () => { + const cwd = f.copy('with-builds'); + const allBuilds = await builds.getHistory(cwd, 'bitbucket', 'atlassian', 'build-stats', { + branch: '*', + result: '*' + }); + + const longestBuild = builds.findLongest(allBuilds); + expect(longestBuild.id).toBe('7') +}); + +test('builds.toTimeRanges()',async () => { + const cwd = f.copy('with-builds'); + const allBuilds = await builds.getHistory(cwd, 'bitbucket', 'atlassian', 'build-stats', { + branch: '*', + result: '*' + }); + + const ranges = builds.toTimeRanges(allBuilds, { + period: 365, // period of 365 days/ 1 year + last: 100 // last 100 years + }); + + // One of the fixtures build is from 1900, so it should be excluded + expect(ranges[0].length).toBe(9); +}); diff --git a/package.json b/package.json index 889600a..2fb4c8b 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,10 @@ "got": "^8.0.1", "inquirer": "^8.2.0", "left-pad": "^1.2.0", + "lodash.flatten": "^4.4.0", "lodash.groupby": "^4.6.0", "lodash.pick": "^4.4.0", + "lodash.without": "^4.4.0", "meow": "^v9.0.0", "mkdirp": "^0.5.1", "ora": "^5.4.1", diff --git a/yarn.lock b/yarn.lock index 2951562..6712071 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3108,6 +3108,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + lodash.groupby@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" @@ -3123,6 +3128,11 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= +lodash.without@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= + lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"