From 811962534085bb53bfbf3ab11c4473fbc4ec7ec6 Mon Sep 17 00:00:00 2001 From: Andrei Ancuta Date: Tue, 8 Sep 2026 12:38:49 +0300 Subject: [PATCH 1/5] fix: handle debug signalR bridge race condition (#1590) (cherry picked from commit 64399bfb7c8c78da1971ba4f73747ba5da1315f2) --- packages/uipath/pyproject.toml | 2 +- packages/uipath/src/uipath/_cli/_debug/_bridge.py | 3 +++ packages/uipath/uv.lock | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/uipath/pyproject.toml b/packages/uipath/pyproject.toml index d086b5ce6..ca5372502 100644 --- a/packages/uipath/pyproject.toml +++ b/packages/uipath/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.10.37" +version = "2.10.37.post1" description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools." readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/packages/uipath/src/uipath/_cli/_debug/_bridge.py b/packages/uipath/src/uipath/_cli/_debug/_bridge.py index 9607398a0..d9afe0e31 100644 --- a/packages/uipath/src/uipath/_cli/_debug/_bridge.py +++ b/packages/uipath/src/uipath/_cli/_debug/_bridge.py @@ -741,6 +741,9 @@ async def _handle_start(self, args: list[Any]) -> None: f"Debug started: breakpoints={self.state.breakpoints}, step_mode={step_mode}" ) + # handle race conditions, runtime connected to debug bridge before the receiver + await self.emit_execution_started() + async def _handle_resume(self, args: list[Any]) -> None: """Handle Resume command from SignalR server. diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index c8ec1eafc..b07fe1e1f 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2543,7 +2543,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.10.37" +version = "2.10.37.post1" source = { editable = "." } dependencies = [ { name = "applicationinsights" }, From 9af7301bfdb376f2274695d15ea9e4ea53d4cfcb Mon Sep 17 00:00:00 2001 From: Andrei Ancuta Date: Tue, 8 Sep 2026 12:39:02 +0300 Subject: [PATCH 2/5] ci: run checks and publish on release branches (#1879) (#1881) (cherry picked from commits 97a1630c and 5695b198) --- .github/workflows/cd.yml | 6 ++++-- .github/workflows/ci.yml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 82aa4ccb2..8d809172f 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -5,6 +5,7 @@ on: push: branches: - main + - 'release/**' paths: - 'packages/*/pyproject.toml' - '!packages/*/samples/**/pyproject.toml' @@ -20,8 +21,8 @@ jobs: detect-publishable-packages: runs-on: ubuntu-latest outputs: - packages: ${{ steps.detect.outputs.packages }} - count: ${{ steps.detect.outputs.count }} + packages: ${{ steps.detect.outputs.packages || '[]' }} + count: ${{ steps.detect.outputs.count || '0' }} steps: - name: Checkout uses: actions/checkout@v4 @@ -33,6 +34,7 @@ jobs: - name: Detect publishable packages id: detect + if: ${{ !github.event.created }} run: python .github/scripts/detect_publishable_packages.py # --- Tier 0: uipath-core (no internal dependencies) --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e05e9c73..55ef1f977 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - 'release/**' permissions: contents: read From 395a03ba40eef98b41cd90e39fb7f750675d6458 Mon Sep 17 00:00:00 2001 From: Andrei Ancuta Date: Tue, 8 Sep 2026 14:55:50 +0300 Subject: [PATCH 3/5] ci: add SonarCloud scan required by the release ruleset --- .github/workflows/ci.yml | 2 ++ .github/workflows/test-packages.yml | 21 +++++++++++++++++++++ sonar-project.properties | 12 ++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 sonar-project.properties diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55ef1f977..f63adfbcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,8 @@ jobs: test: uses: ./.github/workflows/test-packages.yml + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} check-versions: uses: ./.github/workflows/check-version-availability.yml diff --git a/.github/workflows/test-packages.yml b/.github/workflows/test-packages.yml index 58e37a42a..9a8fc8080 100644 --- a/.github/workflows/test-packages.yml +++ b/.github/workflows/test-packages.yml @@ -2,6 +2,9 @@ name: Test Packages on: workflow_call: + secrets: + SONAR_TOKEN: + required: false permissions: contents: read @@ -182,6 +185,24 @@ jobs: continue-on-error: true + sonarcloud: + name: SonarCloud + needs: [test-uipath-core, test-uipath-platform, test-uipath] + runs-on: ubuntu-latest + if: always() && needs.test-uipath-core.result != 'failure' && needs.test-uipath-platform.result != 'failure' && needs.test-uipath.result != 'failure' + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: SonarCloud Scan + uses: SonarSource/sonarqube-scan-action@2f77a1ec69fb1d595b06f35ab27e97605bdef703 # v5 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + test-gate: name: Test needs: [test-uipath-core, test-uipath-platform, test-uipath] diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 000000000..54f64115f --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,12 @@ +sonar.projectKey=UiPath_uipath-python +sonar.organization=ui +sonar.host.url=https://sonarcloud.io + +sonar.sources=packages/uipath/src,packages/uipath-core/src,packages/uipath-platform/src +sonar.tests=packages/uipath/tests,packages/uipath-core/tests,packages/uipath-platform/tests + +sonar.python.version=3.11,3.12,3.13 + +sonar.exclusions=**/samples/**,**/testcases/**,**/template/**,**/_resources/** + +sonar.sourceEncoding=UTF-8 From e9ecb274aa0b5df33142208b6079d3cf2d327406 Mon Sep 17 00:00:00 2001 From: Andrei Ancuta Date: Tue, 8 Sep 2026 15:10:40 +0300 Subject: [PATCH 4/5] test: cover SignalR debug bridge start handler emitting execution started --- packages/uipath/tests/cli/chat/test_bridge.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/uipath/tests/cli/chat/test_bridge.py b/packages/uipath/tests/cli/chat/test_bridge.py index 2da4f31ad..96441b56f 100644 --- a/packages/uipath/tests/cli/chat/test_bridge.py +++ b/packages/uipath/tests/cli/chat/test_bridge.py @@ -351,3 +351,43 @@ async def test_send_with_datetime_does_not_raise(self) -> None: assert parsed_data["message"] == "test message" assert isinstance(parsed_data["timestamp"], str) assert isinstance(parsed_data["nested"]["created_at"], str) + + @pytest.mark.anyio + async def test_handle_start_emits_execution_started(self) -> None: + """Start command applies breakpoints and re-emits ExecutionStarted.""" + bridge = SignalRDebugBridge( + hub_url="wss://test.example.com/signalr", + access_token="test-token", + headers={}, + ) + + mock_client = MagicMock() + mock_client.send = AsyncMock() + bridge._client = mock_client + + await bridge._handle_start( + ['{"breakpoints": ["node-a", "node-b"], "enableStepMode": true}'] + ) + + assert bridge.state.breakpoints == {"node-a", "node-b"} + assert bridge.state.step_mode is True + mock_client.send.assert_awaited_once() + assert mock_client.send.call_args.kwargs["arguments"][0] == ( + "OnExecutionStarted" + ) + + @pytest.mark.anyio + async def test_handle_start_with_empty_args_does_not_emit(self) -> None: + bridge = SignalRDebugBridge( + hub_url="wss://test.example.com/signalr", + access_token="test-token", + headers={}, + ) + + mock_client = MagicMock() + mock_client.send = AsyncMock() + bridge._client = mock_client + + await bridge._handle_start([]) + + mock_client.send.assert_not_awaited() From 01067fbc55c48c5e213c7cce8b5305952f6b3202 Mon Sep 17 00:00:00 2001 From: Andrei Ancuta Date: Tue, 8 Sep 2026 15:12:48 +0300 Subject: [PATCH 5/5] ci: report uipath coverage to SonarCloud v2 --- .github/workflows/test-packages.yml | 25 ++++++++++++++++++++++++- sonar-project.properties | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-packages.yml b/.github/workflows/test-packages.yml index 9a8fc8080..e51109260 100644 --- a/.github/workflows/test-packages.yml +++ b/.github/workflows/test-packages.yml @@ -179,10 +179,23 @@ jobs: run: uv sync --all-extras --python ${{ matrix.python-version }} - name: Run tests - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && !(matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13') working-directory: packages/uipath run: uv run pytest + - name: Run tests with coverage + if: steps.check.outputs.skip != 'true' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13' + working-directory: packages/uipath + run: uv run pytest --cov-report=xml + + - name: Upload coverage XML report + if: steps.check.outputs.skip != 'true' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13' && always() + uses: actions/upload-artifact@v4 + with: + name: coverage-xml-uipath + path: packages/uipath/coverage.xml + retention-days: 30 + continue-on-error: true sonarcloud: @@ -198,6 +211,16 @@ jobs: with: fetch-depth: 0 + - name: Download uipath coverage + uses: actions/download-artifact@v4 + continue-on-error: true + with: + name: coverage-xml-uipath + path: packages/uipath + + - name: Rewrite coverage XML to repo-relative path + run: sed -i -E 's|.*packages/uipath/src\|src|packages/uipath/src|g' packages/uipath/coverage.xml || true + - name: SonarCloud Scan uses: SonarSource/sonarqube-scan-action@2f77a1ec69fb1d595b06f35ab27e97605bdef703 # v5 env: diff --git a/sonar-project.properties b/sonar-project.properties index 54f64115f..9aa72ff12 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,6 +6,7 @@ sonar.sources=packages/uipath/src,packages/uipath-core/src,packages/uipath-platf sonar.tests=packages/uipath/tests,packages/uipath-core/tests,packages/uipath-platform/tests sonar.python.version=3.11,3.12,3.13 +sonar.python.coverage.reportPaths=packages/uipath/coverage.xml sonar.exclusions=**/samples/**,**/testcases/**,**/template/**,**/_resources/**