Skip to content

Update build pipeline to support the microservice.#492

Merged
rahulharpal1603 merged 2 commits intoAOSSIE-Org:mainfrom
rahulharpal1603:GSoC'25/Frontend-Revamp
Aug 30, 2025
Merged

Update build pipeline to support the microservice.#492
rahulharpal1603 merged 2 commits intoAOSSIE-Org:mainfrom
rahulharpal1603:GSoC'25/Frontend-Revamp

Conversation

@rahulharpal1603
Copy link
Contributor

@rahulharpal1603 rahulharpal1603 commented Aug 30, 2025

Summary by CodeRabbit

  • New Features

    • Packaged Sync Microservice builds for Windows, macOS, and Linux are now included in desktop releases.
    • Backend now launches the bundled Sync Microservice in packaged installs and supports smoother startup during development.
    • Sync Microservice can be started directly for simpler local use.
  • Tests

    • Build/tests split so both backend and Sync Microservice are built before tests run.
  • Chores

    • CI/CD expanded to build, package, publish, and consume per‑platform Sync Microservice artifacts alongside server releases.

@rahulharpal1603 rahulharpal1603 added bug Something isn't working GSoC 2025 labels Aug 30, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds CI jobs to build and package a sync microservice per platform, integrates sync artifacts into the publish-and-release and TAURI workflows, restructures PR test steps to build both services, implements frozen vs development startup for the sync service launcher, and enables running the sync server via uvicorn when executed directly.

Changes

Cohort / File(s) Summary
CI: Build & Release workflow updates
.github/workflows/build-and-release.yml
Adds platform-specific build-sync-microservice-* jobs that build the sync microservice with PyInstaller and upload per-platform ZIP artifacts; updates publish-and-release/publish-tauri to depend on sync builds; separates server-artifact and sync-artifact; downloads and extracts both artifacts; installs additional deps/toolchains and adjusts packaging steps.
CI: PR checks restructure
.github/workflows/pr-check-tests.yml
Replaces the single combined install+test step with two build steps (main backend and sync microservice builds via PyInstaller) and a dedicated Run Tests step running pytest.
Backend: Sync service launcher
backend/app/utils/microservice.py
Adds detection of frozen (PyInstaller) vs dev mode; implements _start_frozen_sync_service to launch bundled PictoPy_Sync executable and _start_dev_sync_service to create/use .sync-env venv, install requirements (if present), and start the FastAPI/uvicorn service; improves error handling and logging.
Sync microservice: Direct run entrypoint
sync-microservice/main.py
Adds a __main__ block that configures and runs uvicorn programmatically (host 0.0.0.0, port 8001) so the sync service can be started by executing the script directly.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Backend as Backend
  participant Utils as microservice.py
  participant OS as OS/Process
  participant Sync as Sync Microservice

  User->>Backend: Start application
  Backend->>Utils: start_sync_microservice()
  alt Frozen (PyInstaller)
    Utils->>OS: Launch PictoPy_Sync[.exe] (subprocess) in PictoPy_Sync dir
    note right of OS #D6EAF8: Uses bundled executable\ncaptures stdout/stderr
  else Development
    Utils->>Utils: Ensure .sync-env venv exists (create if needed)
    Utils->>OS: pip install -r requirements.txt (if present)
    Utils->>OS: venv-python run uvicorn sync-microservice.main:app --port 8001
    note right of OS #E9F7EF: Starts uvicorn via venv Python
  end
  OS-->>Utils: PID/handle
  Utils-->>Backend: Started (True/False)
Loading
sequenceDiagram
  autonumber
  participant GH as GitHub Actions
  participant BuildSrv as build-server-*
  participant BuildSync as build-sync-microservice-*
  participant Publish as publish-tauri

  GH->>BuildSrv: Run server build matrix (win/linux/macos)
  GH->>BuildSync: Run sync build matrix (win/linux/macos)
  BuildSrv-->>GH: Upload `server-artifact` per platform
  BuildSync-->>GH: Upload `sync-artifact` per platform
  GH->>Publish: Trigger publish-tauri (needs all builds)
  Publish->>GH: Download `server-artifact` + `sync-artifact`
  Publish->>Publish: Extract artifacts and package Tauri apps
  Publish-->>GH: Upload release assets per platform
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, CI/CD

Poem

