From 9e440aed1d68de12f14054c73ae599dc5ad3f38e Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 20:15:28 +0200 Subject: [PATCH 1/6] Update docs with changelog link and proxy anatomy example --- Docs/docs/core-concepts/runtime-proxy.md | 31 ++++++++++++++++--- .../core-concepts/serialized-interface.md | 2 +- Docs/index.md | 3 +- README.md | 3 +- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Docs/docs/core-concepts/runtime-proxy.md b/Docs/docs/core-concepts/runtime-proxy.md index 1fbcd3b0..26c5c0e2 100644 --- a/Docs/docs/core-concepts/runtime-proxy.md +++ b/Docs/docs/core-concepts/runtime-proxy.md @@ -224,14 +224,35 @@ If a match exists, it is reused. If not, a new asset is created. This keeps runt ### Generated proxy anatomy +User-written code: + +```csharp +using System; +using UnityEngine; + +public class GameManager : MonoBehaviour, IGameObservable, IGameStarter +{ + // From IGameObservable + public event Action OnGameStarted; + + // From IGameObservable + public bool IsGameRunning { get; private set; } + + // From IGameStarter + public void StartGame() + { + } +} +``` + Auto-generated stub script: ```csharp using Plugins.Saneject.Runtime.Proxy; using Plugins.Saneject.Runtime.Attributes; -[GenerateRuntimeProxy] -// GameManager implements IGameObservable, IGameStarter +// Attribute instructs Roslyn generator to generate partial +[GenerateRuntimeProxy] public partial class GameManagerProxyC5D11084 : RuntimeProxy { } @@ -248,20 +269,20 @@ public partial class GameManagerProxyC5D11084 : IGameObservable, IGameStarter private const string ProxyAccessExceptionMessage = "Saneject: RuntimeProxy instances are serialized placeholders and should not be accessed directly."; - // Inherited from IGameObservable and generated by Roslyn + // From IGameObservable (Roslyn-generated) public event Action OnGameStarted { add => throw new InvalidOperationException(ProxyAccessExceptionMessage); remove => throw new InvalidOperationException(ProxyAccessExceptionMessage); } - // Inherited from IGameObservable and generated by Roslyn + // From IGameObservable (Roslyn-generated) public bool IsGameRunning { get => throw new InvalidOperationException(ProxyAccessExceptionMessage); } - // Inherited from IGameStarter and generated by Roslyn + // From IGameStarter (Roslyn-generated) public void StartGame() { throw new InvalidOperationException(ProxyAccessExceptionMessage); diff --git a/Docs/docs/core-concepts/serialized-interface.md b/Docs/docs/core-concepts/serialized-interface.md index fe02335d..efea0e04 100644 --- a/Docs/docs/core-concepts/serialized-interface.md +++ b/Docs/docs/core-concepts/serialized-interface.md @@ -16,7 +16,7 @@ Unity serialization supports concrete serializable data and `UnityEngine.Object` An interface is only a contract, not a concrete serializable type. So a member typed as `IMyService` is skipped by Unity's serializer unless you add an explicit serialization bridge. -In DI-heavy code, this matters because Saneject writes resolved dependencies into serialized members. +This matters because Saneject writes resolved dependencies into serialized members. If interface members cannot serialize, interface-based injection cannot persist in scenes and prefabs. ## What the Saneject Roslyn generator adds diff --git a/Docs/index.md b/Docs/index.md index 3fafd0b2..043cfad1 100644 --- a/Docs/index.md +++ b/Docs/index.md @@ -57,7 +57,7 @@ Add this URL to Unity Package Manager (Unity 2022.3.12 or newer): https://github.com/alexanderlarsen/Saneject.git?path=UnityProject/Saneject/Assets/Plugins/Saneject ``` -Or download the [latest release](https://github.com/alexanderlarsen/Saneject/releases) and import the `Saneject` folder into your Unity project. +Or download the [latest release](https://github.com/alexanderlarsen/Saneject/releases) and import it folder into your Unity project. Then jump to [Quick start](docs/getting-started/quick-start.md). @@ -74,5 +74,6 @@ If you try Saneject and something works well, feels unclear, or seems broken, I - [API](xref:Plugins.Saneject.Editor.Inspectors.SanejectInspector) - [GitHub repo](https://github.com/alexanderlarsen/Saneject) - [Releases](https://github.com/alexanderlarsen/Saneject/releases) +- [Changelog](https://github.com/alexanderlarsen/Saneject/blob/main/CHANGELOG.md) - [MIT license](https://github.com/alexanderlarsen/Saneject/blob/main/LICENSE) diff --git a/README.md b/README.md index 947b96b2..eb6d5120 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Add this URL to Unity Package Manager (Unity 2022.3.12 or newer): https://github.com/alexanderlarsen/Saneject.git?path=UnityProject/Saneject/Assets/Plugins/Saneject ``` -Or download the [latest release](https://github.com/alexanderlarsen/Saneject/releases) and import the `Saneject` folder into your Unity project. +Or download the [latest release](https://github.com/alexanderlarsen/Saneject/releases) and import it folder into your Unity project. Then jump to [Quick start](https://saneject.dev/docs/getting-started/quick-start). @@ -72,4 +72,5 @@ If you try Saneject and something works well, feels unclear, or seems broken, I - [Docs](https://saneject.dev/docs/getting-started/introduction) - [API](https://saneject.dev/api/Plugins.Saneject.Editor.Inspectors.SanejectInspector) - [Releases](https://github.com/alexanderlarsen/Saneject/releases) +- [Changelog](https://github.com/alexanderlarsen/Saneject/blob/main/CHANGELOG.md) - [MIT license](https://github.com/alexanderlarsen/Saneject/blob/main/LICENSE) From f56c7747f421ecb69bb630c4d540e84d41ce6d46 Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 20:36:26 +0200 Subject: [PATCH 2/6] Optimize test workflow with conditional execution. - Removed file path filters in pull request trigger to simplify workflow configuration. - Added logic to detect changes relevant to Unity tests using `git diff` in workflows. - Implemented conditional test execution to skip unnecessary runs when no relevant files are modified. - Updated `actions/checkout` step to fetch full history for `git diff` functionality. --- .github/workflows/tests.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index be3e049d..0bc11fd0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,10 +3,6 @@ on: pull_request: branches: - main - paths: - - 'UnityProject/Saneject/**' - - 'Roslyn/**' - - '.github/workflows/tests.yml' workflow_dispatch: jobs: @@ -19,8 +15,30 @@ jobs: unity: [2022.3.12f1, 2022.3.62f3, 6000.0.58f2, 6000.0.63f1, 6000.1.17f1, 6000.2.6f2, 6000.2.15f1, 6000.3.0f1, 6000.3.12f1, 6000.4.0f1, 6000.4.1f1] steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check if Unity tests are needed + id: test-paths + shell: bash + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "run=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if git diff --quiet "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}" -- UnityProject/Saneject Roslyn .github/workflows/tests.yml; then + echo "run=false" >> "$GITHUB_OUTPUT" + else + echo "run=true" >> "$GITHUB_OUTPUT" + fi + + - name: Skip tests + if: steps.test-paths.outputs.run != 'true' + run: echo "No test-relevant files changed." - name: EditMode tests + if: steps.test-paths.outputs.run == 'true' uses: game-ci/unity-test-runner@v4 env: UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} From 7dec79f200356be031c2b552c1ecd0e845a2d1aa Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 20:43:56 +0200 Subject: [PATCH 3/6] Test commit to see if new workflow is working as expected --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb6d5120..8d400e44 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Saneject logo -

+

![Unity](https://img.shields.io/badge/Unity-2022.3.12+-ff8383) [![Tests](https://img.shields.io/github/actions/workflow/status/alexanderlarsen/Saneject/tests.yml?label=Tests)](https://github.com/alexanderlarsen/Saneject/actions/workflows/tests.yml) From 92a73bdeb60ddc86030132c2bc047f05756bd8e8 Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 20:51:54 +0200 Subject: [PATCH 4/6] Adjust test workflow logic to handle PR updates and branch protection. - Added logic to distinguish between new PRs and updated PR pushes for efficient `git diff` handling. - Ensured matrix jobs always run but conditionally skip Unity tests if no relevant files are modified. - Clarified comments on branch protection requirements for workflow triggers and job conditions. - Updated `actions/checkout` step to fetch full commit history, enabling more granular change detection in workflows. --- .github/workflows/tests.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0bc11fd0..31442b5d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,6 +3,8 @@ on: pull_request: branches: - main + # Do not add a paths filter here. Branch protection requires the matrix + # checks below, so the workflow must create them for every PR to main. workflow_dispatch: jobs: @@ -16,28 +18,46 @@ jobs: steps: - uses: actions/checkout@v4 with: + # Required so git can compare the PR commits below. fetch-depth: 0 - name: Check if Unity tests are needed id: test-paths shell: bash run: | + # Manual runs should always execute the real Unity tests. if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then echo "run=true" >> "$GITHUB_OUTPUT" exit 0 fi - if git diff --quiet "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}" -- UnityProject/Saneject Roslyn .github/workflows/tests.yml; then + # When an existing PR gets a new push, check only the newly pushed + # commits. Otherwise, old test-related commits in the PR would make + # every later README/docs-only push run the full Unity matrix again. + if [[ "${{ github.event.action }}" == "synchronize" ]]; then + diff_base="${{ github.event.before }}" + diff_head="${{ github.event.after }}" + else + # For a newly opened/reopened PR, check the full PR diff. + diff_base="${{ github.event.pull_request.base.sha }}" + diff_head="${{ github.event.pull_request.head.sha }}" + fi + + if git diff --quiet "$diff_base" "$diff_head" -- UnityProject/Saneject Roslyn .github/workflows/tests.yml; then echo "run=false" >> "$GITHUB_OUTPUT" else echo "run=true" >> "$GITHUB_OUTPUT" fi - name: Skip tests + # Keep the required matrix job successful when this PR update did not + # touch test-relevant paths. if: steps.test-paths.outputs.run != 'true' run: echo "No test-relevant files changed." - name: EditMode tests + # Do not put this condition on the job itself. Branch protection + # requires these matrix jobs to complete successfully. if: steps.test-paths.outputs.run == 'true' uses: game-ci/unity-test-runner@v4 env: From 77cc580f18694a875a7c32ff55cb89b88d242c51 Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 20:58:45 +0200 Subject: [PATCH 5/6] Workflow test commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d400e44..eb6d5120 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Saneject logo -

+

![Unity](https://img.shields.io/badge/Unity-2022.3.12+-ff8383) [![Tests](https://img.shields.io/github/actions/workflow/status/alexanderlarsen/Saneject/tests.yml?label=Tests)](https://github.com/alexanderlarsen/Saneject/actions/workflows/tests.yml) From d4a3409ef22139b6dd8f8c4b21b657460728b9e0 Mon Sep 17 00:00:00 2001 From: Alexander Larsen Date: Tue, 28 Apr 2026 21:04:33 +0200 Subject: [PATCH 6/6] Simplify test workflow diff logic. - Removed conditional logic for distinguishing between new PRs and updated PR pushes. - Updated workflow to always check the full PR diff for relevant changes. --- .github/workflows/tests.yml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 31442b5d..4c4f7849 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,19 +31,10 @@ jobs: exit 0 fi - # When an existing PR gets a new push, check only the newly pushed - # commits. Otherwise, old test-related commits in the PR would make - # every later README/docs-only push run the full Unity matrix again. - if [[ "${{ github.event.action }}" == "synchronize" ]]; then - diff_base="${{ github.event.before }}" - diff_head="${{ github.event.after }}" - else - # For a newly opened/reopened PR, check the full PR diff. - diff_base="${{ github.event.pull_request.base.sha }}" - diff_head="${{ github.event.pull_request.head.sha }}" - fi - - if git diff --quiet "$diff_base" "$diff_head" -- UnityProject/Saneject Roslyn .github/workflows/tests.yml; then + # Check the full PR diff. This means docs-only PRs skip tests, while + # PRs that contain any test-relevant changes keep running tests even + # if the latest push only changed docs. + if git diff --quiet "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}" -- UnityProject/Saneject Roslyn .github/workflows/tests.yml; then echo "run=false" >> "$GITHUB_OUTPUT" else echo "run=true" >> "$GITHUB_OUTPUT"