Skip to content

Conversation

Copy link

Copilot AI commented Nov 6, 2025

Implements a Temporal workflow that mirrors GitHub PR comments (issue + review comments) to Launchpad Merge Proposals with fingerprint-based deduplication for idempotency.

Architecture

Database Layer

  • MirroredComment model with SHA256 fingerprint for deduplication
  • Alembic migration d4f9a1b2c3e5 adds mirrored_comment table with unique constraint on fingerprint
  • MirroredCommentsRepository for persistence and duplicate detection

Workflow

  • MirrorPullRequestCommentsWorkflow orchestrates 5 activities:
    • parse_input - validates URLs, extracts identifiers
    • fetch_github_comments - retrieves issue/review comments via GitHub API
    • filter_deduplicate - queries DB for existing fingerprints
    • post_launchpad_comments - posts to MP via launchpadlib
    • record_sync - persists metadata and status
  • Retry policies on network-bound activities (3 attempts, exponential backoff)

API

  • POST /v1/tools/mirror-pr-comments endpoint (authenticated)
  • Optional flags: include_outdated (review comments), include_review_states (approval summaries)
  • Returns workflow ID for async tracking

GitHub Integration

  • Normalizes issue and review comments into UnifiedComment dataclass
  • Preserves file/line context for review comments
  • Optionally fetches review approval/rejection states as pseudo-comments

Launchpad Integration

  • Formats comments with context headers: [File: path/to/file.py | Line: 123]
  • Anonymous login via launchpadlib

Usage

# Start workflow
curl -X POST /v1/tools/mirror-pr-comments \
  -H "Content-Type: application/json" \
  -d '{
    "github_pr_url": "https://github.com/owner/repo/pull/123",
    "launchpad_mp_url": "https://code.launchpad.net/~owner/project/+merge/456"
  }'

# Returns: {"workflow_id": "mirror-pr-comments-<hash>", "status": "started"}

Fingerprinting ensures re-running the workflow skips already-mirrored comments. Requires GITHUB_TOKEN environment variable.

Original prompt

Overview

Add a new productivity tool that mirrors all open comments from a GitHub Pull Request (issue comments + review comments) onto a specified Launchpad Merge Proposal (MP). This should follow the existing architectural patterns used for the current Temporal-based tool that converts a Launchpad Merge Proposal into a GitHub Pull Request.

Objectives

  1. Provide an API endpoint that accepts:
    • github_pr_url
    • launchpad_mp_url
    • Options: include_outdated (bool), include_review_states (bool)
  2. Start a Temporal workflow (MirrorPullRequestCommentsWorkflow) that:
    • Parses and validates both URLs.
    • Fetches all open comments from the GitHub PR (issue comments + review comments; optionally include outdated review comments).
    • Normalizes comments into a unified internal structure.
    • Deduplicates against already mirrored comments using fingerprinting to ensure idempotency.
    • Posts new comments to the Launchpad Merge Proposal via launchpadlib.
    • Records sync metadata (counts, timestamps) in the database.
    • Returns a result object containing counts of fetched, posted, skipped, and errored comments.
  3. Persist mirrored comments for idempotency & audit.
  4. Add Alembic migration for the new table.
  5. Add tests for workflow logic, idempotency, and API endpoint.

Technical Requirements

Workflow & Activities

Create MirrorPullRequestCommentsWorkflow with activities:

  • parse_input – validate and extract owner, repo, PR number, and MP identifier.
  • fetch_github_comments – uses GitHub REST API to collect issue and review comments.
  • filter_deduplicate – checks stored fingerprints in DB and returns only new comments.
  • post_launchpad_comments – posts comments to Launchpad MP using launchpadlib.
  • record_sync – stores summary and mirrored comment records (status posted/skipped/error).

Retry policies: Use Temporal default with exponential backoff for network-bound activities. Ensure activities have reasonable start_to_close_timeout values.

Data Model

Add SQLAlchemy model MirroredComment with columns:

  • id (PK)
  • fingerprint (unique; sha256 of "{source}:{comment_id}:{body}")
  • github_comment_id
  • github_source (issue|review)
  • mp_identifier (string, e.g., project:merge_number)
  • created_at
  • posted_at
  • status (pending|posted|skipped|error)
  • error_message (nullable)

Create Alembic migration to add the mirrored_comments table and index/unique constraint on fingerprint.

GitHub Integration

Use environment variable GITHUB_TOKEN. Endpoints:

  • Issue comments: GET /repos/{owner}/{repo}/issues/{number}/comments
  • Review comments: GET /repos/{owner}/{repo}/pulls/{number}/comments
    Normalize into unified dataclass UnifiedComment (fields: source, id, author_login, body, created_at, path, line, fingerprint).
    Optionally (if include_review_states), also capture review events (GET /repos/{owner}/{repo}/pulls/{number}/reviews) and post a summary comment (e.g., "Review by X: APPROVED" or "CHANGES_REQUESTED") to Launchpad. This can be done by treating review state summaries as pseudo-comments with distinct fingerprint format review_state:{review_id}:{state}.

Launchpad Integration

Reuse existing Launchpad authentication pattern from the current tool. Implement a helper service (e.g., services/launchpad_comments.py) with function to post a textual comment to the Merge Proposal. Prefix review comments with file/line context if available, e.g.:
[File: path/to/file.py | Line: 123]\nOriginal review comment body...

API Endpoint

Add FastAPI route: POST /tools/mirror-pr-comments
Body JSON schema:

{
  "github_pr_url": "https://github.com/owner/repo/pull/123",
  "launchpad_mp_url": "https://code.launchpad.net/~owner/project/+merge/456",
  "include_outdated": false,
  "include_review_states": false
}

Response:

{
  "workflow_id": "mirror-pr-comments-<hash>",
  "status": "started"
}

Idempotency & Deduplication

Fingerprints ensure no duplicate posting. Before posting, query DB for existing fingerprints for the same mp_identifier. Skip those already present. Record skipped counts.

Observability

Log structured entries per activity including workflow_id, counts, and partial (truncated) comment bodies (first 80 chars). Provide final summary metrics via logs. (Optional future enhancement: integrate with metrics system if one exists.)

Error Handling

  • Invalid URLs -> workflow failure (raise early).
  • GitHub 404 -> fail workflow with clear message.
  • Launchpad posting failures -> mark comment as error; continue with others.
  • Rate limiting (HTTP 403 / 429) -> rely on Temporal retries; optionally inspect headers to determine backoff.

Configuration

Add any new env vars to documentation (DEVELOPMENT.md): GITHUB_TOKEN. Confirm Launchpad credentials already documented; extend if needed.

Testing

Add unit tests:

  • Fingerprint generation.
  • Deduplication logic.
  • Parsing URLs (...

This pull request was created as a result of the following prompt from Copilot chat.

Overview

Add a new productivity tool that mirrors all open comments from a GitHub Pull Request (issue comments + review comments) onto a specified Launchpad Merge Proposal (MP). This should follow the existing architectural patterns used for the current Temporal-based tool that converts a Launchpad Merge Proposal into a GitHub Pull Request.

Objectives

  1. Provide an API endpoint that accepts:
    • github_pr_url
    • launchpad_mp_url
    • Options: include_outdated (bool), include_review_states (bool)
  2. Start a Temporal workflow (MirrorPullRequestCommentsWorkflow) that:
    • Parses and validates both URLs.
    • Fetches all open comments from the GitHub PR (issue comments + review comments; optionally include outdated review comments).
    • Normalizes comments into a unified internal structure.
    • Deduplicates against already mirrored comments using fingerprinting to ensure idempotency.
    • Posts new comments to the Launchpad Merge Proposal via launchpadlib.
    • Records sync metadata (counts, timestamps) in the database.
    • Returns a result object containing counts of fetched, posted, skipped, and errored comments.
  3. Persist mirrored comments for idempotency & audit.
  4. Add Alembic migration for the new table.
  5. Add tests for workflow logic, idempotency, and API endpoint.

Technical Requirements

Workflow & Activities

Create MirrorPullRequestCommentsWorkflow with activities:

  • parse_input – validate and extract owner, repo, PR number, and MP identifier.
  • fetch_github_comments – uses GitHub REST API to collect issue and review comments.
  • filter_deduplicate – checks stored fingerprints in DB and returns only new comments.
  • post_launchpad_comments – posts comments to Launchpad MP using launchpadlib.
  • record_sync – stores summary and mirrored comment records (status posted/skipped/error).

Retry policies: Use Temporal default with exponential backoff for network-bound activities. Ensure activities have reasonable start_to_close_timeout values.

Data Model

Add SQLAlchemy model MirroredComment with columns:

  • id (PK)
  • fingerprint (unique; sha256 of "{source}:{comment_id}:{body}")
  • github_comment_id
  • github_source (issue|review)
  • mp_identifier (string, e.g., project:merge_number)
  • created_at
  • posted_at
  • status (pending|posted|skipped|error)
  • error_message (nullable)

Create Alembic migration to add the mirrored_comments table and index/unique constraint on fingerprint.

GitHub Integration

Use environment variable GITHUB_TOKEN. Endpoints:

  • Issue comments: GET /repos/{owner}/{repo}/issues/{number}/comments
  • Review comments: GET /repos/{owner}/{repo}/pulls/{number}/comments
    Normalize into unified dataclass UnifiedComment (fields: source, id, author_login, body, created_at, path, line, fingerprint).
    Optionally (if include_review_states), also capture review events (GET /repos/{owner}/{repo}/pulls/{number}/reviews) and post a summary comment (e.g., "Review by X: APPROVED" or "CHANGES_REQUESTED") to Launchpad. This can be done by treating review state summaries as pseudo-comments with distinct fingerprint format review_state:{review_id}:{state}.

Launchpad Integration

Reuse existing Launchpad authentication pattern from the current tool. Implement a helper service (e.g., services/launchpad_comments.py) with function to post a textual comment to the Merge Proposal. Prefix review comments with file/line context if available, e.g.:
[File: path/to/file.py | Line: 123]\nOriginal review comment body...

API Endpoint

Add FastAPI route: POST /tools/mirror-pr-comments
Body JSON schema:

{
  "github_pr_url": "https://github.com/owner/repo/pull/123",
  "launchpad_mp_url": "https://code.launchpad.net/~owner/project/+merge/456",
  "include_outdated": false,
  "include_review_states": false
}

Response:

{
  "workflow_id": "mirror-pr-comments-<hash>",
  "status": "started"
}

Idempotency & Deduplication

Fingerprints ensure no duplicate posting. Before posting, query DB for existing fingerprints for the same mp_identifier. Skip those already present. Record skipped counts.

Observability

Log structured entries per activity including workflow_id, counts, and partial (truncated) comment bodies (first 80 chars). Provide final summary metrics via logs. (Optional future enhancement: integrate with metrics system if one exists.)

Error Handling

  • Invalid URLs -> workflow failure (raise early).
  • GitHub 404 -> fail workflow with clear message.
  • Launchpad posting failures -> mark comment as error; continue with others.
  • Rate limiting (HTTP 403 / 429) -> rely on Temporal retries; optionally inspect headers to determine backoff.

Configuration

Add any new env vars to documentation (DEVELOPMENT.md): GITHUB_TOKEN. Confirm Launchpad credentials already documented; extend if needed.

Testing

Add unit tests:

  • Fingerprint generation.
  • Deduplication logic.
  • Parsing URLs (valid/invalid cases).
    Mock tests:
  • GitHub API responses (issue + review comments + optional reviews).
  • Launchpad posting success/failure.
    Workflow integration test:
  • Use Temporal test harness (if set up) to execute workflow with mocked activities.
    API test:
  • Use FastAPI TestClient to trigger endpoint; assert workflow start call.

File Additions / Modifications (Proposed)

New files (paths may be adjusted to match existing project layout):

  • spaghettihub/workflows/mirror_pr_comments.py (workflow + activities skeleton)
  • spaghettihub/api/routes/mirror_comments.py (API endpoint)
  • spaghettihub/db/models/mirrored_comments.py (SQLAlchemy model)
  • spaghettihub/services/github_comments.py (GitHub fetch helpers)
  • spaghettihub/services/launchpad_comments.py (Launchpad posting helper)
  • alembic/versions/<timestamp>_add_mirrored_comments_table.py (migration)
  • Update spaghettihub/db/__init__.py or model registry if needed.
  • Update DEVELOPMENT.md to document usage & env vars.
  • Optionally add tests/ modules for each new component.

Implementation Notes

  • Use aiohttp (already in requirements) for async GitHub calls.
  • Ensure proper conversion of GitHub timestamps to datetime objects (ISO8601 parsing).
  • When posting review comments include file context header.
  • Keep Temporal task queue consistent with existing workflows (e.g., spaghettihub-tools).

Acceptance Criteria

  • Calling the new API endpoint starts a Temporal workflow and returns a workflow id.
  • Workflow fetches comments from a sample PR and posts them to a target MP (when credentials valid) without duplicates upon re-run.
  • Database persists mirrored comments with unique fingerprints.
  • Tests cover key logic paths.
  • Documentation updated.

Out of Scope (Future Enhancements)

  • Bi-directional sync.
  • Editing/deleting mirrored comments when originals change.
  • Advanced rate-limit backoff strategy.
  • Metrics export to external system.

Please implement the above with clean, documented code following existing repository style conventions.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits November 6, 2025 08:03
- Add database model and Alembic migration for mirrored_comments table
- Implement Temporal workflow with activities for comment fetching, deduplication, and posting
- Add GitHub API integration to fetch issue and review comments
- Add Launchpad integration to post comments to MP
- Create API endpoint POST /tools/mirror-pr-comments
- Register workflow and activities in worker
- Update documentation with usage instructions

Co-authored-by: r00ta <18282531+r00ta@users.noreply.github.com>
- Add proper dataclass parameters for all activities
- Update workflow to use FetchCommentsParams, FilterDeduplicateParams, PostCommentsParams, RecordSyncParams
- Update activities to accept parameter dataclasses instead of multiple arguments
- Ensures compatibility with Temporal activity invocation patterns

Co-authored-by: r00ta <18282531+r00ta@users.noreply.github.com>
- Replace str | None with Optional[str]
- Replace int | None with Optional[int]
- Replace Client | None with Optional[Client]
- Ensures consistency with existing codebase patterns

Co-authored-by: r00ta <18282531+r00ta@users.noreply.github.com>
Copilot AI changed the title [WIP] Add productivity tool to mirror GitHub PR comments to Launchpad MP Add GitHub PR to Launchpad MP comment mirroring tool Nov 6, 2025
Copilot AI requested a review from r00ta November 6, 2025 08:16
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.

2 participants