From e61ff0d01bced5fd62e25f0ea37d0e179caf4527 Mon Sep 17 00:00:00 2001 From: "smalruby3-editor-bot[bot]" <297607354+smalruby3-editor-bot[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:34:54 +0000 Subject: [PATCH 1/2] =?UTF-8?q?ci(infra):=20classroom=20=E3=81=A8=20admin?= =?UTF-8?q?=20=E3=81=AE=20CI=20=E3=82=B8=E3=83=A7=E3=83=96=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit infra/** の変更でワークフローは起動するのに、この 2 つだけジョブが無く 素通りしていた。cold cache でテストが丸ごと走らない破綻(#1144)も、 tsc の破綻も CI では気付けず、ローカルの結果に頼るしかなかった。 他 4 プロジェクトと同じ 3 ジョブ(Unit Tests / CDK Build & Synth / Security Audit)を、pin した action・node-version-file・npm キャッシュを 含めて同じ形で追加する。node-version-file の参照先が無かったので .node-version も他と同じ 24.8.0 で追加する。 synth は Route53 を引かないよう他と同様にカスタムドメインを無効化する。 Closes #1155 Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci-infra.yml | 124 +++++++++++++++++++++++++ infra/smalruby-admin/.node-version | 1 + infra/smalruby-classroom/.node-version | 1 + 3 files changed, 126 insertions(+) create mode 100644 infra/smalruby-admin/.node-version create mode 100644 infra/smalruby-classroom/.node-version diff --git a/.github/workflows/ci-infra.yml b/.github/workflows/ci-infra.yml index 956e8c35e9..23ad533bcc 100644 --- a/.github/workflows/ci-infra.yml +++ b/.github/workflows/ci-infra.yml @@ -272,3 +272,127 @@ jobs: - name: Run npm audit run: npm audit --audit-level=moderate continue-on-error: true + + # --------------------------------------------------------------------------- + # smalruby-classroom + # --------------------------------------------------------------------------- + smalruby-classroom-unit-tests: + name: "[classroom] Unit Tests" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run unit tests + run: npm test + + smalruby-classroom-cdk-build: + name: "[classroom] CDK Build & Synth" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build TypeScript + run: npm run build + - name: Synthesize CDK stack + env: + CLASSROOM_CUSTOM_DOMAIN: 'false' + run: npx cdk synth --context stage=stg + + smalruby-classroom-security: + name: "[classroom] Security Audit" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run npm audit + run: npm audit --audit-level=moderate + continue-on-error: true + + # --------------------------------------------------------------------------- + # smalruby-admin + # --------------------------------------------------------------------------- + smalruby-admin-unit-tests: + name: "[admin] Unit Tests" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run unit tests + run: npm test + + smalruby-admin-cdk-build: + name: "[admin] CDK Build & Synth" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build TypeScript + run: npm run build + - name: Synthesize CDK stack + env: + ADMIN_CUSTOM_DOMAIN: 'false' + run: npx cdk synth --context stage=stg + + smalruby-admin-security: + name: "[admin] Security Audit" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run npm audit + run: npm audit --audit-level=moderate + continue-on-error: true diff --git a/infra/smalruby-admin/.node-version b/infra/smalruby-admin/.node-version new file mode 100644 index 0000000000..b404027604 --- /dev/null +++ b/infra/smalruby-admin/.node-version @@ -0,0 +1 @@ +24.8.0 diff --git a/infra/smalruby-classroom/.node-version b/infra/smalruby-classroom/.node-version new file mode 100644 index 0000000000..b404027604 --- /dev/null +++ b/infra/smalruby-classroom/.node-version @@ -0,0 +1 @@ +24.8.0 From 32efbffff08a2f1b62a55f5d50aa26c64ba9b06b Mon Sep 17 00:00:00 2001 From: "smalruby3-editor-bot[bot]" <297607354+smalruby3-editor-bot[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:40:01 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(admin):=20=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92=E3=83=A2=E3=82=B8?= =?UTF-8?q?=E3=83=A5=E3=83=BC=E3=83=AB=E5=8C=96=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI ジョブを足したところ handler-notifications.test.ts が TS2554 で suite ごと落ちた。import/export を持たない .ts はグローバルスクリプト扱いになり、 handler.test.ts の 3 引数版 makeEvent 宣言と衝突していた。classroom で #1144 として直したものと同じ構造が admin にも残っていた。 ローカルは ts-jest の温かいキャッシュで隠れており、cold cache の CI で 初めて出た。classroom と同じく export {} を足し、再発防止の回帰テストも 同じ形で置く。走るテストは 54 → 67 件になる。 Co-Authored-By: Claude Opus 5 (1M context) --- .../tests/handler-notifications.test.ts | 4 ++ .../tests/handler-recommend-sharing.test.ts | 4 ++ .../handler-shared-recommendation.test.ts | 4 ++ .../lambda/tests/handler.test.ts | 4 ++ .../tests/test-files-are-modules.test.ts | 45 +++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts diff --git a/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts b/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts index c206038ff4..498cd64c22 100644 --- a/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * お知らせ送信 API tests — EPIC #1111. * diff --git a/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts b/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts index 519ad75d1a..8fd140422e 100644 --- a/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * 共有推奨 API tests — EPIC #1106. * diff --git a/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts b/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts index ded1c59009..fc18dea623 100644 --- a/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * Admin 推薦 API tests — EPIC #1110. * diff --git a/infra/smalruby-admin/lambda/tests/handler.test.ts b/infra/smalruby-admin/lambda/tests/handler.test.ts index d9cf8f3fdf..fd887e2033 100644 --- a/infra/smalruby-admin/lambda/tests/handler.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * Admin API authorization tests (EPIC #1073, S1 #1081). * diff --git a/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts b/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts new file mode 100644 index 0000000000..f0e0b3df85 --- /dev/null +++ b/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts @@ -0,0 +1,45 @@ +/** + * テストファイルがモジュールであることを担保する回帰テスト (issue #1144)。admin も同じ構造だったため CI 追加時に検出した (#1155)。 + * + * `import` / `export` を 1 つも持たない .ts ファイルは TypeScript では「モジュール」ではなく + * グローバルスクリプトとして扱われる。その場合トップレベルの const がファイルを跨いで同じ + * スコープに宣言されるため、`mockSend` のような同名の変数を別ファイルで宣言した瞬間に + * TS2451 (Cannot redeclare block-scoped variable) になる。ts-jest はキャッシュが温かい間は + * 型チェックを再利用するので、この診断は cold cache のときだけ suite ごと落ちる = フレークに + * 見えていた。 + */ +import * as fs from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; + +const testsDir = __dirname; + +const collectTsFiles = (dir: string): string[] => + fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) return collectTsFiles(full); + return entry.isFile() && full.endsWith('.ts') ? [full] : []; + }); + +describe('lambda/tests の .ts ファイル', () => { + const files = collectTsFiles(testsDir); + + test('検査対象のファイルが見つかる', () => { + expect(files.length).toBeGreaterThan(0); + }); + + test.each(files.map((file) => [path.relative(testsDir, file), file]))( + '%s はモジュール (import/export を持つ) である', + (_relative, file) => { + const source = ts.createSourceFile( + file, + fs.readFileSync(file, 'utf8'), + ts.ScriptTarget.ES2020, + /* setParentNodes */ false, + ts.ScriptKind.TS, + ); + + expect(ts.isExternalModule(source)).toBe(true); + }, + ); +});