gha-pipelines
npx skills add https://github.com/ionfury/homelab --skill gha-pipelines
Agent 安装分布
Skill 文档
GitHub Actions Pipelines
Established Patterns
This repository uses a small set of consistent patterns across all workflows. Follow these when creating or modifying workflows.
Tool Setup
All workflows use mise for tool version management, ensuring CI and local dev use identical versions:
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3 # Installs tools at versions from .mise.toml
- run: task k8s:validate # Use Taskfile commands, not raw CLI
Prefer Off-the-Shelf Actions
Use established actions over custom scripts:
| Need | Action | Notes |
|---|---|---|
| Checkout | actions/checkout@v6 |
Always pin major version |
| Tool setup | jdx/mise-action@v3 |
Reads .mise.toml |
| GHCR login | docker/login-action@v3 |
Use GITHUB_TOKEN |
| Complex logic | actions/github-script@v7 |
Prefer over raw bash for GitHub API |
| Flux CLI | fluxcd/flux2/action@v2 |
For OCI artifact operations |
Use github-script Over Raw Bash
For anything involving GitHub API calls, JSON parsing, or conditional logic, prefer actions/github-script over shell scripts:
- name: Discover clusters
id: discover
uses: actions/github-script@v7
with:
script: |
// Use the GitHub API client directly
const versions = await github.rest.packages.getAllPackageVersionsForPackageOwnedByUser({
package_type: 'container',
package_name: packageName,
username: context.repo.owner,
});
core.setOutput('result', JSON.stringify(data));
Dynamic Matrix Builds
For per-cluster or per-module validation, use a discovery job followed by matrix expansion:
jobs:
discover:
outputs:
items: ${{ steps.find.outputs.items }}
steps:
- id: find
uses: actions/github-script@v7
with:
script: |
// Discover items dynamically
core.setOutput('items', JSON.stringify(items));
validate:
needs: discover
strategy:
fail-fast: false
matrix:
item: ${{ fromJson(needs.discover.outputs.items) }}
steps:
- run: task validate-${{ matrix.item }}
Path-Based Triggers
Workflows only run when relevant files change:
on:
pull_request:
paths:
- "kubernetes/**" # Domain files
- ".github/workflows/kubernetes-validate.yaml" # The workflow itself
- ".mise.toml" # Tool versions
- ".taskfiles/kubernetes/**" # Task definitions
workflow_dispatch: # Manual trigger
Always include workflow_dispatch for manual runs.
YAML Schema Validation
All workflow files should include the schema comment for IDE validation:
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: My Workflow
Workflow Inventory
| Workflow | Trigger | Purpose |
|---|---|---|
kubernetes-validate.yaml |
PR (kubernetes/) | Lint, expand ResourceSets, build, template, kubeconform, pluto |
infrastructure-validate.yaml |
PR (infrastructure/) | Format checks, module tests (matrix per module) |
renovate-validate.yaml |
PR (renovate config) | Validate Renovate configuration |
build-platform-artifact.yaml |
Push to main (kubernetes/) | Build OCI artifact, tag for integration |
tag-validated-artifact.yaml |
Status event / manual | Promote validated artifact to stable semver |
renovate.yaml |
Scheduled (hourly) | Dependency update automation |
label-sync.yaml |
Scheduled / manual | Sync GitHub labels |
OCI Promotion Pipeline
The promotion pipeline is the most complex workflow chain. Understand the full flow before modifying any part:
PR merged to main (kubernetes/ changes)
-> build-platform-artifact.yaml
-> flux push artifact :X.Y.Z-rc.N
-> flux tag :sha-<short> and :integration-<short>
-> Integration cluster polls OCIRepository (semver >= 0.0.0-0, accepts RCs)
-> Flux reconciles, posts commit status on success
-> tag-validated-artifact.yaml (triggered by status event)
-> Idempotency check (skip if already validated)
-> flux tag :validated-<short> and :X.Y.Z (stable)
-> Live cluster polls OCIRepository (semver >= 0.0.0, stable only)
Key Design Decisions
- Semver-based polling: Integration accepts pre-releases (
-rc.N), live accepts stable only - Idempotency guard:
tag-validated-artifactchecks for existingvalidated-*tag before re-tagging (Flux Alerts fire on every reconciliation cycle) - Version resolution via GHCR API: Build workflow queries GHCR for latest stable tag, bumps patch, creates next RC
Permissions
permissions:
contents: read # For checkout
packages: write # For GHCR push/tag
statuses: read # For reading commit status events
Always use minimal permissions. Never use permissions: write-all.
Creating a New Validation Workflow
Step-by-Step
- Create
.github/workflows/<domain>-validate.yaml - Add YAML schema comment
- Set path-based triggers including the workflow file itself
- Use
jdx/mise-action@v3for tool setup - Delegate to Taskfile commands (not raw CLI)
- Add matrix builds for per-item validation if applicable
- Run
task k8s:validatelocally to verify the validation commands work
Template
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: <Domain> Validate
on:
pull_request:
paths:
- "<domain>/**"
- ".github/workflows/<domain>-validate.yaml"
- ".mise.toml"
workflow_dispatch:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: task <domain>:validate
Anti-Patterns
- NEVER install tools with
apt-getorbrewin CI â usemise - NEVER use raw
curl/jqfor GitHub API â useactions/github-script - NEVER hardcode versions in workflow files â versions come from
.mise.tomlorversions.env - NEVER use
permissions: write-allâ specify exact permissions needed - NEVER skip
workflow_dispatchâ all workflows should support manual runs
Cross-References
- .github/CLAUDE.md â Declarative knowledge about workflow architecture
- promotion-pipeline skill â Debugging promotion failures
- .taskfiles/CLAUDE.md â Task commands used in workflows