codereivew
This commit is contained in:
12
ChatGPT-CodeReview/.dockerignore
Normal file
12
ChatGPT-CodeReview/.dockerignore
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
**/node_modules/
|
||||||
|
**/.git
|
||||||
|
**/README.md
|
||||||
|
**/LICENSE
|
||||||
|
**/.vscode
|
||||||
|
**/npm-debug.log
|
||||||
|
**/coverage
|
||||||
|
**/.env
|
||||||
|
**/.editorconfig
|
||||||
|
**/dist
|
||||||
|
**/*.pem
|
||||||
|
Dockerfile
|
||||||
25
ChatGPT-CodeReview/.env.example
Normal file
25
ChatGPT-CodeReview/.env.example
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# open ai apikey
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
|
# The ID of your GitHub App
|
||||||
|
APP_ID=
|
||||||
|
WEBHOOK_SECRET=
|
||||||
|
|
||||||
|
# Use `trace` to get verbose logging or `info` to show less
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
# Go to https://smee.io/new set this to the URL that you are redirected to.
|
||||||
|
WEBHOOK_PROXY_URL=
|
||||||
|
PRIVATE_KEY=
|
||||||
|
|
||||||
|
# BOT settings
|
||||||
|
LANGUAGE=
|
||||||
|
MODEL=
|
||||||
|
temperature=
|
||||||
|
top_p=
|
||||||
|
max_tokens=
|
||||||
|
TARGET_LABEL=
|
||||||
|
MAX_PATCH_LENGTH=
|
||||||
|
PROMPT=Below there is a code diff please help me do a code review
|
||||||
|
IGNORE_PATTERNS=/node_modules,*.md # glob pattern or regex pattern to ignore files, separated by comma
|
||||||
|
INCLUDE_PATTERNS=*.js,*.ts # glob pattern or regex pattern to include files, separated by comma
|
||||||
22
ChatGPT-CodeReview/.github/workflows/cr.yml
vendored
Normal file
22
ChatGPT-CodeReview/.github/workflows/cr.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
LANGUAGE: English
|
||||||
|
OPENAI_API_ENDPOINT: https://api.bianxie.ai/v1
|
||||||
|
LOG_LEVEL: debug
|
||||||
|
INCLUDE_PATTERNS: 'src/*'
|
||||||
28
ChatGPT-CodeReview/.github/workflows/translate.yml
vendored
Normal file
28
ChatGPT-CodeReview/.github/workflows/translate.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# name: Translate README
|
||||||
|
|
||||||
|
# on:
|
||||||
|
# push:
|
||||||
|
# branches:
|
||||||
|
# - main
|
||||||
|
|
||||||
|
# permissions:
|
||||||
|
# contents: write
|
||||||
|
|
||||||
|
# jobs:
|
||||||
|
# build:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v2
|
||||||
|
# - name: Setup Node.js
|
||||||
|
# uses: actions/setup-node@v1
|
||||||
|
# with:
|
||||||
|
# node-version: 12.x
|
||||||
|
# # ISO Langusge Codes: https://cloud.google.com/translate/docs/languages
|
||||||
|
# - name: Adding README - Chinese Simplified
|
||||||
|
# uses: dephraiim/translate-readme@main
|
||||||
|
# with:
|
||||||
|
# LANG: zh-CN
|
||||||
|
# - name: Adding README - Chinese Traditional
|
||||||
|
# uses: dephraiim/translate-readme@main
|
||||||
|
# with:
|
||||||
|
# LANG: zh-TW
|
||||||
11
ChatGPT-CodeReview/.gitignore
vendored
Normal file
11
ChatGPT-CodeReview/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
*.pem
|
||||||
|
!mock-cert.pem
|
||||||
|
.env
|
||||||
|
coverage
|
||||||
|
lib
|
||||||
|
*.cache/**
|
||||||
|
dist/
|
||||||
|
lambda/
|
||||||
|
.serverless/
|
||||||
0
ChatGPT-CodeReview/.prettierrc
Normal file
0
ChatGPT-CodeReview/.prettierrc
Normal file
73
ChatGPT-CodeReview/CODE_OF_CONDUCT.md
Normal file
73
ChatGPT-CodeReview/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
|
education, socio-economic status, nationality, personal appearance, race,
|
||||||
|
religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
- Using welcoming and inclusive language
|
||||||
|
- Being respectful of differing viewpoints and experiences
|
||||||
|
- Gracefully accepting constructive criticism
|
||||||
|
- Focusing on what is best for the community
|
||||||
|
- Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
- Public or private harassment
|
||||||
|
- Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
- Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at . All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
39
ChatGPT-CodeReview/CONTRIBUTING.md
Normal file
39
ChatGPT-CodeReview/CONTRIBUTING.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
## Contributing
|
||||||
|
|
||||||
|
[fork]: /fork
|
||||||
|
[pr]: /compare
|
||||||
|
[code-of-conduct]: CODE_OF_CONDUCT.md
|
||||||
|
|
||||||
|
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
|
||||||
|
|
||||||
|
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
||||||
|
|
||||||
|
## Issues and PRs
|
||||||
|
|
||||||
|
If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them.
|
||||||
|
|
||||||
|
We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR.
|
||||||
|
|
||||||
|
## Submitting a pull request
|
||||||
|
|
||||||
|
1. [Fork][fork] and clone the repository.
|
||||||
|
1. Configure and install the dependencies: `npm install`.
|
||||||
|
1. Make sure the tests pass on your machine: `npm test`, note: these tests also apply the linter, so there's no need to lint separately.
|
||||||
|
1. Create a new branch: `git checkout -b my-branch-name`.
|
||||||
|
1. Make your change, add tests, and make sure the tests still pass.
|
||||||
|
1. Push to your fork and [submit a pull request][pr].
|
||||||
|
1. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
||||||
|
|
||||||
|
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||||
|
|
||||||
|
- Write and update tests.
|
||||||
|
- Keep your changes as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
||||||
|
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||||
|
|
||||||
|
Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||||
|
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
||||||
|
- [GitHub Help](https://help.github.com)
|
||||||
7
ChatGPT-CodeReview/Dockerfile
Normal file
7
ChatGPT-CodeReview/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM node:18-slim
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
RUN yarn install --production --frozen-lockfile && yarn cache clean
|
||||||
|
ENV NODE_ENV="production"
|
||||||
|
COPY . .
|
||||||
|
CMD [ "yarn", "start" ]
|
||||||
15
ChatGPT-CodeReview/LICENSE
Normal file
15
ChatGPT-CodeReview/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2023, anc95
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
121
ChatGPT-CodeReview/README.ja.md
Normal file
121
ChatGPT-CodeReview/README.ja.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# CodeReview BOT
|
||||||
|
|
||||||
|
> A code review robot powered by ChatGPT
|
||||||
|
|
||||||
|
Translation Versions: [ENGLISH](./README.md) | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
❗️⚠️ コストを考慮して BOT はテスト目的でのみ使用され、現在 AWS Lambda に展開されて速度制限を受けています。そのため、不安定な状況は完全に正常です。アプリケーションを直接展開することをお勧めします。
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install: [apps/cr-gpt](https://github.com/apps/cr-gpt);
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
1. リポジトリのホームページに移動します
|
||||||
|
2. `settings` をクリックします
|
||||||
|
3. `secrets and variables` メニューの下の `actions` をクリックします
|
||||||
|
4. `New repository variable` をクリックして OpenAI の API キーの登録を行います。変数名は `OPENAI_API_KEY` にしてください。変数の値には OpenAI の API キーを入力します。 (OpenAI のホームページから API キーを取得できます。)
|
||||||
|
<img width="1465" alt="image" src="https://user-images.githubusercontent.com/13167934/218533628-3974b70f-c423-44b0-b096-d1ec2ace85ea.png">
|
||||||
|
|
||||||
|
### Start using
|
||||||
|
|
||||||
|
1. この bot は新しいプルリクエストが作成されたときに自動的にコードレビューを行います。レビュー結果はプルリクエストのタイムラインやファイル変更部分に表示されます。
|
||||||
|
2. `git push` によりプルリクエストの更新が行われたときにも自動的にコードレビューを行います。
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
[ChatGPT-CodeReview/pull/21](https://github.com/anc95/ChatGPT-CodeReview/pull/21)
|
||||||
|
|
||||||
|
<img width="1052" alt="image" src="https://user-images.githubusercontent.com/13167934/218999459-812206e1-d8d2-4900-8ce8-19b5b6e1f5cb.png">
|
||||||
|
|
||||||
|
### Using Github Actions
|
||||||
|
|
||||||
|
> 基本的には、Github Actions での利用を推奨します。
|
||||||
|
|
||||||
|
[actions/chatgpt-codereviewer](https://github.com/marketplace/actions/chatgpt-codereviewer)
|
||||||
|
|
||||||
|
1. `OPENAI_API_KEY` を設定する
|
||||||
|
2. 以下の例のように `.github/workflows/cr.yml` を作成する
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
if: ${{ contains(github.event.*.labels.*.name, 'gpt review') }} # Optional; to run only when a label is attached
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
# Optional
|
||||||
|
LANGUAGE: Chinese
|
||||||
|
MODEL:
|
||||||
|
PROMPT:
|
||||||
|
top_p: 1
|
||||||
|
temperature: 1
|
||||||
|
IGNORE_PATTERNS: /node_modules,*.md # Regex pattern to ignore files, separated by comma
|
||||||
|
```
|
||||||
|
|
||||||
|
## Self-hosting
|
||||||
|
|
||||||
|
1. このリポジトリをクローンします
|
||||||
|
2. `.env.example` を `.env` にリネームし、必要な環境変数を設定します
|
||||||
|
3. 以下のコマンドを順番に実行することで依存関係をインストールし、bot を起動します
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
npm -i g pm2
|
||||||
|
npm run build
|
||||||
|
pm2 start pm2.config.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
詳細は [probot](https://probot.github.io/docs/development/) を参照してください。
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Run the bot
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Build container
|
||||||
|
docker build -t cr-bot .
|
||||||
|
|
||||||
|
# 2. Start container
|
||||||
|
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> cr-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
cr-bot の改善に関する提案やバグ報告は、issue を作成してください。どのような貢献でも歓迎します!!
|
||||||
|
|
||||||
|
より詳しい情報は [Contributing Guide](CONTRIBUTING.md) を参照してください。
|
||||||
|
|
||||||
|
## Credit
|
||||||
|
|
||||||
|
this project is inpired by [codereview.gpt](https://github.com/sturdy-dev/codereview.gpt)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[ISC](LICENSE) © 2023 anc95
|
||||||
117
ChatGPT-CodeReview/README.ko.md
Normal file
117
ChatGPT-CodeReview/README.ko.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# CodeReview BOT
|
||||||
|
|
||||||
|
> cr bot은 ChatGPT를 활용한 코드리뷰 로봇입니다.
|
||||||
|
|
||||||
|
Translation Versions: [ENGLISH](./README.md) | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md)
|
||||||
|
|
||||||
|
## 사용법
|
||||||
|
|
||||||
|
❗️⚠️비용을 고려하여 BOT은 테스트 목적으로만 사용되며, 현재 AWS Lambda에 배포되어 속도 제한을 받고 있습니다. 따라서 불안정한 상황은 완전히 정상적입니다. 응용 프로그램을 직접 배포하는 것이 좋습니다.
|
||||||
|
|
||||||
|
### 설치
|
||||||
|
|
||||||
|
설치: [apps/cr-gpt](https://github.com/apps/cr-gpt);
|
||||||
|
|
||||||
|
### 설정
|
||||||
|
|
||||||
|
1. cr bot을 적용할 레포지토리 홈페이지로 이동합니다.
|
||||||
|
2. `settings` 클릭
|
||||||
|
3. `secrets and variables` 메뉴 밑의 `actions` 를 클릭
|
||||||
|
4. `Variables` 탭으로 변경합니다, `New repository variable` 버튼을 눌러서 새로운 `OPENAI_API_KEY` 변수를 생성합니다. 변수의 값으로 당신의 open api key 를 입력합니다. (OpenAI 홈페이지에서 api 키를 받을 수 있습니다.)
|
||||||
|
<img width="1465" alt="image" src="https://user-images.githubusercontent.com/13167934/218533628-3974b70f-c423-44b0-b096-d1ec2ace85ea.png">
|
||||||
|
|
||||||
|
### 사용 시작하기
|
||||||
|
|
||||||
|
1. 새로운 Pull request를 생성하면 로봇이 자동으로 코드 리뷰를 수행하며, 리뷰 정보는 Pull request 타임라인 / 파일 변경 부분에 표시됩니다.
|
||||||
|
2. `git push` 이후에 Pull request를 업데이트하면, cr bot은 변경된 파일을 다시 검토합니다.
|
||||||
|
|
||||||
|
예시:
|
||||||
|
|
||||||
|
[ChatGPT-CodeReview/pull/21](https://github.com/anc95/ChatGPT-CodeReview/pull/21)
|
||||||
|
|
||||||
|
<img width="1052" alt="image" src="https://user-images.githubusercontent.com/13167934/218999459-812206e1-d8d2-4900-8ce8-19b5b6e1f5cb.png">
|
||||||
|
|
||||||
|
### Github Actions 사용하기
|
||||||
|
|
||||||
|
> 깃허브 봇이 humble vps에서 서비스되므로, 항상 안정적인 상태임을 보장할 수 없기 때문에 이 방법을 권장합니다.
|
||||||
|
|
||||||
|
[actions/chatgpt-codereviewer](https://github.com/marketplace/actions/chatgpt-codereviewer)
|
||||||
|
|
||||||
|
1. `OPENAI_API_KEY` 를 당신의 github actions secrets 에 추가합니다.
|
||||||
|
2. `.github/workflows/cr.yml` 를 생성하고, 아래의 내용을 추가합니다.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
# optional
|
||||||
|
LANGUAGE: Korean
|
||||||
|
PROMPT:
|
||||||
|
IGNORE_PATTERNS: /node_modules,*.md # Regex pattern to ignore files, separated by comma
|
||||||
|
```
|
||||||
|
|
||||||
|
## Self-hosting
|
||||||
|
|
||||||
|
1. 코드를 clone 합니다.
|
||||||
|
2. `.env.example` 을 `.env`로 복제하고, 환경변수(env variable)을 입력합니다.
|
||||||
|
3. 종속성(deps)들을 설치하고 실행합니다.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
npm -i g pm2
|
||||||
|
npm run build
|
||||||
|
pm2 start pm2.config.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
[probot](https://probot.github.io/docs/development/) 더 자세한 정보
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
### 설정
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 종속성 설치
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 봇 실행
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. 컨테이너 빌드
|
||||||
|
docker build -t cr-bot .
|
||||||
|
|
||||||
|
# 2. 컨테이너 시작
|
||||||
|
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> cr-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## 기여하기
|
||||||
|
|
||||||
|
만약 당신이 cr-bot의 개선 제안이나 버그 신고가 있으면 issue를 열어주세요! 모든 당신의 기여를 환영합니다.
|
||||||
|
|
||||||
|
자세한 내용은 [기여 가이드](CONTRIBUTING.md)를 확인하세요.
|
||||||
|
|
||||||
|
## Credit
|
||||||
|
|
||||||
|
이 프로젝트는 [codereview.gpt](https://github.com/sturdy-dev/codereview.gpt)에서 영감을 얻었습니다.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[ISC](LICENSE) © 2023 anc95
|
||||||
130
ChatGPT-CodeReview/README.md
Normal file
130
ChatGPT-CodeReview/README.md
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# CodeReview BOT
|
||||||
|
|
||||||
|
> A code review robot powered by ChatGPT
|
||||||
|
|
||||||
|
Translation Versions: [ENGLISH](./README.md) | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md)
|
||||||
|
|
||||||
|
## Bot Usage
|
||||||
|
|
||||||
|
❗️⚠️ `Due to cost considerations, BOT is only used for testing purposes and is currently deployed on AWS Lambda with ratelimit restrictions. Therefore, unstable situations are completely normal. It is recommended to deploy an app by yourself.`
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
Install: [apps/cr-gpt](https://github.com/apps/cr-gpt);
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
1. Go to the repo homepage which you want integrate this bot
|
||||||
|
2. click `settings`
|
||||||
|
3. click `actions` under `secrets and variables`
|
||||||
|
4. Change to `Variables` tab, create a new variable `OPENAI_API_KEY` with the value of your open api key (For Github Action integration, set it in secrets)
|
||||||
|
<img width="1465" alt="image" src="https://user-images.githubusercontent.com/13167934/218533628-3974b70f-c423-44b0-b096-d1ec2ace85ea.png">
|
||||||
|
|
||||||
|
### Start using
|
||||||
|
|
||||||
|
1. The robot will automatically do the code review when you create a new Pull request, the review information will show in the pr timeline / file changes part.
|
||||||
|
2. After `git push` update the pull request, cr bot will re-review the changed files
|
||||||
|
|
||||||
|
example:
|
||||||
|
|
||||||
|
[ChatGPT-CodeReview/pull/21](https://github.com/anc95/ChatGPT-CodeReview/pull/21)
|
||||||
|
|
||||||
|
<img width="1052" alt="image" src="https://user-images.githubusercontent.com/13167934/218999459-812206e1-d8d2-4900-8ce8-19b5b6e1f5cb.png">
|
||||||
|
|
||||||
|
## Using Github Actions
|
||||||
|
|
||||||
|
[actions/chatgpt-codereviewer](https://github.com/marketplace/actions/chatgpt-codereviewer)
|
||||||
|
|
||||||
|
1. add the `OPENAI_API_KEY` to your github actions secrets
|
||||||
|
2. create `.github/workflows/cr.yml` add bellow content
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
# if: ${{ contains(github.event.*.labels.*.name, 'gpt review') }} # Optional; to run only when a label is attached
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
# Optional
|
||||||
|
LANGUAGE: Chinese
|
||||||
|
OPENAI_API_ENDPOINT: https://api.openai.com/v1
|
||||||
|
MODEL: gpt-3.5-turbo # https://platform.openai.com/docs/models
|
||||||
|
PROMPT: # example: Please check if there are any confusions or irregularities in the following code diff:
|
||||||
|
top_p: 1 # https://platform.openai.com/docs/api-reference/chat/create#chat/create-top_p
|
||||||
|
temperature: 1 # https://platform.openai.com/docs/api-reference/chat/create#chat/create-temperature
|
||||||
|
max_tokens: 10000
|
||||||
|
MAX_PATCH_LENGTH: 10000 # if the patch/diff length is large than MAX_PATCH_LENGTH, will be ignored and won't review. By default, with no MAX_PATCH_LENGTH set, there is also no limit for the patch/diff length.
|
||||||
|
IGNORE_PATTERNS: /node_modules/**/*,*.md # glob pattern or regex pattern to ignore files, separated by comma
|
||||||
|
INCLUDE_PATTERNS: *.js,*.ts # glob pattern or regex pattern to include files, separated by comma
|
||||||
|
|
||||||
|
# IF you are using azure openai
|
||||||
|
AZURE_API_VERSION: xx
|
||||||
|
AZURE_DEPLOYMENT: xx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Self-hosting
|
||||||
|
|
||||||
|
1. clone code
|
||||||
|
2. copy `.env.example` to `.env`, and fill the env variables
|
||||||
|
3. install deps and run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
npm i -g pm2
|
||||||
|
npm run build
|
||||||
|
pm2 start pm2.config.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
[probot](https://probot.github.io/docs/development/) for more detail
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Build code
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Run the bot
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Build container
|
||||||
|
docker build -t cr-bot .
|
||||||
|
|
||||||
|
# 2. Start container
|
||||||
|
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> cr-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
If you have suggestions for how cr-bot could be improved, or want to report a bug, open an issue! We'd love all and any contributions.
|
||||||
|
|
||||||
|
For more, check out the [Contributing Guide](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## Credit
|
||||||
|
|
||||||
|
this project is inpired by [codereview.gpt](https://github.com/sturdy-dev/codereview.gpt)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[ISC](LICENSE) © 2023 anc95
|
||||||
119
ChatGPT-CodeReview/README.zh-CN.md
Normal file
119
ChatGPT-CodeReview/README.zh-CN.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# 代码审查机器人
|
||||||
|
|
||||||
|
> 由 ChatGPT 提供支持的代码审查机器人
|
||||||
|
|
||||||
|
> 想在 Gitlab 使用?
|
||||||
|
> 试试 https://github.com/nangongchengfeng/Chat-CodeReview.git
|
||||||
|
|
||||||
|
翻译版本:[英语](./README.md)\|[简体中文](./README.zh-CN.md)\|[繁體中文](./README.zh-TW.md) \| [한국어](./README.ko.md) \| [日本語](./README.ja.md)
|
||||||
|
|
||||||
|
## 用法
|
||||||
|
|
||||||
|
❗️⚠️ 鉴于成本考虑,BOT 仅用于测试目的,并目前在 AWS Lambda 上部署并受到速率限制。因此,不稳定的情况是完全正常的。建议自己部署应用程序。
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
|
||||||
|
安装:[apps/cr-gpt](https://github.com/apps/cr-gpt);
|
||||||
|
|
||||||
|
### 配置
|
||||||
|
|
||||||
|
1. 转到你要集成此机器人的仓库首页
|
||||||
|
2. 点击`settings`
|
||||||
|
3. 点击`actions`在下面`secrets and variables`
|
||||||
|
4. 切换到`Variables`选项,创建一个新变量`OPENAI_API_KEY`,值为你的 open api 的 key<img width="1465" alt="image" src="https://user-images.githubusercontent.com/13167934/218533628-3974b70f-c423-44b0-b096-d1ec2ace85ea.png">
|
||||||
|
|
||||||
|
### 开始使用
|
||||||
|
|
||||||
|
1. 当你创建一个新的 Pull request 时,机器人会自动进行代码审查,审查信息将显示在 pr timeline / file changes 部分。
|
||||||
|
2. 在`git push`更新 PR 之后,cr bot 将重新审查更改的文件
|
||||||
|
|
||||||
|
例子:
|
||||||
|
|
||||||
|
[ChatGPT-CodeReview/pull/21](https://github.com/anc95/ChatGPT-CodeReview/pull/21)
|
||||||
|
|
||||||
|
<img width="1052" alt="image" src="https://user-images.githubusercontent.com/13167934/218999459-812206e1-d8d2-4900-8ce8-19b5b6e1f5cb.png">
|
||||||
|
|
||||||
|
### 使用 Github Action
|
||||||
|
|
||||||
|
> 这是推荐的方式,因为 github bot 在一个不起眼的 vps 上服务,我不能确保它总是稳定的
|
||||||
|
|
||||||
|
[actions/chatgpt-codereviewer](https://github.com/marketplace/actions/chatgpt-codereviewer)
|
||||||
|
|
||||||
|
1. 添加`OPENAI_API_KEY`到你的 github action 密钥
|
||||||
|
2. 创建`.github/workflows/cr.yml`添加以下内容
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
# optional
|
||||||
|
LANGUAGE: Chinese
|
||||||
|
PROMPT:
|
||||||
|
IGNORE_PATTERNS: /node_modules,*.md # Regex pattern to ignore files, separated by comma
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自托管
|
||||||
|
|
||||||
|
1. 克隆代码
|
||||||
|
2. 复制`.env.example`到`.env`, 并填写环境变量
|
||||||
|
3. 安装 deps 并运行
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
npm -i g pm2
|
||||||
|
npm run build
|
||||||
|
pm2 start pm2.config.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
[机器人](https://probot.github.io/docs/development/)了解更多详情
|
||||||
|
|
||||||
|
## 开发
|
||||||
|
|
||||||
|
### 设置
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Run the bot
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Build container
|
||||||
|
docker build -t cr-bot .
|
||||||
|
|
||||||
|
# 2. Start container
|
||||||
|
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> cr-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
|
||||||
|
如果您对如何改进 cr-bot 有建议,或者想报告错误,请打开一个问题!我们会喜欢所有的贡献。
|
||||||
|
|
||||||
|
有关更多信息,请查看[投稿指南](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## 灵感
|
||||||
|
|
||||||
|
这个项目的灵感来自[代码审查.gpt](https://github.com/sturdy-dev/codereview.gpt)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[ISC](LICENSE)© 2023 anc95
|
||||||
125
ChatGPT-CodeReview/README.zh-TW.md
Normal file
125
ChatGPT-CodeReview/README.zh-TW.md
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# 程式碼審查機器人
|
||||||
|
|
||||||
|
> 由 ChatGPT 提供支援的程式碼審查機器人
|
||||||
|
|
||||||
|
翻譯版本:[English](./README.md) | [簡體中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md)
|
||||||
|
|
||||||
|
## 機器人使用方式
|
||||||
|
|
||||||
|
❗️⚠️ `由於成本考量,BOT 目前僅用於測試目的,並部署在有限制的 AWS Lambda 上。因此,不穩定的情況是完全正常的。建議自行部署 app。`
|
||||||
|
|
||||||
|
### 安裝
|
||||||
|
|
||||||
|
安裝:[apps/cr-gpt](https://github.com/apps/cr-gpt);
|
||||||
|
|
||||||
|
### 設定
|
||||||
|
|
||||||
|
1. 轉到你要整合此機器人的倉庫首頁
|
||||||
|
2. 點選 `settings`
|
||||||
|
3. 點選 `actions` 在下面的 `secrets and variables`
|
||||||
|
4. 切換到 `Variables` 選項,建立一個新變數 `OPENAI_API_KEY`,值為你的 open api key (如果是 Github Action 整合,則設定在 secrets 中)
|
||||||
|
<img width="1465" alt="image" src="https://user-images.githubusercontent.com/13167934/218533628-3974b70f-c423-44b0-b096-d1ec2ace85ea.png">
|
||||||
|
|
||||||
|
### 開始使用
|
||||||
|
|
||||||
|
1. 當你建立一個新的 Pull request 時,機器人會自動進行程式碼審查,審查訊息將顯示在 pr timeline / file changes 部分。
|
||||||
|
2. 在 `git push` 更新 Pull request 之後,cr bot 將重新審查更改的文件
|
||||||
|
|
||||||
|
範例:
|
||||||
|
|
||||||
|
[ChatGPT-CodeReview/pull/21](https://github.com/anc95/ChatGPT-CodeReview/pull/21)
|
||||||
|
|
||||||
|
<img width="1052" alt="image" src="https://user-images.githubusercontent.com/13167934/218999459-812206e1-d8d2-4900-8ce8-19b5b6e1f5cb.png">
|
||||||
|
|
||||||
|
## 使用 Github Actions
|
||||||
|
|
||||||
|
[actions/chatgpt-codereviewer](https://github.com/marketplace/actions/chatgpt-codereviewer)
|
||||||
|
|
||||||
|
1. 新增 `OPENAI_API_KEY` 到你的 github actions secrets
|
||||||
|
2. 建立 `.github/workflows/cr.yml` 新增以下內容
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Code Review
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
# if: ${{ contains(github.event.*.labels.*.name, 'gpt review') }} # Optional; to run only when a label is attached
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: anc95/ChatGPT-CodeReview@main
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
# Optional
|
||||||
|
LANGUAGE: Chinese
|
||||||
|
OPENAI_API_ENDPOINT: https://api.openai.com/v1
|
||||||
|
MODEL: gpt-3.5-turbo # https://platform.openai.com/docs/models
|
||||||
|
PROMPT: # example: Please check if there are any confusions or irregularities in the following code diff:
|
||||||
|
top_p: 1 # https://platform.openai.com/docs/api-reference/chat/create#chat/create-top_p
|
||||||
|
temperature: 1 # https://platform.openai.com/docs/api-reference/chat/create#chat/create-temperature
|
||||||
|
max_tokens: 10000
|
||||||
|
MAX_PATCH_LENGTH: 10000 # if the patch/diff length is large than MAX_PATCH_LENGTH, will be ignored and won't review. By default, with no MAX_PATCH_LENGTH set, there is also no limit for the patch/diff length.
|
||||||
|
IGNORE_PATTERNS: /node_modules,*.md # Regex pattern to ignore files, separated by comma
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自我託管
|
||||||
|
|
||||||
|
1. 複製程式碼
|
||||||
|
2. 複製 `.env.example` 到 `.env`, 並填寫環境變數
|
||||||
|
3. 安裝相依性並執行
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
npm i -g pm2
|
||||||
|
npm run build
|
||||||
|
pm2 start pm2.config.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
[probot](https://probot.github.io/docs/development/) 了解更多詳情
|
||||||
|
|
||||||
|
## 開發
|
||||||
|
|
||||||
|
### 設定
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Build code
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Run the bot
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Build container
|
||||||
|
docker build -t cr-bot .
|
||||||
|
|
||||||
|
# 2. Start container
|
||||||
|
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> cr-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## 貢獻
|
||||||
|
|
||||||
|
如果您對如何改進 cr-bot 有建議,或者想報告錯誤,請開啟一個問題!我們喜歡所有的貢獻。
|
||||||
|
|
||||||
|
有關更多信息,請查看[貢獻指南](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## 靈感
|
||||||
|
|
||||||
|
這個項目的靈感來自[codereview.gpt](https://github.com/sturdy-dev/codereview.gpt)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[ISC](LICENSE)© 2023 anc95
|
||||||
8
ChatGPT-CodeReview/action.yml
Normal file
8
ChatGPT-CodeReview/action.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
name: ChatGPT CodeReviewer
|
||||||
|
description: 'A Code Review Action Powered By ChatGPT'
|
||||||
|
branding:
|
||||||
|
icon: 'gift'
|
||||||
|
color: orange
|
||||||
|
runs:
|
||||||
|
using: 'node20'
|
||||||
|
main: 'action/index.cjs'
|
||||||
452
ChatGPT-CodeReview/action/37.index.cjs.js
Normal file
452
ChatGPT-CodeReview/action/37.index.cjs.js
Normal file
@@ -0,0 +1,452 @@
|
|||||||
|
"use strict";
|
||||||
|
exports.id = 37;
|
||||||
|
exports.ids = [37];
|
||||||
|
exports.modules = {
|
||||||
|
|
||||||
|
/***/ 94037:
|
||||||
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||||
|
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
|
||||||
|
/* harmony export */ });
|
||||||
|
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7972);
|
||||||
|
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68010);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let s = 0;
|
||||||
|
const S = {
|
||||||
|
START_BOUNDARY: s++,
|
||||||
|
HEADER_FIELD_START: s++,
|
||||||
|
HEADER_FIELD: s++,
|
||||||
|
HEADER_VALUE_START: s++,
|
||||||
|
HEADER_VALUE: s++,
|
||||||
|
HEADER_VALUE_ALMOST_DONE: s++,
|
||||||
|
HEADERS_ALMOST_DONE: s++,
|
||||||
|
PART_DATA_START: s++,
|
||||||
|
PART_DATA: s++,
|
||||||
|
END: s++
|
||||||
|
};
|
||||||
|
|
||||||
|
let f = 1;
|
||||||
|
const F = {
|
||||||
|
PART_BOUNDARY: f,
|
||||||
|
LAST_BOUNDARY: f *= 2
|
||||||
|
};
|
||||||
|
|
||||||
|
const LF = 10;
|
||||||
|
const CR = 13;
|
||||||
|
const SPACE = 32;
|
||||||
|
const HYPHEN = 45;
|
||||||
|
const COLON = 58;
|
||||||
|
const A = 97;
|
||||||
|
const Z = 122;
|
||||||
|
|
||||||
|
const lower = c => c | 0x20;
|
||||||
|
|
||||||
|
const noop = () => {};
|
||||||
|
|
||||||
|
class MultipartParser {
|
||||||
|
/**
|
||||||
|
* @param {string} boundary
|
||||||
|
*/
|
||||||
|
constructor(boundary) {
|
||||||
|
this.index = 0;
|
||||||
|
this.flags = 0;
|
||||||
|
|
||||||
|
this.onHeaderEnd = noop;
|
||||||
|
this.onHeaderField = noop;
|
||||||
|
this.onHeadersEnd = noop;
|
||||||
|
this.onHeaderValue = noop;
|
||||||
|
this.onPartBegin = noop;
|
||||||
|
this.onPartData = noop;
|
||||||
|
this.onPartEnd = noop;
|
||||||
|
|
||||||
|
this.boundaryChars = {};
|
||||||
|
|
||||||
|
boundary = '\r\n--' + boundary;
|
||||||
|
const ui8a = new Uint8Array(boundary.length);
|
||||||
|
for (let i = 0; i < boundary.length; i++) {
|
||||||
|
ui8a[i] = boundary.charCodeAt(i);
|
||||||
|
this.boundaryChars[ui8a[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boundary = ui8a;
|
||||||
|
this.lookbehind = new Uint8Array(this.boundary.length + 8);
|
||||||
|
this.state = S.START_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Uint8Array} data
|
||||||
|
*/
|
||||||
|
write(data) {
|
||||||
|
let i = 0;
|
||||||
|
const length_ = data.length;
|
||||||
|
let previousIndex = this.index;
|
||||||
|
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
|
||||||
|
const boundaryLength = this.boundary.length;
|
||||||
|
const boundaryEnd = boundaryLength - 1;
|
||||||
|
const bufferLength = data.length;
|
||||||
|
let c;
|
||||||
|
let cl;
|
||||||
|
|
||||||
|
const mark = name => {
|
||||||
|
this[name + 'Mark'] = i;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear = name => {
|
||||||
|
delete this[name + 'Mark'];
|
||||||
|
};
|
||||||
|
|
||||||
|
const callback = (callbackSymbol, start, end, ui8a) => {
|
||||||
|
if (start === undefined || start !== end) {
|
||||||
|
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataCallback = (name, clear) => {
|
||||||
|
const markSymbol = name + 'Mark';
|
||||||
|
if (!(markSymbol in this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear) {
|
||||||
|
callback(name, this[markSymbol], i, data);
|
||||||
|
delete this[markSymbol];
|
||||||
|
} else {
|
||||||
|
callback(name, this[markSymbol], data.length, data);
|
||||||
|
this[markSymbol] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < length_; i++) {
|
||||||
|
c = data[i];
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case S.START_BOUNDARY:
|
||||||
|
if (index === boundary.length - 2) {
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
flags |= F.LAST_BOUNDARY;
|
||||||
|
} else if (c !== CR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
} else if (index - 1 === boundary.length - 2) {
|
||||||
|
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
|
||||||
|
state = S.END;
|
||||||
|
flags = 0;
|
||||||
|
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
|
||||||
|
index = 0;
|
||||||
|
callback('onPartBegin');
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c !== boundary[index + 2]) {
|
||||||
|
index = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === boundary[index + 2]) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_FIELD_START:
|
||||||
|
state = S.HEADER_FIELD;
|
||||||
|
mark('onHeaderField');
|
||||||
|
index = 0;
|
||||||
|
// falls through
|
||||||
|
case S.HEADER_FIELD:
|
||||||
|
if (c === CR) {
|
||||||
|
clear('onHeaderField');
|
||||||
|
state = S.HEADERS_ALMOST_DONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === COLON) {
|
||||||
|
if (index === 1) {
|
||||||
|
// empty header field
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataCallback('onHeaderField', true);
|
||||||
|
state = S.HEADER_VALUE_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl = lower(c);
|
||||||
|
if (cl < A || cl > Z) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_VALUE_START:
|
||||||
|
if (c === SPACE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark('onHeaderValue');
|
||||||
|
state = S.HEADER_VALUE;
|
||||||
|
// falls through
|
||||||
|
case S.HEADER_VALUE:
|
||||||
|
if (c === CR) {
|
||||||
|
dataCallback('onHeaderValue', true);
|
||||||
|
callback('onHeaderEnd');
|
||||||
|
state = S.HEADER_VALUE_ALMOST_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_VALUE_ALMOST_DONE:
|
||||||
|
if (c !== LF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
break;
|
||||||
|
case S.HEADERS_ALMOST_DONE:
|
||||||
|
if (c !== LF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback('onHeadersEnd');
|
||||||
|
state = S.PART_DATA_START;
|
||||||
|
break;
|
||||||
|
case S.PART_DATA_START:
|
||||||
|
state = S.PART_DATA;
|
||||||
|
mark('onPartData');
|
||||||
|
// falls through
|
||||||
|
case S.PART_DATA:
|
||||||
|
previousIndex = index;
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
// boyer-moore derrived algorithm to safely skip non-boundary data
|
||||||
|
i += boundaryEnd;
|
||||||
|
while (i < bufferLength && !(data[i] in boundaryChars)) {
|
||||||
|
i += boundaryLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
i -= boundaryEnd;
|
||||||
|
c = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < boundary.length) {
|
||||||
|
if (boundary[index] === c) {
|
||||||
|
if (index === 0) {
|
||||||
|
dataCallback('onPartData', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else if (index === boundary.length) {
|
||||||
|
index++;
|
||||||
|
if (c === CR) {
|
||||||
|
// CR = part boundary
|
||||||
|
flags |= F.PART_BOUNDARY;
|
||||||
|
} else if (c === HYPHEN) {
|
||||||
|
// HYPHEN = end boundary
|
||||||
|
flags |= F.LAST_BOUNDARY;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else if (index - 1 === boundary.length) {
|
||||||
|
if (flags & F.PART_BOUNDARY) {
|
||||||
|
index = 0;
|
||||||
|
if (c === LF) {
|
||||||
|
// unset the PART_BOUNDARY flag
|
||||||
|
flags &= ~F.PART_BOUNDARY;
|
||||||
|
callback('onPartEnd');
|
||||||
|
callback('onPartBegin');
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (flags & F.LAST_BOUNDARY) {
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
callback('onPartEnd');
|
||||||
|
state = S.END;
|
||||||
|
flags = 0;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
// when matching a possible boundary, keep a lookbehind reference
|
||||||
|
// in case it turns out to be a false lead
|
||||||
|
lookbehind[index - 1] = c;
|
||||||
|
} else if (previousIndex > 0) {
|
||||||
|
// if our boundary turned out to be rubbish, the captured lookbehind
|
||||||
|
// belongs to partData
|
||||||
|
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
|
||||||
|
callback('onPartData', 0, previousIndex, _lookbehind);
|
||||||
|
previousIndex = 0;
|
||||||
|
mark('onPartData');
|
||||||
|
|
||||||
|
// reconsider the current character even so it interrupted the sequence
|
||||||
|
// it could be the beginning of a new sequence
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unexpected state entered: ${state}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataCallback('onHeaderField');
|
||||||
|
dataCallback('onHeaderValue');
|
||||||
|
dataCallback('onPartData');
|
||||||
|
|
||||||
|
// Update properties for the next call
|
||||||
|
this.index = index;
|
||||||
|
this.state = state;
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
end() {
|
||||||
|
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
|
||||||
|
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
|
||||||
|
this.onPartEnd();
|
||||||
|
} else if (this.state !== S.END) {
|
||||||
|
throw new Error('MultipartParser.end(): stream ended unexpectedly');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fileName(headerValue) {
|
||||||
|
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||||
|
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
|
||||||
|
if (!m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = m[2] || m[3] || '';
|
||||||
|
let filename = match.slice(match.lastIndexOf('\\') + 1);
|
||||||
|
filename = filename.replace(/%22/g, '"');
|
||||||
|
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
|
||||||
|
return String.fromCharCode(code);
|
||||||
|
});
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toFormData(Body, ct) {
|
||||||
|
if (!/multipart/i.test(ct)) {
|
||||||
|
throw new TypeError('Failed to fetch');
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
|
||||||
|
|
||||||
|
if (!m) {
|
||||||
|
throw new TypeError('no or bad content-type header, no multipart boundary');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new MultipartParser(m[1] || m[2]);
|
||||||
|
|
||||||
|
let headerField;
|
||||||
|
let headerValue;
|
||||||
|
let entryValue;
|
||||||
|
let entryName;
|
||||||
|
let contentType;
|
||||||
|
let filename;
|
||||||
|
const entryChunks = [];
|
||||||
|
const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
|
||||||
|
|
||||||
|
const onPartData = ui8a => {
|
||||||
|
entryValue += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendToFile = ui8a => {
|
||||||
|
entryChunks.push(ui8a);
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendFileToFormData = () => {
|
||||||
|
const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
|
||||||
|
formData.append(entryName, file);
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendEntryToFormData = () => {
|
||||||
|
formData.append(entryName, entryValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
decoder.decode();
|
||||||
|
|
||||||
|
parser.onPartBegin = function () {
|
||||||
|
parser.onPartData = onPartData;
|
||||||
|
parser.onPartEnd = appendEntryToFormData;
|
||||||
|
|
||||||
|
headerField = '';
|
||||||
|
headerValue = '';
|
||||||
|
entryValue = '';
|
||||||
|
entryName = '';
|
||||||
|
contentType = '';
|
||||||
|
filename = null;
|
||||||
|
entryChunks.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderField = function (ui8a) {
|
||||||
|
headerField += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderValue = function (ui8a) {
|
||||||
|
headerValue += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderEnd = function () {
|
||||||
|
headerValue += decoder.decode();
|
||||||
|
headerField = headerField.toLowerCase();
|
||||||
|
|
||||||
|
if (headerField === 'content-disposition') {
|
||||||
|
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||||
|
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
|
||||||
|
|
||||||
|
if (m) {
|
||||||
|
entryName = m[2] || m[3] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = _fileName(headerValue);
|
||||||
|
|
||||||
|
if (filename) {
|
||||||
|
parser.onPartData = appendToFile;
|
||||||
|
parser.onPartEnd = appendFileToFormData;
|
||||||
|
}
|
||||||
|
} else if (headerField === 'content-type') {
|
||||||
|
contentType = headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerValue = '';
|
||||||
|
headerField = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
for await (const chunk of Body) {
|
||||||
|
parser.write(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.end();
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
};
|
||||||
|
;
|
||||||
BIN
ChatGPT-CodeReview/action/_tiktoken_bg.wasm
Normal file
BIN
ChatGPT-CodeReview/action/_tiktoken_bg.wasm
Normal file
Binary file not shown.
1
ChatGPT-CodeReview/action/encoder.json
Normal file
1
ChatGPT-CodeReview/action/encoder.json
Normal file
File diff suppressed because one or more lines are too long
12
ChatGPT-CodeReview/action/file.js
Normal file
12
ChatGPT-CodeReview/action/file.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const pino = require('./pino')
|
||||||
|
const { once } = require('events')
|
||||||
|
|
||||||
|
module.exports = async function (opts = {}) {
|
||||||
|
const destOpts = Object.assign({}, opts, { dest: opts.destination || 1, sync: false })
|
||||||
|
delete destOpts.destination
|
||||||
|
const destination = pino.destination(destOpts)
|
||||||
|
await once(destination, 'ready')
|
||||||
|
return destination
|
||||||
|
}
|
||||||
242420
ChatGPT-CodeReview/action/github-action.js
Normal file
242420
ChatGPT-CodeReview/action/github-action.js
Normal file
File diff suppressed because one or more lines are too long
167802
ChatGPT-CodeReview/action/index.cjs
Normal file
167802
ChatGPT-CodeReview/action/index.cjs
Normal file
File diff suppressed because one or more lines are too long
4
ChatGPT-CodeReview/action/middleware.d.ts
vendored
Normal file
4
ChatGPT-CodeReview/action/middleware.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export declare const config: {
|
||||||
|
matcher: string;
|
||||||
|
};
|
||||||
|
export default function middleware(request: any): Promise<Response>;
|
||||||
473
ChatGPT-CodeReview/action/multipart-parser-d1d13d05.js
Normal file
473
ChatGPT-CodeReview/action/multipart-parser-d1d13d05.js
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('node:fs');
|
||||||
|
require('node:path');
|
||||||
|
var githubAction = require('./github-action.js');
|
||||||
|
require('path');
|
||||||
|
require('os');
|
||||||
|
require('vm');
|
||||||
|
require('events');
|
||||||
|
require('fs');
|
||||||
|
require('util');
|
||||||
|
require('tty');
|
||||||
|
require('stream');
|
||||||
|
require('buffer');
|
||||||
|
require('url');
|
||||||
|
require('http');
|
||||||
|
require('https');
|
||||||
|
require('domain');
|
||||||
|
require('crypto');
|
||||||
|
require('assert');
|
||||||
|
require('string_decoder');
|
||||||
|
require('net');
|
||||||
|
require('tls');
|
||||||
|
require('dns');
|
||||||
|
require('punycode');
|
||||||
|
require('zlib');
|
||||||
|
require('querystring');
|
||||||
|
require('process');
|
||||||
|
require('http2');
|
||||||
|
require('constants');
|
||||||
|
require('child_process');
|
||||||
|
require('worker_threads');
|
||||||
|
require('module');
|
||||||
|
require('node:http');
|
||||||
|
require('node:https');
|
||||||
|
require('node:zlib');
|
||||||
|
require('node:stream');
|
||||||
|
require('node:buffer');
|
||||||
|
require('node:util');
|
||||||
|
require('node:url');
|
||||||
|
require('node:net');
|
||||||
|
|
||||||
|
let s = 0;
|
||||||
|
const S = {
|
||||||
|
START_BOUNDARY: s++,
|
||||||
|
HEADER_FIELD_START: s++,
|
||||||
|
HEADER_FIELD: s++,
|
||||||
|
HEADER_VALUE_START: s++,
|
||||||
|
HEADER_VALUE: s++,
|
||||||
|
HEADER_VALUE_ALMOST_DONE: s++,
|
||||||
|
HEADERS_ALMOST_DONE: s++,
|
||||||
|
PART_DATA_START: s++,
|
||||||
|
PART_DATA: s++,
|
||||||
|
END: s++
|
||||||
|
};
|
||||||
|
|
||||||
|
let f = 1;
|
||||||
|
const F = {
|
||||||
|
PART_BOUNDARY: f,
|
||||||
|
LAST_BOUNDARY: f *= 2
|
||||||
|
};
|
||||||
|
|
||||||
|
const LF = 10;
|
||||||
|
const CR = 13;
|
||||||
|
const SPACE = 32;
|
||||||
|
const HYPHEN = 45;
|
||||||
|
const COLON = 58;
|
||||||
|
const A = 97;
|
||||||
|
const Z = 122;
|
||||||
|
|
||||||
|
const lower = c => c | 0x20;
|
||||||
|
|
||||||
|
const noop = () => {};
|
||||||
|
|
||||||
|
class MultipartParser {
|
||||||
|
/**
|
||||||
|
* @param {string} boundary
|
||||||
|
*/
|
||||||
|
constructor(boundary) {
|
||||||
|
this.index = 0;
|
||||||
|
this.flags = 0;
|
||||||
|
|
||||||
|
this.onHeaderEnd = noop;
|
||||||
|
this.onHeaderField = noop;
|
||||||
|
this.onHeadersEnd = noop;
|
||||||
|
this.onHeaderValue = noop;
|
||||||
|
this.onPartBegin = noop;
|
||||||
|
this.onPartData = noop;
|
||||||
|
this.onPartEnd = noop;
|
||||||
|
|
||||||
|
this.boundaryChars = {};
|
||||||
|
|
||||||
|
boundary = '\r\n--' + boundary;
|
||||||
|
const ui8a = new Uint8Array(boundary.length);
|
||||||
|
for (let i = 0; i < boundary.length; i++) {
|
||||||
|
ui8a[i] = boundary.charCodeAt(i);
|
||||||
|
this.boundaryChars[ui8a[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boundary = ui8a;
|
||||||
|
this.lookbehind = new Uint8Array(this.boundary.length + 8);
|
||||||
|
this.state = S.START_BOUNDARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Uint8Array} data
|
||||||
|
*/
|
||||||
|
write(data) {
|
||||||
|
let i = 0;
|
||||||
|
const length_ = data.length;
|
||||||
|
let previousIndex = this.index;
|
||||||
|
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
|
||||||
|
const boundaryLength = this.boundary.length;
|
||||||
|
const boundaryEnd = boundaryLength - 1;
|
||||||
|
const bufferLength = data.length;
|
||||||
|
let c;
|
||||||
|
let cl;
|
||||||
|
|
||||||
|
const mark = name => {
|
||||||
|
this[name + 'Mark'] = i;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear = name => {
|
||||||
|
delete this[name + 'Mark'];
|
||||||
|
};
|
||||||
|
|
||||||
|
const callback = (callbackSymbol, start, end, ui8a) => {
|
||||||
|
if (start === undefined || start !== end) {
|
||||||
|
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataCallback = (name, clear) => {
|
||||||
|
const markSymbol = name + 'Mark';
|
||||||
|
if (!(markSymbol in this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear) {
|
||||||
|
callback(name, this[markSymbol], i, data);
|
||||||
|
delete this[markSymbol];
|
||||||
|
} else {
|
||||||
|
callback(name, this[markSymbol], data.length, data);
|
||||||
|
this[markSymbol] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < length_; i++) {
|
||||||
|
c = data[i];
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case S.START_BOUNDARY:
|
||||||
|
if (index === boundary.length - 2) {
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
flags |= F.LAST_BOUNDARY;
|
||||||
|
} else if (c !== CR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
} else if (index - 1 === boundary.length - 2) {
|
||||||
|
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
|
||||||
|
state = S.END;
|
||||||
|
flags = 0;
|
||||||
|
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
|
||||||
|
index = 0;
|
||||||
|
callback('onPartBegin');
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c !== boundary[index + 2]) {
|
||||||
|
index = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === boundary[index + 2]) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_FIELD_START:
|
||||||
|
state = S.HEADER_FIELD;
|
||||||
|
mark('onHeaderField');
|
||||||
|
index = 0;
|
||||||
|
// falls through
|
||||||
|
case S.HEADER_FIELD:
|
||||||
|
if (c === CR) {
|
||||||
|
clear('onHeaderField');
|
||||||
|
state = S.HEADERS_ALMOST_DONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === COLON) {
|
||||||
|
if (index === 1) {
|
||||||
|
// empty header field
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataCallback('onHeaderField', true);
|
||||||
|
state = S.HEADER_VALUE_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl = lower(c);
|
||||||
|
if (cl < A || cl > Z) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_VALUE_START:
|
||||||
|
if (c === SPACE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark('onHeaderValue');
|
||||||
|
state = S.HEADER_VALUE;
|
||||||
|
// falls through
|
||||||
|
case S.HEADER_VALUE:
|
||||||
|
if (c === CR) {
|
||||||
|
dataCallback('onHeaderValue', true);
|
||||||
|
callback('onHeaderEnd');
|
||||||
|
state = S.HEADER_VALUE_ALMOST_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.HEADER_VALUE_ALMOST_DONE:
|
||||||
|
if (c !== LF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
break;
|
||||||
|
case S.HEADERS_ALMOST_DONE:
|
||||||
|
if (c !== LF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback('onHeadersEnd');
|
||||||
|
state = S.PART_DATA_START;
|
||||||
|
break;
|
||||||
|
case S.PART_DATA_START:
|
||||||
|
state = S.PART_DATA;
|
||||||
|
mark('onPartData');
|
||||||
|
// falls through
|
||||||
|
case S.PART_DATA:
|
||||||
|
previousIndex = index;
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
// boyer-moore derrived algorithm to safely skip non-boundary data
|
||||||
|
i += boundaryEnd;
|
||||||
|
while (i < bufferLength && !(data[i] in boundaryChars)) {
|
||||||
|
i += boundaryLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
i -= boundaryEnd;
|
||||||
|
c = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < boundary.length) {
|
||||||
|
if (boundary[index] === c) {
|
||||||
|
if (index === 0) {
|
||||||
|
dataCallback('onPartData', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else if (index === boundary.length) {
|
||||||
|
index++;
|
||||||
|
if (c === CR) {
|
||||||
|
// CR = part boundary
|
||||||
|
flags |= F.PART_BOUNDARY;
|
||||||
|
} else if (c === HYPHEN) {
|
||||||
|
// HYPHEN = end boundary
|
||||||
|
flags |= F.LAST_BOUNDARY;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else if (index - 1 === boundary.length) {
|
||||||
|
if (flags & F.PART_BOUNDARY) {
|
||||||
|
index = 0;
|
||||||
|
if (c === LF) {
|
||||||
|
// unset the PART_BOUNDARY flag
|
||||||
|
flags &= ~F.PART_BOUNDARY;
|
||||||
|
callback('onPartEnd');
|
||||||
|
callback('onPartBegin');
|
||||||
|
state = S.HEADER_FIELD_START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (flags & F.LAST_BOUNDARY) {
|
||||||
|
if (c === HYPHEN) {
|
||||||
|
callback('onPartEnd');
|
||||||
|
state = S.END;
|
||||||
|
flags = 0;
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
// when matching a possible boundary, keep a lookbehind reference
|
||||||
|
// in case it turns out to be a false lead
|
||||||
|
lookbehind[index - 1] = c;
|
||||||
|
} else if (previousIndex > 0) {
|
||||||
|
// if our boundary turned out to be rubbish, the captured lookbehind
|
||||||
|
// belongs to partData
|
||||||
|
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
|
||||||
|
callback('onPartData', 0, previousIndex, _lookbehind);
|
||||||
|
previousIndex = 0;
|
||||||
|
mark('onPartData');
|
||||||
|
|
||||||
|
// reconsider the current character even so it interrupted the sequence
|
||||||
|
// it could be the beginning of a new sequence
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case S.END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unexpected state entered: ${state}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataCallback('onHeaderField');
|
||||||
|
dataCallback('onHeaderValue');
|
||||||
|
dataCallback('onPartData');
|
||||||
|
|
||||||
|
// Update properties for the next call
|
||||||
|
this.index = index;
|
||||||
|
this.state = state;
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
end() {
|
||||||
|
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
|
||||||
|
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
|
||||||
|
this.onPartEnd();
|
||||||
|
} else if (this.state !== S.END) {
|
||||||
|
throw new Error('MultipartParser.end(): stream ended unexpectedly');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fileName(headerValue) {
|
||||||
|
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||||
|
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
|
||||||
|
if (!m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = m[2] || m[3] || '';
|
||||||
|
let filename = match.slice(match.lastIndexOf('\\') + 1);
|
||||||
|
filename = filename.replace(/%22/g, '"');
|
||||||
|
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
|
||||||
|
return String.fromCharCode(code);
|
||||||
|
});
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toFormData(Body, ct) {
|
||||||
|
if (!/multipart/i.test(ct)) {
|
||||||
|
throw new TypeError('Failed to fetch');
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
|
||||||
|
|
||||||
|
if (!m) {
|
||||||
|
throw new TypeError('no or bad content-type header, no multipart boundary');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new MultipartParser(m[1] || m[2]);
|
||||||
|
|
||||||
|
let headerField;
|
||||||
|
let headerValue;
|
||||||
|
let entryValue;
|
||||||
|
let entryName;
|
||||||
|
let contentType;
|
||||||
|
let filename;
|
||||||
|
const entryChunks = [];
|
||||||
|
const formData = new githubAction.FormData();
|
||||||
|
|
||||||
|
const onPartData = ui8a => {
|
||||||
|
entryValue += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendToFile = ui8a => {
|
||||||
|
entryChunks.push(ui8a);
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendFileToFormData = () => {
|
||||||
|
const file = new githubAction.File(entryChunks, filename, {type: contentType});
|
||||||
|
formData.append(entryName, file);
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendEntryToFormData = () => {
|
||||||
|
formData.append(entryName, entryValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
decoder.decode();
|
||||||
|
|
||||||
|
parser.onPartBegin = function () {
|
||||||
|
parser.onPartData = onPartData;
|
||||||
|
parser.onPartEnd = appendEntryToFormData;
|
||||||
|
|
||||||
|
headerField = '';
|
||||||
|
headerValue = '';
|
||||||
|
entryValue = '';
|
||||||
|
entryName = '';
|
||||||
|
contentType = '';
|
||||||
|
filename = null;
|
||||||
|
entryChunks.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderField = function (ui8a) {
|
||||||
|
headerField += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderValue = function (ui8a) {
|
||||||
|
headerValue += decoder.decode(ui8a, {stream: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.onHeaderEnd = function () {
|
||||||
|
headerValue += decoder.decode();
|
||||||
|
headerField = headerField.toLowerCase();
|
||||||
|
|
||||||
|
if (headerField === 'content-disposition') {
|
||||||
|
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
|
||||||
|
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
|
||||||
|
|
||||||
|
if (m) {
|
||||||
|
entryName = m[2] || m[3] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = _fileName(headerValue);
|
||||||
|
|
||||||
|
if (filename) {
|
||||||
|
parser.onPartData = appendToFile;
|
||||||
|
parser.onPartEnd = appendFileToFormData;
|
||||||
|
}
|
||||||
|
} else if (headerField === 'content-type') {
|
||||||
|
contentType = headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerValue = '';
|
||||||
|
headerField = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
for await (const chunk of Body) {
|
||||||
|
parser.write(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.end();
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.toFormData = toFormData;
|
||||||
2
ChatGPT-CodeReview/action/rollup.config.d.ts
vendored
Normal file
2
ChatGPT-CodeReview/action/rollup.config.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
declare const _default: import("rollup").RollupOptions[];
|
||||||
|
export default _default;
|
||||||
2
ChatGPT-CodeReview/action/src/bot.d.ts
vendored
Normal file
2
ChatGPT-CodeReview/action/src/bot.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import { Probot } from 'probot';
|
||||||
|
export declare const robot: (app: Probot) => void;
|
||||||
10
ChatGPT-CodeReview/action/src/chat.d.ts
vendored
Normal file
10
ChatGPT-CodeReview/action/src/chat.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export declare class Chat {
|
||||||
|
private openai;
|
||||||
|
private isAzure;
|
||||||
|
constructor(apikey: string);
|
||||||
|
private generatePrompt;
|
||||||
|
codeReview: (patch: string) => Promise<{
|
||||||
|
lgtm: boolean;
|
||||||
|
review_comment: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
1
ChatGPT-CodeReview/action/src/index.d.ts
vendored
Normal file
1
ChatGPT-CodeReview/action/src/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
2
ChatGPT-CodeReview/action/src/log.d.ts
vendored
Normal file
2
ChatGPT-CodeReview/action/src/log.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import log from "loglevel";
|
||||||
|
export default log;
|
||||||
50001
ChatGPT-CodeReview/action/vocab.bpe
Normal file
50001
ChatGPT-CodeReview/action/vocab.bpe
Normal file
File diff suppressed because it is too large
Load Diff
38
ChatGPT-CodeReview/action/worker-pipeline.js
Normal file
38
ChatGPT-CodeReview/action/worker-pipeline.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const EE = require('events')
|
||||||
|
const loadTransportStreamBuilder = require('./transport-stream')
|
||||||
|
const { pipeline, PassThrough } = require('stream')
|
||||||
|
|
||||||
|
// This file is not checked by the code coverage tool,
|
||||||
|
// as it is not reliable.
|
||||||
|
|
||||||
|
/* istanbul ignore file */
|
||||||
|
|
||||||
|
module.exports = async function ({ targets }) {
|
||||||
|
const streams = await Promise.all(targets.map(async (t) => {
|
||||||
|
const fn = await loadTransportStreamBuilder(t.target)
|
||||||
|
const stream = await fn(t.options)
|
||||||
|
return stream
|
||||||
|
}))
|
||||||
|
const ee = new EE()
|
||||||
|
|
||||||
|
const stream = new PassThrough({
|
||||||
|
autoDestroy: true,
|
||||||
|
destroy (_, cb) {
|
||||||
|
ee.on('error', cb)
|
||||||
|
ee.on('closed', cb)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
pipeline(stream, ...streams, function (err) {
|
||||||
|
if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||||
|
ee.emit('error', err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ee.emit('closed')
|
||||||
|
})
|
||||||
|
|
||||||
|
return stream
|
||||||
|
}
|
||||||
54
ChatGPT-CodeReview/action/worker.js
Normal file
54
ChatGPT-CodeReview/action/worker.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const pino = require('../pino.js')
|
||||||
|
const build = require('pino-abstract-transport')
|
||||||
|
const loadTransportStreamBuilder = require('./transport-stream')
|
||||||
|
|
||||||
|
// This file is not checked by the code coverage tool,
|
||||||
|
// as it is not reliable.
|
||||||
|
|
||||||
|
/* istanbul ignore file */
|
||||||
|
|
||||||
|
module.exports = async function ({ targets, levels, dedupe }) {
|
||||||
|
targets = await Promise.all(targets.map(async (t) => {
|
||||||
|
const fn = await loadTransportStreamBuilder(t.target)
|
||||||
|
const stream = await fn(t.options)
|
||||||
|
return {
|
||||||
|
level: t.level,
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
return build(process, {
|
||||||
|
parse: 'lines',
|
||||||
|
metadata: true,
|
||||||
|
close (err, cb) {
|
||||||
|
let expected = 0
|
||||||
|
for (const transport of targets) {
|
||||||
|
expected++
|
||||||
|
transport.stream.on('close', closeCb)
|
||||||
|
transport.stream.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeCb () {
|
||||||
|
if (--expected === 0) {
|
||||||
|
cb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function process (stream) {
|
||||||
|
const multi = pino.multistream(targets, { levels, dedupe })
|
||||||
|
// TODO manage backpressure
|
||||||
|
stream.on('data', function (chunk) {
|
||||||
|
const { lastTime, lastMsg, lastObj, lastLevel } = this
|
||||||
|
multi.lastLevel = lastLevel
|
||||||
|
multi.lastTime = lastTime
|
||||||
|
multi.lastMsg = lastMsg
|
||||||
|
multi.lastObj = lastObj
|
||||||
|
|
||||||
|
// TODO handle backpressure
|
||||||
|
multi.write(chunk + '\n')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
153
ChatGPT-CodeReview/action/worker1.js
Normal file
153
ChatGPT-CodeReview/action/worker1.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { realImport, realRequire } = require('real-require')
|
||||||
|
const { workerData, parentPort } = require('worker_threads')
|
||||||
|
const { WRITE_INDEX, READ_INDEX } = require('./indexes')
|
||||||
|
const { waitDiff } = require('./wait')
|
||||||
|
|
||||||
|
const {
|
||||||
|
dataBuf,
|
||||||
|
filename,
|
||||||
|
stateBuf
|
||||||
|
} = workerData
|
||||||
|
|
||||||
|
let destination
|
||||||
|
|
||||||
|
const state = new Int32Array(stateBuf)
|
||||||
|
const data = Buffer.from(dataBuf)
|
||||||
|
|
||||||
|
async function start () {
|
||||||
|
let worker
|
||||||
|
try {
|
||||||
|
if (filename.endsWith('.ts') || filename.endsWith('.cts')) {
|
||||||
|
// TODO: add support for the TSM modules loader ( https://github.com/lukeed/tsm ).
|
||||||
|
if (!process[Symbol.for('ts-node.register.instance')]) {
|
||||||
|
realRequire('ts-node/register')
|
||||||
|
} else if (process.env.TS_NODE_DEV) {
|
||||||
|
realRequire('ts-node-dev')
|
||||||
|
}
|
||||||
|
// TODO: Support ES imports once tsc, tap & ts-node provide better compatibility guarantees.
|
||||||
|
// Remove extra forwardslash on Windows
|
||||||
|
worker = realRequire(decodeURIComponent(filename.replace(process.platform === 'win32' ? 'file:///' : 'file://', '')))
|
||||||
|
} else {
|
||||||
|
worker = (await realImport(filename))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// A yarn user that tries to start a ThreadStream for an external module
|
||||||
|
// provides a filename pointing to a zip file.
|
||||||
|
// eg. require.resolve('pino-elasticsearch') // returns /foo/pino-elasticsearch-npm-6.1.0-0c03079478-6915435172.zip/bar.js
|
||||||
|
// The `import` will fail to try to load it.
|
||||||
|
// This catch block executes the `require` fallback to load the module correctly.
|
||||||
|
// In fact, yarn modifies the `require` function to manage the zipped path.
|
||||||
|
// More details at https://github.com/pinojs/pino/pull/1113
|
||||||
|
// The error codes may change based on the node.js version (ENOTDIR > 12, ERR_MODULE_NOT_FOUND <= 12 )
|
||||||
|
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND') &&
|
||||||
|
filename.startsWith('file://')) {
|
||||||
|
worker = realRequire(decodeURIComponent(filename.replace('file://', '')))
|
||||||
|
} else if (error.code === undefined) {
|
||||||
|
// When bundled with pkg, an undefined error is thrown when called with realImport
|
||||||
|
worker = realRequire(decodeURIComponent(filename.replace(process.platform === 'win32' ? 'file:///' : 'file://', '')))
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on how the default export is performed, and on how the code is
|
||||||
|
// transpiled, we may find cases of two nested "default" objects.
|
||||||
|
// See https://github.com/pinojs/pino/issues/1243#issuecomment-982774762
|
||||||
|
if (typeof worker === 'object') worker = worker.default
|
||||||
|
if (typeof worker === 'object') worker = worker.default
|
||||||
|
|
||||||
|
destination = await worker(workerData.workerData)
|
||||||
|
|
||||||
|
destination.on('error', function (err) {
|
||||||
|
Atomics.store(state, WRITE_INDEX, -2)
|
||||||
|
Atomics.notify(state, WRITE_INDEX)
|
||||||
|
|
||||||
|
Atomics.store(state, READ_INDEX, -2)
|
||||||
|
Atomics.notify(state, READ_INDEX)
|
||||||
|
|
||||||
|
parentPort.postMessage({
|
||||||
|
code: 'ERROR',
|
||||||
|
err
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
destination.on('close', function () {
|
||||||
|
// process._rawDebug('worker close emitted')
|
||||||
|
const end = Atomics.load(state, WRITE_INDEX)
|
||||||
|
Atomics.store(state, READ_INDEX, end)
|
||||||
|
Atomics.notify(state, READ_INDEX)
|
||||||
|
setImmediate(() => {
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// No .catch() handler,
|
||||||
|
// in case there is an error it goes
|
||||||
|
// to unhandledRejection
|
||||||
|
start().then(function () {
|
||||||
|
parentPort.postMessage({
|
||||||
|
code: 'READY'
|
||||||
|
})
|
||||||
|
|
||||||
|
process.nextTick(run)
|
||||||
|
})
|
||||||
|
|
||||||
|
function run () {
|
||||||
|
const current = Atomics.load(state, READ_INDEX)
|
||||||
|
const end = Atomics.load(state, WRITE_INDEX)
|
||||||
|
|
||||||
|
// process._rawDebug(`pre state ${current} ${end}`)
|
||||||
|
|
||||||
|
if (end === current) {
|
||||||
|
if (end === data.length) {
|
||||||
|
waitDiff(state, READ_INDEX, end, Infinity, run)
|
||||||
|
} else {
|
||||||
|
waitDiff(state, WRITE_INDEX, end, Infinity, run)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// process._rawDebug(`post state ${current} ${end}`)
|
||||||
|
|
||||||
|
if (end === -1) {
|
||||||
|
// process._rawDebug('end')
|
||||||
|
destination.end()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const toWrite = data.toString('utf8', current, end)
|
||||||
|
// process._rawDebug('worker writing: ' + toWrite)
|
||||||
|
|
||||||
|
const res = destination.write(toWrite)
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
Atomics.store(state, READ_INDEX, end)
|
||||||
|
Atomics.notify(state, READ_INDEX)
|
||||||
|
setImmediate(run)
|
||||||
|
} else {
|
||||||
|
destination.once('drain', function () {
|
||||||
|
Atomics.store(state, READ_INDEX, end)
|
||||||
|
Atomics.notify(state, READ_INDEX)
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('unhandledRejection', function (err) {
|
||||||
|
parentPort.postMessage({
|
||||||
|
code: 'ERROR',
|
||||||
|
err
|
||||||
|
})
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('uncaughtException', function (err) {
|
||||||
|
parentPort.postMessage({
|
||||||
|
code: 'ERROR',
|
||||||
|
err
|
||||||
|
})
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
BIN
ChatGPT-CodeReview/api/github/.DS_Store
vendored
Normal file
BIN
ChatGPT-CodeReview/api/github/.DS_Store
vendored
Normal file
Binary file not shown.
7
ChatGPT-CodeReview/api/github/webhooks/index.ts
Normal file
7
ChatGPT-CodeReview/api/github/webhooks/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { createNodeMiddleware, createProbot } from "probot";
|
||||||
|
|
||||||
|
import { robot as app } from "../../../src/bot.js"
|
||||||
|
|
||||||
|
const probot = createProbot();
|
||||||
|
|
||||||
|
export default createNodeMiddleware(app, { probot, webhooksPath: '/api/github/webhooks' });
|
||||||
137
ChatGPT-CodeReview/app.yml
Normal file
137
ChatGPT-CodeReview/app.yml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# This is a GitHub App Manifest. These settings will be used by default when
|
||||||
|
# initially configuring your GitHub App.
|
||||||
|
#
|
||||||
|
# NOTE: changing this file will not update your GitHub App settings.
|
||||||
|
# You must visit github.com/settings/apps/your-app-name to edit them.
|
||||||
|
#
|
||||||
|
# Read more about configuring your GitHub App:
|
||||||
|
# https://probot.github.io/docs/development/#configuring-a-github-app
|
||||||
|
#
|
||||||
|
# Read more about GitHub App Manifests:
|
||||||
|
# https://developer.github.com/apps/building-github-apps/creating-github-apps-from-a-manifest/
|
||||||
|
|
||||||
|
# The list of events the GitHub App subscribes to.
|
||||||
|
# Uncomment the event names below to enable them.
|
||||||
|
default_events:
|
||||||
|
# - check_run
|
||||||
|
# - check_suite
|
||||||
|
# - commit_comment
|
||||||
|
# - create
|
||||||
|
# - delete
|
||||||
|
# - deployment
|
||||||
|
# - deployment_status
|
||||||
|
# - fork
|
||||||
|
# - gollum
|
||||||
|
# - issue_comment
|
||||||
|
- issues
|
||||||
|
# - label
|
||||||
|
# - milestone
|
||||||
|
# - member
|
||||||
|
# - membership
|
||||||
|
# - org_block
|
||||||
|
# - organization
|
||||||
|
# - page_build
|
||||||
|
# - project
|
||||||
|
# - project_card
|
||||||
|
# - project_column
|
||||||
|
# - public
|
||||||
|
# - pull_request
|
||||||
|
# - pull_request_review
|
||||||
|
# - pull_request_review_comment
|
||||||
|
# - push
|
||||||
|
# - release
|
||||||
|
# - repository
|
||||||
|
# - repository_import
|
||||||
|
# - status
|
||||||
|
# - team
|
||||||
|
# - team_add
|
||||||
|
# - watch
|
||||||
|
|
||||||
|
# The set of permissions needed by the GitHub App. The format of the object uses
|
||||||
|
# the permission name for the key (for example, issues) and the access type for
|
||||||
|
# the value (for example, write).
|
||||||
|
# Valid values are `read`, `write`, and `none`
|
||||||
|
default_permissions:
|
||||||
|
# Repository creation, deletion, settings, teams, and collaborators.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-administration
|
||||||
|
# administration: read
|
||||||
|
|
||||||
|
# Checks on code.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-checks
|
||||||
|
# checks: read
|
||||||
|
|
||||||
|
# Repository contents, commits, branches, downloads, releases, and merges.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-contents
|
||||||
|
# contents: read
|
||||||
|
|
||||||
|
# Deployments and deployment statuses.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-deployments
|
||||||
|
# deployments: read
|
||||||
|
|
||||||
|
# Issues and related comments, assignees, labels, and milestones.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-issues
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
# Search repositories, list collaborators, and access repository metadata.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#metadata-permissions
|
||||||
|
metadata: read
|
||||||
|
|
||||||
|
# Retrieve Pages statuses, configuration, and builds, as well as create new builds.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-pages
|
||||||
|
# pages: read
|
||||||
|
|
||||||
|
# Pull requests and related comments, assignees, labels, milestones, and merges.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-pull-requests
|
||||||
|
# pull_requests: read
|
||||||
|
|
||||||
|
# Manage the post-receive hooks for a repository.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-repository-hooks
|
||||||
|
# repository_hooks: read
|
||||||
|
|
||||||
|
# Manage repository projects, columns, and cards.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-repository-projects
|
||||||
|
# repository_projects: read
|
||||||
|
|
||||||
|
# Retrieve security vulnerability alerts.
|
||||||
|
# https://developer.github.com/v4/object/repositoryvulnerabilityalert/
|
||||||
|
# vulnerability_alerts: read
|
||||||
|
|
||||||
|
# Commit statuses.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-statuses
|
||||||
|
# statuses: read
|
||||||
|
|
||||||
|
# Organization members and teams.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-members
|
||||||
|
# members: read
|
||||||
|
|
||||||
|
# View and manage users blocked by the organization.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-organization-user-blocking
|
||||||
|
# organization_user_blocking: read
|
||||||
|
|
||||||
|
# Manage organization projects, columns, and cards.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-organization-projects
|
||||||
|
# organization_projects: read
|
||||||
|
|
||||||
|
# Manage team discussions and related comments.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-team-discussions
|
||||||
|
# team_discussions: read
|
||||||
|
|
||||||
|
# Manage the post-receive hooks for an organization.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/#permission-on-organization-hooks
|
||||||
|
# organization_hooks: read
|
||||||
|
|
||||||
|
# Get notified of, and update, content references.
|
||||||
|
# https://developer.github.com/v3/apps/permissions/
|
||||||
|
# organization_administration: read
|
||||||
|
# The name of the GitHub App. Defaults to the name specified in package.json
|
||||||
|
# name: My Probot App
|
||||||
|
|
||||||
|
# The homepage of your GitHub App.
|
||||||
|
# url: https://example.com/
|
||||||
|
|
||||||
|
# A description of the GitHub App.
|
||||||
|
# description: A description of my awesome app
|
||||||
|
|
||||||
|
# Set to true when your GitHub App is available to the public or false when it is only accessible to the owner of the app.
|
||||||
|
# Default: true
|
||||||
|
# public: false
|
||||||
9
ChatGPT-CodeReview/jest.config.js
Normal file
9
ChatGPT-CodeReview/jest.config.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module.exports = {
|
||||||
|
roots: ["<rootDir>/src/", "<rootDir>/test/"],
|
||||||
|
transform: {
|
||||||
|
"^.+\\.tsx?$": "ts-jest",
|
||||||
|
},
|
||||||
|
testRegex: "(/__tests__/.*|\\.(test|spec))\\.[tj]sx?$",
|
||||||
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||||
|
testEnvironment: "node",
|
||||||
|
};
|
||||||
29
ChatGPT-CodeReview/middleware.ts
Normal file
29
ChatGPT-CodeReview/middleware.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { next, rewrite } from '@vercel/edge';
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: '/api/github/webhooks',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function middleware(request: any) {
|
||||||
|
let json;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('enter');
|
||||||
|
json = await request?.json?.();
|
||||||
|
} catch {
|
||||||
|
return rewrite(new URL('https://github.com/apps/cr-gpt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json) {
|
||||||
|
console.log('received is not a json');
|
||||||
|
return rewrite(new URL('https://github.com/apps/cr-gpt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json.before || !json.after || !json.commits) {
|
||||||
|
console.log('invalid event');
|
||||||
|
return rewrite(new URL('https://github.com/apps/cr-gpt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('GO next');
|
||||||
|
return next();
|
||||||
|
}
|
||||||
8235
ChatGPT-CodeReview/package-lock.json
generated
Normal file
8235
ChatGPT-CodeReview/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
ChatGPT-CodeReview/package.json
Normal file
56
ChatGPT-CodeReview/package.json
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"name": "cr-bot",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "A Probot app",
|
||||||
|
"author": "anc95",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "module",
|
||||||
|
"homepage": "https://github.com//",
|
||||||
|
"keywords": [
|
||||||
|
"probot",
|
||||||
|
"github",
|
||||||
|
"probot-app",
|
||||||
|
"code review"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"start": "node -r dotenv/config ./dist/index.js",
|
||||||
|
"test": "jest",
|
||||||
|
"build": "rm -rf dist && rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript && ncc build src/github-action.cjs -o action",
|
||||||
|
"build:lambda": "ncc build src/aws-lambda.cjs -o lambda"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@probot/adapter-aws-lambda-serverless": "^3.0.2",
|
||||||
|
"@probot/adapter-github-actions": "^3.1.3",
|
||||||
|
"@vercel/edge": "^0.2.7",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"loglevel": "^1.9.2",
|
||||||
|
"minimatch": "^10.0.1",
|
||||||
|
"next": "^13.1.6",
|
||||||
|
"node-fetch": "^3.3.0",
|
||||||
|
"openai": "^4.71.0",
|
||||||
|
"probot": "^12.2.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-commonjs": "^24.0.1",
|
||||||
|
"@rollup/plugin-json": "^6.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||||
|
"@rollup/plugin-typescript": "^11.0.0",
|
||||||
|
"@types/jest": "^29.0.0",
|
||||||
|
"@types/node": "^18.0.0",
|
||||||
|
"@types/pino-std-serializers": "^4.0.0",
|
||||||
|
"@vercel/ncc": "^0.36.1",
|
||||||
|
"esbuild": "^0.17.7",
|
||||||
|
"jest": "^29.0.0",
|
||||||
|
"nock": "^13.0.5",
|
||||||
|
"rollup": "^3.15.0",
|
||||||
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
|
"rollup-plugin-esbuild": "^5.0.0",
|
||||||
|
"smee-client": "^1.2.2",
|
||||||
|
"ts-jest": "^29.0.0",
|
||||||
|
"typescript": "^4.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
ChatGPT-CodeReview/pm2.config.cjs
Normal file
10
ChatGPT-CodeReview/pm2.config.cjs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const config = {
|
||||||
|
apps : [{
|
||||||
|
name : 'Bot',
|
||||||
|
script : 'dist/index.js',
|
||||||
|
interpreter_args : '-r dotenv/config',
|
||||||
|
time: true
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config;
|
||||||
19
ChatGPT-CodeReview/public/index.html
Normal file
19
ChatGPT-CodeReview/public/index.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Hello from Vercel</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello from Vercel</h1>
|
||||||
|
|
||||||
|
<p>Edit this file in <code>public/index.html</code></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your app receives webhook requests at
|
||||||
|
<code>POST /api/github/webhooks</code>
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
42
ChatGPT-CodeReview/rollup.config.ts
Normal file
42
ChatGPT-CodeReview/rollup.config.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import esbuild from 'rollup-plugin-esbuild';
|
||||||
|
import { defineConfig } from 'rollup';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
input: 'middleware.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/middleware.js',
|
||||||
|
format: 'esm',
|
||||||
|
inlineDynamicImports: true,
|
||||||
|
},
|
||||||
|
plugins: [esbuild(), commonjs(), nodeResolve()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/bot.ts',
|
||||||
|
output: {
|
||||||
|
dir: 'dist/lib/',
|
||||||
|
format: 'esm',
|
||||||
|
inlineDynamicImports: false,
|
||||||
|
},
|
||||||
|
plugins: [esbuild({ include: 'src/*.ts' })],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/index.ts',
|
||||||
|
output: {
|
||||||
|
dir: 'dist/',
|
||||||
|
format: 'esm',
|
||||||
|
inlineDynamicImports: false,
|
||||||
|
},
|
||||||
|
plugins: [esbuild()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ['api/github/webhooks/index.ts'],
|
||||||
|
output: {
|
||||||
|
dir: 'dist/api/github/webhooks',
|
||||||
|
format: 'esm',
|
||||||
|
},
|
||||||
|
plugins: [esbuild()],
|
||||||
|
},
|
||||||
|
]);
|
||||||
32
ChatGPT-CodeReview/serverless.yml
Normal file
32
ChatGPT-CodeReview/serverless.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
service: cr-bot
|
||||||
|
frameworkVersion: '3'
|
||||||
|
useDotenv: true
|
||||||
|
|
||||||
|
provider:
|
||||||
|
name: aws
|
||||||
|
runtime: nodejs18.x
|
||||||
|
environment:
|
||||||
|
APP_ID: ${env:APP_ID}
|
||||||
|
WEBHOOK_SECRET: ${env:WEBHOOK_SECRET}
|
||||||
|
PRIVATE_KEY_PATH: ${env:PRIVATE_KEY_PATH}
|
||||||
|
|
||||||
|
package:
|
||||||
|
patterns:
|
||||||
|
- lambda/**
|
||||||
|
- '!node_modules/**'
|
||||||
|
- '!actions/**'
|
||||||
|
- '!.git/**'
|
||||||
|
|
||||||
|
functions:
|
||||||
|
webhooks:
|
||||||
|
handler: lambda.webhooks
|
||||||
|
events:
|
||||||
|
- httpApi:
|
||||||
|
path: /api/github/webhooks
|
||||||
|
method: post
|
||||||
|
|
||||||
|
|
||||||
|
memorySize:
|
||||||
|
- 256
|
||||||
|
timeout: 30
|
||||||
|
logRetentionInDays: 14
|
||||||
9
ChatGPT-CodeReview/src/aws-lambda.cjs
Normal file
9
ChatGPT-CodeReview/src/aws-lambda.cjs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const {
|
||||||
|
createLambdaFunction,
|
||||||
|
createProbot,
|
||||||
|
} = require("@probot/adapter-aws-lambda-serverless");
|
||||||
|
const appFn = require('./bot').robot;
|
||||||
|
|
||||||
|
module.exports.webhooks = createLambdaFunction(appFn, {
|
||||||
|
probot: createProbot(),
|
||||||
|
});
|
||||||
210
ChatGPT-CodeReview/src/bot.ts
Normal file
210
ChatGPT-CodeReview/src/bot.ts
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import { Context, Probot } from 'probot';
|
||||||
|
import { minimatch } from 'minimatch'
|
||||||
|
|
||||||
|
import { Chat } from './chat.js';
|
||||||
|
import log from 'loglevel';
|
||||||
|
|
||||||
|
const OPENAI_API_KEY = 'OPENAI_API_KEY';
|
||||||
|
const MAX_PATCH_COUNT = process.env.MAX_PATCH_LENGTH
|
||||||
|
? +process.env.MAX_PATCH_LENGTH
|
||||||
|
: Infinity;
|
||||||
|
|
||||||
|
export const robot = (app: Probot) => {
|
||||||
|
const loadChat = async (context: Context) => {
|
||||||
|
if (process.env.OPENAI_API_KEY) {
|
||||||
|
return new Chat(process.env.OPENAI_API_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
const repo = context.repo();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = (await context.octokit.request(
|
||||||
|
'GET /repos/{owner}/{repo}/actions/variables/{name}',
|
||||||
|
{
|
||||||
|
owner: repo.owner,
|
||||||
|
repo: repo.repo,
|
||||||
|
name: OPENAI_API_KEY,
|
||||||
|
}
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (!data?.value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Chat(data.value);
|
||||||
|
} catch {
|
||||||
|
await context.octokit.issues.createComment({
|
||||||
|
repo: repo.repo,
|
||||||
|
owner: repo.owner,
|
||||||
|
issue_number: context.pullRequest().pull_number,
|
||||||
|
body: `Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow [readme](https://github.com/anc95/ChatGPT-CodeReview) for more information`,
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
app.on(
|
||||||
|
['pull_request.opened', 'pull_request.synchronize'],
|
||||||
|
async (context) => {
|
||||||
|
const repo = context.repo();
|
||||||
|
const chat = await loadChat(context);
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
log.info('Chat initialized failed');
|
||||||
|
return 'no chat';
|
||||||
|
}
|
||||||
|
|
||||||
|
const pull_request = context.payload.pull_request;
|
||||||
|
|
||||||
|
log.debug('pull_request:', pull_request);
|
||||||
|
|
||||||
|
if (
|
||||||
|
pull_request.state === 'closed' ||
|
||||||
|
pull_request.locked
|
||||||
|
) {
|
||||||
|
log.info('invalid event payload');
|
||||||
|
return 'invalid event payload';
|
||||||
|
}
|
||||||
|
|
||||||
|
const target_label = process.env.TARGET_LABEL;
|
||||||
|
if (
|
||||||
|
target_label &&
|
||||||
|
(!pull_request.labels?.length ||
|
||||||
|
pull_request.labels.every((label) => label.name !== target_label))
|
||||||
|
) {
|
||||||
|
log.info('no target label attached');
|
||||||
|
return 'no target label attached';
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await context.octokit.repos.compareCommits({
|
||||||
|
owner: repo.owner,
|
||||||
|
repo: repo.repo,
|
||||||
|
base: context.payload.pull_request.base.sha,
|
||||||
|
head: context.payload.pull_request.head.sha,
|
||||||
|
});
|
||||||
|
|
||||||
|
let { files: changedFiles, commits } = data.data;
|
||||||
|
|
||||||
|
log.debug("compareCommits, base:", context.payload.pull_request.base.sha, "head:", context.payload.pull_request.head.sha)
|
||||||
|
log.debug("compareCommits.commits:", commits)
|
||||||
|
log.debug("compareCommits.files", changedFiles)
|
||||||
|
|
||||||
|
if (context.payload.action === 'synchronize' && commits.length >= 2) {
|
||||||
|
const {
|
||||||
|
data: { files },
|
||||||
|
} = await context.octokit.repos.compareCommits({
|
||||||
|
owner: repo.owner,
|
||||||
|
repo: repo.repo,
|
||||||
|
base: commits[commits.length - 2].sha,
|
||||||
|
head: commits[commits.length - 1].sha,
|
||||||
|
});
|
||||||
|
|
||||||
|
changedFiles = files
|
||||||
|
}
|
||||||
|
|
||||||
|
const ignoreList = (process.env.IGNORE || process.env.ignore || '')
|
||||||
|
.split('\n')
|
||||||
|
.filter((v) => v !== '');
|
||||||
|
const ignorePatterns = (process.env.IGNORE_PATTERNS || '').split(',').filter((v) => Boolean(v.trim()));
|
||||||
|
const includePatterns = (process.env.INCLUDE_PATTERNS || '').split(',').filter((v) => Boolean(v.trim()));
|
||||||
|
|
||||||
|
log.debug('ignoreList:', ignoreList);
|
||||||
|
log.debug('ignorePatterns:', ignorePatterns);
|
||||||
|
log.debug('includePatterns:', includePatterns);
|
||||||
|
|
||||||
|
changedFiles = changedFiles?.filter(
|
||||||
|
(file) => {
|
||||||
|
const url = new URL(file.contents_url)
|
||||||
|
const pathname = decodeURIComponent(url.pathname)
|
||||||
|
// if includePatterns is not empty, only include files that match the pattern
|
||||||
|
if (includePatterns.length) {
|
||||||
|
return matchPatterns(includePatterns, pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreList.includes(file.filename)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ignorePatterns is not empty, ignore files that match the pattern
|
||||||
|
if (ignorePatterns.length) {
|
||||||
|
return !matchPatterns(ignorePatterns, pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!changedFiles?.length) {
|
||||||
|
log.info('no change found');
|
||||||
|
return 'no change';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.time('gpt cost');
|
||||||
|
|
||||||
|
const ress = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < changedFiles.length; i++) {
|
||||||
|
const file = changedFiles[i];
|
||||||
|
const patch = file.patch || '';
|
||||||
|
|
||||||
|
if (file.status !== 'modified' && file.status !== 'added') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!patch || patch.length > MAX_PATCH_COUNT) {
|
||||||
|
log.info(
|
||||||
|
`${file.filename} skipped caused by its diff is too large`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await chat?.codeReview(patch);
|
||||||
|
if (!res.lgtm && !!res.review_comment) {
|
||||||
|
ress.push({
|
||||||
|
path: file.filename,
|
||||||
|
body: res.review_comment,
|
||||||
|
position: patch.split('\n').length - 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.info(`review ${file.filename} failed`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await context.octokit.pulls.createReview({
|
||||||
|
repo: repo.repo,
|
||||||
|
owner: repo.owner,
|
||||||
|
pull_number: context.pullRequest().pull_number,
|
||||||
|
body: ress.length ? "Code review by ChatGPT" : "LGTM 👍",
|
||||||
|
event: 'COMMENT',
|
||||||
|
commit_id: commits[commits.length - 1].sha,
|
||||||
|
comments: ress,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log.info(`Failed to create review`, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.timeEnd('gpt cost');
|
||||||
|
log.info(
|
||||||
|
'successfully reviewed',
|
||||||
|
context.payload.pull_request.html_url
|
||||||
|
);
|
||||||
|
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchPatterns = (patterns: string[], path: string) => {
|
||||||
|
return patterns.some((pattern) => {
|
||||||
|
try {
|
||||||
|
return minimatch(path, pattern.startsWith('/') ? "**" + pattern : pattern.startsWith("**") ? pattern : "**/" + pattern);
|
||||||
|
} catch {
|
||||||
|
// if the pattern is not a valid glob pattern, try to match it as a regular expression
|
||||||
|
try {
|
||||||
|
return new RegExp(pattern).test(path);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
94
ChatGPT-CodeReview/src/chat.ts
Normal file
94
ChatGPT-CodeReview/src/chat.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import { OpenAI, AzureOpenAI } from 'openai';
|
||||||
|
|
||||||
|
export class Chat {
|
||||||
|
private openai: OpenAI | AzureOpenAI;
|
||||||
|
private isAzure: boolean;
|
||||||
|
|
||||||
|
constructor(apikey: string) {
|
||||||
|
this.isAzure = Boolean(
|
||||||
|
process.env.AZURE_API_VERSION && process.env.AZURE_DEPLOYMENT,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.isAzure) {
|
||||||
|
// Azure OpenAI configuration
|
||||||
|
this.openai = new AzureOpenAI({
|
||||||
|
apiKey: apikey,
|
||||||
|
endpoint: process.env.OPENAI_API_ENDPOINT || '',
|
||||||
|
apiVersion: process.env.AZURE_API_VERSION || '',
|
||||||
|
deployment: process.env.AZURE_DEPLOYMENT || '',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Standard OpenAI configuration
|
||||||
|
this.openai = new OpenAI({
|
||||||
|
apiKey: apikey,
|
||||||
|
baseURL: process.env.OPENAI_API_ENDPOINT || 'https://api.openai.com/v1',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePrompt = (patch: string) => {
|
||||||
|
const answerLanguage = process.env.LANGUAGE
|
||||||
|
? `Answer me in ${process.env.LANGUAGE},`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const userPrompt = process.env.PROMPT || 'Please review the following code patch. Focus on potential bugs, risks, and improvement suggestions.';
|
||||||
|
|
||||||
|
const jsonFormatRequirement = '\nProvide your feedback in a strict JSON format with the following structure:\n' +
|
||||||
|
'{\n' +
|
||||||
|
' "lgtm": boolean, // true if the code looks good to merge, false if there are concerns\n' +
|
||||||
|
' "review_comment": string // Your detailed review comments. You can use markdown syntax in this string, but the overall response must be a valid JSON\n' +
|
||||||
|
'}\n' +
|
||||||
|
'Ensure your response is a valid JSON object.\n';
|
||||||
|
|
||||||
|
return `${userPrompt}${jsonFormatRequirement} ${answerLanguage}:
|
||||||
|
${patch}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
public codeReview = async (patch: string): Promise<{ lgtm: boolean, review_comment: string }> => {
|
||||||
|
if (!patch) {
|
||||||
|
return {
|
||||||
|
lgtm: true,
|
||||||
|
review_comment: ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.time('code-review cost');
|
||||||
|
const prompt = this.generatePrompt(patch);
|
||||||
|
|
||||||
|
const res = await this.openai.chat.completions.create({
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: prompt,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
model: process.env.MODEL || 'gpt-4o-mini',
|
||||||
|
temperature: +(process.env.temperature || 0) || 1,
|
||||||
|
top_p: +(process.env.top_p || 0) || 1,
|
||||||
|
max_tokens: process.env.max_tokens ? +process.env.max_tokens : undefined,
|
||||||
|
response_format: {
|
||||||
|
type: "json_object"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.timeEnd('code-review cost');
|
||||||
|
|
||||||
|
if (res.choices.length) {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(res.choices[0].message.content || "");
|
||||||
|
return json
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
lgtm: false,
|
||||||
|
review_comment: res.choices[0].message.content || ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lgtm: true,
|
||||||
|
review_comment: ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
9
ChatGPT-CodeReview/src/fetch-polyfill.cjs
Normal file
9
ChatGPT-CodeReview/src/fetch-polyfill.cjs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const { Headers, Request, Response } = require('node-fetch');
|
||||||
|
const fetch = require('node-fetch').default;
|
||||||
|
|
||||||
|
if (!globalThis.fetch) {
|
||||||
|
globalThis.fetch = fetch;
|
||||||
|
globalThis.Headers = Headers;
|
||||||
|
globalThis.Request = Request;
|
||||||
|
globalThis.Response = Response;
|
||||||
|
}
|
||||||
6
ChatGPT-CodeReview/src/github-action.cjs
Normal file
6
ChatGPT-CodeReview/src/github-action.cjs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
require('./fetch-polyfill.cjs');
|
||||||
|
const { run } = require('@probot/adapter-github-actions');
|
||||||
|
const { robot } = require('./bot');
|
||||||
|
require('./log');
|
||||||
|
|
||||||
|
run(robot);
|
||||||
7
ChatGPT-CodeReview/src/index.ts
Normal file
7
ChatGPT-CodeReview/src/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { run } from "probot";
|
||||||
|
import log from "./log.js";
|
||||||
|
import { robot } from "./bot.js";
|
||||||
|
|
||||||
|
log.info("Starting probot");
|
||||||
|
|
||||||
|
run(robot)
|
||||||
5
ChatGPT-CodeReview/src/log.ts
Normal file
5
ChatGPT-CodeReview/src/log.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import log, { LogLevelNames } from "loglevel";
|
||||||
|
|
||||||
|
log.setLevel((process.env.LOG_LEVEL as LogLevelNames) || "info");
|
||||||
|
|
||||||
|
export default log;
|
||||||
18
ChatGPT-CodeReview/test/fixtures/issues.opened.json
vendored
Normal file
18
ChatGPT-CodeReview/test/fixtures/issues.opened.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"action": "opened",
|
||||||
|
"issue": {
|
||||||
|
"number": 1,
|
||||||
|
"user": {
|
||||||
|
"login": "hiimbex"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"name": "testing-things",
|
||||||
|
"owner": {
|
||||||
|
"login": "hiimbex"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation": {
|
||||||
|
"id": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
27
ChatGPT-CodeReview/test/fixtures/mock-cert.pem
vendored
Normal file
27
ChatGPT-CodeReview/test/fixtures/mock-cert.pem
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAli7V49NdZe+XYC1pLaHM0te8kiDmZBJ1u2HJHN8GdbROB6NO
|
||||||
|
VpC3xK7NxQn6xpvZ9ux20NvcDvGle+DOptZztBH+np6h2jZQ1/kD1yG1eQvVH4th
|
||||||
|
/9oqHuIjmIfO8lIe4Hyd5Fw5xHkGqVETTGR+0c7kdZIlHmkOregUGtMYZRUi4YG+
|
||||||
|
q0w+uFemiHpGKXbeCIAvkq7aIkisEzvPWfSyYdA6WJHpxFk7tD7D8VkzABLVRHCq
|
||||||
|
AuyqPG39BhGZcGLXx5rGK56kDBJkyTR1t3DkHpwX+JKNG5UYNwOG4LcQj1fteeta
|
||||||
|
TdkYUMjIyWbanlMYyC+dq7B5fe7el99jXQ1gXwIDAQABAoIBADKfiPOpzKLOtzzx
|
||||||
|
MbHzB0LO+75aHq7+1faayJrVxqyoYWELuB1P3NIMhknzyjdmU3t7S7WtVqkm5Twz
|
||||||
|
lBUC1q+NHUHEgRQ4GNokExpSP4SU63sdlaQTmv0cBxmkNarS6ZuMBgDy4XoLvaYX
|
||||||
|
MSUf/uukDLhg0ehFS3BteVFtdJyllhDdTenF1Nb1rAeN4egt8XLsE5NQDr1szFEG
|
||||||
|
xH5lb+8EDtzgsGpeIddWR64xP0lDIKSZWst/toYKWiwjaY9uZCfAhvYQ1RsO7L/t
|
||||||
|
sERmpYgh+rAZUh/Lr98EI8BPSPhzFcSHmtqzzejvC5zrZPHcUimz0CGA3YBiLoJX
|
||||||
|
V1OrxmECgYEAxkd8gpmVP+LEWB3lqpSvJaXcGkbzcDb9m0OPzHUAJDZtiIIf0UmO
|
||||||
|
nvL68/mzbCHSj+yFjZeG1rsrAVrOzrfDCuXjAv+JkEtEx0DIevU1u60lGnevOeky
|
||||||
|
r8Be7pmymFB9/gzQAd5ezIlTv/COgoO986a3h1yfhzrrzbqSiivw308CgYEAwecI
|
||||||
|
aZZwqH3GifR+0+Z1B48cezA5tC8LZt5yObGzUfxKTWy30d7lxe9N59t0KUVt/QL5
|
||||||
|
qVkd7mqGzsUMyxUN2U2HVnFTWfUFMhkn/OnCnayhILs8UlCTD2Xxoy1KbQH/9FIr
|
||||||
|
xf0pbMNJLXeGfyRt/8H+BzSZKBw9opJBWE4gqfECgYBp9FdvvryHuBkt8UQCRJPX
|
||||||
|
rWsRy6pY47nf11mnazpZH5Cmqspv3zvMapF6AIxFk0leyYiQolFWvAv+HFV5F6+t
|
||||||
|
Si1mM8GCDwbA5zh6pEBDewHhw+UqMBh63HSeUhmi1RiOwrAA36CO8i+D2Pt+eQHv
|
||||||
|
ir52IiPJcs4BUNrv5Q1BdwKBgBHgVNw3LGe8QMOTMOYkRwHNZdjNl2RPOgPf2jQL
|
||||||
|
d/bFBayhq0jD/fcDmvEXQFxVtFAxKAc+2g2S8J67d/R5Gm/AQAvuIrsWZcY6n38n
|
||||||
|
pfOXaLt1x5fnKcevpFlg4Y2vM4O416RHNLx8PJDehh3Oo/2CSwMrDDuwbtZAGZok
|
||||||
|
icphAoGBAI74Tisfn+aeCZMrO8KxaWS5r2CD1KVzddEMRKlJvSKTY+dOCtJ+XKj1
|
||||||
|
OsZdcDvDC5GtgcywHsYeOWHldgDWY1S8Z/PUo4eK9qBXYBXp3JEZQ1dqzFdz+Txi
|
||||||
|
rBn2WsFLsxV9j2/ugm0PqWVBcU2bPUCwvaRu3SOms2teaLwGCkhr
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
74
ChatGPT-CodeReview/test/index.test.ts
Normal file
74
ChatGPT-CodeReview/test/index.test.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// You can import your modules
|
||||||
|
// import index from '../src/index'
|
||||||
|
|
||||||
|
import nock from "nock";
|
||||||
|
// Requiring our app implementation
|
||||||
|
import myProbotApp from "../src";
|
||||||
|
import { Probot, ProbotOctokit } from "probot";
|
||||||
|
// Requiring our fixtures
|
||||||
|
import payload from "./fixtures/issues.opened.json";
|
||||||
|
const issueCreatedBody = { body: "Thanks for opening this issue!" };
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const privateKey = fs.readFileSync(
|
||||||
|
path.join(__dirname, "fixtures/mock-cert.pem"),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
|
||||||
|
describe("My Probot app", () => {
|
||||||
|
let probot: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
nock.disableNetConnect();
|
||||||
|
probot = new Probot({
|
||||||
|
appId: 123,
|
||||||
|
privateKey,
|
||||||
|
// disable request throttling and retries for testing
|
||||||
|
Octokit: ProbotOctokit.defaults({
|
||||||
|
retry: { enabled: false },
|
||||||
|
throttle: { enabled: false },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
// Load our app into probot
|
||||||
|
probot.load(myProbotApp);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("creates a comment when an issue is opened", async () => {
|
||||||
|
const mock = nock("https://api.github.com")
|
||||||
|
// Test that we correctly return a test token
|
||||||
|
.post("/app/installations/2/access_tokens")
|
||||||
|
.reply(200, {
|
||||||
|
token: "test",
|
||||||
|
permissions: {
|
||||||
|
issues: "write",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test that a comment is posted
|
||||||
|
.post("/repos/hiimbex/testing-things/issues/1/comments", (body: any) => {
|
||||||
|
expect(body).toMatchObject(issueCreatedBody);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
// Receive a webhook event
|
||||||
|
await probot.receive({ name: "issues", payload });
|
||||||
|
|
||||||
|
expect(mock.pendingMocks()).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
nock.cleanAll();
|
||||||
|
nock.enableNetConnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// For more information about testing with Jest see:
|
||||||
|
// https://facebook.github.io/jest/
|
||||||
|
|
||||||
|
// For more information about using TypeScript in your tests, Jest recommends:
|
||||||
|
// https://github.com/kulshekhar/ts-jest
|
||||||
|
|
||||||
|
// For more information about testing with Nock see:
|
||||||
|
// https://github.com/nock/nock
|
||||||
72
ChatGPT-CodeReview/tsconfig.json
Normal file
72
ChatGPT-CodeReview/tsconfig.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
/* Basic Options */
|
||||||
|
"incremental": true /* Enable incremental compilation */,
|
||||||
|
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
|
||||||
|
"module": "NodeNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||||
|
"lib": [
|
||||||
|
"es2015",
|
||||||
|
"es2017"
|
||||||
|
] /* Specify library files to be included in the compilation. */,
|
||||||
|
"allowJs": true /* Allow javascript files to be compiled. */,
|
||||||
|
"checkJs": true /* Report errors in .js files. */,
|
||||||
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
|
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||||
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
|
"sourceMap": true /* Generates corresponding '.map' file. */,
|
||||||
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
|
"outDir": "./lib" /* Redirect output structure to the directory. */,
|
||||||
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
|
// "composite": true, /* Enable project compilation */
|
||||||
|
// "tsBuildInfoFile": "./" /* Specify file to store incremental compilation information */,
|
||||||
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
/* Strict Type-Checking Options */
|
||||||
|
"strict": true /* Enable all strict type-checking options. */,
|
||||||
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||||
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
/* Additional Checks */
|
||||||
|
"noUnusedLocals": true /* Report errors on unused locals. */,
|
||||||
|
"noUnusedParameters": true /* Report errors on unused parameters. */,
|
||||||
|
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
|
||||||
|
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
|
||||||
|
/* Module Resolution Options */
|
||||||
|
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
||||||
|
// "baseUrl": "./src" /* Base directory to resolve non-absolute module names. */,
|
||||||
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just type checking. */
|
||||||
|
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
||||||
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
/* Source Map Options */
|
||||||
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
|
/* Experimental Options */
|
||||||
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
/* Advanced Options */
|
||||||
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"pretty": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/",
|
||||||
|
"*.ts",
|
||||||
|
],
|
||||||
|
"compileOnSave": false
|
||||||
|
}
|
||||||
4580
ChatGPT-CodeReview/yarn.lock
Normal file
4580
ChatGPT-CodeReview/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user