I hopped through YAML fields by night,
Zipping syncs in moonlit byte,
Frozen builds and venv delight,
Uvicorn hums while carrots bite.
Release bells ring — hop, deploy, take flight! 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b0d878d and 49c4d80.

📒 Files selected for processing (1)
  • backend/app/utils/microservice.py (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rahulharpal1603 rahulharpal1603 merged commit 4a6a656 into AOSSIE-Org:main Aug 30, 2025
2 of 4 checks passed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
.github/workflows/pr-check-tests.yml (1)

68-72: Update setup-python to v5.

actionlint flags v4 as too old on current runners. Use v5 for reliability.

-      - name: Set up Python
-        uses: actions/setup-python@v4
+      - name: Set up Python
+        uses: actions/setup-python@v5
         with:
           python-version: "3.11"
backend/app/utils/microservice.py (2)

230-236: Start the dev server via uvicorn and specify the app.

fastapi dev requires the CLI package and a target; current command omits it and may fail. Use uvicorn with explicit app and host/port.

-        print(python_executable)
-        cmd = [str(python_executable), "-m", "fastapi", "dev", "--port", "8001"]
+        host = os.getenv("PICTOPY_SYNC_HOST", "127.0.0.1")
+        port = os.getenv("PICTOPY_SYNC_PORT", "8001")
+        cmd = [
+            str(python_executable),
+            "-m",
+            "uvicorn",
+            "main:app",
+            "--host",
+            host,
+            "--port",
+            port,
+        ]

245-252: Preserve traceback on dev start failure.

-    except Exception as e:
-        logger.error(f"Error starting FastAPI service: {e}")
+    except Exception:
+        logger.exception("Error starting FastAPI service")
.github/workflows/build-and-release.yml (2)

307-314: Cross-platform extraction: avoid unzip on Windows.

windows-latest often lacks unzip. Use OS-conditional extraction (Expand-Archive) on Windows.

-      - name: Extract server files
-        shell: bash
-        run: |
-          cd backend/dist
-          unzip -o *.zip
-          rm *.zip
-          ls -l
+      - name: Extract server files (Windows)
+        if: runner.os == 'Windows'
+        run: |
+          cd backend/dist
+          powershell -Command "Expand-Archive -Path (Get-ChildItem -Filter *.zip).FullName -DestinationPath . -Force"
+          del *.zip
+          dir
+      - name: Extract server files (Unix)
+        if: runner.os != 'Windows'
+        run: |
+          cd backend/dist
+          unzip -o *.zip && rm *.zip && ls -l
@@
-      - name: Extract sync microservice files
-        shell: bash
-        run: |
-          cd sync-microservice/dist
-          unzip -o *.zip
-          rm *.zip
-          ls -l
+      - name: Extract sync microservice files (Windows)
+        if: runner.os == 'Windows'
+        run: |
+          cd sync-microservice/dist
+          powershell -Command "Expand-Archive -Path (Get-ChildItem -Filter *.zip).FullName -DestinationPath . -Force"
+          del *.zip
+          dir
+      - name: Extract sync microservice files (Unix)
+        if: runner.os != 'Windows'
+        run: |
+          cd sync-microservice/dist
+          unzip -o *.zip && rm *.zip && ls -l

Also applies to: 315-322


29-31: Non-interactive pip uninstall can hang.

Add -y to avoid prompts on CI.

-          pip uninstall onnxruntime
+          pip uninstall -y onnxruntime
@@
-          pip uninstall onnxruntime
+          pip uninstall -y onnxruntime

Also applies to: 71-73

🧹 Nitpick comments (3)
backend/app/utils/microservice.py (3)

58-67: Allow overriding bundled executable path.

Hardcoding PictoPy_Sync under app_dir makes packaging brittle. Support an override env.

-        sync_dir = app_dir / "PictoPy_Sync"
+        sync_dir = Path(os.getenv("PICTOPY_SYNC_DIR", str(app_dir / "PictoPy_Sync")))

240-242: Log the actual bound URL.

-        logger.info("Service should be available at http://localhost:8001")
+        logger.info(f"Service should be available at http://{host}:{port}")

135-137: Optional: wait for readiness before returning True.

Consider polling the health endpoint (with timeout) to ensure the service is actually up before signaling success.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6ec18af and b0d878d.

📒 Files selected for processing (4)
  • .github/workflows/build-and-release.yml (2 hunks)
  • .github/workflows/pr-check-tests.yml (1 hunks)
  • backend/app/utils/microservice.py (3 hunks)
  • sync-microservice/main.py (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.7)
.github/workflows/build-and-release.yml

144-144: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


184-184: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


224-224: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tauri Tests
  • GitHub Check: Backend Tests
🔇 Additional comments (1)
.github/workflows/pr-check-tests.yml (1)

86-89: Confirm pytest is installed.

If not pinned in backend/requirements.txt, this step will fail. Either add it to requirements or install here.

Would you like me to add a minimal backend/requirements-dev.txt and wire it in this job?

Comment on lines +144 to +147
uses: actions/setup-python@v4
with:
python-version: 3.12

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Bump setup-python to v5 across new sync jobs.

Fixes “runner too old” errors flagged by actionlint.

-      - name: Setup Python
-        uses: actions/setup-python@v4
+      - name: Setup Python
+        uses: actions/setup-python@v5
         with:
           python-version: 3.12

Also applies to: 184-187, 224-227

🧰 Tools
🪛 actionlint (1.7.7)

144-144: the runner of "actions/setup-python@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In .github/workflows/build-and-release.yml around lines 144-147 (and also update
occurrences at 184-187 and 224-227), the workflow uses actions/setup-python@v4
which triggers “runner too old” actionlint errors; change the action reference
to actions/setup-python@v5 in each location (keeping the same python-version
values) so the workflow uses the newer setup-python action.

