Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,36 +44,7 @@ jobs:
env:
PYTHONPATH: src
PAPERBOT_DB_URL: sqlite:///data/paperbot-ci.db
run: |
python -m pytest -q \
tests/unit/test_scholar_from_config.py \
tests/unit/test_source_registry_modes.py \
tests/unit/test_arq_worker_settings.py \
tests/unit/test_jobs_routes_import.py \
tests/unit/test_dailypaper.py \
tests/unit/test_paper_judge.py \
tests/unit/test_memory_module.py \
tests/unit/test_memory_metric_collector.py \
tests/unit/test_llm_service.py \
tests/unit/test_di_container.py \
tests/unit/test_pipeline.py \
tests/unit/repro/test_agents.py \
tests/unit/repro/test_blueprint.py \
tests/unit/repro/test_memory.py \
tests/unit/repro/test_orchestrator.py \
tests/unit/repro/test_rag.py \
tests/integration/test_eventlog_sqlalchemy.py \
tests/integration/test_crawler_contract_parsers.py \
tests/integration/test_arxiv_connector_fixture.py \
tests/integration/test_reddit_connector_fixture.py \
tests/integration/test_x_importer_fixture.py \
tests/integration/test_repro_deepcode.py \
tests/test_generation_agent.py \
tests/test_repro_planning.py \
tests/test_repro_agent.py \
tests/test_repro_e2e.py \
tests/test_repro_models.py \
tests/e2e/test_api_track_fullstack_offline.py
run: bash scripts/ci/run_backend_offline_gates.sh

- name: Run eval smokes
env:
Expand Down
135 changes: 135 additions & 0 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: sonarcloud

on:
push:
branches:
- master
- dev
pull_request:
branches:
- master
- dev
workflow_dispatch:

concurrency:
group: sonarcloud-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
scan:
name: SonarCloud Scan
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
pull-requests: read
env:
PYTHONPATH: src
PAPERBOT_DB_URL: sqlite:///data/paperbot-ci.db
SONAR_ORGANIZATION: ${{ vars.SONAR_ORGANIZATION || 'jerry609' }}
SONAR_PROJECT_KEY: ${{ vars.SONAR_PROJECT_KEY || 'jerry609_PaperBot' }}
Comment on lines +30 to +31
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check SonarCloud settings
id: sonar_config
shell: bash
run: |
set -euo pipefail
if [ -z "${SONAR_TOKEN}" ]; then
echo "scan_enabled=false" >> "${GITHUB_OUTPUT}"
{
echo "### SonarCloud scan skipped"
echo
echo "Repository secret SONAR_TOKEN is not configured."
echo "The workflow remains available and will start scanning once the secret is added."
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
echo "scan_enabled=true" >> "${GITHUB_OUTPUT}"

- name: Set up Python
if: steps.sonar_config.outputs.scan_enabled == 'true'
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Cache pip
if: steps.sonar_config.outputs.scan_enabled == 'true'
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-sonar-pip-${{ hashFiles('requirements-ci.txt') }}
restore-keys: |
${{ runner.os }}-sonar-pip-

- name: Install backend dependencies
if: steps.sonar_config.outputs.scan_enabled == 'true'
run: |
python -m pip install -U pip
python -m pip install -r requirements-ci.txt

- name: Run backend tests with coverage
if: steps.sonar_config.outputs.scan_enabled == 'true'
run: bash scripts/ci/run_backend_offline_gates.sh --cov=src --cov-report=xml:coverage.xml

- name: Set up Node.js
if: steps.sonar_config.outputs.scan_enabled == 'true'
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: web/package-lock.json

- name: Install web dependencies
if: steps.sonar_config.outputs.scan_enabled == 'true'
working-directory: web
run: npm ci

- name: Run web tests with coverage
if: steps.sonar_config.outputs.scan_enabled == 'true'
working-directory: web
run: npm run test:coverage

- name: Cache SonarCloud packages
if: steps.sonar_config.outputs.scan_enabled == 'true'
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar-cache
restore-keys: |
${{ runner.os }}-sonar-cache
Comment on lines +105 to +107

- name: SonarCloud scan
if: steps.sonar_config.outputs.scan_enabled == 'true'
uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # v7.0.0
with:
args: >
-Dsonar.organization=${{ env.SONAR_ORGANIZATION }}
-Dsonar.projectKey=${{ env.SONAR_PROJECT_KEY }}
-Dsonar.qualitygate.wait=true
-Dsonar.qualitygate.timeout=300
Comment on lines +109 to +117

fork_notice:
name: Fork PR notice
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
runs-on: ubuntu-latest
steps:
- name: Record skip reason for fork PR
shell: bash
run: |
set -euo pipefail
echo "Fork PR detected; SonarCloud scan is skipped because GitHub Actions does not expose repository secrets to workflows from forks."
{
echo "### Fork PR SonarCloud scan skipped"
echo
echo "This pull request comes from a fork, so GitHub Actions cannot access the repository secrets needed for SonarCloud analysis."
echo
echo "Run the scan on a branch inside the main repository if you need PR decoration before merge."
} >> "${GITHUB_STEP_SUMMARY}"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Thumbs.db
logs/
/data/
/papers/
.coverage
coverage.xml
.scannerwork/
debug_*.txt
debug_*.json
response.html
Expand All @@ -54,6 +57,8 @@ reports/

# Node.js
node_modules/
coverage/
web/coverage/
cli/dist/
npm-debug.log

Expand Down
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies = [
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-cov>=5.0.0",
"pytest-asyncio>=0.21.0",
"pytest-mock>=3.12.0",
"black>=23.0.0",
Expand Down Expand Up @@ -125,6 +126,13 @@ live_mode = true
testpaths = ["tests"]
asyncio_mode = "strict"

[tool.coverage.run]
relative_files = true
source = ["src"]

[tool.coverage.report]
omit = ["tests/*"]

[tool.black]
line-length = 100
target-version = ['py310']
Expand Down
1 change: 1 addition & 0 deletions requirements-ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ SQLAlchemy>=2.0.0
alembic>=1.13.0

pytest>=7.2.0
pytest-cov>=5.0.0
pytest-asyncio>=0.21.0
pytest-mock>=3.12.0

Expand Down
36 changes: 36 additions & 0 deletions scripts/ci/run_backend_offline_gates.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")/../.."

export PYTHONPATH="${PYTHONPATH:-src}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Always include src in PYTHONPATH.

Line 6 preserves any pre-existing PYTHONPATH as-is; if it does not include src, imports can fail unexpectedly in CI/local runners.

💡 Proposed fix
-export PYTHONPATH="${PYTHONPATH:-src}"
+export PYTHONPATH="src${PYTHONPATH:+:${PYTHONPATH}}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/ci/run_backend_offline_gates.sh` at line 6, The current export
preserves PYTHONPATH as-is which can omit src; change the export line that sets
PYTHONPATH so that it always prepends "src" to the existing PYTHONPATH, using
shell parameter expansion to add the colon only when PYTHONPATH is non-empty
(i.e., replace the existing export of PYTHONPATH with one that guarantees src is
first in PYTHONPATH while preserving any existing entries).


python -m pytest -q "$@" \
tests/unit/test_scholar_from_config.py \
tests/unit/test_source_registry_modes.py \
tests/unit/test_arq_worker_settings.py \
tests/unit/test_jobs_routes_import.py \
tests/unit/test_dailypaper.py \
tests/unit/test_paper_judge.py \
tests/unit/test_memory_module.py \
tests/unit/test_memory_metric_collector.py \
tests/unit/test_llm_service.py \
tests/unit/test_di_container.py \
tests/unit/test_pipeline.py \
tests/unit/repro/test_agents.py \
tests/unit/repro/test_blueprint.py \
tests/unit/repro/test_memory.py \
tests/unit/repro/test_orchestrator.py \
tests/unit/repro/test_rag.py \
tests/integration/test_eventlog_sqlalchemy.py \
tests/integration/test_crawler_contract_parsers.py \
tests/integration/test_arxiv_connector_fixture.py \
tests/integration/test_reddit_connector_fixture.py \
tests/integration/test_x_importer_fixture.py \
tests/integration/test_repro_deepcode.py \
tests/test_generation_agent.py \
tests/test_repro_planning.py \
tests/test_repro_agent.py \
tests/test_repro_e2e.py \
tests/test_repro_models.py \
tests/e2e/test_api_track_fullstack_offline.py
Comment on lines +8 to +36
12 changes: 12 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sonar.projectName=PaperBot
sonar.sourceEncoding=UTF-8

sonar.sources=src,web/src
sonar.tests=tests,web/src
sonar.test.inclusions=tests/**/*,web/src/**/*.test.ts,web/src/**/*.test.tsx,web/src/**/*.spec.ts,web/src/**/*.spec.tsx
sonar.exclusions=web/src/**/*.test.ts,web/src/**/*.test.tsx,web/src/**/*.spec.ts,web/src/**/*.spec.tsx,**/__pycache__/**,**/*.pyc
sonar.coverage.exclusions=tests/**,web/src/**/*.test.ts,web/src/**/*.test.tsx,web/src/**/*.spec.ts,web/src/**/*.spec.tsx

sonar.python.coverage.reportPaths=coverage.xml
sonar.javascript.lcov.reportPaths=web/coverage/lcov.info
sonar.typescript.lcov.reportPaths=web/coverage/lcov.info
Loading
Loading