From 3336ee7d4e977ff007f81a94a77aec89d43bc10b Mon Sep 17 00:00:00 2001 From: Igor Soloydenko Date: Thu, 19 Dec 2024 21:49:38 -0800 Subject: [PATCH 1/3] feat: replace single org with hierarchical repo list command --- README.md | 1 - ...command-ado-list-remote-repos-hierarchy.ts | 97 ------------------- src/commands/command-ado-list-remote-repos.ts | 74 +++++++++++--- src/commands/index.ts | 2 - 4 files changed, 62 insertions(+), 112 deletions(-) delete mode 100644 src/commands/command-ado-list-remote-repos-hierarchy.ts diff --git a/README.md b/README.md index 2eeb4d4..9b49406 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,6 @@ npm install -g . * NPM * ✅ `npm-audit` * ADO - * 🔨 `ado-list-remote-repos-hierarchy` * ✅ `ado-list-remote-repos` * 🧠 `ado-list-deploys` * SCV diff --git a/src/commands/command-ado-list-remote-repos-hierarchy.ts b/src/commands/command-ado-list-remote-repos-hierarchy.ts deleted file mode 100644 index 4dc9913..0000000 --- a/src/commands/command-ado-list-remote-repos-hierarchy.ts +++ /dev/null @@ -1,97 +0,0 @@ -import axios, { AxiosResponse } from 'axios'; -import { createExecutionContext, parseCommonOptions } from '../cli'; -import { renderTable } from '../cli/render-table'; -import { AdoListProjectsResponse, AdoListRepositoriesResponse, AdoRepository } from '../types'; -import { commonAdoOptions } from './ado-options'; -import { CliCommandMetadata, CliOption } from './cli-option'; - -const commandName = `ado-list-remote-repos-hierarchy`; - -const sortOption: CliOption = { - short: 's', - long: `sort`, - codeName: `sort`, - description: `Column to sort by.`, - exampleValue: `project or repo`, - defaultValue: `project`, -}; - -const { project, ...otherCommonOptions } = commonAdoOptions; -const listRemoteReposCommandOptions = { - ...otherCommonOptions, - sortOption, -}; - -async function adoListRemoteReposAsyncCommand(this: any, str: any, options: any) { - const executionContext = createExecutionContext(parseCommonOptions(options)); - const { organization, project, login, token, sort } = str; - const { logger } = executionContext; - - const org = organization || listRemoteReposCommandOptions.organization.defaultValue; - const listProjectsResponse = await axios.get<{}, AxiosResponse>(`https://dev.azure.com/${org}/_apis/projects`, { - headers: { - Authorization: `Basic ${Buffer.from(`${login}:${token}`).toString('base64')}`, - }, - }); - - const xPromises = listProjectsResponse - .data - .value - .filter((adoProject) => !project ? true : adoProject.name === project) - .map(async (adoProject) => { - try { - const listRepositoriesResponse = await axios.get<{}, AxiosResponse>(`https://dev.azure.com/${org}/${adoProject.id}/_apis/git/repositories`, { - headers: { - Authorization: `Basic ${Buffer.from(`${login}:${token}`).toString('base64')}`, - }, - }); - - if (listRepositoriesResponse.status < 200 && listRepositoriesResponse.status >= 300) - // TODO: refactor into axios wrapper? - throw new Error(`Failed to list repositories. Status: ${listRepositoriesResponse.status}.`); - - return { adoProject, adoRepos: listRepositoriesResponse.data.value }; - } catch (e) { - return { adoProject, error: e }; - } - }); - const promiseResults = await Promise.allSettled(xPromises); - - const columnDefs = [ - { title: 'project', width: 40, selector: (repo: AdoRepository) => repo.project.name }, - // { title: 'repo id', width: 38, selector: (repo: AdoRepository) => repo.id }, - { title: 'repo name', width: 40, selector: (repo: AdoRepository) => repo.name }, - { title: 'remoteUrl', width: 160, selector: (repo: AdoRepository) => repo.remoteUrl }, - ]; - const rows = - promiseResults.reduce( - (result, promiseResult) => { - if (promiseResult.status !== 'rejected') { - (promiseResult.value.adoRepos || []).forEach((repo) => { - result.push(repo); - }); - } - return result; - }, - [] as AdoRepository[], - ) - .sort((repo1, repo2) => { - const select = (repo: AdoRepository) => - sort === 'repo' ? repo.name : - sort === 'project' ? repo.project.name : - repo.name; - return select(repo1).localeCompare(select(repo2)); - }); - - console.log(renderTable( - columnDefs, - rows, - )) -}; - -export const command: CliCommandMetadata = { - name: commandName, - description: `List remote repositories in ADO project.`, - options: listRemoteReposCommandOptions, - impl: adoListRemoteReposAsyncCommand, -} diff --git a/src/commands/command-ado-list-remote-repos.ts b/src/commands/command-ado-list-remote-repos.ts index d5a7247..65ed4a9 100644 --- a/src/commands/command-ado-list-remote-repos.ts +++ b/src/commands/command-ado-list-remote-repos.ts @@ -1,42 +1,92 @@ import axios, { AxiosResponse } from 'axios'; import { createExecutionContext, parseCommonOptions } from '../cli'; import { renderTable } from '../cli/render-table'; -import { AdoListRepositoriesResponse, AdoRepository } from '../types'; +import { AdoListProjectsResponse, AdoListRepositoriesResponse, AdoRepository } from '../types'; import { commonAdoOptions } from './ado-options'; -import { CliCommandMetadata } from './cli-option'; +import { CliCommandMetadata, CliOption } from './cli-option'; const commandName = `ado-list-remote-repos`; +const sortOption: CliOption = { + short: 's', + long: `sort`, + codeName: `sort`, + description: `Column to sort by.`, + exampleValue: `project or repo`, + defaultValue: `project`, +}; + +const { project, ...otherCommonOptions } = commonAdoOptions; const listRemoteReposCommandOptions = { - ...commonAdoOptions, + ...otherCommonOptions, + sortOption, }; async function adoListRemoteReposAsyncCommand(this: any, str: any, options: any) { const executionContext = createExecutionContext(parseCommonOptions(options)); - const { organization, project, login, token } = str; + const { organization, project, login, token, sort } = str; const { logger } = executionContext; const org = organization || listRemoteReposCommandOptions.organization.defaultValue; - const proj = project || listRemoteReposCommandOptions.project.defaultValue; - const listRepositoriesResponse = await axios.get<{}, AxiosResponse>(`https://dev.azure.com/${org}/${proj}/_apis/git/repositories`, { + const listProjectsResponse = await axios.get<{}, AxiosResponse>(`https://dev.azure.com/${org}/_apis/projects`, { headers: { Authorization: `Basic ${Buffer.from(`${login}:${token}`).toString('base64')}`, }, }); - if (listRepositoriesResponse.status < 200 && listRepositoriesResponse.status >= 300) - // TODO: refactor into axios wrapper? - throw new Error(`Failed to list repositories. Status: ${listRepositoriesResponse.status}.`); + const xPromises = listProjectsResponse + .data + .value + .filter((adoProject) => !project ? true : adoProject.name === project) + .map(async (adoProject) => { + try { + const listRepositoriesResponse = await axios.get<{}, AxiosResponse>(`https://dev.azure.com/${org}/${adoProject.id}/_apis/git/repositories`, { + headers: { + Authorization: `Basic ${Buffer.from(`${login}:${token}`).toString('base64')}`, + }, + }); + + if (listRepositoriesResponse.status < 200 && listRepositoriesResponse.status >= 300) + // TODO: refactor into axios wrapper? + throw new Error(`Failed to list repositories. Status: ${listRepositoriesResponse.status}.`); + + return { adoProject, adoRepos: listRepositoriesResponse.data.value }; + } catch (e) { + return { adoProject, error: e }; + } + }); + const promiseResults = await Promise.allSettled(xPromises); const columnDefs = [ - { title: 'repo id', width: 38, selector: (repo: AdoRepository) => repo.id }, + { title: 'project', width: 40, selector: (repo: AdoRepository) => repo.project.name }, + // { title: 'repo id', width: 38, selector: (repo: AdoRepository) => repo.id }, { title: 'repo name', width: 40, selector: (repo: AdoRepository) => repo.name }, { title: 'remoteUrl', width: 160, selector: (repo: AdoRepository) => repo.remoteUrl }, ]; + const rows = + promiseResults.reduce( + (result, promiseResult) => { + if (promiseResult.status !== 'rejected') { + (promiseResult.value.adoRepos || []).forEach((repo) => { + result.push(repo); + }); + } + return result; + }, + [] as AdoRepository[], + ) + .sort((repo1, repo2) => { + const select = (repo: AdoRepository) => + sort === 'repo' ? repo.name : + sort === 'project' ? repo.project.name : + repo.name; + return select(repo1).localeCompare(select(repo2)); + }); + console.log(renderTable( columnDefs, - listRepositoriesResponse.data.value, - )); + rows, + )) }; export const command: CliCommandMetadata = { diff --git a/src/commands/index.ts b/src/commands/index.ts index de7e42e..419bab4 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,7 +1,6 @@ import { compareStrings, sort } from '../algos/sort'; import { command as adoListDeploys } from './command-ado-list-deploys'; import { command as adoListRemoteRepos } from './command-ado-list-remote-repos'; -import { command as adoListRemoteReposHierarchy } from './command-ado-list-remote-repos-hierarchy'; import { command as csvStats } from './command-csv-stats'; import { command as gitRepoStats } from './command-git-repo-stats'; import { command as monoAnalyze } from './command-mono-analyze'; @@ -15,7 +14,6 @@ export const allCommands = sort( [ adoListDeploys, adoListRemoteRepos, - adoListRemoteReposHierarchy, csvStats, gitRepoStats, monoAnalyze, From f3acbb656e4575bc2124e04c44212d59a10d4ce3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:41:25 +0000 Subject: [PATCH 2/3] build(deps-dev): bump @types/node from 22.9.3 to 22.10.2 Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.9.3 to 22.10.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 17 ++++++++--------- package.json | 2 +- pnpm-lock.yaml | 24 ++++++++++++------------ 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48bea56..2f57012 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "solo": "dist/index.js" }, "devDependencies": { - "@types/node": "^22.9.3", + "@types/node": "^22.10.2", "@types/semver": "^7.5.8" } }, @@ -88,12 +88,11 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, "node_modules/@types/node": { - "version": "22.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", - "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", - "license": "MIT", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/semver": { @@ -435,9 +434,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", diff --git a/package.json b/package.json index a6e3e65..ee2c321 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "typescript": "^5.7.2" }, "devDependencies": { - "@types/node": "^22.9.3", + "@types/node": "^22.10.2", "@types/semver": "^7.5.8" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da5fcb7..d2fc4c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,14 +25,14 @@ importers: version: 7.6.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.9.3)(typescript@5.7.2) + version: 10.9.2(@types/node@22.10.2)(typescript@5.7.2) typescript: specifier: ^5.7.2 version: 5.7.2 devDependencies: '@types/node': - specifier: ^22.9.3 - version: 22.9.3 + specifier: ^22.10.2 + version: 22.10.2 '@types/semver': specifier: ^7.5.8 version: 7.5.8 @@ -69,8 +69,8 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@types/node@22.9.3': - resolution: {integrity: sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==} + '@types/node@22.10.2': + resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -209,8 +209,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -245,9 +245,9 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@types/node@22.9.3': + '@types/node@22.10.2': dependencies: - undici-types: 6.19.8 + undici-types: 6.20.0 '@types/semver@7.5.8': {} @@ -344,14 +344,14 @@ snapshots: dependencies: has-flag: 4.0.0 - ts-node@10.9.2(@types/node@22.9.3)(typescript@5.7.2): + ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.3 + '@types/node': 22.10.2 acorn: 8.12.1 acorn-walk: 8.3.3 arg: 4.1.3 @@ -364,7 +364,7 @@ snapshots: typescript@5.7.2: {} - undici-types@6.19.8: {} + undici-types@6.20.0: {} v8-compile-cache-lib@3.0.1: {} From c40c6248bf4bf850ef6ec161721497aa97c515ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:49:48 +0000 Subject: [PATCH 3/3] build(deps): bump axios from 1.7.7 to 1.7.9 Bumps [axios](https://github.com/axios/axios) from 1.7.7 to 1.7.9. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.7.7...v1.7.9) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f57012..2ae42d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "axios": "^1.7.7", + "axios": "^1.7.9", "chalk": "^4.1.2", "cli-table3": "^0.6.5", "commander": "^12.1.0", @@ -156,9 +156,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index ee2c321..cb666e8 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "url": "https://github.com/another-guy/solo" }, "dependencies": { - "axios": "^1.7.7", + "axios": "^1.7.9", "chalk": "^4.1.2", "cli-table3": "^0.6.5", "commander": "^12.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2fc4c9..96d0065 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: axios: - specifier: ^1.7.7 - version: 1.7.7 + specifier: ^1.7.9 + version: 1.7.9 chalk: specifier: ^4.1.2 version: 4.1.2 @@ -98,8 +98,8 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -267,7 +267,7 @@ snapshots: asynckit@0.4.0: {} - axios@1.7.7: + axios@1.7.9: dependencies: follow-redirects: 1.15.6 form-data: 4.0.0