- Status: accepted
- Date: 2025-10-22
- Tags: ci-cd, github-actions, deployment, developer-experience
When reviewers evaluate pull requests that add or modify benchmark submissions, they need to see how the changes affect the generated HTML reports. Currently, reviewers must:
- Pull the PR branch locally
- Set up the Nix environment
- Run
cape submission measure --all - Run
cape submission report --all - Open the generated reports in a browser
This creates friction in the review process and makes it harder to spot performance regressions or improvements.
Question: How can we provide automatic, isolated preview sites for PRs that modify submission data?
- Visual feedback: Reviewers need to see report changes without local setup
- Isolation: Multiple PRs should have separate previews without conflicts
- Automation: Previews should update automatically on push
- Cleanup: Remove previews when PRs close to avoid clutter
- Efficiency: Only generate reports when submission data actually changes
- Compatibility: Coexist with existing
static.ymlworkflow for main branch
Approach: Use the official actions/upload-pages-artifact and actions/deploy-pages actions.
Pros:
- Official GitHub solution
- Well-maintained and documented
- Already used in
static.yml
Cons:
- Deploys to root of GitHub Pages site (replaces entire site)
- Cannot deploy to subdirectories
- Would conflict with main branch deployments
- Each deployment overwrites previous content
Verdict: ❌ Not suitable for PR previews due to lack of subdirectory support
Approach: Push report content directly to the gh-pages branch under PR-specific subdirectories.
Pros:
- Supports
destination_dirfor subdirectory deployments keep_files: truepreserves other PR previews- Compatible with existing main branch deployment
- Widely used and battle-tested action
- Automatic conflict resolution
Cons:
- Slightly more complex than official actions
- Direct git operations on gh-pages branch
Verdict: ✅ Chosen solution
Approach: Use external preview deployment services.
Pros:
- Purpose-built for preview deployments
- Advanced features (custom domains, redirects)
Cons:
- Requires third-party service setup
- Additional authentication/secrets management
- Project already uses GitHub Pages
- Adds external dependency
Verdict: ❌ Unnecessary complexity
Chosen option: "Git-based Deployment with peaceiris/actions-gh-pages", because it:
- Enables subdirectory deployments (
pr-<number>/) - Preserves existing previews and main branch site
- Integrates seamlessly with existing GitHub Pages setup
- Provides automatic cleanup workflow
- Requires no additional external services
Two GitHub Actions workflows:
Triggers:
- Pull request opened, synchronized, or reopened
- Path filter: Only runs when
submissions/**changes
Optimization Strategy (Hybrid Approach):
- Coarse-grained filter:
paths: submissions/**prevents workflow execution for non-submission PRs - Fine-grained validation: Git diff checks if
.uplcormetadata.jsonfiles changed - Early exit: Skips report generation if only documentation/README changed
Key Steps:
- Checkout PR branch with full history (
fetch-depth: 0) - Check if submission data files actually changed:
git diff --name-only origin/main...HEAD | grep -qE 'submissions/.*\.(uplc|metadata\.json)$'
- If no data changes: Skip remaining steps (optimization)
- If data changed:
- Set up Nix environment with Cachix
- Build
measureexecutable - Run
cape submission measure --all - Run
cape submission report --all - Deploy to
gh-pagesunderpr-<number>/subdirectory - Post sticky comment with preview URL
Deployment Configuration:
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./report
destination_dir: pr-${{ github.event.pull_request.number }}
keep_files: trueComment Integration:
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-preview
message: |
## 🚀 PR Preview Deployed
Preview URL: https://intersectmbo.github.io/UPLC-CAPE/pr-<number>/Triggers:
- Pull request closed (merged or abandoned)
Key Steps:
- Checkout
gh-pagesbranch - Remove
pr-<number>/directory if exists - Commit and push changes
Idempotency: Safely handles cases where preview directory doesn't exist.
concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true- Prevents multiple simultaneous deployments for the same PR
- Cancels in-progress runs when new commits are pushed
https://intersectmbo.github.io/UPLC-CAPE/pr-<number>/
Examples:
- PR #42:
https://intersectmbo.github.io/UPLC-CAPE/pr-42/ - PR #110:
https://intersectmbo.github.io/UPLC-CAPE/pr-110/
- Main branch (
static.yml): Deploys to root usingactions/deploy-pages - PR branches (
pr-preview.yml): Deploy to subdirectories usingpeaceiris/actions-gh-pages - No conflicts: Different deployment mechanisms target different locations
- Improved review workflow: Reviewers see visual changes immediately
- No local setup required: Preview sites accessible from any browser
- Isolated environments: Each PR has independent preview
- Automatic updates: Previews refresh on every push
- Automatic cleanup: No manual intervention needed when PRs close
- Resource efficiency: Only generates reports when submission data changes
- Smart filtering: Avoids unnecessary CI runs for documentation-only changes
- Sticky comments: Preview link stays at top of PR conversation
- Zero configuration: Uses default
GITHUB_TOKEN, no secrets needed
- CI resource usage: Measuring and reporting adds ~5-10 minutes per PR
- Mitigated by: Path filters and git diff checks
- gh-pages branch growth: Each PR adds a subdirectory
- Mitigated by: Automatic cleanup on PR close
- Preview URL lifetime: Links become invalid after PR closes
- Acceptable: Previews are temporary by design
- Concurrent PR limitations: Many simultaneous PRs could create many subdirectories
- Acceptable: Cleanup workflow keeps it manageable
The implementation uses a two-layer filtering approach:
on:
pull_request:
paths:
- "submissions/**"Effect: Prevents workflow from running for PRs that don't touch submissions/ at all.
Catches:
- Documentation changes in root
- Code changes in
lib/,measure-app/, etc. - CI/CD configuration changes
git diff --name-only origin/main...HEAD | grep -qE 'submissions/.*\.(uplc|metadata\.json)$'Effect: Skips report generation if only non-data files changed in submissions/.
Catches:
- README updates in submission directories
- Documentation improvements in
source/directories - Comment changes in metadata
Scenario 1: PR modifies lib/Cape/Compile.hs
- ✅ Layer 1 blocks → Workflow doesn't run at all
Scenario 2: PR updates submissions/fibonacci/Plinth_1.0.0_baseline/README.md
- ❌ Layer 1 allows → Workflow starts
- ✅ Layer 2 blocks → Early exit, no report generation
Scenario 3: PR adds new submissions/fibonacci/MyCompiler_2.0.0_handle/fibonacci.uplc
- ❌ Layer 1 allows → Workflow starts
- ❌ Layer 2 allows → Full report generation and deployment
Option A: Only use paths filter
- Simpler configuration
- Wastes CI resources on README-only changes
Option B: Only use git diff check
- Workflow runs for all PRs
- Adds unnecessary setup overhead
Decision: Hybrid approach provides best balance of simplicity and efficiency.
Expanded "Live Performance Reports" section to include:
- New subsection on PR Preview Sites
- Preview URL pattern explanation
- Trigger conditions (submission data changes)
- Automatic update and cleanup behavior
- Reference to this ADR
Added brief note about:
- PR preview functionality
- When previews are generated
- Reference to README.md for details
Manual Testing:
- Create PR with submission changes → Verify preview deploys
- Push additional commits → Verify preview updates
- Create PR with only README changes → Verify no deployment
- Close PR → Verify cleanup removes directory
Validation Points:
- Preview URL returns 200 status
- Report content reflects PR branch data
- Sticky comment appears on PR
- Preview directory removed after close
- Related Issue: #110
- Deployment Action: peaceiris/actions-gh-pages
- Comment Action: marocchino/sticky-pull-request-comment
- Related Workflow:
.github/workflows/static.yml(main branch deployment) - GitHub Pages: https://intersectmbo.github.io/UPLC-CAPE/