brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
github-actionsUse this skill when the user says 'GitHub Actions', 'CI/CD', 'workflow', 'reusable workflow', 'composite action', 'matrix build', 'actions/checkout', 'GITHUB_TOKEN', 'self-hosted runner', or when setting up CI/CD pipelines on GitHub. Covers: workflow files, reusable workflows, composite actions, matrix strategies, expressions, environments, artifacts, cachi…
Independent GitHub snapshot · Automated classification · Original documentation governs
Define CI/CD pipelines using GitHub Actions workflows, reusable workflows, and composite actions.
Exact user phrases: "GitHub Actions", "CI/CD", "workflow", "reusable workflow", "composite action", "matrix build", "actions/checkout", "GITHUB_TOKEN", "self-hosted runner".
Writes to .github/workflows/.yml, action.yml, and/or .github/actions//action.yml.
YAML workflow file with no extraneous explanation.
No preamble. No postamble. No explanations. No filler/hedging/transitions.
| Complexity | Approach | Best For |
|---|---|---|
| Simple, single job | Single workflow file | Small projects, one build |
| Multi-job with dependencies | Stages with needs | Medium projects, build-test-deploy |
| Shared across repos | Reusable workflows | Org-wide CI standardization |
| Custom step logic | Composite actions | Encapsulated multi-step setup |
| Complex matrix | Strategy matrix + include/exclude | Multi-version, multi-OS testing |
| Monorepo | Path filters + matrix | Multi-package monorepo |
| Runner Type | Maintenance | Network | Security | Cost |
|---|---|---|---|---|
| GitHub-hosted | None | Public internet | Ephemeral, isolated | Included in plan |
| Self-hosted (Linux) | Team manages | Corporate network | Persistent, needs hardening | Free (no GH billing) |
| Self-hosted (Windows) | Team manages | Corporate network | Persistent, needs hardening | Free (no GH billing) |
| Auto-scaling self-hosted | Complex setup | Corporate network | Ephemeral options | Free + infra cost |
| Larger runners | None | Public internet | Ephemeral | Pay per minute |
| Trigger | Typical Use | Notes |
|---|---|---|
| push (branches) | CI on merge to main | Build + test + deploy |
| pull_request | CI on PR | Build + test only |
| workflow_dispatch | Manual trigger | Deploy, maintenance, custom |
| schedule (cron) | Nightly builds | Security scan, dependency update |
| release | Package publishing | Create release artifacts |
| workflow_call | Reusable workflow | Called by other workflows |
| repository_dispatch | External trigger | Webhook from external systems |
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "22"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- run: npm ci
- run: npm test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: test-results-${{ matrix.os }}-${{ matrix.node-version }}
path: test-results/
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
node-version:
required: true
type: string
description: "Node.js version to use"
build-command:
required: false
type: string
default: "npm run build"
description: "Build command"
secrets:
NPM_TOKEN:
required: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
registry-url: "https://npm.pkg.github.com"
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: ${{ inputs.build-command }}
- run: npm test
# Calling workflow
name: CI
on: [pull_request]
jobs:
test-node-20:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: "20"
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
test-node-22:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: "22"
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# .github/actions/setup-project/action.yml
name: "Setup Project"
description: "Checkout, install deps, cache, and build"
inputs:
node-version:
description: "Node.js version"
required: false
default: "22"
install-command:
description: "Dependency install command"
required: false
default: "npm ci"
build-command:
description: "Build command"
required: false
default: "npm run build"
runs:
using: "composite"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: "npm"
- name: Install dependencies
run: ${{ inputs.install-command }}
shell: bash
- name: Build project
run: ${{ inputs.build-command }}
shell: bash
- name: Cache build output
uses: actions/cache@v4
with:
path: dist/
key: build-${{ github.sha }}
# Using the composite action
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: ./.github/actions/setup-project
with:
node-version: "22"
build-command: "npm run build:prod"
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
exclude:
- os: macos-latest
node: 18
include:
- os: ubuntu-latest
node: 22
experimental: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental || false }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
name: Deploy
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- run: ./deploy-staging.sh
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: us-east-1
- run: npm ci
- run: npm run build
- run: ./deploy-prod.sh
jobs:
build:
steps:
- uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
restore-keys: |
pip-${{ runner.os }}-
steps:
- name: Conditional step on event
if: github.event_name == 'pull_request' && github.event.pull_request.draft == false
run: npm test
- name: Skip if docs only
if: contains(github.event.head_commit.message, '[skip ci]')
run: echo "Skipping CI"
- name: Conditional on failure
if: failure()
run: echo "Previous step failed"
- name: Conditional on success
if: success()
run: echo "All steps passed"
- name: Deploy based on branch
if: github.ref_name == 'main' || startsWith(github.ref_name, 'release/')
run: npm run deploy
- name: Always run even on failure
if: always()
uses: actions/upload-artifact@v4
with:
name: logs
path: logs/
name: CI on Self-Hosted
on: [push]
jobs:
build:
runs-on: [self-hosted, linux, x64, gpu]
steps:
- uses: actions/checkout@v4
- run: nvidia-smi
- run: docker build -t app .
- run: docker run --gpus all app pytest
Writing secrets directly in workflow files exposes them in git history and to anyone with repo access. Always use secrets.X or OIDC for cloud authentication.
Using @main or @v1 for actions means the action can change without notice, breaking CI or introducing supply chain attacks. Pin to SHA or full semver tag.
Without caching, CI pipelines reinstall all dependencies on every run, adding 1-5 minutes per job. Always configure actions/cache or use setup-action cache parameter.
Putting everything in one workflow file makes it hard to maintain and debug. Split into multiple workflows by purpose (ci.yml, deploy.yml, security.yml).
Using a single OS/node version misses compatibility issues. Use matrix strategy for multi-version and multi-OS testing.
Running deploy before tests complete can deploy broken code. Use needs to define job dependencies. Test must complete before deploy starts.
When tests fail, test results are not available for debugging. Always use if: failure() or if: always() with upload-artifact.
GitHub Actions: GitHub-native, marketplace, tight integration, free for public repos. GitLab CI: single app for code + CI, auto DevOps, built-in registry. CircleCI: fast, parallel by default, powerful caching, orbs. Choose based on where your code lives.
Reusable workflows: call another workflow file, support secrets and matrix, good for multi-job patterns. Composite actions: encapsulate steps for reuse within a job, support inputs, good for setup logic. Use reusable workflows for multi-job pipelines, composite actions for setup sequences.
After completing this skill:
| Decision | Composite Action | Reusable Workflow |
|---|---|---|
| Scope | Single job (multi-step) | Full workflow (multi-job) |
| Call context | Same workflow, step level | Separate workflow call |
| Input/Output | inputs, outputs | workflow_call inputs, secrets |
| Use case | Shared step logic (build, test) | Shared pipeline (deploy, release) |
| Versioning | Branch/commit SHA | Branch/tag in uses |
| Debugging | Step inside caller's workflow | Separate run, harder to trace |
| Aspect | GitHub-hosted | Self-hosted |
|---|---|---|
| Maintenance | Zero (GitHub managed) | Team maintains patching |
| Scale | Auto-scales | Fixed capacity |
| Network | Public internet | VPC, private access |
| Cost | Included in plan minutes | Compute cost only |
| Customization | Limited OS/images | Any OS, any tooling |
| Security | Ephemeral (clean slate) | Persistent, needs hardening |
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run test -- --coverage
- uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.node-version }}
path: coverage/
build-and-push:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
environment: production
steps:
- run: |
echo "Deploying ${{ github.sha }} to production"
#!/usr/bin/env bash
trigger_workflow() {
local repo=$1
local workflow=$2
local branch=$3
local payload=$4
gh workflow run "$workflow" \
--repo "$repo" \
--ref "$branch" \
--json "$payload"
}
verify_run() {
local run_id
run_id=$(gh run list --repo "$1" --limit 1 --json databaseId --jq '.[0].databaseId')
gh run watch "$run_id" --repo "$1" --exit-status
}
GITHUB_TOKEN with excessive permissions — scope permissions: per jobuses: actions/checkout v no @v4) — breaks on major updatesrestore-keys to fall back to previous cache if exact match not founddocker/build-push-action cache-from and cache-to layersstrategy.fail-fast: false for full resultspaths-ignore) to skip CI for documentation-only changesactions/cache or actions/setup-* restore featurespermissions: block instead of default broad accesspull_request_target only with safe checkout patterns