ci: min-API lint for the Unity 2021.3 floor#32
Conversation
The dev project and Unity test job both run on 6000.3, so they can't catch APIs that fail to compile on an early 2021.3.x consumer (the class of bug from issue #11 / the FindAnyObjectByType fix). This license-free static check flags Find*ByType usage that is NOT behind a version guard; an awk pass tracks #if/#elif/#else/#endif nesting so guarded usage (#if UNITY_2023_1_OR_NEWER ... #else FindObjectOfType) is allowed. Verified: passes on current sources, catches an unguarded control.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1e8f4b5490
ℹ️ 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".
| function isver(s){ return (s ~ /UNITY_[0-9]/ || s ~ /OR_NEWER/) } | ||
| /^[ \t]*#[ \t]*if/ { depth++; g[depth]=isver($0)?1:0; next } | ||
| /^[ \t]*#[ \t]*elif/ { if(depth>0 && isver($0)) g[depth]=1; next } | ||
| /^[ \t]*#[ \t]*else/ { next } |
There was a problem hiding this comment.
Reset guard state on #else branches
In a version guard, the #else branch is the code compiled by older Unity versions, but this rule leaves g[depth] set when it reaches #else. As a result, #if UNITY_2023_1_OR_NEWER ... #else FindFirstObjectByType<T>() #endif is treated as guarded and produces no HITS, even though the denied API is exactly in the 2021.3 fallback path this workflow is meant to protect.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1e8f4b5. Configure here.
| function isver(s){ return (s ~ /UNITY_[0-9]/ || s ~ /OR_NEWER/) } | ||
| /^[ \t]*#[ \t]*if/ { depth++; g[depth]=isver($0)?1:0; next } | ||
| /^[ \t]*#[ \t]*elif/ { if(depth>0 && isver($0)) g[depth]=1; next } | ||
| /^[ \t]*#[ \t]*else/ { next } |
There was a problem hiding this comment.
#else branch inherits version-guard, missing real violations
Medium Severity
The #else handler simply does next without resetting g[depth], so the #else branch of a version-guarded #if is still considered "guarded." The #else branch is the code path for old Unity versions (where the denied APIs don't exist), so a denied API placed there is exactly the bug this lint exists to catch — yet it would be silently allowed. For example, if someone copies FindFirstObjectByType into the #else fallback by mistake, the linter would not flag it.
Reviewed by Cursor Bugbot for commit 1e8f4b5. Configure here.
| printf "%s:%d:%s\n", file, NR, $0 | ||
| } | ||
| ' "$f" | ||
| done < <(find "$PKG" -name '*.cs' -print0)) |
There was a problem hiding this comment.
Lint silently passes when package directory is missing
Low Severity
If the $PKG directory doesn't exist (e.g., the package is renamed), find fails inside the process substitution, but its exit status is silently discarded. HITS ends up empty and the script reports "Min-API lint passed" with exit 0 — even though nothing was actually scanned. The set -uo pipefail flags don't help here because process substitution exit codes aren't captured by pipefail, and set -e is not enabled. A pre-flight [ -d "$PKG" ] check would prevent the lint from becoming a silent no-op.
Reviewed by Cursor Bugbot for commit 1e8f4b5. Configure here.


From #26 (floor verification). A true 2021.3 test matrix isn't possible here — the dev project is Unity 6000.3 and 2021.3 can't open a newer-editor project. This adds a license-free static lint instead, targeting the exact regression class that bit the floor before (issue #11 /
FindAnyObjectByType).What it does
Flags
FindAnyObjectByType/FindFirstObjectByType/FindObjectsByType(added 2021.3.18f1 / 2022.2) when used without a version guard. An awk pass tracks#if/#elif/#else/#endifnesting and marks a level version-guarded when its condition mentionsUNITY_<year>/*_OR_NEWER, so the existing guarded usages are allowed:Singleton.csFindFirstObjectByType(behind#if UNITY_2023_1_OR_NEWER/#else FindObjectOfType)HandleDemo.csFindAnyObjectByType(same guard)Runs on PRs/pushes touching
Packages/**/*.cs. No Unity license/image.Verified locally
Heuristic, not a full compile (tradeoff chosen over a heavy minimal-2021.3 project).
ci:only → no release.Note
Low Risk
CI-only heuristic; no runtime or package source behavior changes.
Overview
Adds a license-free GitHub Actions job that enforces the package’s declared Unity 2021.3 minimum when the repo’s dev/tests run on 6000.3 and cannot compile on early 2021.3 consumers.
On pushes/PRs that touch
Packages/**/*.cs, an awk-based scan ofPackages/com.orkunmanap.runtime-transform-handlesfails CI ifFindAnyObjectByType,FindFirstObjectByType, orFindObjectsByTypeappear outside#ifregions whose conditions referenceUNITY_<year>or*_OR_NEWER—so existing guarded fallbacks toFindObjectOfTypestay allowed. The deny list is documented as extensible for future floor regressions.Reviewed by Cursor Bugbot for commit 1e8f4b5. Bugbot is set up for automated code reviews on this repo. Configure here.