Merge pull request #13 from cds-snc/feat/gotta-catch-em-all

Support time range and multi-repositories option
This commit is contained in:
Jimmy Royer 2025-01-07 09:09:35 -05:00 committed by GitHub
commit 3a2e4353e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 308 additions and 215 deletions

17
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,17 @@
# Use the official TypeScript Node.js image as a base
FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm
# Install additional features
RUN apt-get update && apt-get install -y \
awscli \
curl \
exa \
jq \
fzf \
locate \
manpages \
ripgrep \
shellcheck \
&& rm -rf /var/lib/apt/lists/*
ENV SHELL /bin/zsh

View file

@ -1,18 +1,31 @@
{ {
"name": "Node.js & TypeScript", "name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "dockerComposeFile": "docker-compose.yml",
"service": "ai-code-reviewer",
"workspaceFolder": "/workspace",
"features": { "features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/eitsupi/devcontainer-features/jq-likes:2": {},
"ghcr.io/dhoeric/features/act:1": {}
// "ghcr.io/guiyomh/features/just:0": {}, // "ghcr.io/guiyomh/features/just:0": {},
// "ghcr.io/jungaretti/features/ripgrep:1": {}, // "ghcr.io/jungaretti/features/ripgrep:1": {},
// "ghcr.io/lukewiwa/features/shellcheck:0": {}, // "ghcr.io/lukewiwa/features/shellcheck:0": {},
}, },
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": ["yzhang.markdown-all-in-one"] "extensions": [
"eamodio.gitlens",
"fill-labs.dependi",
"GitHub.copilot",
"github.copilot-chat",
"github.vscode-pull-request-github",
"kaiwood.center-editor-window",
"ms-azuretools.vscode-docker",
"ms-vsliveshare.vsliveshare",
"timonwong.shellcheck",
"usernamehw.errorlens",
"visualstudioexptteam.vscodeintellicode",
"wenfangdu.jump",
"yzhang.markdown-all-in-one"
]
} }
} }
} }

View file

@ -0,0 +1,10 @@
version: '3.8'
services:
ai-code-reviewer:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace
command: sleep infinity

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
node_modules node_modules
.env
.idea .idea
lib/**/* lib/**/*
act/.secrets act/.secrets

34
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,34 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Collect AI Feedback",
"type": "node",
"request": "launch",
"args": [
"src/exportComments.ts",
"--owner",
"cds-snc",
"--repos",
"notification-terraform",
"notification-manifests",
"--author",
"github-actions[bot]",
"--since",
"2024-12-01",
"--until",
"2024-12-08",
],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

150
package-lock.json generated
View file

@ -9,16 +9,17 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.11.1",
"@octokit/rest": "^19.0.7", "@octokit/rest": "^19.0.7",
"axios": "1.7.7", "axios": "^1.7.9",
"csv-writer": "^1.6.0", "csv-writer": "^1.6.0",
"dotenv": "^16.4.7",
"minimatch": "^7.4.2", "minimatch": "^7.4.2",
"nock": "^13.5.5", "nock": "^13.5.6",
"openai": "^4.20.1", "openai": "^4.77.0",
"parse-diff": "^0.11.1", "parse-diff": "^0.11.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.2",
"yargs": "17.7.2" "yargs": "^17.7.2"
}, },
"devDependencies": { "devDependencies": {
"@types/axios": "0.14.0", "@types/axios": "0.14.0",
@ -30,13 +31,22 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.10.0", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/exec": "^1.1.1",
"uuid": "^8.3.2" "@actions/http-client": "^2.0.1"
}
},
"node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"license": "MIT",
"dependencies": {
"@actions/io": "^1.0.1"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
@ -48,6 +58,12 @@
"tunnel": "^0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@actions/io": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
"license": "MIT"
},
"node_modules/@cspotcode/source-map-support": { "node_modules/@cspotcode/source-map-support": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -404,9 +420,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.7.7", "version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.6",
@ -420,11 +436,6 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/base-64": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
},
"node_modules/before-after-hook": { "node_modules/before-after-hook": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
@ -440,15 +451,6 @@
"balanced-match": "^1.0.0" "balanced-match": "^1.0.0"
} }
}, },
"node_modules/charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
"license": "BSD-3-Clause",
"engines": {
"node": "*"
}
},
"node_modules/cliui": { "node_modules/cliui": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@ -499,15 +501,6 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
"license": "BSD-3-Clause",
"engines": {
"node": "*"
}
},
"node_modules/csv-writer": { "node_modules/csv-writer": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz", "resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz",
@ -561,14 +554,16 @@
"node": ">=0.3.1" "node": ">=0.3.1"
} }
}, },
"node_modules/digest-fetch": { "node_modules/dotenv": {
"version": "1.3.0", "version": "16.4.7",
"resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "ISC", "license": "BSD-2-Clause",
"dependencies": { "engines": {
"base-64": "^0.1.0", "node": ">=12"
"md5": "^2.3.0" },
"funding": {
"url": "https://dotenvx.com"
} }
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
@ -675,12 +670,6 @@
"ms": "^2.0.0" "ms": "^2.0.0"
} }
}, },
"node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"license": "MIT"
},
"node_modules/is-fullwidth-code-point": { "node_modules/is-fullwidth-code-point": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -711,17 +700,6 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
"license": "BSD-3-Clause",
"dependencies": {
"charenc": "0.0.2",
"crypt": "0.0.2",
"is-buffer": "~1.1.6"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -765,9 +743,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/nock": { "node_modules/nock": {
"version": "13.5.5", "version": "13.5.6",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.5.5.tgz", "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.6.tgz",
"integrity": "sha512-XKYnqUrCwXC8DGG1xX4YH5yNIrlh9c065uaMZZHUoeUUINTOyt+x/G+ezYk0Ft6ExSREVIs+qBJDK503viTfFA==", "integrity": "sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.1.0", "debug": "^4.1.0",
@ -827,23 +805,29 @@
} }
}, },
"node_modules/openai": { "node_modules/openai": {
"version": "4.20.1", "version": "4.77.0",
"resolved": "https://registry.npmjs.org/openai/-/openai-4.20.1.tgz", "resolved": "https://registry.npmjs.org/openai/-/openai-4.77.0.tgz",
"integrity": "sha512-Dd3q8EvINfganZFtg6V36HjrMaihqRgIcKiHua4Nq9aw/PxOP48dhbsk8x5klrxajt5Lpnc1KTOG5i1S6BKAJA==", "integrity": "sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4", "@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0", "abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1", "agentkeepalive": "^4.2.1",
"digest-fetch": "^1.3.0",
"form-data-encoder": "1.7.2", "form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2", "formdata-node": "^4.3.2",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7"
"web-streams-polyfill": "^3.2.1"
}, },
"bin": { "bin": {
"openai": "bin/cli" "openai": "bin/cli"
},
"peerDependencies": {
"zod": "^3.23.8"
},
"peerDependenciesMeta": {
"zod": {
"optional": true
}
} }
}, },
"node_modules/parse-diff": { "node_modules/parse-diff": {
@ -925,9 +909,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/ts-node": { "node_modules/ts-node": {
"version": "10.9.1", "version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
@ -995,30 +979,12 @@
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": { "node_modules/v8-compile-cache-lib": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/web-streams-polyfill": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/webidl-conversions": { "node_modules/webidl-conversions": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",

View file

@ -12,16 +12,17 @@
"lint": "prettier --check ." "lint": "prettier --check ."
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.11.1",
"@octokit/rest": "^19.0.7", "@octokit/rest": "^19.0.7",
"axios": "1.7.7", "axios": "^1.7.9",
"csv-writer": "^1.6.0", "csv-writer": "^1.6.0",
"dotenv": "^16.4.7",
"minimatch": "^7.4.2", "minimatch": "^7.4.2",
"nock": "^13.5.5", "nock": "^13.5.6",
"openai": "^4.20.1", "openai": "^4.77.0",
"parse-diff": "^0.11.1", "parse-diff": "^0.11.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.2",
"yargs": "17.7.2" "yargs": "^17.7.2"
}, },
"devDependencies": { "devDependencies": {
"@types/axios": "0.14.0", "@types/axios": "0.14.0",

View file

@ -1,24 +1,38 @@
/** /**
* This script fetches comments from specified GitHub pull requests and exports them to a CSV file. * This script fetches comments from specified GitHub repositories, for a given time frame,
* and exports these to a CSV file.
*
* It uses the GitHub API to retrieve the comments and filters them based on the provided author (if specified). * It uses the GitHub API to retrieve the comments and filters them based on the provided author (if specified).
* The resulting CSV file contains the pull request number, author, comment, and a link to the comment. * The resulting CSV file contains the date, AI feedback, pull request number, author, comment, and a link to
* the comment.
* *
* Usage: * Usage:
* npx ts-node exportComments.ts --token <your_github_token> --owner <repo_owner> --repo <repo_name> --prs <pr_numbers> [--author <author_name>] * npx ts-node exportComments.ts --token <your_github_token> --owner <repo_owner> --repo <repo_name> --prs <pr_numbers> [--author <author_name>]
* *
* Options: * Options:
* --token, -t GitHub personal access token (can also be set via the GITHUB_TOKEN environment variable) * --owner, -o Repository owner (required)
* --repos, -r Repositories to search into (required)
* --author, -a Author of the comments to filter with (optional -- likely the AI bot author name)
* --since, -s Filter comments since the given date (YYYY-MM-DD) (required)
* --until, -u Filter comments until the given date (YYYY-MM-DD) (optional, defaults to current date)
* --token, -t GitHub personal access token (can also be set via the GITHUB_TOKEN environment variable or `.env` file)
* It is recommended to use the environment variable to avoid exposing sensitive information. * It is recommended to use the environment variable to avoid exposing sensitive information.
* --owner, -o Repository owner
* --repo, -r Repository name
* --prs, -p Comma-separated list of pull request numbers
* --author, -a Author of the comments to filter with (optional)
* *
* Example: * Examples:
* npx ts-node exportComments.ts --owner cds-snc --repo cds-ai-codereviewer --prs 6,7,8 --author github-actions[bot] * npx ts-node exportComments.ts --owner cds-snc --repos cds-ai-codereviewer --author 'github-actions[bot]' --since 2024-12-01
*
* npx ts-node src/exportComments.ts --owner cds-snc --repos notification-terraform notification-api --author 'github-actions[bot]' --since 2024-12-01 --until 2024-12-31
* *
* Environment Variable: * Environment Variable:
* GITHUB_TOKEN GitHub personal access token (recommended to use this instead of --token argument) * GITHUB_TOKEN GitHub personal access token (recommended to use this instead of --token argument)
*
* The GITHUB_TOKEN can be configured using a .env file at the root of the project:
*
* Example .env file:
*
* ```txt
* GITHUB_TOKEN=your_actual_token_here
* ```
*/ */
import axios from "axios"; import axios from "axios";
@ -26,12 +40,16 @@ import { createObjectCsvWriter } from "csv-writer";
import yargs from "yargs"; import yargs from "yargs";
import { hideBin } from "yargs/helpers"; import { hideBin } from "yargs/helpers";
// filepath: /workspace/src/exportComments.ts
import dotenv from 'dotenv';
dotenv.config();
const argv = yargs(hideBin(process.argv)) const argv = yargs(hideBin(process.argv))
.option("token", { .option("token", {
alias: "t", alias: "t",
type: "string", type: "string",
description: "GitHub personal access token", description: "GitHub personal access token",
demandOption: false, demandOption: true,
default: process.env.GITHUB_TOKEN, default: process.env.GITHUB_TOKEN,
}) })
.option("owner", { .option("owner", {
@ -40,28 +58,41 @@ const argv = yargs(hideBin(process.argv))
description: "Repository owner", description: "Repository owner",
demandOption: true, demandOption: true,
}) })
.option("repo", { .option("repos", {
alias: "r", alias: "r",
type: "string", type: "array",
description: "Repository name", description: "List of repository names",
demandOption: true,
})
.option("prs", {
alias: "p",
type: "string",
description: "Comma-separated list of pull request numbers",
demandOption: true, demandOption: true,
}) })
.array("repos")
.string("repos")
.option("author", { .option("author", {
alias: "a", alias: "a",
type: "string", type: "string",
description: "Author of the comments to filter with", description: "Author of the comments to filter with",
demandOption: false, demandOption: false,
}) })
.option("since", {
alias: "s",
type: "string",
description: "Filter comments since the given date (YYYY-MM-DD)",
demandOption: true,
coerce: coerceDate,
})
.option("until", {
alias: "u",
type: "string",
description: "Filter comments until the given date (YYYY-MM-DD)",
demandOption: false,
coerce: coerceDate,
default: new Date(),
})
.parseSync(); // Use parseSync to ensure argv is not a Promise .parseSync(); // Use parseSync to ensure argv is not a Promise
interface Comment { interface Comment {
date: string;
author: string; author: string;
repository: string;
prNumber: string; prNumber: string;
category: string[]; category: string[];
comment: string; comment: string;
@ -71,7 +102,9 @@ interface Comment {
const csvWriter = createObjectCsvWriter({ const csvWriter = createObjectCsvWriter({
path: "pr_comments.csv", path: "pr_comments.csv",
header: [ header: [
{ id: "date", title: "Date" },
{ id: "author", title: "Author" }, { id: "author", title: "Author" },
{ id: "repository", title: "Repository" },
{ id: "prNumber", title: "PR Number" }, { id: "prNumber", title: "PR Number" },
{ id: "category", title: "Category" }, { id: "category", title: "Category" },
{ id: "comment", title: "Comment" }, { id: "comment", title: "Comment" },
@ -79,41 +112,37 @@ const csvWriter = createObjectCsvWriter({
], ],
}); });
function coerceDate(dateStr: string): Date {
const date = new Date(dateStr);
if (isNaN(date.getTime())) {
throw new Error("Invalid date format. Please use YYYY-MM-DD.");
}
return date;
}
const reactionToCategory: Record<string, string> = { const reactionToCategory: Record<string, string> = {
"+1": "Useful", "+1": "Useful",
eyes: "Noisy", eyes: "Noisy",
confused: "Hallucination", confused: "Hallucination",
rocket: "Teachable", rocket: "Teachable",
"-1": "Incorrect", "-1": "Incorrect",
null: "None",
}; };
function extractCategories(reactions: Record<string, any>): string[] { function extractCategories(reactions: Record<string, any>): string[] {
return Object.keys(reactions) const category = Object.keys(reactions)
.filter( .filter(
(reaction) => reactionToCategory[reaction] && reactions[reaction] > 0 (reaction) => reactionToCategory[reaction] && reactions[reaction] > 0
) )
.map((reaction) => reactionToCategory[reaction]); .map((reaction) => reactionToCategory[reaction]);
const nonEmptyCategory = category?.length === 0 ? ["None"] : category;
return nonEmptyCategory;
} }
async function fetchComments(): Promise<void> { async function fetchCommentsForPR(owner: string, repository: string, prNumber: number, author?: string): Promise<Comment[]> {
const prNumbers = argv.prs
.split(",")
.map((pr: string) => parseInt(pr.trim(), 10));
let allComments: Comment[] = [];
for (const prNumber of prNumbers) {
const comments = await fetchCommentsForPR(prNumber);
allComments = allComments.concat(comments);
}
await csvWriter.writeRecords(allComments);
console.log("CSV file written successfully");
}
async function fetchCommentsForPR(prNumber: number): Promise<Comment[]> {
try { try {
const response = await axios.get( const response = await axios.get(
`https://api.github.com/repos/${argv.owner}/${argv.repo}/pulls/${prNumber}/comments`, `https://api.github.com/repos/${owner}/${repository}/pulls/${prNumber}/comments`,
{ {
headers: { headers: {
Authorization: `token ${argv.token}`, Authorization: `token ${argv.token}`,
@ -124,8 +153,11 @@ async function fetchCommentsForPR(prNumber: number): Promise<Comment[]> {
let comments: Comment[] = await Promise.all( let comments: Comment[] = await Promise.all(
response.data.map(async (comment: Record<string, any>) => { response.data.map(async (comment: Record<string, any>) => {
const categories = extractCategories(comment.reactions); const categories = extractCategories(comment.reactions);
console.debug(`Categories for comment ${repository}/pull/${prNumber}/${comment.id}:`, categories);
return { return {
date: comment.created_at,
author: comment.user.login, author: comment.user.login,
repository: `${owner}/${repository}`,
prNumber: prNumber.toString(), prNumber: prNumber.toString(),
category: categories, category: categories,
comment: comment.body, comment: comment.body,
@ -134,8 +166,8 @@ async function fetchCommentsForPR(prNumber: number): Promise<Comment[]> {
}) })
); );
if (argv.author) { if (author) {
comments = comments.filter((comment) => comment.author === argv.author); comments = comments.filter((comment) => comment.author === author);
} }
return comments; return comments;
@ -145,4 +177,55 @@ async function fetchCommentsForPR(prNumber: number): Promise<Comment[]> {
} }
} }
fetchComments(); // Function to fetch comments for multiple repositories
async function fetchCommentsForRepos(owner: string, repositories: string[], since: Date, until: Date, author?: string): Promise<Comment[]> {
let allComments: Comment[] = [];
for (const repository of repositories) {
console.log(`Fetching comments for repository ${owner}/${repository}...`);
const pullRequests = await fetchPullRequests(owner, repository, since, until);
for (const pr of pullRequests) {
const prComments = await fetchCommentsForPR(owner, repository, pr.number, author);
allComments = allComments.concat(prComments);
}
}
await csvWriter.writeRecords(allComments);
console.log("CSV file written successfully");
return allComments;
}
async function fetchPullRequests(owner: string, repo: string, since: Date, until: Date) {
const pullRequests = [];
let page = 1;
let hasMore = true;
console.debug(`Fetching pull requests for ${owner}/${repo}...`);
while (hasMore) {
const response = await axios.get(`https://api.github.com/repos/${owner}/${repo}/pulls`, {
headers: {
Authorization: `token ${argv.token}`,
Accept: 'application/vnd.github.v3+json',
},
params: {
state: 'all',
per_page: 100,
page,
sort: 'updated',
direction: 'desc',
},
});
const filteredPRs = response.data.filter((pr: any) => new Date(pr.updated_at) >= since && new Date(pr.updated_at) <= until);
pullRequests.push(...filteredPRs);
if (response.data.length < 100) {
hasMore = false;
} else {
page++;
}
}
console.debug(`Fetched ${pullRequests.length} pull requests for ${owner}/${repo}`);
return pullRequests;
}
fetchCommentsForRepos(argv.owner, argv.repos, argv.since, argv.until, argv.author);

108
yarn.lock
View file

@ -2,13 +2,20 @@
# yarn lockfile v1 # yarn lockfile v1
"@actions/core@^1.10.0": "@actions/core@^1.11.1":
version "1.10.0" version "1.11.1"
resolved "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz" resolved "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz"
integrity sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug== integrity sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==
dependencies: dependencies:
"@actions/exec" "^1.1.1"
"@actions/http-client" "^2.0.1" "@actions/http-client" "^2.0.1"
uuid "^8.3.2"
"@actions/exec@^1.1.1":
version "1.1.1"
resolved "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz"
integrity sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==
dependencies:
"@actions/io" "^1.0.1"
"@actions/http-client@^2.0.1": "@actions/http-client@^2.0.1":
version "2.1.0" version "2.1.0"
@ -17,6 +24,11 @@
dependencies: dependencies:
tunnel "^0.0.6" tunnel "^0.0.6"
"@actions/io@^1.0.1":
version "1.1.3"
resolved "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz"
integrity sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==
"@cspotcode/source-map-support@^0.8.0": "@cspotcode/source-map-support@^0.8.0":
version "0.8.1" version "0.8.1"
resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz"
@ -246,10 +258,10 @@ asynckit@^0.4.0:
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
axios@*, axios@1.7.7: axios@*, axios@^1.7.9:
version "1.7.7" version "1.7.9"
resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz" resolved "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz"
integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==
dependencies: dependencies:
follow-redirects "^1.15.6" follow-redirects "^1.15.6"
form-data "^4.0.0" form-data "^4.0.0"
@ -260,11 +272,6 @@ balanced-match@^1.0.0:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base-64@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz"
integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
before-after-hook@^2.2.0: before-after-hook@^2.2.0:
version "2.2.3" version "2.2.3"
resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz" resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz"
@ -277,11 +284,6 @@ brace-expansion@^2.0.1:
dependencies: dependencies:
balanced-match "^1.0.0" balanced-match "^1.0.0"
charenc@0.0.2:
version "0.0.2"
resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz"
integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==
cliui@^8.0.1: cliui@^8.0.1:
version "8.0.1" version "8.0.1"
resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
@ -315,11 +317,6 @@ create-require@^1.1.0:
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
crypt@0.0.2:
version "0.0.2"
resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz"
integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==
csv-writer@^1.6.0: csv-writer@^1.6.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz" resolved "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz"
@ -347,13 +344,10 @@ diff@^4.0.1:
resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
digest-fetch@^1.3.0: dotenv@^16.4.7:
version "1.3.0" version "16.4.7"
resolved "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz"
integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
dependencies:
base-64 "^0.1.0"
md5 "^2.3.0"
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
@ -409,11 +403,6 @@ humanize-ms@^1.2.1:
dependencies: dependencies:
ms "^2.0.0" ms "^2.0.0"
is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-fullwidth-code-point@^3.0.0: is-fullwidth-code-point@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
@ -434,15 +423,6 @@ make-error@^1.1.1:
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
md5@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz"
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
charenc "0.0.2"
crypt "0.0.2"
is-buffer "~1.1.6"
mime-db@1.52.0: mime-db@1.52.0:
version "1.52.0" version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
@ -472,10 +452,10 @@ ms@2.1.2:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nock@^13.5.5: nock@^13.5.6:
version "13.5.5" version "13.5.6"
resolved "https://registry.npmjs.org/nock/-/nock-13.5.5.tgz" resolved "https://registry.npmjs.org/nock/-/nock-13.5.6.tgz"
integrity sha512-XKYnqUrCwXC8DGG1xX4YH5yNIrlh9c065uaMZZHUoeUUINTOyt+x/G+ezYk0Ft6ExSREVIs+qBJDK503viTfFA== integrity sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==
dependencies: dependencies:
debug "^4.1.0" debug "^4.1.0"
json-stringify-safe "^5.0.1" json-stringify-safe "^5.0.1"
@ -500,20 +480,18 @@ once@^1.4.0:
dependencies: dependencies:
wrappy "1" wrappy "1"
openai@^4.20.1: openai@^4.77.0:
version "4.20.1" version "4.77.0"
resolved "https://registry.npmjs.org/openai/-/openai-4.20.1.tgz" resolved "https://registry.npmjs.org/openai/-/openai-4.77.0.tgz"
integrity sha512-Dd3q8EvINfganZFtg6V36HjrMaihqRgIcKiHua4Nq9aw/PxOP48dhbsk8x5klrxajt5Lpnc1KTOG5i1S6BKAJA== integrity sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw==
dependencies: dependencies:
"@types/node" "^18.11.18" "@types/node" "^18.11.18"
"@types/node-fetch" "^2.6.4" "@types/node-fetch" "^2.6.4"
abort-controller "^3.0.0" abort-controller "^3.0.0"
agentkeepalive "^4.2.1" agentkeepalive "^4.2.1"
digest-fetch "^1.3.0"
form-data-encoder "1.7.2" form-data-encoder "1.7.2"
formdata-node "^4.3.2" formdata-node "^4.3.2"
node-fetch "^2.6.7" node-fetch "^2.6.7"
web-streams-polyfill "^3.2.1"
parse-diff@^0.11.1: parse-diff@^0.11.1:
version "0.11.1" version "0.11.1"
@ -561,10 +539,10 @@ tr46@~0.0.3:
resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
ts-node@^10.9.1: ts-node@^10.9.2:
version "10.9.1" version "10.9.2"
resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz"
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==
dependencies: dependencies:
"@cspotcode/source-map-support" "^0.8.0" "@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7" "@tsconfig/node10" "^1.0.7"
@ -595,21 +573,11 @@ universal-user-agent@^6.0.0:
resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz" resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache-lib@^3.0.1: v8-compile-cache-lib@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
web-streams-polyfill@^3.2.1:
version "3.2.1"
resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz"
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
web-streams-polyfill@4.0.0-beta.3: web-streams-polyfill@4.0.0-beta.3:
version "4.0.0-beta.3" version "4.0.0-beta.3"
resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz" resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz"
@ -652,7 +620,7 @@ yargs-parser@^21.1.1:
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@17.7.2: yargs@^17.7.2:
version "17.7.2" version "17.7.2"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==