Comment on lines +73 to +79
- name: Build check(Main backend)
run: |
cd backend
python -m pip install --upgrade pip
pip install -r requirements.txt
pyinstaller main.py --name PictoPy_Server --onedir --distpath dist

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure PyInstaller is available for the backend build.

This step assumes pyinstaller is in backend’s requirements. Make it explicit to avoid hidden coupling.

       - name: Build check(Main backend)
         run: |
           cd backend
           python -m pip install --upgrade pip
           pip install -r requirements.txt
+          pip install pyinstaller
           pyinstaller main.py --name PictoPy_Server --onedir --distpath dist
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Build check(Main backend)
run: |
cd backend
python -m pip install --upgrade pip
pip install -r requirements.txt
pyinstaller main.py --name PictoPy_Server --onedir --distpath dist
- name: Build check(Main backend)
run: |
cd backend
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller
pyinstaller main.py --name PictoPy_Server --onedir --distpath dist
🤖 Prompt for AI Agents
.github/workflows/pr-check-tests.yml around lines 73 to 79: the workflow calls
pyinstaller but relies on it being present implicitly in backend requirements;
explicitly install PyInstaller before invoking it to avoid hidden coupling —
update the build step to install PyInstaller (e.g., run python -m pip install
pyinstaller or pip install pyinstaller) immediately after installing
requirements so the pyinstaller command is guaranteed to exist.

Comment on lines +80 to +85
- name: Build check(Sync Microservice)
run: |
cd sync-microservice
pip install -r requirements.txt
pyinstaller main.py --name PictoPy_Sync_Microservice --onedir --distpath dist

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Install PyInstaller for the sync build too.

       - name: Build check(Sync Microservice)
         run: |
           cd sync-microservice
           pip install -r requirements.txt
+          pip install pyinstaller
           pyinstaller main.py --name PictoPy_Sync_Microservice --onedir --distpath dist
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Build check(Sync Microservice)
run: |
cd sync-microservice
pip install -r requirements.txt
pyinstaller main.py --name PictoPy_Sync_Microservice --onedir --distpath dist
- name: Build check(Sync Microservice)
run: |
cd sync-microservice
pip install -r requirements.txt
pip install pyinstaller
pyinstaller main.py --name PictoPy_Sync_Microservice --onedir --distpath dist
🤖 Prompt for AI Agents
In .github/workflows/pr-check-tests.yml around lines 80 to 85, the workflow runs
pyinstaller in the sync-microservice step but never installs PyInstaller; update
the step to ensure PyInstaller is available by either (a) running pip install
pyinstaller before invoking pyinstaller, or (b) adding pyinstaller to
sync-microservice/requirements.txt and keeping pip install -r requirements.txt;
ensure the install runs in the same job/step before the pyinstaller command so
the build succeeds.

Comment on lines 29 to 41
try:
# Check if running as a frozen executable (PyInstaller)
if getattr(sys, "frozen", False):
logger.info("Running as frozen executable, using bundled sync microservice...")
return _start_frozen_sync_service()

