|
| 1 | +# Composite Actions — Rules & Conventions |
| 2 | + |
| 3 | +Use these rules whenever creating or editing a composite action in `src/`. |
| 4 | + |
| 5 | +## Before you create anything |
| 6 | + |
| 7 | +**Step 1 — Check if it already exists in this repo** |
| 8 | + |
| 9 | +Search `src/` before starting. If a composite already covers the same capability: |
| 10 | + |
| 11 | +- Summarize what the existing composite does and which inputs it exposes |
| 12 | +- Identify the gap between the existing behavior and the new requirement |
| 13 | +- Propose an **adaptation plan** (add an input, extend steps, split into two) instead of creating a new file |
| 14 | + |
| 15 | +**Step 2 — Check the GitHub Actions Marketplace first** |
| 16 | + |
| 17 | +Before writing custom steps from scratch, search the [Marketplace](https://github.com/marketplace?type=actions) for an existing action that covers the need: |
| 18 | + |
| 19 | +- Prefer a well-maintained marketplace action over custom shell scripting for non-trivial logic |
| 20 | +- Wrap it in a composite if it needs input normalization or additional steps |
| 21 | +- Pin to a specific tag or SHA — never `@main` or `@master` |
| 22 | +- Document in the composite `README.md` why that action was chosen |
| 23 | + |
| 24 | +Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements. |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## Directory layout |
| 29 | + |
| 30 | +Composite actions are grouped by capability inside `src/`: |
| 31 | + |
| 32 | +``` |
| 33 | +src/ |
| 34 | +├── setup/ ← language runtime setup (Go, Node, etc.) |
| 35 | +├── build/ ← build and artifact generation |
| 36 | +├── test/ ← test execution and coverage |
| 37 | +├── deploy/ ← deployment and release steps |
| 38 | +└── config/ ← repository configuration management |
| 39 | +``` |
| 40 | + |
| 41 | +Each composite lives in `src/<capability>/<name>/` with exactly two files: |
| 42 | + |
| 43 | +``` |
| 44 | +src/config/labels-sync/ |
| 45 | +├── action.yml ← required |
| 46 | +└── README.md ← required |
| 47 | +``` |
| 48 | + |
| 49 | +## action.yml structure |
| 50 | + |
| 51 | +```yaml |
| 52 | +name: Human-readable name |
| 53 | +description: One-line description. |
| 54 | + |
| 55 | +inputs: |
| 56 | + github-token: |
| 57 | + description: GitHub token with required permissions |
| 58 | + required: true |
| 59 | + some-option: |
| 60 | + description: What this option controls |
| 61 | + required: false |
| 62 | + default: "default-value" |
| 63 | + |
| 64 | +runs: |
| 65 | + using: composite |
| 66 | + steps: |
| 67 | + - name: Checkout |
| 68 | + uses: actions/checkout@v4 |
| 69 | + - name: Do the work |
| 70 | + uses: some-owner/some-action@v1 |
| 71 | + with: |
| 72 | + token: ${{ inputs.github-token }} |
| 73 | + option: ${{ inputs.some-option }} |
| 74 | +``` |
| 75 | +
|
| 76 | +## Design rules |
| 77 | +
|
| 78 | +- **5–15 steps maximum** — split if larger |
| 79 | +- **Single responsibility** — one composite, one capability |
| 80 | +- Must not define jobs or call other workflows |
| 81 | +- Must not contain pipeline control logic |
| 82 | +- Never combine multiple language runtimes in the same composite |
| 83 | +
|
| 84 | +## Language-specific vs cross-language |
| 85 | +
|
| 86 | +Specialize by runtime when toolchains differ: |
| 87 | +
|
| 88 | +``` |
| 89 | +src/setup/setup-go/ ← Go toolchain, GOPATH, module cache |
| 90 | +src/setup/setup-node/ ← Node.js, npm/yarn/pnpm, cache |
| 91 | +src/build/build-go/ ← go build, cross-compilation |
| 92 | +src/test/test-go/ ← go test, coverage upload |
| 93 | +``` |
| 94 | + |
| 95 | +Cross-language composites stay language-agnostic: |
| 96 | + |
| 97 | +``` |
| 98 | +src/build/docker-build/ ← any image |
| 99 | +src/deploy/helm-deploy/ ← any chart |
| 100 | +src/config/labels-sync/ ← any repo |
| 101 | +``` |
| 102 | + |
| 103 | +## README.md requirements |
| 104 | + |
| 105 | +1. Logo header — HTML table layout (logo left, `h1` title right) |
| 106 | +2. Inputs table — `Input | Description | Required | Default` |
| 107 | +3. Usage as composite step (full YAML) |
| 108 | +4. Usage as reusable workflow (full YAML with `secrets: inherit`) |
| 109 | +5. Required permissions block |
| 110 | + |
| 111 | +### Usage example ref policy |
| 112 | + |
| 113 | +Examples in README.md must never use `@main`. Use the correct ref for each context: |
| 114 | + |
| 115 | +```yaml |
| 116 | +# ✅ Testing — point to develop or feature branch |
| 117 | +uses: LerianStudio/github-actions-shared-workflows/.github/workflows/labels-sync.yml@develop |
| 118 | +uses: LerianStudio/github-actions-shared-workflows/.github/workflows/labels-sync.yml@feat/my-branch |
| 119 | + |
| 120 | +# ✅ Production — always a pinned stable version |
| 121 | +uses: LerianStudio/github-actions-shared-workflows/.github/workflows/labels-sync.yml@v1.2.3 |
| 122 | + |
| 123 | +# ❌ Never in examples |
| 124 | +uses: LerianStudio/github-actions-shared-workflows/.github/workflows/labels-sync.yml@main |
| 125 | +``` |
| 126 | +
|
| 127 | +## After creating a new composite |
| 128 | +
|
| 129 | +- Update root `README.md` if the composite is meant to be used by external callers |
| 130 | + |
| 131 | +### Labels checklist |
| 132 | + |
| 133 | +Check `.github/labels.yml` for a label matching the composite's capability group. If it doesn't exist, add it: |
| 134 | + |
| 135 | +```yaml |
| 136 | +- name: <capability> # e.g. "infrastructure", "notifications" |
| 137 | + color: "0075ca" # pick a distinct hex color |
| 138 | + description: Changes to <capability> composite actions |
| 139 | +``` |
| 140 | + |
| 141 | +After adding, run the `Sync Labels` workflow (`workflow_dispatch`) to create it in the repository. |
| 142 | + |
| 143 | +### Dependabot checklist |
| 144 | + |
| 145 | +For every third-party action used in the new composite (`uses: owner/action@vX`), check `.github/dependabot.yml`: |
| 146 | + |
| 147 | +- If `owner/*` already matches an existing group → no change needed |
| 148 | +- If not → add to the most appropriate group, or create a new one: |
| 149 | + |
| 150 | +```yaml |
| 151 | +new-tool-category: |
| 152 | + patterns: |
| 153 | + - "owner/new-action" |
| 154 | + update-types: |
| 155 | + - "minor" |
| 156 | + - "patch" |
| 157 | +``` |
| 158 | + |
| 159 | +Never add `LerianStudio/*` actions to dependabot — pinned to `@main` intentionally. |
0 commit comments