From 23510c8c860b43ecfcf4cd335ce8c2d2910eb4d4 Mon Sep 17 00:00:00 2001 From: kobenlys Date: Fri, 4 Sep 2026 10:16:43 +0900 Subject: [PATCH 1/3] =?UTF-8?q?ci:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A7=A4=ED=8A=B8=EB=A6=AD=EC=8A=A4=EC=97=90=20macOS=C2=B7Wind?= =?UTF-8?q?ows=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit better-sqlite3는 네이티브 모듈이라 플랫폼별 prebuild가 실제로 붙는지 확인이 필요한데 지금까지 linux-x64 하나만 검증됐다. 잡 3개 -> 9개(3 OS x 3 Node). 저장소가 public이라 러너는 무료다. --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b6e01d..0cf9365 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,11 +13,13 @@ concurrency: jobs: unit-tests: - name: Unit Tests (Node ${{ matrix.node }}) - runs-on: ubuntu-latest + name: Unit Tests (${{ matrix.os }} / Node ${{ matrix.node }}) + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: + # better-sqlite3는 네이티브 모듈이라 플랫폼별 prebuild가 실제로 붙는지 확인해야 한다. + os: [ubuntu-latest, macos-latest, windows-latest] node: ['22', '24', '26'] # 지원 Node 버전(engines와 일치) steps: - uses: actions/checkout@v4 From da9dd3fb74e21370ed135e33ae7847eaee4519c6 Mon Sep 17 00:00:00 2001 From: kobenlys Date: Fri, 4 Sep 2026 10:56:30 +0900 Subject: [PATCH 2/3] =?UTF-8?q?test:=20launchctl=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=9D=B8=EC=9E=90=EB=A5=BC=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20?= =?UTF-8?q?=EB=8C=80=EC=8B=A0=20=EC=99=84=EC=A0=84=20=EC=9D=BC=EC=B9=98?= =?UTF-8?q?=EB=A1=9C=20=EB=8B=A8=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows에서 os.userInfo().uid가 -1이라 `\d+` 정규식이 'gui/-1/...'을 받지 못해 실패했다. 이 테스트는 platform을 주입해 어느 OS에서든 돌도록 설계됐고(파일 상단 주석), 스킵하면 그 의도가 깨진다. 호스트의 실제 uid로 완전 일치를 단언하도록 바꿨다. 테스트 목적인 "prefix·glob 금지, 완전 일치 조회"를 정규식 부분 매칭보다 정확히 검증한다. --- test/hook-reconcile.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hook-reconcile.test.js b/test/hook-reconcile.test.js index 7f8175c..9e5efb5 100644 --- a/test/hook-reconcile.test.js +++ b/test/hook-reconcile.test.js @@ -1,6 +1,7 @@ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'fs'; +import { userInfo } from 'os'; import { probeHookRegistration } from '../src/scheduler.js'; import { reconcileHookRegistration } from '../src/hook-reconcile.js'; @@ -102,7 +103,7 @@ test('probeHookRegistration(mac) — 라벨과 도메인을 완전 일치로 조 const [{ file, args }] = run.calls; assert.equal(file, 'launchctl'); assert.equal(args[0], 'print'); - assert.match(args[1], new RegExp(`^gui/\\d+/${TASK_LABEL.replace(/\./g, '\\.')}$`)); + assert.equal(args[1], `gui/${userInfo().uid}/${TASK_LABEL}`); }); test('probeHookRegistration(mac) — 조회에 타임아웃을 지정한다', () => { From c92f1536e69690941882290ce591d502b3663591 Mon Sep 17 00:00:00 2001 From: kobenlys Date: Fri, 4 Sep 2026 10:56:30 +0900 Subject: [PATCH 3/3] =?UTF-8?q?ci:=20npm=20ci=EC=97=90=EC=84=9C=20install?= =?UTF-8?q?=20script=20=EC=8A=A4=ED=82=B5=ED=95=98=EA=B3=A0=20=EC=A0=84?= =?UTF-8?q?=EC=97=AD=20=EC=84=A4=EC=B9=98=20=EC=8A=A4=EB=AA=A8=ED=81=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit better-sqlite3@13은 gypfile:false로 암묵 node-gyp를 막아뒀지만, 그 필드가 lockfile과 abbreviated packument 양쪽에서 유실된다. npm ci는 lockfile로 트리를 만들어 gypfile이 undefined가 되고, 조건을 통과해 node-gyp rebuild를 합성한다. Windows Node 22에서 VS 미검출로 설치가 실패했다. (npm/cli#9837, WiseLibs/better-sqlite3#1516) prebuild 로드는 lib/binding.js의 fs.existsSync 하나에만 의존하므로 스크립트를 건너뛰어도 무해하다. Node 24/26 잡이 이미 실증했다 - npm 11의 allowScripts가 gyp를 차단했는데도 SQLite 테스트가 전부 통과했다. 추가로 전역 설치 스모크 스텝을 붙였다. CI는 npm ci(lockfile 경로)만 검증했고 실사용자는 npm i -g(lockfile 없는 경로)로 들어온다. 그 사각지대를 닫는다. --- .github/workflows/ci.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cf9365..beebf83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,19 @@ jobs: node-version: ${{ matrix.node }} cache: npm # 의존성 캐시 - - run: npm ci # 의존성 설치 - - run: npm test # 테스트 실행 + # npm#9837: lockfile 경로에서 better-sqlite3의 gypfile:false가 무시돼 암묵 node-gyp가 돈다. + # prebuild는 압축 해제만으로 로드되므로(lib/binding.js) 스크립트를 건너뛰어도 무해하다. + # 이 트리에 install script를 쓰는 의존성은 없다 — 추가하려면 이 플래그를 먼저 재검토할 것. + - run: npm ci --ignore-scripts # 의존성 설치 + - run: npm test # 테스트 실행 + + # 실사용자는 lockfile 없는 경로(npm i -g)로 설치한다. CI가 그 경로를 안 보고 있었다. + - name: 전역 설치 스모크 + shell: bash + run: | + TARBALL=$(npm pack --silent) + npm i -g "./$TARBALL" + tokenphage --version coverage: name: Coverage @@ -43,5 +54,5 @@ jobs: node-version: '24' # 커버리지 임계 플래그 지원 cache: npm - - run: npm ci # 의존성 설치 + - run: npm ci --ignore-scripts # 의존성 설치 (위 unit-tests 주석 참조) - run: npm run test:coverage # 로직 코어 80% 미만이면 실패