| name | github-actions |
| description | Author and maintain GitHub Actions workflows for CI/CD pipelines. Use when creating new workflows, modifying ci.yml, adding workflow jobs, configuring matrix builds, setting up caching, managing secrets, writing workflow_run triggers, creating release pipelines, or debugging GitHub Actions issues. Covers CI, benchmarking, release, and documentation workflows for cqlsh-rs. |
GitHub Actions Workflow Authoring
Author, maintain, and debug GitHub Actions workflows for the cqlsh-rs project. All workflows live in .github/workflows/.
Before Starting
- Read the existing CI workflow:
.github/workflows/ci.yml
- Check related plans for workflow requirements:
docs/plans/10-testing-strategy.md — CI matrix design
docs/plans/11-benchmarking.md — Benchmark workflow (bench.yml)
docs/plans/12-cross-platform-release.md — Release workflow (release.yml)
docs/plans/14-documentation.md — Docs workflow (docs.yml)
docs/plans/15-ai-ci-failure-summaries.md — Failure analysis workflow
Planned Workflows
| Workflow | File | Trigger | Status |
|---|
| CI | ci.yml | push to main, PRs | Implemented |
| CI Failure Analysis | ci-failure-analysis.yml | workflow_run (CI failed) | Planned (SP15) |
| Benchmarks | bench.yml | push to main, PR label, weekly | Planned (SP11) |
| Release | release.yml | tag push (v*) | Planned (SP12) |
| Documentation | docs.yml | push to main (docs/**) | Planned (SP14) |
Workflow Conventions
Standard Job Structure
Every job should follow this pattern:
jobs:
job-name:
name: Human-Readable Name
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- run: cargo <command>
Caching
Always use Swatinem/rust-cache@v2 for Cargo build caching. It caches:
~/.cargo/registry
~/.cargo/git
target/
For custom cache keys (e.g., nextest binary):
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
key: nextest
Environment Variables
Set project-wide env vars at the workflow level:
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
Permissions
Follow the principle of least privilege. Common patterns:
permissions:
contents: read
permissions:
contents: read
pull-requests: write
actions: read
permissions:
contents: write
id-token: write
Secrets Management
| Secret | Scope | Purpose |
|---|
GITHUB_TOKEN | Auto-provided | GitHub API access |
ANTHROPIC_API_KEY | Repository | Claude API for failure analysis |
CARGO_REGISTRY_TOKEN | Repository | crates.io publishing (future) |
Never hardcode secrets. Use ${{ secrets.SECRET_NAME }} syntax.
Trigger Patterns
Standard CI (every push/PR)
on:
push:
branches: [main]
pull_request:
branches: [main]
Post-CI Analysis (workflow_run)
on:
workflow_run:
workflows: ["CI"]
types: [completed]
Access the triggering run's data via github.event.workflow_run.*.
Conditional Execution
if: github.event.workflow_run.conclusion == 'failure'
if: github.event.workflow_run.event == 'pull_request'
if: startsWith(github.ref, 'refs/tags/v')
on:
push:
paths:
- "src/**"
- "Cargo.toml"
- "Cargo.lock"
Matrix Builds
For cross-platform or multi-version testing:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, beta]
db: [cassandra:4.0, cassandra:5.0, scylladb/scylla:6.0]
exclude:
- os: windows-latest
db: cassandra:4.0
Rust-Specific Patterns
Installing cargo-nextest
- uses: taiki-e/install-action@nextest
- run: cargo nextest run --all-targets --all-features
JUnit XML Output (for test reporting)
- run: cargo nextest run --message-format junit --output-file test-results.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: test-results.xml
Release Build with Optimizations
- run: cargo build --release
env:
CARGO_PROFILE_RELEASE_LTO: thin
CARGO_PROFILE_RELEASE_STRIP: true
Cross-Compilation
- uses: cross-rs/cross-action@v1
with:
command: build
target: aarch64-unknown-linux-musl
args: --release
Artifact Patterns
Upload/Download Within Same Workflow
- uses: actions/upload-artifact@v4
with:
name: artifact-name
path: path/to/file
retention-days: 30
- uses: actions/download-artifact@v4
with:
name: artifact-name
Cross-Workflow Artifact Access
For workflow_run triggered workflows accessing artifacts from the triggering run:
- uses: actions/download-artifact@v4
with:
name: test-results
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
PR Comments from Workflows
Using actions/github-script
- uses: actions/github-script@v7
with:
script: |
// Find existing comment to update (deduplication)
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const existing = comments.data.find(c =>
c.user.type === 'Bot' && c.body.includes('<!-- marker -->')
);
const body = `<!-- marker -->\n## Title\n${content}`;
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body
});
}
Collapsible Sections
<details>
<summary>Section Title (click to expand)</summary>
Content here — leave a blank line after `</summary>`.
</details>
Debugging Workflows
Common Issues
| Issue | Cause | Fix |
|---|
Permission denied on PR comment | Missing pull-requests: write | Add to permissions: block |
workflow_run doesn't trigger | Workflow name mismatch | Ensure workflows: ["CI"] matches exactly |
| Artifacts not found cross-workflow | Wrong run-id | Use ${{ github.event.workflow_run.id }} |
| Cache miss every run | Different keys per job | Use shared Swatinem/rust-cache@v2 config |
| Slow CI (>15 min) | No caching, no parallelism | Add rust-cache, split into parallel jobs |
Viewing Logs
gh run view <run-id> --log-failed
gh run list --workflow ci.yml --limit 5
gh run rerun <run-id> --failed
Validation Checklist
Before merging workflow changes: