Skip to content

feat(cli): scan token-first rules, default path and include globs - #289

Merged
fernandotonon merged 6 commits into
masterfrom
feature/scan-token-precedence-and-default-globs
Apr 15, 2026
Merged

feat(cli): scan token-first rules, default path and include globs#289
fernandotonon merged 6 commits into
masterfrom
feature/scan-token-precedence-and-default-globs

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Apr 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • qtmesh scan with no path scans the current directory (same as ScanEngine when no override and no scan.roots in config).
  • Config precedence when --config is not passed: ingest token → fetch rules from QtMesh Cloud → on failure use built-in defaults; without a token, auto-load qtmesh.yml / qtmesh.yaml / qtmesh.json if present, else defaults.
  • Default scan.include: all file extensions registered by Assimp importers, plus .mesh and .mesh.xml for Ogre; overridden only when set in YAML/JSON/API config.
  • GitHub Action: input-file is optional, default ..

Testing

  • Added unit tests for default include globs and for local qtmesh.yml applying when no token (env cleared in test).
  • CI should run UnitTests on Linux.

API / token note

A manual GET https://api.qtmesh.dev/v1/ingest/rules with a test token returned 401 Unauthorized — that indicates an invalid, expired, or wrong-format ingest token on the qtmesh.dev side, not a client regression. Please confirm the ingest token from the dashboard matches what the CLI expects (e.g. Authorization: Bearer …). Do not commit tokens to the repo.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Auto-detect supported file formats for scanning, including Assimp-compatible formats and Ogre mesh files.
  • Bug Fixes

    • Cloud rules now take precedence over local configuration when an authentication token is present; fall back to defaults if cloud fetch fails.
  • Chores

    • Project version bumped to 2.27.0.
    • File/directory input parameter made optional; defaults to the workspace root when unspecified.
  • Tests

    • Added and adjusted tests to verify cloud-vs-local rule precedence and default include patterns.

- Default scan path to current directory; GitHub Action input-file defaults to '.'
- When ingest token is set and --config is omitted, fetch rules from QtMesh Cloud
  before auto-detected local qtmesh.yml|yaml|json
- Default scan.include to Assimp-registered extensions plus Ogre .mesh/.mesh.xml
- Tests: clear QTMESH_* env for local-yml case; assert default include globs
- Bump version to 2.27.0

Made-with: Cursor
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@fernandotonon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 47 minutes and 24 seconds before requesting another review.

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 47 minutes and 24 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 04fb20a5-ea92-4343-a888-c1ab5c1bad1c

📥 Commits

Reviewing files that changed from the base of the PR and between a39cccb and 3139121.

📒 Files selected for processing (4)
  • CMakeLists.txt
  • README.md
  • website/src/DocsApp.jsx
  • website/src/data/content.js
📝 Walkthrough

Walkthrough

The PR bumps project version to 2.27.0, makes the GitHub Action input-file optional with default '.', changes CLI scan precedence to prefer remote cloud rules when an ingest token exists, and adds dynamic default include patterns derived from Assimp importer extensions.

Changes

Cohort / File(s) Summary
GitHub Actions inputs
\.github/actions/qtmesh/action.yml, action.yml
Made input-file optional (required: false) with default: '.' and clarified description; runtime uses . when omitted.
Project manifest
CMakeLists.txt
Bumped project version from 2.26.0 to 2.27.0.
CLI scan behavior
src/CLIPipeline.cpp
Reordered config-loading: when an ingest token is present, attempt cloud fetch first and skip local qtmesh.yml (unless --config given); updated help text and messages.
CLI tests
src/CLIPipeline_test.cpp
Renamed test to reflect new precedence; added test ensuring token presence skips local qtmesh.yml and falls back to defaults on cloud failure.
ScanConfig implementation
src/ScanConfig.h, src/ScanConfig.cpp
Added ScanConfig() ctor and defaultIncludePatternsForAssimpImports() to generate default include globs from Assimp extensions (plus .mesh/.mesh.xml); adjusted fromVariantMap() to only override includePatterns when scan.include exists.
ScanConfig tests
src/ScanEngine_test.cpp
Added test asserting default constructor yields include patterns covering Assimp-derived extensions (e.g., FBX, mesh).

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI (cmdScan)
    participant Token as Token Resolver
    participant Cloud as QtMeshCloudClient
    participant Local as Local Config Loader
    participant Defaults as ScanConfig Defaults

    CLI->>Token: resolveIngestToken()
    alt Token present
        Token-->>CLI: token
        CLI->>Cloud: fetchRules(token)
        alt Cloud success
            Cloud-->>CLI: remote rules
        else Cloud failure
            Cloud-->>CLI: error/null
            CLI->>Defaults: use defaults()
            Defaults-->>CLI: default rules
        end
    else No token
        Token-->>CLI: empty/null
        CLI->>Local: load ./qtmesh.yml
        alt Local config found
            Local-->>CLI: local rules
        else not found
            Local-->>CLI: not found
            CLI->>Defaults: use defaults()
            Defaults-->>CLI: default rules
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I nibble globs from Assimp's tree,
Tokens whisper clouds to show me.
Default paths sprout, the workspace hums,
Version jumps up — new carrots come.
Hooray for scans and mesh-day drums! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main changes: token-first rule precedence, default scan path, and default include glob patterns for file scanning.
Description check ✅ Passed The PR description is well-structured and covers all required sections from the template, including a comprehensive summary, technical details, testing approach, and important API/token notes.

✏️ 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 feature/scan-token-precedence-and-default-globs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86509a5616

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ScanConfig.cpp Outdated
}
// Ogre mesh formats used by the editor (may or may not appear as separate Assimp importers)
extSet.insert(QStringLiteral("mesh"));
extSet.insert(QStringLiteral("mesh.xml"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat .mesh.xml files as their own format

Adding mesh.xml to the default include set means these assets are now scanned by default, but rule evaluation still keys off asset.format from ScanEngine::inspectAsset() (QFileInfo::suffix()), which resolves foo.mesh.xml to xml instead of mesh.xml. In projects that use allowed_formats/forbidden_extensions, this misclassifies Ogre mesh XML files and can produce incorrect pass/fail results (for example, allowed_formats: [mesh.xml] will wrongly reject them unless xml is also allowed).

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/ScanConfig.cpp (2)

291-322: Consider caching the computed default patterns.

defaultIncludePatternsForAssimpImports() creates an Assimp::Importer and iterates all registered importers on every invocation. Since Assimp's registered importers are static for a given build, the result is deterministic. This function is called:

  1. In the default constructor (line 287)
  2. Twice in fromVariantMap fallback paths (lines 366, 372)

If ScanConfig objects are created frequently, consider caching the result:

♻️ Optional: Cache the computed patterns
 QStringList ScanConfig::defaultIncludePatternsForAssimpImports()
 {
+    static const QStringList cached = []() {
     QSet<QString> extSet;
     Assimp::Importer importer;
     // ... existing logic ...
     globs.sort(Qt::CaseInsensitive);
     return globs;
+    }();
+    return cached;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ScanConfig.cpp` around lines 291 - 322,
defaultIncludePatternsForAssimpImports() recreates Assimp::Importer and
recomputes the same QStringList on every call; make the computed patterns
persistent by computing them once and returning the cached result on subsequent
calls (e.g., use a function-local static QStringList cachedPatterns computed on
first entry inside ScanConfig::defaultIncludePatternsForAssimpImports),
preserving the existing logic (including inserting "mesh" and "mesh.xml"), then
return cachedPatterns (local static initialization is thread-safe in C++11+).

363-372: Redundant fallback logic and unclear empty-list semantics.

Two observations:

  1. Redundant check: Lines 371-372 appear redundant. If scan.include is present, lines 365-366 already restore defaults when empty. If scan.include is absent, the constructor (line 287) already initialized includePatterns with defaults. The only path to an empty includePatterns at line 371 would be if the constructor didn't run, which isn't possible.

  2. User intent ambiguity: If a user explicitly sets scan.include: [] in their config, they might intend "scan no files." The current logic overrides this to defaults, which may be unexpected. Consider whether this is intentional behavior.

♻️ Simplify the fallback logic

If the intent is "always have defaults when config doesn't specify includes":

     if (scan.contains("include")) {
         config.includePatterns = scan.value("include").toStringList();
-        if (config.includePatterns.isEmpty())
-            config.includePatterns = ScanConfig::defaultIncludePatternsForAssimpImports();
     }
-    if (scan.contains("exclude"))
-        config.excludePatterns = scan.value("exclude").toStringList();
-    }
-    if (config.includePatterns.isEmpty())
-        config.includePatterns = ScanConfig::defaultIncludePatternsForAssimpImports();
+    if (scan.contains("exclude"))
+        config.excludePatterns = scan.value("exclude").toStringList();

The constructor already provides defaults; only override if the user explicitly provides a non-empty list.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ScanConfig.cpp` around lines 363 - 372, The fallback logic is redundant
and overrides an explicit empty user list; update the parsing in ScanConfig so
the constructor's defaults (set in the ScanConfig constructor) remain the only
automatic fallback: in the block handling scan.contains("include") assign
config.includePatterns = scan.value("include").toStringList() but do not replace
an explicit empty list with
ScanConfig::defaultIncludePatternsForAssimpImports(); then remove the later
unconditional if (config.includePatterns.isEmpty()) fallback. This preserves
constructor defaults when the key is absent but respects an explicit empty
include list from the user.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@action.yml`:
- Around line 13-16: The default for the input-file input now applies to all
commands and causes non-scan subcommands to receive '.'; change runtime handling
so the default '.' is only used when command == "scan" and all other commands
must explicitly validate that input-file is provided and is not '.'; update the
container entrypoint or CLI bootstrap to check the action input named input-file
and the command string (e.g., "scan", "info", "convert", "fix", "anim",
"validate", "lod", "pose") and: if command == "scan" allow default '.' to be
substituted, otherwise reject '.' (or missing) with a clear error and exit
non-zero so non-scan commands fail fast. Ensure the validation mirrors
CLIPipeline.cpp behavior (reject non-directory targets for scan) and keep
action.yml's input-file description unchanged except for runtime gating.

---

Nitpick comments:
In `@src/ScanConfig.cpp`:
- Around line 291-322: defaultIncludePatternsForAssimpImports() recreates
Assimp::Importer and recomputes the same QStringList on every call; make the
computed patterns persistent by computing them once and returning the cached
result on subsequent calls (e.g., use a function-local static QStringList
cachedPatterns computed on first entry inside
ScanConfig::defaultIncludePatternsForAssimpImports), preserving the existing
logic (including inserting "mesh" and "mesh.xml"), then return cachedPatterns
(local static initialization is thread-safe in C++11+).
- Around line 363-372: The fallback logic is redundant and overrides an explicit
empty user list; update the parsing in ScanConfig so the constructor's defaults
(set in the ScanConfig constructor) remain the only automatic fallback: in the
block handling scan.contains("include") assign config.includePatterns =
scan.value("include").toStringList() but do not replace an explicit empty list
with ScanConfig::defaultIncludePatternsForAssimpImports(); then remove the later
unconditional if (config.includePatterns.isEmpty()) fallback. This preserves
constructor defaults when the key is absent but respects an explicit empty
include list from the user.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8306ff3e-3321-4bf5-b494-9869f02f8896

📥 Commits

Reviewing files that changed from the base of the PR and between bf046ec and 86509a5.

📒 Files selected for processing (8)
  • .github/actions/qtmesh/action.yml
  • CMakeLists.txt
  • action.yml
  • src/CLIPipeline.cpp
  • src/CLIPipeline_test.cpp
  • src/ScanConfig.cpp
  • src/ScanConfig.h
  • src/ScanEngine_test.cpp

Comment thread action.yml
- Fix build failures: aiImporterDesc incomplete type on Linux/macOS/Windows by including assimp/importerdesc.h
- Cache default include glob computation (Assimp importer enumeration)
- Respect explicit empty scan.include (treat as configured override)
- GitHub Action: require input-file for non-scan commands; scan still defaults to '.'

Made-with: Cursor
Update website docs and README links from qtmesh.ftonon.uk to qtmesh.dev (including API host).

Made-with: Cursor
@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 542b7d4 into master Apr 15, 2026
19 checks passed
@fernandotonon
fernandotonon deleted the feature/scan-token-precedence-and-default-globs branch April 15, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant