feat(#501): npm CLI wrapper 패키지 초기 구조 추가#613
Conversation
packages/npm/ 아래에 govon npm thin wrapper를 구성합니다. Python 3.10+ 및 govon CLI 설치 여부를 확인하고, 미설치 시 pip install govon 안내 메시지를 출력합니다. GitHub Actions publish-npm.yml 워크플로우도 함께 추가합니다.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 3 minutes and 44 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
Note
|
| Cohort / File(s) | Summary |
|---|---|
npm 배포 자동화 .github/workflows/publish-npm.yml |
태그 푸시 또는 수동 실행 시 npm 레지스트리에 자동 배포하는 GitHub Actions 워크플로우 추가. 패키지 검증(npm pack --dry-run), bin/govon.js 실행 가능 확인, 버전 동기화, provenance 서명 포함. |
npm 패키지 설정 packages/npm/package.json, packages/npm/.gitignore, packages/npm/README.md |
npm 패키지 매니페스트 정의(bin.govon 엔트리, postinstall 스크립트, Node.js ≥18 요구), lib/ 디렉토리 예외 규칙, Python 의존성 및 설치 가이드 문서화. |
CLI 래퍼 및 환경 검증 packages/npm/bin/govon.js, packages/npm/lib/python-check.js |
Node.js 기반 CLI 엔트리포인트와 Python ≥3.10 및 govon 패키지 설치 여부를 검증하는 환경 체크 모듈. 누락된 요구사항 시 사용자 안내 메시지 출력. |
Sequence Diagram(s)
sequenceDiagram
actor User
participant npm as npm CLI
participant Installer as postinstall<br/>Script
participant Wrapper as bin/govon.js
participant PyCheck as lib/python-check.js
participant Python as Python CLI<br/>(govon)
User->>npm: npm install -g govon
npm->>Installer: 실행 (postinstall)
Installer->>Wrapper: node ./bin/govon.js --check-install
Wrapper->>PyCheck: printEnvironmentStatus()
PyCheck->>PyCheck: Python 실행파일 탐색<br/>(python3, python)
PyCheck->>PyCheck: Python 버전 확인<br/>(≥3.10)
PyCheck->>PyCheck: govon 모듈<br/>설치 여부 확인
alt 환경 정상
PyCheck->>Wrapper: true 반환
Wrapper->>Installer: 종료 (exit 0)
Installer->>npm: 완료
else 환경 부족
PyCheck->>User: 설치 안내 메시지 출력
PyCheck->>Wrapper: false 반환
Wrapper->>Installer: 종료 (exit 1)
end
User->>Wrapper: govon [args]
Wrapper->>PyCheck: printEnvironmentStatus()
alt 환경 정상
PyCheck->>Wrapper: true
Wrapper->>Python: spawn('govon', [args])
Python->>User: 결과 출력
else 환경 부족
PyCheck->>User: 설치 안내 메시지
Wrapper->>User: 종료 (exit 1)
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
검토 코멘트
[MUST] 환경 검증 로직의 견고성
packages/npm/lib/python-check.js에서:
- ✅ Python 버전 파싱 로직이 명확하고 타임아웃(5초)으로 무한 대기 방지
- ✅
node_modules경로 제외로 npm 래퍼 재귀 호출 방지 - 📌
which/where명령어 실패 시 동작: 현재 구현이 catch 블록에서null을 반환하는데, 이는 안전하나 로깅이 없음. 사용자가 PATH 문제를 진단하기 어려울 수 있음 → 디버그 모드 문서화 추천
packages/npm/bin/govon.js에서:
- ✅
ENOENT에러 처리로 명확한 사용자 메시지 제공 - ✅ 환경 검증 실패 시 spawn 호출 차단
[SHOULD] 배포 워크플로우의 완전성
.github/workflows/publish-npm.yml에서:
- ✅
--provenance플래그로 npm Sigstore 서명 활성화 - ✅
npm pack --dry-run으로 배포 전 사전 검증 - 📌
validate잡에서--check-install실패가|| true로 처리됨 → 이것이 의도인지 확인 필요. 문법 검증 실패해도 배포가 진행될 수 있음
[SHOULD] Python 버전 호환성 범위
packages/npm/package.json 및 README.md:
- 📌 Node.js 최소 버전 명시(≥18)는 좋으나, Python 3.10+ 요구사항이 package.json에는 없음
- 추천:
engines필드에 Python 요구사항 문서화 또는 설치 시 더 명확한 에러 메시지 제공
[MINOR] 가독성 및 문서화
- ✅ README.md에 설치 및 사용법이 명확함
- ✅ postinstall 스크립트가
|| true로 설정되어 설치 실패 방지 - 📌
lib/python-check.js의 timeout 값(5초)이 하드코딩됨 → 명확한 주석 또는 상수 정의 추천
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | 제목이 PR의 주요 변경 사항인 'npm CLI wrapper 패키지 초기 구조 추가'를 명확하게 반영하고 있습니다. |
| Linked Issues check | ✅ Passed | PR이 #501의 모든 주요 요구사항을 충족합니다: npm 래퍼 패키지 구조, package.json 설정, bin 엔트리, Python 검사 로직, GitHub Actions 워크플로우, 명확한 에러 메시지가 모두 구현되었습니다. |
| Out of Scope Changes check | ✅ Passed | 모든 변경사항이 #501의 요구 범위 내에 있습니다: npm 패키지 구조, Python 환경 검사, 배포 워크플로우 등이 모두 정의된 범위에 해당합니다. |
| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feat/501-npm-package
Comment @coderabbitai help to get the list of available commands and usage tips.
- actions/checkout@v6 → @v4 (존재하지 않는 버전 수정) - npm 캐시 설정 제거 (의존성 없는 패키지에 불필요) - postinstall 스크립트에 || true 추가 (Python 미설치 시 npm install 실패 방지)
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/publish-npm.yml:
- Around line 15-18: Move the top-level id-token: write permission into the
publish job's permissions block so only the publish job can request OIDC tokens;
specifically remove or change the top-level "id-token: write" under permissions:
and add "permissions: contents: read id-token: write" (or just "id-token:
write") inside the publish job definition that runs the npm publish --provenance
step, leaving other jobs (e.g., validate) without id-token privileges to adhere
to least-privilege.
- Around line 65-71: The run script in the "Extract version from tag" step
currently injects `${{ github.ref_name }}` directly into shell which is unsafe;
change the step to pass the tag into the shell via an env variable (e.g., env:
REF_NAME: ${{ github.ref_name }}) and then perform safe expansion inside the
script using that env variable (e.g., VERSION="${REF_NAME#v}") before writing to
GITHUB_OUTPUT and GITHUB_STEP_SUMMARY; update the step with id "version" to use
the env variable rather than direct interpolation.
- Around line 27-30: Replace the moving tags for external GitHub Actions with
their immutable commit SHAs: find usages of actions/checkout@v6 and
actions/setup-node@v6 (and the other two occurrences referenced) in the
publish-npm.yml workflow and change each uses: entry to uses:
actions/checkout@<COMMIT_SHA> and uses: actions/setup-node@<COMMIT_SHA>
(substitute the correct commit SHA from the action's repository release/commit)
so the workflow pins to exact commits instead of the floating v6 tags.
- Around line 37-41: The step currently pipes `npm pack --dry-run` into `tee
pack-output.txt`, which masks `npm`'s exit code; update the run block so the
step fails when `npm pack --dry-run` fails by either enabling bash pipefail (add
`set -o pipefail` at the start of the run) or capture and propagate the upstream
exit status (e.g., run `npm pack --dry-run 2>&1 | tee pack-output.txt;
rc=${PIPESTATUS[0]}; echo "### npm pack --dry-run" >> $GITHUB_STEP_SUMMARY; cat
pack-output.txt >> $GITHUB_STEP_SUMMARY; exit $rc`), ensuring `npm pack
--dry-run`, `tee pack-output.txt`, and the writes to `GITHUB_STEP_SUMMARY`
remain unchanged except for the added exit handling.
- Around line 43-46: The current verification step ignores failures because it
runs "node bin/govon.js --check-install || true" and then always echoes success;
remove the "|| true" and split syntax validation from environment checks so
failures propagate: run "node bin/govon.js --check-install" (no "|| true") to
fail the job on real errors, and if you want a separate quick syntax test keep a
distinct command (e.g., a plain "node -c" or a dedicated "node bin/govon.js
--syntax-check") before or after, ensuring the echo message only runs when the
preceding command succeeds; update the step that references "node bin/govon.js
--check-install" and the trailing "echo" accordingly.
In `@packages/npm/bin/govon.js`:
- Around line 21-24: The current spawn('govon', args, ...) risks recursively
invoking the wrapper from PATH; instead use the Python executable detected by
python-check.js (checkEnvironment() -> pythonCmd) and spawn pythonCmd with
arguments ['-m', 'govon', ...args] so the real Python runs the govon module;
update the spawn call in govon.js (where child is created using spawn and args)
to use pythonCmd and the '-m', 'govon' prefix while preserving stdio: 'inherit'
and shell: false.
- Around line 42-44: The callback for child.on('close') must accept both (code,
signal) and not treat a signal termination as a successful exit; update the
child.on('close', ...) handler to accept the second parameter signal and call
process.exit with a non-zero code when signal is present (for example use code
if defined, otherwise 1 when signal is truthy, else 0), and optionally include
the signal name in a log before exiting so callers/CI can detect signal-term
failures; change the existing handler around child.on('close', ...) and
process.exit(...) accordingly.
In `@packages/npm/README.md`:
- Around line 19-24: README에 있는 설치 명령 `pip install govon`은 다중 Python 환경에서 잘못된
인터프리터에 설치될 수 있으므로, 문서를 수정하여 현재 사용 중인 인터프리터와 같은 pip를 사용하도록 안내하세요: 기존의 `pip
install govon`을 `python -m pip install govon`으로 교체(또는 더 명확히 하려면 `python3 -m pip
install govon`)하여 래퍼가 검사한 인터프리터와 동일한 환경에 패키지가 설치되도록 만드세요.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ad2b87a7-cea8-493a-a2ea-9ff709e009f3
📒 Files selected for processing (6)
.github/workflows/publish-npm.ymlpackages/npm/.gitignorepackages/npm/README.mdpackages/npm/bin/govon.jspackages/npm/lib/python-check.jspackages/npm/package.json
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/publish-npm.ymlRepository: GovOn-Org/GovOn
Length of output: 3564
[SHOULD] 외부 액션을 moving tag 대신 커밋 SHA로 고정해 주세요.
actions/checkout@v6, actions/setup-node@v6는 태그가 가리키는 커밋이 변경되어도 자동으로 따라갑니다. npm 배포 같은 민감한 작업의 경우 예상치 못한 변경에 대비하기 위해 SHA 고정이 권장됩니다.
예: uses: actions/checkout@<COMMIT_SHA>
라인 27, 30, 57, 60에 적용됩니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/publish-npm.yml around lines 27 - 30, Replace the moving
tags for external GitHub Actions with their immutable commit SHAs: find usages
of actions/checkout@v6 and actions/setup-node@v6 (and the other two occurrences
referenced) in the publish-npm.yml workflow and change each uses: entry to uses:
actions/checkout@<COMMIT_SHA> and uses: actions/setup-node@<COMMIT_SHA>
(substitute the correct commit SHA from the action's repository release/commit)
so the workflow pins to exact commits instead of the floating v6 tags.
| - name: Verify bin executable | ||
| run: | | ||
| node bin/govon.js --check-install || true | ||
| echo "bin/govon.js syntax OK" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/publish-npm.yml | sed -n '35,55p'Repository: GovOn-Org/GovOn
Length of output: 863
🏁 Script executed:
cat -n .github/workflows/publish-npm.ymlRepository: GovOn-Org/GovOn
Length of output: 3564
🏁 Script executed:
test -f packages/npm/bin/govon.js && echo "File exists" || echo "File not found"
head -5 packages/npm/bin/govon.js 2>/dev/null || echo "Cannot read file"Repository: GovOn-Org/GovOn
Length of output: 234
|| true로 인해 검증 실패를 무시하고 항상 성공으로 처리합니다.
node bin/govon.js --check-install || true는 환경 점검 실패를 허용하지만, 그 결과 문법 오류나 런타임 초기화 오류도 모두 성공처럼 보입니다. 뒤따르는 echo 문장이 실행 결과와 무관하게 항상 출력되므로 이 단계의 검증 목적이 무의미해집니다. 문법 검사와 환경 점검을 분리하여 실제 오류를 감지할 수 있도록 개선이 필요합니다.
- name: Verify bin executable
run: |
+ node --check bin/govon.js
node bin/govon.js --check-install || true
- echo "bin/govon.js syntax OK"
+ echo "bin/govon.js syntax check OK"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Verify bin executable | |
| run: | | |
| node bin/govon.js --check-install || true | |
| echo "bin/govon.js syntax OK" | |
| - name: Verify bin executable | |
| run: | | |
| node --check bin/govon.js | |
| node bin/govon.js --check-install || true | |
| echo "bin/govon.js syntax check OK" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/publish-npm.yml around lines 43 - 46, The current
verification step ignores failures because it runs "node bin/govon.js
--check-install || true" and then always echoes success; remove the "|| true"
and split syntax validation from environment checks so failures propagate: run
"node bin/govon.js --check-install" (no "|| true") to fail the job on real
errors, and if you want a separate quick syntax test keep a distinct command
(e.g., a plain "node -c" or a dedicated "node bin/govon.js --syntax-check")
before or after, ensuring the echo message only runs when the preceding command
succeeds; update the step that references "node bin/govon.js --check-install"
and the trailing "echo" accordingly.
| const child = spawn('govon', args, { | ||
| stdio: 'inherit', | ||
| shell: false, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find packages/npm -name "*.js" -type f | head -20Repository: GovOn-Org/GovOn
Length of output: 117
🏁 Script executed:
cat -n packages/npm/bin/govon.jsRepository: GovOn-Org/GovOn
Length of output: 1297
🏁 Script executed:
cat -n packages/npm/lib/python-check.jsRepository: GovOn-Org/GovOn
Length of output: 5176
[MUST] PATH 기반 govon 재귀 호출 위험
spawn('govon', args)는 PATH에서 govon을 찾아 실행하는데, npm 설치 시 node_modules/.bin/govon 쉼이 PATH에 추가됩니다. 이 쉼 디렉터리가 Python 바이너리보다 PATH에서 우선하면, 이 래퍼 스크립트가 자기 자신을 다시 호출해 무한 재귀가 발생합니다.
python-check.js의 checkEnvironment()는 이미 pythonCmd를 제공하고 있으므로, 감지된 Python 실행 파일을 직접 사용해 spawn(pythonCmd, ['-m', 'govon', ...args])로 호출하는 것이 안전합니다.
수정 예시
-const { printEnvironmentStatus, isGovonInstalled } = require('../lib/python-check');
+const { checkEnvironment, printEnvironmentStatus } = require('../lib/python-check');
// postinstall 또는 직접 호출 시 환경 점검만 수행하고 종료
if (args[0] === '--check-install') {
@@ -16,10 +16,11 @@
process.exit(1);
}
+const { pythonCmd } = checkEnvironment();
// govon CLI를 실제로 실행
-const child = spawn('govon', args, {
+const child = spawn(pythonCmd, ['-m', 'govon', ...args], {
stdio: 'inherit',
shell: false,
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/npm/bin/govon.js` around lines 21 - 24, The current spawn('govon',
args, ...) risks recursively invoking the wrapper from PATH; instead use the
Python executable detected by python-check.js (checkEnvironment() -> pythonCmd)
and spawn pythonCmd with arguments ['-m', 'govon', ...args] so the real Python
runs the govon module; update the spawn call in govon.js (where child is created
using spawn and args) to use pythonCmd and the '-m', 'govon' prefix while
preserving stdio: 'inherit' and shell: false.
| child.on('close', (code) => { | ||
| process.exit(code ?? 0); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n packages/npm/bin/govon.js | head -60Repository: GovOn-Org/GovOn
Length of output: 1297
🌐 Web query:
Node.js child_process close event signal parameter callback
💡 Result:
In Node.js, the ChildProcess 'close' event handler is called as:
child.on('close', (code, signal) => { /* ... */ })code(number | null): the exit code if the process exited normally; otherwisenull.signal(string | null): the signal name (e.g.'SIGHUP','SIGTERM') if the process was terminated by a signal; otherwisenull. One ofcodeorsignalwill be non-null. [1]
Notes:
'close'fires after the process has ended and after its stdio streams are closed, and it always happens after'exit'(or after'error'if the process failed to spawn). [1]- Example showing the
signalargument being populated when you kill the child with a signal: [1]
Sources:
[1] Node.js child_process docs (events 'close' / 'exit', example with (code, signal)) (nodejs.org)
Citations:
Signal 종료를 성공 코드로 변환하여 상위 호출자가 실패를 감지하지 못합니다.
close 이벤트의 콜백은 (code, signal) 두 매개변수를 받습니다. 프로세스가 signal로 종료되면 code는 null이고 signal에 신호명(예: 'SIGINT', 'SIGTERM')이 전달됩니다. 현재 코드는 code ?? 0으로 인해 signal 종료를 성공(0)으로 변환하므로, 상위 호출자나 CI/CD 파이프라인이 비정상 종료를 감지하지 못합니다.
수정 예시
-child.on('close', (code) => {
- process.exit(code ?? 0);
+child.on('close', (code, signal) => {
+ if (signal) {
+ process.kill(process.pid, signal);
+ return;
+ }
+ process.exit(code ?? 1);
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| child.on('close', (code) => { | |
| process.exit(code ?? 0); | |
| }); | |
| child.on('close', (code, signal) => { | |
| if (signal) { | |
| process.kill(process.pid, signal); | |
| return; | |
| } | |
| process.exit(code ?? 1); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/npm/bin/govon.js` around lines 42 - 44, The callback for
child.on('close') must accept both (code, signal) and not treat a signal
termination as a successful exit; update the child.on('close', ...) handler to
accept the second parameter signal and call process.exit with a non-zero code
when signal is present (for example use code if defined, otherwise 1 when signal
is truthy, else 0), and optionally include the signal name in a log before
exiting so callers/CI can detect signal-term failures; change the existing
handler around child.on('close', ...) and process.exit(...) accordingly.
| 설치 후 Python 환경이 자동으로 확인됩니다. | ||
| `govon` Python 패키지가 설치되어 있지 않다면 아래 명령어로 설치하세요. | ||
|
|
||
| ```bash | ||
| pip install govon | ||
| ``` |
There was a problem hiding this comment.
[SHOULD] README의 설치 명령은 검사에 사용한 인터프리터와 같은 pip를 가리키도록 맞춰 주세요.
지금의 pip install govon은 다중 Python 환경에서 다른 인터프리터에 설치될 수 있습니다. 그러면 설치 후에도 래퍼는 계속 govon 미설치로 판단할 수 있으니, 문서도 python -m pip install govon 형태로 안내하는 편이 안전합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/npm/README.md` around lines 19 - 24, README에 있는 설치 명령 `pip install
govon`은 다중 Python 환경에서 잘못된 인터프리터에 설치될 수 있으므로, 문서를 수정하여 현재 사용 중인 인터프리터와 같은 pip를
사용하도록 안내하세요: 기존의 `pip install govon`을 `python -m pip install govon`으로 교체(또는 더
명확히 하려면 `python3 -m pip install govon`)하여 래퍼가 검사한 인터프리터와 동일한 환경에 패키지가 설치되도록
만드세요.
- pipefail 추가: npm pack 실패 시 tee가 masking하는 문제 방지 - script injection 방지: github.ref_name/steps.outputs → env 변수로 전환 - id-token: write를 publish job 레벨로 이동 (최소 권한)
관련 이슈
Closes #501
작업 배경
PyPI 패키지(#499) 배포 이전에 npm wrapper 패키지 구조를 미리 준비합니다.
npm 생태계 사용자가
npm install -g govon으로 CLI를 설치할 수 있도록Python CLI를 감싸는 thin wrapper를 제공합니다.
주요 변경 사항
packages/npm/package.json: name=govon, version=0.1.0, bin/engines/files 설정packages/npm/bin/govon.js: Python 3.10+ 및 govon CLI 설치 확인 후 spawn으로 위임packages/npm/lib/python-check.js: Python 환경 검사 유틸 (findPython, isGovonInstalled, printEnvironmentStatus)packages/npm/README.md: 설치 및 동작 방식 문서packages/npm/.gitignore: 루트 .gitignore의 lib/ 규칙 무효화.github/workflows/publish-npm.yml: v* 태그 push 시 npm publish with provenance, dry-run 사전 검증테스트 결과
node bin/govon.js --check-install실행 → 안내 메시지 정상 출력 확인기타 사항
pip install govon) #499)가 배포되기 전까지publishjob은 실제로 실행되지 않습니다 (tag push 조건)머지 조건 체크리스트
리뷰어 가이드
[MUST][MUST] API 키가 로그에 노출됩니다.[SHOULD][SHOULD] 이 로직은 별도 함수로 분리하는 것이 좋습니다.[NITS][NITS] 변수명을 \result`보다 `parsed_output`이 명확합니다.`[QUESTION][QUESTION] 이 조건이 항상 True일 수 있지 않나요?Summary by CodeRabbit
새로운 기능
문서