DevOps & Development Flow¶
Full CI/CD pipeline, PR lifecycle, and notification architecture across all repos.
For the rendered version with interactive diagrams, see the docs site.
Overview¶
All repos follow GitHub Flow: trunk-based development with feature branches and squash merge to main. The pipeline is fully automated from PR creation through merge, release tagging, and Discord notifications.
PR Lifecycle¶
sequenceDiagram
participant Agent as Developer / AI Agent
participant Git as GitHub
participant CI as CI Runner
participant Copilot as Copilot Review
participant Auto as Auto-merge
participant Discord as Discord #tasks
Agent->>Git: git push + gh pr create
activate Git
par Parallel triggers
Git->>CI: build-and-test.yml
Git->>Copilot: Automatic code review
Git->>Discord: request-review.yml<br/>(create thread)
Git->>Auto: auto-merge.yml<br/>(start waiting)
end
CI-->>Git: Check result (pass/fail)
Git->>Discord: build-status-to-discord.yml
Copilot-->>Git: Review (approve/request changes)
Git->>Discord: forward-copilot-reviews.yml
Note over Auto: Wait for CI (10 min timeout)
Note over Auto: Wait for Copilot (60s)
Note over Auto: Check unresolved conversations
alt All checks pass + no unresolved threads
Auto->>Git: Enable auto-merge (squash)
Git-->>Auto: PR merged
Auto->>Discord: Merge notification + author mention
Auto->>Git: Trigger release-please
Auto->>Git: Close linked issues
else Checks failed or unresolved threads
Auto-->>Discord: Failure notification
end
deactivate Git
Auto-merge Decision Flow¶
flowchart TD
A[PR opened/synchronized] --> B{manual-merge label?}
B -->|Yes| Z[Skip - manual merge required]
B -->|No| C[Wait for CI checks]
C --> D{All checks completed?}
D -->|No, timeout 10min| Z2[Fail - timeout]
D -->|Yes| E{All passed or skipped?}
E -->|No| Z3[Fail - checks failed]
E -->|Yes| F[Wait 60s for Copilot]
F --> G[Query review threads via GraphQL]
G --> H{Unresolved conversations?}
H -->|Yes| Z4[Fail - unresolved threads]
H -->|No| I[Try GraphQL enableAutoMerge]
I --> J{GraphQL succeeded?}
J -->|Yes| K[Auto-merge enabled]
J -->|No| L[Fallback: REST pulls.merge]
L --> M{REST merge succeeded?}
M -->|Yes| K
M -->|No| Z5[Fail - merge blocked]
K --> N[Poll for merged_at - 2 min]
N --> O{PR merged?}
O -->|Yes| P[Post-merge actions]
O -->|No, timeout| Z6[Skip post-merge]
P --> P1[Trigger release-please]
P --> P2{ios/ files changed?}
P2 -->|Yes| P3[Trigger Xcode Cloud monitor]
P2 -->|No| P4[Skip]
P --> P5[Discord merge notification]
P --> P6[Close linked issues]
style Z fill:#f66,color:#fff
style Z2 fill:#f66,color:#fff
style Z3 fill:#f66,color:#fff
style Z4 fill:#f66,color:#fff
style Z5 fill:#f66,color:#fff
style K fill:#6f6,color:#000
Discord Notification Architecture¶
flowchart LR
subgraph GitHub Events
E1[PR opened]
E2[CI completed]
E3[Review submitted]
E4[PR push]
E5[PR merged]
end
subgraph Workflows
W1[request-review.yml]
W2[build-status-to-discord.yml]
W3[pr-comments-to-discord.yml]
W4[forward-copilot-reviews.yml]
W5[auto-merge.yml]
end
subgraph Discord Thread
T1[New PR notification]
T2[CI pass/fail]
T3[Review comments]
T4[Copilot review]
T5[Merge notification]
end
E1 --> W1 --> T1
E2 --> W2 --> T2
E3 --> W3 --> T3
E4 --> W4 --> T4
E5 --> W5 --> T5
T1 -. "thread ID stored as<br>PR comment" .-> W2
T1 -. "thread ID" .-> W3
T1 -. "thread ID" .-> W4
T1 -. "thread ID" .-> W5
Release Flow¶
flowchart TD
A[PR merged to main] --> B[release-please.yml triggered]
B --> C{Releasable commits?}
C -->|No| D[No action]
C -->|Yes| E[Open/update Release PR]
E --> F[Release PR contains:<br>- version bump in version.txt<br>- CHANGELOG.md update]
F --> G{Release PR merged?}
G -->|No| H[Accumulate more commits]
H --> C
G -->|Yes| I[Create GitHub Release + git tag]
I --> J[post-release-check.yml]
J --> K[Verify release tag and assets]
I --> L{iOS files changed?}
L -->|Yes| M[Xcode Cloud builds new version]
M --> N[TestFlight distribution]
L -->|No| O[Done]
style I fill:#6f6,color:#000
PR State Machine¶
stateDiagram-v2
[*] --> Open: PR created
Open --> ChecksRunning: CI triggered
ChecksRunning --> ChecksPassed: All pass
ChecksRunning --> ChecksFailed: Any fail
ChecksFailed --> ChecksRunning: New push (synchronize)
ChecksPassed --> UnderReview: Copilot + Review-E
UnderReview --> ChangesRequested: Reviewer requests changes
ChangesRequested --> ChecksRunning: Agent pushes fix
UnderReview --> Approved: All reviews approve
Approved --> ConversationCheck: Auto-merge checks threads
ConversationCheck --> Blocked: Unresolved threads
Blocked --> ConversationCheck: Threads resolved
ConversationCheck --> Merging: No unresolved threads
Merging --> Merged: Squash merge
Merged --> Released: release-please tags
Released --> [*]
Workflow Inventory¶
Standard Workflows (all repos)¶
| Workflow | Trigger | Purpose |
|---|---|---|
auto-merge.yml |
pull_request: [opened, synchronize, reopened] |
Wait for checks, merge PR |
request-review.yml |
pull_request: [opened] |
Post new PR to Discord #tasks |
pr-comments-to-discord.yml |
pull_request_review, review_comment, issue_comment |
Forward review comments to Discord |
forward-copilot-reviews.yml |
pull_request: [opened, synchronize] |
Forward Copilot reviews (bypasses actor gate) |
build-status-to-discord.yml |
workflow_run: [completed] |
Post CI result to Discord |
auto-resolve-copilot-conversations.yml |
pull_request_review: [submitted] |
Auto-resolve Copilot suggestions |
notify-failure.yml |
workflow_run: [completed] |
Notify on workflow failures |
release-please.yml |
push: [main] or workflow_dispatch |
Version bump, changelog, GitHub Release |
iOS-specific Workflows¶
| Workflow | Trigger | Purpose |
|---|---|---|
build-and-test.yml |
pull_request |
Build iOS app, run tests |
monitor-xcode-cloud.yml |
workflow_dispatch |
Monitor Xcode Cloud build after merge |
post-release-check.yml |
release: [published] |
Verify release artifacts |
Infrastructure¶
| Type | Host | Labels |
|---|---|---|
| macOS runners | MacBook Air M4 | [self-hosted, macOS, ARM64, ios] per-repo |
| Linux runners | Dell k3s (ARC 0.13.1) | arc-linux-{repo} per-repo |
All uses: actions are SHA-pinned. Branch protection requires PR, CI pass, and Copilot review. No force push or direct push to main.
Discord Thread Model¶
Each PR gets a dedicated Discord thread:
request-review.ymlcreates thread on PR open- Thread ID stored as HTML comment in PR:
<!-- discord-review-msg-id:XXXX --> - Channel ID stored as:
<!-- discord-review-channel:XXXX --> - All workflows look up thread ID from PR comments to post updates
Known Issues¶
-
GitHub Contents API workflow registration: Workflows added via API sometimes don't register their
name:field. Events may not trigger. Fix: re-push the file. -
Copilot actor approval gate: GitHub requires manual approval for Copilot-triggered workflow runs. Workaround:
forward-copilot-reviews.ymltriggers on PR push events instead. -
Webhook payload case sensitivity:
pull_request_reviewwebhook payloads use lowercasereview.state. REST API returns uppercase. Always normalize with.toUpperCase(). -
Release-please pipeline gap: Release-please PRs (bot-opened) bypass the entire pipeline: no CI, no Discord, no review, no auto-merge. Tracked in #312.
Repo Status Matrix¶
| Repo | auto-merge | request-review | pr-comments | forward-copilot | build-status | auto-resolve | notify-failure | release-please | monitor-xcode | post-release |
|---|---|---|---|---|---|---|---|---|---|---|
| nutri-e | old | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| star-rewards | partial | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| fast-e | partial | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| count-e | latest | yes | yes | yes | yes | yes | yes | yes | yes | yes |
| drink-e | fixed | yes | yes | yes | yes | yes | yes | yes | no | no |
| heart-e | template | yes | yes | yes | yes | yes | yes | yes | no | no |
| cutie | yes | yes | yes | no | yes | no | no | yes | n/a | n/a |
Standardization tracked in #309.