# Development mode - use virtual environment setup
logger.info("Running in development mode, using virtual environment...")
return _start_dev_sync_service(sync_service_path)

except Exception as e:
logger.error(f"Error starting sync microservice: {e}")
return False
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Log full trace on startup failures.

Use logger.exception to capture stack traces; it eases diagnosing environment/path issues.

-    except Exception as e:
-        logger.error(f"Error starting sync microservice: {e}")
+    except Exception:
+        logger.exception("Error starting sync microservice")
         return False
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
# Check if running as a frozen executable (PyInstaller)
if getattr(sys, "frozen", False):
logger.info("Running as frozen executable, using bundled sync microservice...")
return _start_frozen_sync_service()
# Development mode - use virtual environment setup
logger.info("Running in development mode, using virtual environment...")
return _start_dev_sync_service(sync_service_path)
except Exception as e:
logger.error(f"Error starting sync microservice: {e}")
return False
try:
# Check if running as a frozen executable (PyInstaller)
if getattr(sys, "frozen", False):
logger.info("Running as frozen executable, using bundled sync microservice...")
return _start_frozen_sync_service()
# Development mode - use virtual environment setup
logger.info("Running in development mode, using virtual environment...")
return _start_dev_sync_service(sync_service_path)
except Exception:
logger.exception("Error starting sync microservice")
return False
🤖 Prompt for AI Agents
In backend/app/utils/microservice.py around lines 29 to 41, the except block
currently uses logger.error which omits the stack trace; replace
logger.error(f"Error starting sync microservice: {e}") with
logger.exception("Error starting sync microservice") so the full traceback is
logged (no need to interpolate the exception), ensuring failures during startup
record the full stack trace for diagnostics.

Comment on lines +74 to +81
# Start the sync microservice executable
process = subprocess.Popen(
[str(sync_executable)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=str(sync_dir), # Set working directory to sync service directory
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid piping stdout/stderr without readers (deadlock risk).

Long-running services can block when pipes fill. Inherit parent stdio or redirect to DEVNULL.

-        process = subprocess.Popen(
-            [str(sync_executable)],
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            text=True,
-            cwd=str(sync_dir),  # Set working directory to sync service directory
-        )
+        process = subprocess.Popen(
+            [str(sync_executable)],
+            stdout=None,
+            stderr=None,
+            cwd=str(sync_dir),
+        )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Start the sync microservice executable
process = subprocess.Popen(
[str(sync_executable)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=str(sync_dir), # Set working directory to sync service directory
)
# Start the sync microservice executable
process = subprocess.Popen(
[str(sync_executable)],
stdout=None,
stderr=None,
cwd=str(sync_dir),
)
🤖 Prompt for AI Agents
In backend/app/utils/microservice.py around lines 74 to 81, the code starts the
sync microservice with stdout and stderr piped which risks deadlock if no
readers consume them; change creation so the child does not pipe output—either
inherit the parent stdio by removing stdout/stderr arguments or explicitly
redirect to subprocess.DEVNULL (or to rotating log files) so the subprocess
cannot block when its output buffers fill.

@@ -1,4 +1,5 @@
from fastapi import FastAPI
from uvicorn import Config, Server
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Make host/port configurable and exit with proper status.

Allow overriding via env vars and propagate uvicorn’s run() result to the process exit code.

+import os
+import sys
 from uvicorn import Config, Server
@@
 if __name__ == "__main__":
-    config = Config(app=app, host="0.0.0.0", port=8001, log_config=None)
+    host = os.getenv("PICTOPY_SYNC_HOST", "0.0.0.0")
+    port = int(os.getenv("PICTOPY_SYNC_PORT", "8001"))
+    config = Config(app=app, host=host, port=port, log_config=None)
     server = Server(config)
-    server.run()
+    ok = server.run()
+    sys.exit(0 if ok else 1)

Also applies to: 19-22

🤖 Prompt for AI Agents
In sync-microservice/main.py around lines 2 and 19-22, make the server host and
port configurable from environment variables (e.g., read HOST with a sensible
default like "0.0.0.0" and PORT defaulting to 8000, converting PORT to int) and
use uvicorn.run(...) with return_exit_status=True so you can capture its
returned exit code; then call sys.exit(exit_code) to propagate the server run
result to the process exit status. Ensure you import os and sys and replace the
hardcoded host/port and current run invocation accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working GSoC 2025

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant