diff options
| -rw-r--r-- | src/actions/checkDependencies.ts | 80 | ||||
| -rw-r--r-- | src/actions/fixDependencies.ts | 21 | ||||
| -rw-r--r-- | src/actions/sendEmail.ts | 8 | ||||
| -rw-r--r-- | src/commands/fix.ts | 14 | ||||
| -rw-r--r-- | src/index.ts | 2 | ||||
| -rw-r--r-- | src/lib/project.ts | 85 | ||||
| -rw-r--r-- | src/utils/helper.ts | 15 |
7 files changed, 154 insertions, 71 deletions
diff --git a/src/actions/checkDependencies.ts b/src/actions/checkDependencies.ts index 4234bf9..999733e 100644 --- a/src/actions/checkDependencies.ts +++ b/src/actions/checkDependencies.ts @@ -1,77 +1,21 @@ -import fs from "fs/promises"; -import ora, { type Ora } from "ora"; -import type { Config, Project } from "../types.js"; +import ora from "ora"; +import type { Config } from "../types.js"; import { getConfig } from "../utils/config.js"; -import { exec, type ExecException } from "child_process"; +import { getProjectAudits, goThroughProjects } from "../lib/project.js"; export async function checkDependencies() { - const spinner = ora("Getting all Project Data").start(); - const config: Config = await getConfig(); - let projectAudits: PromiseSettledResult<Project>[]; - let projects: Promise<Project>[] = []; - - try { - const entries = await fs.readdir(config.path, { withFileTypes: true }); - - for (let entry of entries) { - if (!entry.isDirectory()) { - continue; - } - - let dirFullPath = `${config.path}${entry.name}`; - const projectDir = await fs.readdir(dirFullPath); - - if (projectDir.includes("package.json")) { - let auditPromise = getAuditPromise(dirFullPath, entry.name, spinner); - projects.push(auditPromise); - } - } - - projectAudits = await Promise.allSettled(projects); - - spinner.succeed("Got the Data successfully"); - return projectAudits; - } catch (error) { - spinner.fail("Ups and Error :("); - throw error; - } -} - -async function getAuditPromise( - path: string, - dirname: string, - spinner: Ora, -): Promise<Project> { - await pullLatest(path, spinner); - - spinner.text = "getting audit"; - - let { stdout } = await promiseExec(`cd "${path}" && npm audit --json`); + let spinnerProjects = ora("Getting all projects").start(); + let projects = await goThroughProjects(config); + spinnerProjects.succeed("Got all projects"); - let output = JSON.parse(stdout); - let project: Project = { projectName: dirname, ...output }; - if (project.error) { - throw new Error( - `${dirname} could not be audited, maybe package lock is corrupted`, - ); - } + let spinnerAudit = ora("Getting all audits").start(); + let projectAudits = await getProjectAudits(projects); - return project; -} - -async function pullLatest(path: string, spinner: Ora) { - spinner.text = "pulling latest"; - await promiseExec(`cd "${path}" && git pull`); -} + spinnerAudit.text = "Resolving audits"; + let audit = await Promise.allSettled(projectAudits); + spinnerAudit.succeed("Successfully resolved audits"); -function promiseExec( - cmd: string, -): Promise<{ error: ExecException | null; stdout: string; stderr: string }> { - return new Promise((resolve, _) => { - exec(cmd, (error, stdout, stderr) => { - resolve({ error, stdout, stderr }); - }); - }); + return audit; } diff --git a/src/actions/fixDependencies.ts b/src/actions/fixDependencies.ts new file mode 100644 index 0000000..9dfb6c6 --- /dev/null +++ b/src/actions/fixDependencies.ts @@ -0,0 +1,21 @@ +import ora from "ora"; +import type { Config } from "../types.js"; +import { getConfig } from "../utils/config.js"; +import { getProjectFixes, goThroughProjects } from "../lib/project.js"; + +export async function fixDependencies(force: boolean) { + const config: Config = await getConfig(); + + let spinnerProjects = ora("Getting all projects").start(); + let projects = await goThroughProjects(config); + spinnerProjects.succeed("Got all projects"); + + let spinnerFixes = ora("Getting all fixes").start(); + let projectFixes = await getProjectFixes(projects, force); + + spinnerFixes.text = "Resolving fixes"; + let fixes = await Promise.allSettled(projectFixes); + spinnerFixes.succeed("Successfully resolved fixes"); + + return fixes; +} diff --git a/src/actions/sendEmail.ts b/src/actions/sendEmail.ts index 4509a8e..62c527f 100644 --- a/src/actions/sendEmail.ts +++ b/src/actions/sendEmail.ts @@ -1,11 +1,11 @@ import nodemailer from "nodemailer"; import { emailConfig } from "../utils/email.js"; -import type { Project } from "../types.js"; +import type { ProjectAudit } from "../types.js"; const transporter = nodemailer.createTransport(emailConfig); export const sendAuditEmail = async ( - projects: PromiseSettledResult<Project>[], + projects: PromiseSettledResult<ProjectAudit>[], ) => { const text = emailContent(projects); const email = await transporter.sendMail({ @@ -18,7 +18,9 @@ export const sendAuditEmail = async ( return email; }; -const emailContent = (projects: PromiseSettledResult<Project>[]): string => { +const emailContent = ( + projects: PromiseSettledResult<ProjectAudit>[], +): string => { return `Here is your Report: ${projects.map((project) => { if (project.status === "fulfilled") { diff --git a/src/commands/fix.ts b/src/commands/fix.ts new file mode 100644 index 0000000..94ab2e4 --- /dev/null +++ b/src/commands/fix.ts @@ -0,0 +1,14 @@ +import type { Command } from "commander"; +import { fixDependencies } from "../actions/fixDependencies.js"; +import { outputFixes } from "../actions/output.js"; + +export const fix = (program: Command) => { + program + .command("fix") + .description("Runs 'npm audit fix' on each project") + .option("-f, --force", "Uses 'npm audit fix --force' on each project") + .action(async (options) => { + let tests = await fixDependencies(options.force); + outputFixes(tests); + }); +}; diff --git a/src/index.ts b/src/index.ts index 3a6b348..0f81fdb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,10 +2,12 @@ import { Command } from "commander"; import { check } from "./commands/check.js"; import { config } from "./commands/config.js"; +import { fix } from "./commands/fix.js"; const program = new Command(); check(program); +fix(program); config(program); program.parse(process.argv); diff --git a/src/lib/project.ts b/src/lib/project.ts new file mode 100644 index 0000000..fc1f6b8 --- /dev/null +++ b/src/lib/project.ts @@ -0,0 +1,85 @@ +import type { + AuditOutput, + Config, + FixOutput, + ProjectAudit, + ProjectFix, +} from "../types.js"; +import fs from "fs/promises"; +import { promiseExec } from "../utils/helper.js"; + +export async function getProjectAudits(projects: any[]) { + let audits = []; + for (let project of projects) { + let auditPromise = getAuditPromise(project.path, project.name); + audits.push(auditPromise); + } + return audits; +} + +export async function getProjectFixes(projects: any[], force: boolean) { + let fixes = []; + for (let project of projects) { + let fixPromise = getFixPromise(project.path, project.name, force); + fixes.push(fixPromise); + } + return fixes; +} + +export async function goThroughProjects(config: Config) { + let projects = []; + try { + const entries = await fs.readdir(config.path, { withFileTypes: true }); + + for (let entry of entries) { + if (!entry.isDirectory()) { + continue; + } + + let dirFullPath = `${config.path}${entry.name}`; + const projectDir = await fs.readdir(dirFullPath); + + if (projectDir.includes("package.json")) { + projects.push({ path: dirFullPath, name: entry.name }); + } + } + + return projects; + } catch (error) { + throw error; + } +} + +async function getAuditPromise( + path: string, + dirname: string, +): Promise<ProjectAudit> { + let { stdout } = await promiseExec(`cd "${path}" && npm audit --json`); + + let output: AuditOutput = JSON.parse(stdout); + let project: ProjectAudit = { projectName: dirname, ...output }; + if (project.error) { + throw new Error( + `${dirname} could not be audited, maybe package lock is corrupted`, + ); + } + + return project; +} + +async function getFixPromise( + path: string, + dirname: string, + force: boolean, +): Promise<ProjectFix> { + let { stdout } = await promiseExec( + `cd "${path}" && npm audit fix --json ${force && "--force"}`, + ); + + let output: FixOutput = JSON.parse(stdout); + let project: ProjectFix = { projectName: dirname, ...output }; + if (project.error) { + throw new Error(`${dirname} could not be fixed`); + } + return project; +} diff --git a/src/utils/helper.ts b/src/utils/helper.ts new file mode 100644 index 0000000..379aeef --- /dev/null +++ b/src/utils/helper.ts @@ -0,0 +1,15 @@ +import { exec, type ExecException } from "child_process"; + +export async function pullLatest(path: string) { + await promiseExec(`cd "${path}" && git pull`); +} + +export function promiseExec( + cmd: string, +): Promise<{ error: ExecException | null; stdout: string; stderr: string }> { + return new Promise((resolve, _) => { + exec(cmd, (error, stdout, stderr) => { + resolve({ error, stdout, stderr }); + }); + }); +} |
