Skip to content

ci: min-API lint for the Unity 2021.3 floor#32

Merged
manaporkun merged 1 commit into
mainfrom
ci/min-api-lint
Jun 1, 2026
Merged

ci: min-API lint for the Unity 2021.3 floor#32
manaporkun merged 1 commit into
mainfrom
ci/min-api-lint

Conversation

@manaporkun
Copy link
Copy Markdown
Owner

@manaporkun manaporkun commented Jun 1, 2026

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/#endif nesting and marks a level version-guarded when its condition mentions UNITY_<year> / *_OR_NEWER, so the existing guarded usages are allowed:

  • Singleton.cs FindFirstObjectByType (behind #if UNITY_2023_1_OR_NEWER / #else FindObjectOfType)
  • HandleDemo.cs FindAnyObjectByType (same guard)

Runs on PRs/pushes touching Packages/**/*.cs. No Unity license/image.

Verified locally

  • Current sources → pass (both guarded uses ignored)
  • Unguarded control line → caught

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 of Packages/com.orkunmanap.runtime-transform-handles fails CI if FindAnyObjectByType, FindFirstObjectByType, or FindObjectsByType appear outside #if regions whose conditions reference UNITY_<year> or *_OR_NEWER—so existing guarded fallbacks to FindObjectOfType stay 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.

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.
Copy link
Copy Markdown

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

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: 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 }
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 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 👍 / 👎.

@manaporkun manaporkun merged commit 92fffba into main Jun 1, 2026
7 checks passed
@manaporkun manaporkun deleted the ci/min-api-lint branch June 1, 2026 23:15
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ 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 }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

#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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1e8f4b5. Configure here.

printf "%s:%d:%s\n", file, NR, $0
}
' "$f"
done < <(find "$PKG" -name '*.cs' -print0))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1e8f4b5. Configure here.

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