From cd2e1b91e75ebfc69b70c08d78c42c43c8b93377 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Tue, 23 Jun 2026 21:06:07 +0900 Subject: [PATCH 1/6] =?UTF-8?q?ci:=20SonarCloud=20=EB=B6=84=EC=84=9D=20?= =?UTF-8?q?=EB=B0=8F=20TS=C2=B7Rust=20=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sonar-project.properties: projectKey/organization, 소스 경로, lcov 리포트 경로 설정 - .github/workflows/sonar.yml: bun lcov + cargo-llvm-cov 생성 후 SonarCloud 스캔 - Rust는 minimal 툴체인이라 llvm-tools-preview 컴포넌트 추가 스텝 포함 --- .github/workflows/sonar.yml | 58 +++++++++++++++++++++++++++++++++++++ sonar-project.properties | 19 ++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 .github/workflows/sonar.yml create mode 100644 sonar-project.properties diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml new file mode 100644 index 0000000..4346c09 --- /dev/null +++ b/.github/workflows/sonar.yml @@ -0,0 +1,58 @@ +name: Sonar + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +concurrency: + group: sonar-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + sonar: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + # Full history so SonarQube Cloud can attribute new code / blame. + fetch-depth: 0 + + # --- TypeScript coverage (coverage/lcov.info) --- + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: 1.3.14 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Test with coverage (TypeScript) + run: bun test --coverage --coverage-reporter=lcov + + # --- Rust coverage (coverage/rust-lcov.info) --- + # rust-toolchain.toml uses `profile = "minimal"`, so the llvm-tools-preview + # component (required by cargo-llvm-cov) is not present by default. + - name: Add llvm-tools-preview component + run: rustup component add llvm-tools-preview + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@9e1e5806d4a4822de933115878265be9aaa786d9 # v2 + with: + tool: cargo-llvm-cov + + - name: Test with coverage (Rust) + # #[ignore] (network-gated) tests are excluded by default, keeping this + # offline (see ADR-0004). --all-features mirrors the Rust CI gate. + run: cargo llvm-cov --workspace --locked --all-features --lcov --output-path coverage/rust-lcov.info + + # --- SonarQube Cloud analysis --- + - name: SonarQube Cloud scan + uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..084c162 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,19 @@ +# SonarQube Cloud (sonarcloud.io) configuration. +# +# Analysis runs from CI (.github/workflows/sonar.yml). For this to work the +# SonarCloud project must have Automatic Analysis DISABLED and a SONAR_TOKEN +# secret configured in the repository (or org) settings. +sonar.projectKey=pleaseai_code-search +sonar.organization=pleaseai + +# Polyglot repo: TypeScript library under src/ + Rust port under crates/. +sonar.sources=src,crates + +# Keep the npm distribution wrapper, build output, and dependency/target dirs +# out of analysis (npm/** mirrors the .codacy.yaml exclusion). +sonar.exclusions=npm/**,dist/**,target/**,node_modules/** + +# Coverage reports (LCOV). TypeScript via `bun test --coverage`, Rust via +# `cargo llvm-cov`. Both are generated in CI before the scan step. +sonar.javascript.lcov.reportPaths=coverage/lcov.info +sonar.rust.lcov.reportPaths=coverage/rust-lcov.info From 97ace7a92ff7bfa1d5e3d8a683d52604eb6f416e Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Tue, 23 Jun 2026 21:06:07 +0900 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20README=EC=97=90=20SonarCloud=20Qual?= =?UTF-8?q?ity=20Gate=20=EB=B0=B0=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 영문/한국어 README 동기화 --- README.ko.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.ko.md b/README.ko.md index 7bcdf1f..e5424fe 100644 --- a/README.ko.md +++ b/README.ko.md @@ -9,6 +9,7 @@ npm version crates.io version Coverage + Quality Gate Status Socket Badge License - MIT diff --git a/README.md b/README.md index 19ad260..3f2bd19 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ npm version crates.io version Coverage + Quality Gate Status Socket Badge License - MIT From 1c06c8f558fe48b3d53b202b71db5a4e6d4697bd Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Tue, 23 Jun 2026 21:18:59 +0900 Subject: [PATCH 3/6] =?UTF-8?q?ci:=20Rust=20=EC=BB=A4=EB=B2=84=EB=A6=AC?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20Codecov=EC=97=90=EB=8F=84=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sonar.yml: cargo llvm-cov 결과(rust-lcov.info)를 flag=rust 로 Codecov 업로드 - ci.yml: 기존 TS 업로드에 flag=typescript 추가하여 언어별 분리 --- .github/workflows/ci.yml | 1 + .github/workflows/sonar.yml | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d0fc99..9674283 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,7 @@ jobs: uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: files: ./coverage/lcov.info + flags: typescript fail_ci_if_error: false env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 4346c09..4334e85 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -51,6 +51,17 @@ jobs: # offline (see ADR-0004). --all-features mirrors the Rust CI gate. run: cargo llvm-cov --workspace --locked --all-features --lcov --output-path coverage/rust-lcov.info + # Rust coverage to Codecov (TypeScript is uploaded from ci.yml). Flags keep + # the two languages separable in the Codecov report. + - name: Upload Rust coverage to Codecov + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + files: ./coverage/rust-lcov.info + flags: rust + fail_ci_if_error: false + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + # --- SonarQube Cloud analysis --- - name: SonarQube Cloud scan uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0 From 8b3d4e167fcc907d9b795dbc8ad5471882ec9456 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Wed, 24 Jun 2026 16:35:42 +0900 Subject: [PATCH 4/6] =?UTF-8?q?ci:=20Codecov=20flag=C2=B7component?= =?UTF-8?q?=EB=A1=9C=20=EC=96=B8=EC=96=B4=EB=B3=84=20=EC=BB=A4=EB=B2=84?= =?UTF-8?q?=EB=A6=AC=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - flags: typescript(src/)·rust(crates/) 정의 + carryforward 활성화 - component_management: TypeScript·Rust 컴포넌트로 UI/코멘트 분리 집계 - comment 레이아웃에 components 추가 --- codecov.yml | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/codecov.yml b/codecov.yml index ec0e8f5..f4cf1e5 100644 --- a/codecov.yml +++ b/codecov.yml @@ -16,8 +16,35 @@ coverage: informational: true comment: - layout: 'reach, diff, flags, files' + layout: 'reach, diff, flags, components, files' require_changes: false -# Coverage is generated by `bun test --coverage` (lcov). Test files are already -# excluded from the lcov report, so only product source is measured. +# Upload-time flags. ci.yml uploads TypeScript coverage with `flags: typescript` +# and sonar.yml uploads Rust coverage with `flags: rust`. carryforward keeps the +# last known coverage for a flag when its workflow doesn't run on a given commit. +flags: + typescript: + paths: + - src/ + carryforward: true + rust: + paths: + - crates/ + carryforward: true + +# Components group coverage by path at display time (independent of upload flags), +# giving a per-language breakdown in the Codecov UI and PR comment. +component_management: + individual_components: + - component_id: typescript + name: TypeScript + paths: + - src/** + - component_id: rust + name: Rust + paths: + - crates/** + +# Coverage is generated by `bun test --coverage` (TypeScript, lcov) and +# `cargo llvm-cov` (Rust, lcov). Test files are excluded from both lcov reports, +# so only product source is measured. From 0e9b9f1fe4c40cc518c3b410a27f619e77d6095c Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Wed, 24 Jun 2026 16:50:24 +0900 Subject: [PATCH 5/6] chore: apply AI code review suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sonar.yml: pull-requests: read 권한 추가 (cubic) - sonar.yml: fork PR에서 SONAR_TOKEN 미존재 시 스캔 스킵 (coderabbit) --- .github/workflows/sonar.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 466be2a..3786a5e 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -8,6 +8,7 @@ on: permissions: contents: read + pull-requests: read concurrency: group: sonar-${{ github.workflow }}-${{ github.ref }} @@ -16,6 +17,8 @@ concurrency: jobs: sonar: runs-on: ubuntu-latest + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} steps: - name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 @@ -51,7 +54,9 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # --- SonarQube Cloud analysis --- + # pull_request runs from forks don't get the SONAR_TOKEN secret; skip the + # scan there (env is checked instead of secrets, which isn't available in + # step `if:` conditions) so external PRs aren't blocked. - name: SonarQube Cloud scan + if: ${{ env.SONAR_TOKEN != '' }} uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 20bb022233ff305bdb7fb721d3d5eb2d10699013 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Wed, 24 Jun 2026 19:14:05 +0900 Subject: [PATCH 6/6] chore: apply AI code review suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sonar.yml: fork PR에서만 스캔 스킵, push(main)은 토큰 누락 시 실패 (cubic) --- .github/workflows/sonar.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 3786a5e..f745133 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -54,9 +54,11 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # --- SonarQube Cloud analysis --- - # pull_request runs from forks don't get the SONAR_TOKEN secret; skip the - # scan there (env is checked instead of secrets, which isn't available in - # step `if:` conditions) so external PRs aren't blocked. + # On pull_request runs from forks the SONAR_TOKEN secret isn't exposed, so + # skip the scan there instead of blocking external PRs. On push (main) the + # scan always runs — a missing token then fails loudly so a misconfigured + # Sonar setup is surfaced rather than silently skipped. (env is checked + # because the `secrets` context isn't available in step `if:` conditions.) - name: SonarQube Cloud scan - if: ${{ env.SONAR_TOKEN != '' }} + if: ${{ github.event_name != 'pull_request' || env.SONAR_TOKEN != '' }} uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0