@hybridlabor-api/aos 4.7.2 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents.md +1 -1
- package/.agents/nodes.json +1 -1
- package/.agents/vendor-manifest.json +23 -1
- package/.claude/agents/godmode-media-eventtech.md +1 -1
- package/.claude/hooks/conventional-commits.mjs +125 -0
- package/.claude/hooks/env-file-protection.mjs +105 -0
- package/.claude/hooks/go-gate.mjs +101 -81
- package/.claude/settings.json +13 -0
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/docs/skills_table.md +1 -1
- package/installer.js +309 -101
- package/package.json +6 -2
- package/packages/aos-cli/README.md +80 -0
- package/packages/aos-cli/bin/aos-cli.mjs +134 -0
- package/packages/aos-cli/core-skills.json +12 -0
- package/packages/aos-cli/extensions/aos.ts +321 -0
- package/packages/aos-cli/package-lock.json +1923 -0
- package/packages/aos-cli/package.json +29 -0
- package/packages/aos-cli/scripts/check-theme.mjs +63 -0
- package/packages/aos-cli/themes/aos.json +97 -0
- package/scripts/build-plugin-manifest.mjs +131 -0
- package/scripts/validate-skills.mjs +81 -6
- package/skills/basic/ao-orchestrator/SKILL.md +116 -0
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/ask-tim/SKILL.md +4 -4
- package/skills/global_config/bash-script-generator/SKILL.md +201 -0
- package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
- package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
- package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
- package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
- package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
- package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
- package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
- package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
- package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
- package/skills/global_config/bash-script-validator/SKILL.md +249 -0
- package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
- package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
- package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
- package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
- package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
- package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
- package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
- package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
- package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
- package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
- package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
- package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
- package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
- package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
- package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
- package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
- package/skills/global_config/ci-pipeline/SKILL.md +135 -0
- package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
- package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
- package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
- package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
- package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
- package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
- package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
- package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
- package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
- package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
- package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
- package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
- package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
- package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
- package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
- package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
- package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
- package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
- package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
- package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
- package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
- package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
- package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
- package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
- package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
- package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
- package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
- package/skills/global_config/github-actions-generator/SKILL.md +353 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
- package/skills/global_config/github-actions-generator/examples/README.md +147 -0
- package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
- package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
- package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
- package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
- package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
- package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
- package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
- package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
- package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
- package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
- package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
- package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
- package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
- package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
- package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
- package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
- package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
- package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
- package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
- package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
- package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
- package/skills/global_config/github-actions-templates/SKILL.md +7 -0
- package/skills/global_config/github-actions-validator/SKILL.md +576 -0
- package/skills/global_config/github-actions-validator/examples/README.md +88 -0
- package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
- package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
- package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
- package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
- package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
- package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
- package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
- package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
- package/skills/global_config/github-actions-validator/references/runners.md +317 -0
- package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
- package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
- package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
- package/skills/global_config/makefile-generator/SKILL.md +614 -0
- package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
- package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
- package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
- package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
- package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
- package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
- package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
- package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
- package/skills/global_config/makefile-validator/SKILL.md +244 -0
- package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
- package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
- package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
- package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
- package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
- package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
- package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
- package/skills/global_config/{MCP_Manage → mcp-manage}/SKILL.md +3 -3
- package/skills/global_config/requesting-code-review/SKILL.md +98 -0
- package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
- package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
- package/skills/global_config/verification-before-completion/SKILL.md +123 -0
- package/skills/global_config/writing-plans/SKILL.md +126 -46
- package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
# GitHub Actions Best Practices
|
|
2
|
+
|
|
3
|
+
**Last Updated:** November 2025
|
|
4
|
+
**Based on:** Official GitHub Actions documentation and Context7 verified sources
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
1. [Security Best Practices](#security-best-practices)
|
|
8
|
+
2. [Performance Optimization](#performance-optimization)
|
|
9
|
+
3. [Workflow Design](#workflow-design)
|
|
10
|
+
4. [Action Selection and Versioning](#action-selection-and-versioning)
|
|
11
|
+
5. [Error Handling](#error-handling)
|
|
12
|
+
6. [Maintainability](#maintainability)
|
|
13
|
+
7. [Common Patterns](#common-patterns)
|
|
14
|
+
8. [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
|
|
15
|
+
|
|
16
|
+
## Security Best Practices
|
|
17
|
+
|
|
18
|
+
### 1. Pin Actions to Full SHA (Critical Security Practice)
|
|
19
|
+
|
|
20
|
+
**Best Practice:**
|
|
21
|
+
```yaml
|
|
22
|
+
# ✅ BEST: Pinned to specific full SHA (40 characters) with version comment
|
|
23
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Why:**
|
|
27
|
+
- Immutable: SHA cannot be changed, preventing supply chain attacks
|
|
28
|
+
- Reproducible: Same code runs every time
|
|
29
|
+
- Verifiable: Can audit exact code being executed
|
|
30
|
+
|
|
31
|
+
**Acceptable Alternative:**
|
|
32
|
+
```yaml
|
|
33
|
+
# ✅ ACCEPTABLE: Major version tag (for official GitHub actions)
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Avoid:**
|
|
38
|
+
```yaml
|
|
39
|
+
# ❌ BAD: Mutable references
|
|
40
|
+
- uses: actions/checkout@main
|
|
41
|
+
- uses: actions/checkout@master
|
|
42
|
+
- uses: actions/checkout@latest
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Minimal Permissions
|
|
46
|
+
|
|
47
|
+
**Best Practice:**
|
|
48
|
+
```yaml
|
|
49
|
+
# Top-level: Set default to read-only
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
|
|
53
|
+
jobs:
|
|
54
|
+
build:
|
|
55
|
+
# Job-level: Grant only necessary permissions
|
|
56
|
+
permissions:
|
|
57
|
+
contents: read
|
|
58
|
+
packages: write
|
|
59
|
+
pull-requests: write
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Common Permission Scopes:**
|
|
63
|
+
- `contents`: Repository contents (read/write)
|
|
64
|
+
- `packages`: GitHub Packages (read/write)
|
|
65
|
+
- `pull-requests`: PR comments and labels (read/write)
|
|
66
|
+
- `issues`: Issue management (read/write)
|
|
67
|
+
- `statuses`: Commit statuses (write)
|
|
68
|
+
- `checks`: Check runs (write)
|
|
69
|
+
- `deployments`: Deployment status (write)
|
|
70
|
+
|
|
71
|
+
### 3. Secrets Management
|
|
72
|
+
|
|
73
|
+
**Best Practice:**
|
|
74
|
+
```yaml
|
|
75
|
+
# ✅ GOOD: Use secrets properly
|
|
76
|
+
- name: Deploy to production
|
|
77
|
+
env:
|
|
78
|
+
API_KEY: ${{ secrets.API_KEY }}
|
|
79
|
+
run: |
|
|
80
|
+
echo "::add-mask::$API_KEY"
|
|
81
|
+
./deploy.sh
|
|
82
|
+
|
|
83
|
+
# ✅ GOOD: Pass secrets to actions
|
|
84
|
+
- uses: aws-actions/configure-aws-credentials@v4
|
|
85
|
+
with:
|
|
86
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
87
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Avoid:**
|
|
91
|
+
```yaml
|
|
92
|
+
# ❌ BAD: Exposing secrets
|
|
93
|
+
- run: echo "API_KEY=${{ secrets.API_KEY }}"
|
|
94
|
+
|
|
95
|
+
# ❌ BAD: Using secrets in URLs
|
|
96
|
+
- run: git clone https://${{ secrets.GITHUB_TOKEN }}@github.com/user/repo.git
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Input Validation and Injection Prevention
|
|
100
|
+
|
|
101
|
+
**Critical Security Issue:** Script injection through untrusted input is one of the most common security vulnerabilities in GitHub Actions.
|
|
102
|
+
|
|
103
|
+
**Best Practice - Use Environment Variables:**
|
|
104
|
+
```yaml
|
|
105
|
+
# ✅ BEST: Always use environment variables for untrusted input (Bash)
|
|
106
|
+
- name: Check PR title
|
|
107
|
+
env:
|
|
108
|
+
TITLE: ${{ github.event.pull_request.title }}
|
|
109
|
+
run: |
|
|
110
|
+
if [[ "$TITLE" =~ ^octocat ]]; then
|
|
111
|
+
echo "PR title starts with 'octocat'"
|
|
112
|
+
exit 0
|
|
113
|
+
else
|
|
114
|
+
echo "PR title did not start with 'octocat'"
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# ✅ BEST: Validate inputs with strict patterns
|
|
119
|
+
- name: Build image
|
|
120
|
+
env:
|
|
121
|
+
IMAGE_NAME: ${{ github.event.inputs.image-name }}
|
|
122
|
+
run: |
|
|
123
|
+
if [[ ! "$IMAGE_NAME" =~ ^[a-z0-9-]+$ ]]; then
|
|
124
|
+
echo "::error::Invalid image name"
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
docker build -t "$IMAGE_NAME" .
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Alternative - Use JavaScript Action:**
|
|
131
|
+
```yaml
|
|
132
|
+
# ✅ GOOD: Create a JavaScript action to process context values
|
|
133
|
+
- uses: fakeaction/checktitle@v3
|
|
134
|
+
with:
|
|
135
|
+
title: ${{ github.event.pull_request.title }}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Avoid:**
|
|
139
|
+
```yaml
|
|
140
|
+
# ❌ BAD: Direct interpolation of user input (vulnerable to injection)
|
|
141
|
+
- run: echo "PR: ${{ github.event.pull_request.title }}"
|
|
142
|
+
- run: docker build -t ${{ github.event.inputs.tag }} .
|
|
143
|
+
- run: echo "${{ github.event.pull_request.title }}" | grep "fix"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 5. Dependency Review and SBOM Attestations (New in 2025)
|
|
147
|
+
|
|
148
|
+
**Dependency Review Action:**
|
|
149
|
+
```yaml
|
|
150
|
+
name: Dependency Review
|
|
151
|
+
on:
|
|
152
|
+
pull_request:
|
|
153
|
+
paths-ignore:
|
|
154
|
+
- "README.md"
|
|
155
|
+
|
|
156
|
+
permissions:
|
|
157
|
+
contents: read
|
|
158
|
+
|
|
159
|
+
jobs:
|
|
160
|
+
dependency-review:
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
steps:
|
|
163
|
+
- name: Checkout code
|
|
164
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
165
|
+
|
|
166
|
+
- name: Dependency Review
|
|
167
|
+
uses: actions/dependency-review-action@v4
|
|
168
|
+
with:
|
|
169
|
+
# Fail on critical vulnerabilities
|
|
170
|
+
fail-on-severity: critical
|
|
171
|
+
# Allow specific dependencies
|
|
172
|
+
allow-licenses: MIT, Apache-2.0, BSD-3-Clause
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**SBOM Attestations for Container Images:**
|
|
176
|
+
```yaml
|
|
177
|
+
permissions:
|
|
178
|
+
id-token: write
|
|
179
|
+
contents: read
|
|
180
|
+
attestations: write
|
|
181
|
+
packages: write
|
|
182
|
+
|
|
183
|
+
steps:
|
|
184
|
+
- name: Build container image
|
|
185
|
+
run: docker build -t ${{ env.REGISTRY }}/myapp:${{ github.sha }} .
|
|
186
|
+
|
|
187
|
+
- name: Generate SBOM
|
|
188
|
+
uses: anchore/sbom-action@v0
|
|
189
|
+
with:
|
|
190
|
+
image: ${{ env.REGISTRY }}/myapp:${{ github.sha }}
|
|
191
|
+
format: spdx-json
|
|
192
|
+
output-file: sbom.json
|
|
193
|
+
|
|
194
|
+
- name: Generate SBOM attestation
|
|
195
|
+
uses: actions/attest-sbom@v2
|
|
196
|
+
with:
|
|
197
|
+
subject-name: ${{ env.REGISTRY }}/myapp
|
|
198
|
+
subject-digest: sha256:${{ steps.build.outputs.digest }}
|
|
199
|
+
sbom-path: sbom.json
|
|
200
|
+
push-to-registry: true
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Performance Optimization
|
|
204
|
+
|
|
205
|
+
### 1. Dependency Caching (Updated November 2025)
|
|
206
|
+
|
|
207
|
+
**Important:** actions/cache v5.0.3 is recommended (Node 24 runtime). The cache service was rewritten for improved performance in 2025. Legacy cache service was sunset on February 1, 2025.
|
|
208
|
+
|
|
209
|
+
**Cache Size Limits (New):** As of November 2025, repositories can exceed the previous 10 GB cache limit using a pay-as-you-go model. All repositories receive 10 GB free, with additional storage available.
|
|
210
|
+
|
|
211
|
+
**NPM/Node.js with Built-in Caching:**
|
|
212
|
+
```yaml
|
|
213
|
+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
214
|
+
with:
|
|
215
|
+
node-version: '24'
|
|
216
|
+
cache: 'npm'
|
|
217
|
+
cache-dependency-path: '**/package-lock.json'
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Manual Caching with actions/cache@v5:**
|
|
221
|
+
```yaml
|
|
222
|
+
- name: Cache node modules
|
|
223
|
+
id: cache-npm
|
|
224
|
+
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
|
225
|
+
env:
|
|
226
|
+
cache-name: cache-node-modules
|
|
227
|
+
with:
|
|
228
|
+
path: ~/.npm
|
|
229
|
+
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
230
|
+
restore-keys: |
|
|
231
|
+
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
232
|
+
${{ runner.os }}-build-
|
|
233
|
+
${{ runner.os }}-
|
|
234
|
+
|
|
235
|
+
- name: Check cache hit
|
|
236
|
+
if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
|
|
237
|
+
run: echo "Cache miss - installing dependencies"
|
|
238
|
+
|
|
239
|
+
- name: Install dependencies
|
|
240
|
+
run: npm ci
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Maven with Built-in Caching:**
|
|
244
|
+
```yaml
|
|
245
|
+
- uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
|
246
|
+
with:
|
|
247
|
+
java-version: '17'
|
|
248
|
+
distribution: 'temurin'
|
|
249
|
+
cache: 'maven'
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Ruby Gems with Matrix Strategy:**
|
|
253
|
+
```yaml
|
|
254
|
+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
|
255
|
+
with:
|
|
256
|
+
path: vendor/bundle
|
|
257
|
+
key: bundle-${{ matrix.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
|
|
258
|
+
restore-keys: |
|
|
259
|
+
bundle-${{ matrix.os }}-${{ matrix.ruby-version }}-
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**.NET Dependencies:**
|
|
263
|
+
```yaml
|
|
264
|
+
- uses: actions/setup-dotnet@v4
|
|
265
|
+
with:
|
|
266
|
+
dotnet-version: '8.x'
|
|
267
|
+
cache: true # Caches NuGet global-packages folder
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 2. Concurrency Control
|
|
271
|
+
|
|
272
|
+
**Best Practice:**
|
|
273
|
+
```yaml
|
|
274
|
+
# Cancel in-progress runs when new commit pushed
|
|
275
|
+
concurrency:
|
|
276
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
277
|
+
cancel-in-progress: true
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Per-PR Concurrency:**
|
|
281
|
+
```yaml
|
|
282
|
+
concurrency:
|
|
283
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
284
|
+
cancel-in-progress: true
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 3. Shallow Checkout
|
|
288
|
+
|
|
289
|
+
**Best Practice:**
|
|
290
|
+
```yaml
|
|
291
|
+
# ✅ GOOD: Shallow clone when full history not needed
|
|
292
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
293
|
+
with:
|
|
294
|
+
fetch-depth: 1
|
|
295
|
+
|
|
296
|
+
# ✅ GOOD: Fetch specific depth for changelog generation
|
|
297
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
298
|
+
with:
|
|
299
|
+
fetch-depth: 50
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 4. Matrix Strategy Optimization
|
|
303
|
+
|
|
304
|
+
**Best Practice:**
|
|
305
|
+
```yaml
|
|
306
|
+
strategy:
|
|
307
|
+
matrix:
|
|
308
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
309
|
+
node: [18, 20, 22]
|
|
310
|
+
exclude:
|
|
311
|
+
# Exclude expensive combinations
|
|
312
|
+
- os: macos-latest
|
|
313
|
+
node: 18
|
|
314
|
+
fail-fast: false # Continue other jobs even if one fails
|
|
315
|
+
max-parallel: 3 # Limit concurrent jobs
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Workflow Design
|
|
319
|
+
|
|
320
|
+
### 1. Job Dependencies
|
|
321
|
+
|
|
322
|
+
**Best Practice:**
|
|
323
|
+
```yaml
|
|
324
|
+
jobs:
|
|
325
|
+
lint:
|
|
326
|
+
runs-on: ubuntu-latest
|
|
327
|
+
steps:
|
|
328
|
+
- run: npm run lint
|
|
329
|
+
|
|
330
|
+
test:
|
|
331
|
+
runs-on: ubuntu-latest
|
|
332
|
+
steps:
|
|
333
|
+
- run: npm test
|
|
334
|
+
|
|
335
|
+
build:
|
|
336
|
+
needs: [lint, test] # Wait for both
|
|
337
|
+
runs-on: ubuntu-latest
|
|
338
|
+
steps:
|
|
339
|
+
- run: npm run build
|
|
340
|
+
|
|
341
|
+
deploy:
|
|
342
|
+
needs: build
|
|
343
|
+
if: github.ref == 'refs/heads/main'
|
|
344
|
+
runs-on: ubuntu-latest
|
|
345
|
+
steps:
|
|
346
|
+
- run: ./deploy.sh
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 2. Conditional Execution
|
|
350
|
+
|
|
351
|
+
**Best Practice:**
|
|
352
|
+
```yaml
|
|
353
|
+
# Job-level condition
|
|
354
|
+
jobs:
|
|
355
|
+
deploy:
|
|
356
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
357
|
+
|
|
358
|
+
# Step-level condition
|
|
359
|
+
steps:
|
|
360
|
+
- name: Deploy to staging
|
|
361
|
+
if: github.ref == 'refs/heads/develop'
|
|
362
|
+
run: ./deploy-staging.sh
|
|
363
|
+
|
|
364
|
+
- name: Notify on failure
|
|
365
|
+
if: failure()
|
|
366
|
+
run: ./notify.sh
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Common Conditions:**
|
|
370
|
+
- `success()`: Previous steps succeeded
|
|
371
|
+
- `failure()`: Any previous step failed
|
|
372
|
+
- `always()`: Run regardless of status
|
|
373
|
+
- `cancelled()`: Workflow was cancelled
|
|
374
|
+
|
|
375
|
+
### 3. Reusable Workflows
|
|
376
|
+
|
|
377
|
+
**Caller Workflow:**
|
|
378
|
+
```yaml
|
|
379
|
+
# .github/workflows/ci.yml
|
|
380
|
+
jobs:
|
|
381
|
+
call-workflow:
|
|
382
|
+
uses: ./.github/workflows/reusable-build.yml
|
|
383
|
+
with:
|
|
384
|
+
environment: production
|
|
385
|
+
secrets:
|
|
386
|
+
token: ${{ secrets.DEPLOY_TOKEN }}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Reusable Workflow:**
|
|
390
|
+
```yaml
|
|
391
|
+
# .github/workflows/reusable-build.yml
|
|
392
|
+
name: Reusable Build
|
|
393
|
+
|
|
394
|
+
on:
|
|
395
|
+
workflow_call:
|
|
396
|
+
inputs:
|
|
397
|
+
environment:
|
|
398
|
+
required: true
|
|
399
|
+
type: string
|
|
400
|
+
node-version:
|
|
401
|
+
required: false
|
|
402
|
+
type: string
|
|
403
|
+
default: '20'
|
|
404
|
+
secrets:
|
|
405
|
+
token:
|
|
406
|
+
required: true
|
|
407
|
+
outputs:
|
|
408
|
+
build-id:
|
|
409
|
+
description: "Build identifier"
|
|
410
|
+
value: ${{ jobs.build.outputs.id }}
|
|
411
|
+
|
|
412
|
+
jobs:
|
|
413
|
+
build:
|
|
414
|
+
runs-on: ubuntu-latest
|
|
415
|
+
outputs:
|
|
416
|
+
id: ${{ steps.build.outputs.id }}
|
|
417
|
+
steps:
|
|
418
|
+
- name: Build
|
|
419
|
+
id: build
|
|
420
|
+
run: echo "id=build-${{ github.sha }}" >> $GITHUB_OUTPUT
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Action Selection and Versioning
|
|
424
|
+
|
|
425
|
+
### 1. Prefer Official GitHub Actions
|
|
426
|
+
|
|
427
|
+
**Priority Order:**
|
|
428
|
+
1. Official GitHub actions (`actions/*`)
|
|
429
|
+
2. Official organization actions (`docker/*`, `aws-actions/*`)
|
|
430
|
+
3. Verified creators
|
|
431
|
+
4. Community actions (with careful review)
|
|
432
|
+
|
|
433
|
+
### 2. Version Pinning Strategy
|
|
434
|
+
|
|
435
|
+
**Recommended Approach:**
|
|
436
|
+
```yaml
|
|
437
|
+
# Format: @<SHA> # <version-tag>
|
|
438
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Finding SHAs:**
|
|
442
|
+
```bash
|
|
443
|
+
# Get SHA for specific tag
|
|
444
|
+
git ls-remote https://github.com/actions/checkout v4.1.1
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### 3. Regular Updates
|
|
448
|
+
|
|
449
|
+
**Process:**
|
|
450
|
+
1. Monitor action releases and security advisories
|
|
451
|
+
2. Update SHAs with new versions
|
|
452
|
+
3. Test in PR before merging
|
|
453
|
+
4. Document version changes in commit message
|
|
454
|
+
|
|
455
|
+
**Automated Updates:**
|
|
456
|
+
Use Dependabot for automatic action updates:
|
|
457
|
+
```yaml
|
|
458
|
+
# .github/dependabot.yml
|
|
459
|
+
version: 2
|
|
460
|
+
updates:
|
|
461
|
+
- package-ecosystem: "github-actions"
|
|
462
|
+
directory: "/"
|
|
463
|
+
schedule:
|
|
464
|
+
interval: "weekly"
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Error Handling
|
|
468
|
+
|
|
469
|
+
### 1. Timeouts
|
|
470
|
+
|
|
471
|
+
**Best Practice:**
|
|
472
|
+
```yaml
|
|
473
|
+
jobs:
|
|
474
|
+
build:
|
|
475
|
+
runs-on: ubuntu-latest
|
|
476
|
+
timeout-minutes: 30 # Prevent hung jobs
|
|
477
|
+
steps:
|
|
478
|
+
- name: Run tests
|
|
479
|
+
timeout-minutes: 15 # Step-level timeout
|
|
480
|
+
run: npm test
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### 2. Failure Handling
|
|
484
|
+
|
|
485
|
+
**Best Practice:**
|
|
486
|
+
```yaml
|
|
487
|
+
jobs:
|
|
488
|
+
test:
|
|
489
|
+
steps:
|
|
490
|
+
- name: Run tests
|
|
491
|
+
id: tests
|
|
492
|
+
continue-on-error: true
|
|
493
|
+
run: npm test
|
|
494
|
+
|
|
495
|
+
- name: Upload test results
|
|
496
|
+
if: always()
|
|
497
|
+
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
|
498
|
+
with:
|
|
499
|
+
name: test-results
|
|
500
|
+
path: test-results/
|
|
501
|
+
|
|
502
|
+
- name: Check test results
|
|
503
|
+
if: steps.tests.outcome == 'failure'
|
|
504
|
+
run: exit 1
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### 3. Cleanup Steps
|
|
508
|
+
|
|
509
|
+
**Best Practice:**
|
|
510
|
+
```yaml
|
|
511
|
+
steps:
|
|
512
|
+
- name: Start test environment
|
|
513
|
+
run: docker-compose up -d
|
|
514
|
+
|
|
515
|
+
- name: Run tests
|
|
516
|
+
run: npm test
|
|
517
|
+
|
|
518
|
+
- name: Cleanup
|
|
519
|
+
if: always()
|
|
520
|
+
run: docker-compose down
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
## Maintainability
|
|
524
|
+
|
|
525
|
+
### 1. Naming Conventions
|
|
526
|
+
|
|
527
|
+
**Best Practice:**
|
|
528
|
+
```yaml
|
|
529
|
+
# Workflow file: lowercase with hyphens
|
|
530
|
+
# File: .github/workflows/ci-pipeline.yml
|
|
531
|
+
|
|
532
|
+
name: CI Pipeline # Descriptive workflow name
|
|
533
|
+
|
|
534
|
+
jobs:
|
|
535
|
+
test-node: # Descriptive job ID
|
|
536
|
+
name: Test on Node ${{ matrix.version }} # Human-readable job name
|
|
537
|
+
steps:
|
|
538
|
+
- name: Install dependencies # Action-oriented step name
|
|
539
|
+
run: npm ci
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### 2. Documentation
|
|
543
|
+
|
|
544
|
+
**Best Practice:**
|
|
545
|
+
```yaml
|
|
546
|
+
# CI Pipeline
|
|
547
|
+
#
|
|
548
|
+
# This workflow runs on every push and pull request to validate code quality.
|
|
549
|
+
# It performs linting, testing, and builds the application.
|
|
550
|
+
#
|
|
551
|
+
# Required secrets:
|
|
552
|
+
# - CODECOV_TOKEN: For uploading coverage reports
|
|
553
|
+
#
|
|
554
|
+
# Required permissions:
|
|
555
|
+
# - contents: read
|
|
556
|
+
# - checks: write
|
|
557
|
+
|
|
558
|
+
name: CI Pipeline
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### 3. Environment Variables
|
|
562
|
+
|
|
563
|
+
**Best Practice:**
|
|
564
|
+
```yaml
|
|
565
|
+
# Top-level environment variables
|
|
566
|
+
env:
|
|
567
|
+
NODE_VERSION: '20'
|
|
568
|
+
CACHE_VERSION: 'v1'
|
|
569
|
+
|
|
570
|
+
jobs:
|
|
571
|
+
build:
|
|
572
|
+
env:
|
|
573
|
+
BUILD_ENV: production
|
|
574
|
+
steps:
|
|
575
|
+
- name: Build
|
|
576
|
+
env:
|
|
577
|
+
API_URL: ${{ secrets.API_URL }}
|
|
578
|
+
run: npm run build
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
## Common Patterns
|
|
582
|
+
|
|
583
|
+
### 1. Multi-Environment Deployment
|
|
584
|
+
|
|
585
|
+
```yaml
|
|
586
|
+
jobs:
|
|
587
|
+
deploy-staging:
|
|
588
|
+
if: github.ref == 'refs/heads/develop'
|
|
589
|
+
environment:
|
|
590
|
+
name: staging
|
|
591
|
+
url: https://staging.example.com
|
|
592
|
+
steps:
|
|
593
|
+
- name: Deploy to staging
|
|
594
|
+
run: ./deploy.sh staging
|
|
595
|
+
|
|
596
|
+
deploy-production:
|
|
597
|
+
if: github.ref == 'refs/heads/main'
|
|
598
|
+
environment:
|
|
599
|
+
name: production
|
|
600
|
+
url: https://example.com
|
|
601
|
+
steps:
|
|
602
|
+
- name: Deploy to production
|
|
603
|
+
run: ./deploy.sh production
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### 2. Manual Approval
|
|
607
|
+
|
|
608
|
+
```yaml
|
|
609
|
+
jobs:
|
|
610
|
+
deploy:
|
|
611
|
+
environment:
|
|
612
|
+
name: production
|
|
613
|
+
# Requires manual approval from configured reviewers
|
|
614
|
+
steps:
|
|
615
|
+
- name: Deploy
|
|
616
|
+
run: ./deploy.sh
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### 3. Artifact Sharing Between Jobs
|
|
620
|
+
|
|
621
|
+
```yaml
|
|
622
|
+
jobs:
|
|
623
|
+
build:
|
|
624
|
+
steps:
|
|
625
|
+
- name: Build application
|
|
626
|
+
run: npm run build
|
|
627
|
+
|
|
628
|
+
- name: Upload build artifacts
|
|
629
|
+
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
|
630
|
+
with:
|
|
631
|
+
name: build-${{ github.sha }}
|
|
632
|
+
path: dist/
|
|
633
|
+
retention-days: 7
|
|
634
|
+
|
|
635
|
+
test:
|
|
636
|
+
needs: build
|
|
637
|
+
steps:
|
|
638
|
+
- name: Download build artifacts
|
|
639
|
+
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
|
|
640
|
+
with:
|
|
641
|
+
name: build-${{ github.sha }}
|
|
642
|
+
path: dist/
|
|
643
|
+
|
|
644
|
+
- name: Test build
|
|
645
|
+
run: npm run test:integration
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### 4. Dynamic Matrix from JSON
|
|
649
|
+
|
|
650
|
+
```yaml
|
|
651
|
+
jobs:
|
|
652
|
+
setup:
|
|
653
|
+
runs-on: ubuntu-latest
|
|
654
|
+
outputs:
|
|
655
|
+
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
656
|
+
steps:
|
|
657
|
+
- name: Set matrix
|
|
658
|
+
id: set-matrix
|
|
659
|
+
run: |
|
|
660
|
+
echo 'matrix={"version":["18","20","22"]}' >> $GITHUB_OUTPUT
|
|
661
|
+
|
|
662
|
+
test:
|
|
663
|
+
needs: setup
|
|
664
|
+
strategy:
|
|
665
|
+
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
## Anti-Patterns to Avoid
|
|
669
|
+
|
|
670
|
+
### 1. Storing Secrets in Code
|
|
671
|
+
|
|
672
|
+
```yaml
|
|
673
|
+
# ❌ NEVER DO THIS
|
|
674
|
+
env:
|
|
675
|
+
API_KEY: "hardcoded-secret-123"
|
|
676
|
+
PASSWORD: ${{ github.event.inputs.password }}
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### 2. Using Deprecated Actions
|
|
680
|
+
|
|
681
|
+
```yaml
|
|
682
|
+
# ❌ BAD: Deprecated actions
|
|
683
|
+
- uses: actions/setup-node@v1 # Use v6 instead (Node 24 runtime)
|
|
684
|
+
- uses: actions/cache@v1 # Use v5.0.3+ instead (Node 24 runtime, required as of Feb 2025)
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### 3. Overly Broad Permissions
|
|
688
|
+
|
|
689
|
+
```yaml
|
|
690
|
+
# ❌ BAD: Unnecessary permissions
|
|
691
|
+
permissions: write-all
|
|
692
|
+
|
|
693
|
+
# ✅ GOOD: Minimal permissions
|
|
694
|
+
permissions:
|
|
695
|
+
contents: read
|
|
696
|
+
pull-requests: write
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### 4. Long-Running Jobs Without Timeout
|
|
700
|
+
|
|
701
|
+
```yaml
|
|
702
|
+
# ❌ BAD: No timeout
|
|
703
|
+
jobs:
|
|
704
|
+
build:
|
|
705
|
+
runs-on: ubuntu-latest
|
|
706
|
+
# Could run forever, consuming minutes
|
|
707
|
+
|
|
708
|
+
# ✅ GOOD: With timeout
|
|
709
|
+
jobs:
|
|
710
|
+
build:
|
|
711
|
+
runs-on: ubuntu-latest
|
|
712
|
+
timeout-minutes: 30
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### 5. Hardcoded Values
|
|
716
|
+
|
|
717
|
+
```yaml
|
|
718
|
+
# ❌ BAD: Hardcoded
|
|
719
|
+
- name: Deploy
|
|
720
|
+
run: kubectl set image deployment/myapp myapp=myapp:1.0.0
|
|
721
|
+
|
|
722
|
+
# ✅ GOOD: Using variables
|
|
723
|
+
- name: Deploy
|
|
724
|
+
env:
|
|
725
|
+
IMAGE_TAG: ${{ github.sha }}
|
|
726
|
+
run: kubectl set image deployment/myapp myapp=myapp:$IMAGE_TAG
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### 6. Unnecessary Checkouts
|
|
730
|
+
|
|
731
|
+
```yaml
|
|
732
|
+
# ❌ BAD: Checkout when not needed
|
|
733
|
+
jobs:
|
|
734
|
+
notify:
|
|
735
|
+
steps:
|
|
736
|
+
- uses: actions/checkout@v4 # Not needed for notification
|
|
737
|
+
- run: ./notify.sh
|
|
738
|
+
|
|
739
|
+
# ✅ GOOD: Only checkout when needed
|
|
740
|
+
jobs:
|
|
741
|
+
notify:
|
|
742
|
+
steps:
|
|
743
|
+
- run: curl -X POST ${{ secrets.WEBHOOK_URL }}
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
## Summary
|
|
747
|
+
|
|
748
|
+
**Key Takeaways:**
|
|
749
|
+
1. Security first: Pin actions, use minimal permissions, protect secrets
|
|
750
|
+
2. Optimize performance: Cache dependencies, use concurrency controls
|
|
751
|
+
3. Design for maintainability: Clear naming, documentation, reusable components
|
|
752
|
+
4. Handle errors gracefully: Timeouts, cleanup, notifications
|
|
753
|
+
5. Follow conventions: Standard naming, proper versioning, community practices
|
|
754
|
+
|
|
755
|
+
Always validate workflows with the github-actions-validator skill before deploying.
|