@hybridlabor-api/aos 4.8.0 → 4.10.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 → AGENTS.md} +3 -1
- package/.agents/nodes.json +3 -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/hooks/memb-inject.mjs +29 -1
- package/.claude/settings.json +13 -0
- package/.claude/workflows/startcycle-dispatch.mjs +23 -1
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/CLAUDE.md +0 -571
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +126 -0
- package/bin/aos-doctor.mjs +1 -1
- package/docs/skills_table.md +1 -1
- package/installer.js +187 -55
- package/package.json +7 -3
- 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/basic/bdb-eventagency-skill/SKILL.md +252 -0
- package/skills/basic/bdb-shipping-skill/SKILL.md +161 -0
- package/skills/basic/godmode-eventtech/SKILL.md +4 -1
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/aos-project-init/SKILL.md +2 -0
- package/skills/global_config/aos-project-init/assets/AGENTS.template.md +1 -1
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +1 -1
- package/skills/global_config/aos-setup/SKILL.md +1 -1
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
- package/skills/global_config/ask-tim/SKILL.md +7 -7
- 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/deja-memory/SKILL.md +3 -1
- 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/plan-canvas/SKILL.md +9 -2
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +10 -2
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +1 -1
- package/skills/global_config/read-the-damn-docs/SKILL.md +175 -0
- 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 +152 -0
- package/.claude/CLAUDE.md +0 -12
- package/mcps/RhinoMCP/docs/content/docs/getting-started/gemini.md +0 -61
- /package/{GEMINI.md → RULES.md} +0 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
# GitHub Actions Expressions and Contexts
|
|
2
|
+
|
|
3
|
+
**Last Updated:** November 2025
|
|
4
|
+
**Source:** Official GitHub Actions documentation and Context7 verified examples
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
1. [Expression Syntax](#expression-syntax)
|
|
8
|
+
2. [Contexts](#contexts)
|
|
9
|
+
3. [Functions](#functions)
|
|
10
|
+
4. [Operators](#operators)
|
|
11
|
+
5. [Common Patterns](#common-patterns)
|
|
12
|
+
6. [Debugging and Troubleshooting](#debugging-and-troubleshooting)
|
|
13
|
+
|
|
14
|
+
## Expression Syntax
|
|
15
|
+
|
|
16
|
+
GitHub Actions expressions use `${{ }}` syntax to evaluate values dynamically.
|
|
17
|
+
|
|
18
|
+
**Basic Usage:**
|
|
19
|
+
```yaml
|
|
20
|
+
- name: Print environment
|
|
21
|
+
run: echo "Running on ${{ runner.os }}"
|
|
22
|
+
|
|
23
|
+
- name: Conditional step
|
|
24
|
+
if: ${{ github.ref == 'refs/heads/main' }}
|
|
25
|
+
run: echo "On main branch"
|
|
26
|
+
|
|
27
|
+
# Note: 'if' doesn't require ${{ }}, it's implicit
|
|
28
|
+
- name: Conditional step (preferred)
|
|
29
|
+
if: github.ref == 'refs/heads/main'
|
|
30
|
+
run: echo "On main branch"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Where Expressions Can Be Used:**
|
|
34
|
+
- `if` conditionals (implicit `${{ }}`, can omit)
|
|
35
|
+
- `env` values (must use `${{ }}`)
|
|
36
|
+
- `with` inputs (must use `${{ }}`)
|
|
37
|
+
- Step `name` values (must use `${{ }}`)
|
|
38
|
+
- Job `outputs` (must use `${{ }}`)
|
|
39
|
+
- `environment.name` (can use expressions for dynamic environments)
|
|
40
|
+
|
|
41
|
+
**Important Notes:**
|
|
42
|
+
- Expressions are interpolated **before** the job is sent to the runner
|
|
43
|
+
- Use environment variables via `env` context for safer variable handling
|
|
44
|
+
- Avoid direct interpolation of untrusted input (use `env` context instead)
|
|
45
|
+
|
|
46
|
+
## Contexts
|
|
47
|
+
|
|
48
|
+
Contexts are objects containing information about workflow runs, variables, environments, and more.
|
|
49
|
+
|
|
50
|
+
### github context
|
|
51
|
+
|
|
52
|
+
Contains information about the workflow run and triggering event.
|
|
53
|
+
|
|
54
|
+
**Common Properties:**
|
|
55
|
+
```yaml
|
|
56
|
+
# Event information
|
|
57
|
+
${{ github.event_name }} # Event that triggered workflow (push, pull_request, etc.)
|
|
58
|
+
${{ github.event.action }} # Action that triggered event (opened, synchronize, etc.)
|
|
59
|
+
|
|
60
|
+
# Repository information
|
|
61
|
+
${{ github.repository }} # owner/repo
|
|
62
|
+
${{ github.repository_owner }} # Repository owner
|
|
63
|
+
${{ github.ref }} # Full ref (refs/heads/main, refs/tags/v1.0.0)
|
|
64
|
+
${{ github.ref_name }} # Short ref (main, v1.0.0)
|
|
65
|
+
${{ github.sha }} # Commit SHA that triggered workflow
|
|
66
|
+
|
|
67
|
+
# Actor information
|
|
68
|
+
${{ github.actor }} # Username that triggered workflow
|
|
69
|
+
${{ github.triggering_actor }} # User that initiated the workflow run
|
|
70
|
+
|
|
71
|
+
# Workflow information
|
|
72
|
+
${{ github.workflow }} # Workflow name
|
|
73
|
+
${{ github.run_id }} # Unique workflow run ID
|
|
74
|
+
${{ github.run_number }} # Workflow run number
|
|
75
|
+
${{ github.job }} # Current job ID
|
|
76
|
+
|
|
77
|
+
# Pull request information (when event is pull_request)
|
|
78
|
+
${{ github.event.pull_request.number }}
|
|
79
|
+
${{ github.event.pull_request.title }}
|
|
80
|
+
${{ github.event.pull_request.head.ref }} # Source branch
|
|
81
|
+
${{ github.event.pull_request.base.ref }} # Target branch
|
|
82
|
+
${{ github.event.pull_request.head.sha }}
|
|
83
|
+
|
|
84
|
+
# Push information (when event is push)
|
|
85
|
+
${{ github.event.head_commit.message }}
|
|
86
|
+
${{ github.event.head_commit.author.name }}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Examples:**
|
|
90
|
+
```yaml
|
|
91
|
+
# Build image tagged with commit SHA
|
|
92
|
+
- name: Build Docker image
|
|
93
|
+
run: docker build -t myapp:${{ github.sha }} .
|
|
94
|
+
|
|
95
|
+
# Deploy only on main branch
|
|
96
|
+
- name: Deploy
|
|
97
|
+
if: github.ref == 'refs/heads/main'
|
|
98
|
+
run: ./deploy.sh
|
|
99
|
+
|
|
100
|
+
# Different behavior for PR vs push
|
|
101
|
+
- name: Set environment
|
|
102
|
+
run: |
|
|
103
|
+
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
104
|
+
echo "ENV=preview" >> $GITHUB_ENV
|
|
105
|
+
else
|
|
106
|
+
echo "ENV=production" >> $GITHUB_ENV
|
|
107
|
+
fi
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### env context
|
|
111
|
+
|
|
112
|
+
Access environment variables defined in workflow, job, or step.
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
env:
|
|
116
|
+
NODE_VERSION: '20'
|
|
117
|
+
BUILD_TYPE: 'production'
|
|
118
|
+
|
|
119
|
+
jobs:
|
|
120
|
+
build:
|
|
121
|
+
env:
|
|
122
|
+
API_URL: 'https://api.example.com'
|
|
123
|
+
steps:
|
|
124
|
+
- name: Print variables
|
|
125
|
+
run: |
|
|
126
|
+
echo "Node: ${{ env.NODE_VERSION }}"
|
|
127
|
+
echo "API: ${{ env.API_URL }}"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### runner context
|
|
131
|
+
|
|
132
|
+
Information about the runner executing the job.
|
|
133
|
+
|
|
134
|
+
**Common Properties:**
|
|
135
|
+
```yaml
|
|
136
|
+
${{ runner.os }} # OS (Linux, Windows, macOS)
|
|
137
|
+
${{ runner.arch }} # Architecture (X64, ARM64)
|
|
138
|
+
${{ runner.name }} # Runner name
|
|
139
|
+
${{ runner.temp }} # Temp directory path
|
|
140
|
+
${{ runner.tool_cache }} # Tool cache directory path
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Examples:**
|
|
144
|
+
```yaml
|
|
145
|
+
# OS-specific commands
|
|
146
|
+
- name: Install dependencies
|
|
147
|
+
run: |
|
|
148
|
+
if [ "${{ runner.os }}" == "Linux" ]; then
|
|
149
|
+
sudo apt-get update
|
|
150
|
+
elif [ "${{ runner.os }}" == "macOS" ]; then
|
|
151
|
+
brew update
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Cache key with OS
|
|
155
|
+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
|
156
|
+
with:
|
|
157
|
+
path: ~/.cache
|
|
158
|
+
key: ${{ runner.os }}-cache-${{ hashFiles('**/lock.file') }}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### secrets context
|
|
162
|
+
|
|
163
|
+
Access encrypted secrets defined in repository or organization settings.
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
- name: Deploy to production
|
|
167
|
+
env:
|
|
168
|
+
API_KEY: ${{ secrets.API_KEY }}
|
|
169
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
170
|
+
run: ./deploy.sh
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Security Notes:**
|
|
174
|
+
- Secrets are automatically masked in logs
|
|
175
|
+
- Use `echo "::add-mask::$VALUE"` to mask additional values
|
|
176
|
+
- Pass secrets via environment variables, not command arguments
|
|
177
|
+
|
|
178
|
+
### matrix context
|
|
179
|
+
|
|
180
|
+
Access matrix configuration values when using matrix strategy.
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
strategy:
|
|
184
|
+
matrix:
|
|
185
|
+
os: [ubuntu-latest, windows-latest]
|
|
186
|
+
node: [18, 20, 22]
|
|
187
|
+
include:
|
|
188
|
+
- os: ubuntu-latest
|
|
189
|
+
node: 20
|
|
190
|
+
experimental: true
|
|
191
|
+
|
|
192
|
+
steps:
|
|
193
|
+
- name: Setup Node.js ${{ matrix.node }}
|
|
194
|
+
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
195
|
+
with:
|
|
196
|
+
node-version: ${{ matrix.node }}
|
|
197
|
+
|
|
198
|
+
- name: Mark experimental
|
|
199
|
+
if: matrix.experimental
|
|
200
|
+
run: echo "Experimental build"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### steps context
|
|
204
|
+
|
|
205
|
+
Access information about steps that have already run.
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
steps:
|
|
209
|
+
- name: Run tests
|
|
210
|
+
id: tests
|
|
211
|
+
run: npm test
|
|
212
|
+
|
|
213
|
+
- name: Upload results
|
|
214
|
+
if: steps.tests.outcome == 'success'
|
|
215
|
+
run: ./upload-results.sh
|
|
216
|
+
|
|
217
|
+
- name: Use step output
|
|
218
|
+
run: echo "Test result: ${{ steps.tests.outputs.result }}"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Step Properties:**
|
|
222
|
+
- `steps.<step_id>.outputs.<output_name>`: Output value
|
|
223
|
+
- `steps.<step_id>.outcome`: Result before `continue-on-error` (`success`, `failure`, `cancelled`, `skipped`)
|
|
224
|
+
- `steps.<step_id>.conclusion`: Final result after `continue-on-error`
|
|
225
|
+
|
|
226
|
+
### job context
|
|
227
|
+
|
|
228
|
+
Access information about currently running job.
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
jobs:
|
|
232
|
+
build:
|
|
233
|
+
outputs:
|
|
234
|
+
build-id: ${{ steps.build.outputs.id }}
|
|
235
|
+
steps:
|
|
236
|
+
- name: Build
|
|
237
|
+
id: build
|
|
238
|
+
run: echo "id=build-123" >> $GITHUB_OUTPUT
|
|
239
|
+
|
|
240
|
+
deploy:
|
|
241
|
+
needs: build
|
|
242
|
+
steps:
|
|
243
|
+
- name: Deploy build
|
|
244
|
+
run: ./deploy.sh ${{ needs.build.outputs.build-id }}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### inputs context
|
|
248
|
+
|
|
249
|
+
Access workflow or reusable workflow inputs.
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
on:
|
|
253
|
+
workflow_dispatch:
|
|
254
|
+
inputs:
|
|
255
|
+
environment:
|
|
256
|
+
description: 'Environment to deploy'
|
|
257
|
+
required: true
|
|
258
|
+
type: choice
|
|
259
|
+
options: [dev, staging, production]
|
|
260
|
+
debug:
|
|
261
|
+
description: 'Enable debug mode'
|
|
262
|
+
required: false
|
|
263
|
+
type: boolean
|
|
264
|
+
default: false
|
|
265
|
+
|
|
266
|
+
jobs:
|
|
267
|
+
deploy:
|
|
268
|
+
steps:
|
|
269
|
+
- name: Deploy to ${{ inputs.environment }}
|
|
270
|
+
run: ./deploy.sh ${{ inputs.environment }}
|
|
271
|
+
|
|
272
|
+
- name: Enable debug
|
|
273
|
+
if: inputs.debug
|
|
274
|
+
run: echo "Debug mode enabled"
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Functions
|
|
278
|
+
|
|
279
|
+
### String Functions
|
|
280
|
+
|
|
281
|
+
**contains()**
|
|
282
|
+
```yaml
|
|
283
|
+
# Check if string contains substring
|
|
284
|
+
if: contains(github.ref, 'refs/tags/')
|
|
285
|
+
if: contains(github.event.head_commit.message, '[skip ci]')
|
|
286
|
+
if: contains(fromJSON('["main", "develop"]'), github.ref_name)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**startsWith()**
|
|
290
|
+
```yaml
|
|
291
|
+
# Check if string starts with prefix
|
|
292
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
293
|
+
if: startsWith(github.event.pull_request.title, 'feat:')
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**endsWith()**
|
|
297
|
+
```yaml
|
|
298
|
+
# Check if string ends with suffix
|
|
299
|
+
if: endsWith(github.ref, '/main')
|
|
300
|
+
if: endsWith(github.event.pull_request.head.ref, '-hotfix')
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**format()**
|
|
304
|
+
```yaml
|
|
305
|
+
# Format string with placeholders
|
|
306
|
+
- name: Print message
|
|
307
|
+
run: echo "${{ format('Building {0} on {1}', github.ref_name, runner.os) }}"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Type Conversion Functions
|
|
311
|
+
|
|
312
|
+
**toJSON()**
|
|
313
|
+
```yaml
|
|
314
|
+
# Convert object to JSON string
|
|
315
|
+
- name: Print context
|
|
316
|
+
run: echo '${{ toJSON(github) }}'
|
|
317
|
+
|
|
318
|
+
- name: Print matrix
|
|
319
|
+
run: echo '${{ toJSON(matrix) }}'
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**fromJSON()**
|
|
323
|
+
```yaml
|
|
324
|
+
# Parse JSON string to object
|
|
325
|
+
strategy:
|
|
326
|
+
matrix:
|
|
327
|
+
config: ${{ fromJSON('{"versions":[18,20,22]}') }}
|
|
328
|
+
|
|
329
|
+
# Use with dynamic matrix
|
|
330
|
+
jobs:
|
|
331
|
+
setup:
|
|
332
|
+
outputs:
|
|
333
|
+
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
334
|
+
steps:
|
|
335
|
+
- id: set-matrix
|
|
336
|
+
run: echo 'matrix={"version":["18","20"]}' >> $GITHUB_OUTPUT
|
|
337
|
+
|
|
338
|
+
build:
|
|
339
|
+
needs: setup
|
|
340
|
+
strategy:
|
|
341
|
+
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Hash Functions
|
|
345
|
+
|
|
346
|
+
**hashFiles()**
|
|
347
|
+
```yaml
|
|
348
|
+
# Generate hash of file contents (for cache keys)
|
|
349
|
+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
|
350
|
+
with:
|
|
351
|
+
path: ~/.npm
|
|
352
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
|
353
|
+
|
|
354
|
+
# Multiple patterns
|
|
355
|
+
key: ${{ hashFiles('**/*.go', '**/go.sum') }}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Status Check Functions
|
|
359
|
+
|
|
360
|
+
**success()**
|
|
361
|
+
```yaml
|
|
362
|
+
# Run only if all previous steps succeeded
|
|
363
|
+
- name: Deploy
|
|
364
|
+
if: success()
|
|
365
|
+
run: ./deploy.sh
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**failure()**
|
|
369
|
+
```yaml
|
|
370
|
+
# Run only if any previous step failed
|
|
371
|
+
- name: Notify on failure
|
|
372
|
+
if: failure()
|
|
373
|
+
run: ./notify-failure.sh
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**always()**
|
|
377
|
+
```yaml
|
|
378
|
+
# Run regardless of previous step status
|
|
379
|
+
- name: Cleanup
|
|
380
|
+
if: always()
|
|
381
|
+
run: ./cleanup.sh
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**cancelled()**
|
|
385
|
+
```yaml
|
|
386
|
+
# Run if workflow was cancelled
|
|
387
|
+
- name: Cleanup on cancel
|
|
388
|
+
if: cancelled()
|
|
389
|
+
run: ./cancel-cleanup.sh
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Operators
|
|
393
|
+
|
|
394
|
+
### Comparison Operators
|
|
395
|
+
|
|
396
|
+
```yaml
|
|
397
|
+
# Equality
|
|
398
|
+
if: github.ref == 'refs/heads/main'
|
|
399
|
+
if: runner.os != 'Windows'
|
|
400
|
+
|
|
401
|
+
# Logical
|
|
402
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
403
|
+
if: github.event_name == 'pull_request' || github.event_name == 'push'
|
|
404
|
+
if: "!(github.event_name == 'pull_request')"
|
|
405
|
+
|
|
406
|
+
# Comparison
|
|
407
|
+
if: github.event.pull_request.changed_files < 10
|
|
408
|
+
if: matrix.node-version >= 20
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Operator Precedence
|
|
412
|
+
|
|
413
|
+
1. `()`
|
|
414
|
+
2. `!`
|
|
415
|
+
3. `<`, `<=`, `>`, `>=`
|
|
416
|
+
4. `==`, `!=`
|
|
417
|
+
5. `&&`
|
|
418
|
+
6. `||`
|
|
419
|
+
|
|
420
|
+
## Common Patterns
|
|
421
|
+
|
|
422
|
+
### Branch-Based Conditions
|
|
423
|
+
|
|
424
|
+
```yaml
|
|
425
|
+
# Main branch only
|
|
426
|
+
if: github.ref == 'refs/heads/main'
|
|
427
|
+
|
|
428
|
+
# Any branch except main
|
|
429
|
+
if: github.ref != 'refs/heads/main'
|
|
430
|
+
|
|
431
|
+
# Specific branches
|
|
432
|
+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
|
433
|
+
|
|
434
|
+
# Tag pushes only
|
|
435
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
436
|
+
|
|
437
|
+
# Version tags only (v1.0.0 format)
|
|
438
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Event-Based Conditions
|
|
442
|
+
|
|
443
|
+
```yaml
|
|
444
|
+
# Push event only
|
|
445
|
+
if: github.event_name == 'push'
|
|
446
|
+
|
|
447
|
+
# PR opened or synchronized
|
|
448
|
+
if: |
|
|
449
|
+
github.event_name == 'pull_request' &&
|
|
450
|
+
(github.event.action == 'opened' || github.event.action == 'synchronize')
|
|
451
|
+
|
|
452
|
+
# Manual dispatch only
|
|
453
|
+
if: github.event_name == 'workflow_dispatch'
|
|
454
|
+
|
|
455
|
+
# Scheduled run only
|
|
456
|
+
if: github.event_name == 'schedule'
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Step Status Patterns
|
|
460
|
+
|
|
461
|
+
```yaml
|
|
462
|
+
# Run if specific step succeeded
|
|
463
|
+
if: steps.tests.outcome == 'success'
|
|
464
|
+
|
|
465
|
+
# Run if step failed but continue
|
|
466
|
+
if: steps.tests.outcome == 'failure'
|
|
467
|
+
|
|
468
|
+
# Run cleanup always
|
|
469
|
+
if: always()
|
|
470
|
+
|
|
471
|
+
# Run only on failure
|
|
472
|
+
if: failure()
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Matrix Patterns
|
|
476
|
+
|
|
477
|
+
```yaml
|
|
478
|
+
# Specific matrix combination
|
|
479
|
+
if: matrix.os == 'ubuntu-latest' && matrix.node == 20
|
|
480
|
+
|
|
481
|
+
# Exclude certain combinations
|
|
482
|
+
strategy:
|
|
483
|
+
matrix:
|
|
484
|
+
os: [ubuntu, windows, macos]
|
|
485
|
+
node: [18, 20, 22]
|
|
486
|
+
exclude:
|
|
487
|
+
- os: windows
|
|
488
|
+
node: 18
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Dynamic Values
|
|
492
|
+
|
|
493
|
+
```yaml
|
|
494
|
+
# Build tags with multiple values
|
|
495
|
+
tags: |
|
|
496
|
+
myapp:latest
|
|
497
|
+
myapp:${{ github.sha }}
|
|
498
|
+
myapp:${{ github.ref_name }}
|
|
499
|
+
|
|
500
|
+
# Conditional environment
|
|
501
|
+
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
|
|
502
|
+
|
|
503
|
+
# Dynamic timeout
|
|
504
|
+
timeout-minutes: ${{ github.event_name == 'schedule' && 120 || 30 }}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Combining Contexts
|
|
508
|
+
|
|
509
|
+
```yaml
|
|
510
|
+
# Artifact name with context values
|
|
511
|
+
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
|
512
|
+
with:
|
|
513
|
+
name: build-${{ runner.os }}-${{ github.sha }}
|
|
514
|
+
path: dist/
|
|
515
|
+
|
|
516
|
+
# Cache key with multiple factors
|
|
517
|
+
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
|
518
|
+
with:
|
|
519
|
+
path: ~/.cache
|
|
520
|
+
key: ${{ runner.os }}-${{ hashFiles('**/*.lock') }}-${{ github.ref_name }}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Safe String Interpolation
|
|
524
|
+
|
|
525
|
+
```yaml
|
|
526
|
+
# ❌ UNSAFE: Direct interpolation of user input
|
|
527
|
+
- run: echo "Title: ${{ github.event.pull_request.title }}"
|
|
528
|
+
|
|
529
|
+
# ✅ SAFE: Use environment variables
|
|
530
|
+
- name: Print PR title
|
|
531
|
+
env:
|
|
532
|
+
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
533
|
+
run: echo "Title: $PR_TITLE"
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### JSON Manipulation
|
|
537
|
+
|
|
538
|
+
```yaml
|
|
539
|
+
# Create dynamic matrix
|
|
540
|
+
- id: set-matrix
|
|
541
|
+
run: |
|
|
542
|
+
if [ "${{ github.event_name }}" == "push" ]; then
|
|
543
|
+
echo 'matrix={"os":["ubuntu","windows","macos"]}' >> $GITHUB_OUTPUT
|
|
544
|
+
else
|
|
545
|
+
echo 'matrix={"os":["ubuntu"]}' >> $GITHUB_OUTPUT
|
|
546
|
+
fi
|
|
547
|
+
|
|
548
|
+
# Use matrix
|
|
549
|
+
strategy:
|
|
550
|
+
matrix: ${{ fromJSON(steps.set-matrix.outputs.matrix) }}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
## Debugging and Troubleshooting
|
|
554
|
+
|
|
555
|
+
### Dumping Contexts to Logs
|
|
556
|
+
|
|
557
|
+
The most effective way to debug workflow issues is to dump context information to logs:
|
|
558
|
+
|
|
559
|
+
**Dump All Contexts:**
|
|
560
|
+
```yaml
|
|
561
|
+
name: Context Debugging
|
|
562
|
+
on: push
|
|
563
|
+
|
|
564
|
+
jobs:
|
|
565
|
+
dump_contexts:
|
|
566
|
+
runs-on: ubuntu-latest
|
|
567
|
+
steps:
|
|
568
|
+
- name: Dump GitHub context
|
|
569
|
+
env:
|
|
570
|
+
GITHUB_CONTEXT: ${{ toJson(github) }}
|
|
571
|
+
run: echo "$GITHUB_CONTEXT"
|
|
572
|
+
|
|
573
|
+
- name: Dump job context
|
|
574
|
+
env:
|
|
575
|
+
JOB_CONTEXT: ${{ toJson(job) }}
|
|
576
|
+
run: echo "$JOB_CONTEXT"
|
|
577
|
+
|
|
578
|
+
- name: Dump steps context
|
|
579
|
+
env:
|
|
580
|
+
STEPS_CONTEXT: ${{ toJson(steps) }}
|
|
581
|
+
run: echo "$STEPS_CONTEXT"
|
|
582
|
+
|
|
583
|
+
- name: Dump runner context
|
|
584
|
+
env:
|
|
585
|
+
RUNNER_CONTEXT: ${{ toJson(runner) }}
|
|
586
|
+
run: echo "$RUNNER_CONTEXT"
|
|
587
|
+
|
|
588
|
+
- name: Dump strategy context
|
|
589
|
+
env:
|
|
590
|
+
STRATEGY_CONTEXT: ${{ toJson(strategy) }}
|
|
591
|
+
run: echo "$STRATEGY_CONTEXT"
|
|
592
|
+
|
|
593
|
+
- name: Dump matrix context
|
|
594
|
+
env:
|
|
595
|
+
MATRIX_CONTEXT: ${{ toJson(matrix) }}
|
|
596
|
+
run: echo "$MATRIX_CONTEXT"
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Example Runner Context Output:**
|
|
600
|
+
```json
|
|
601
|
+
{
|
|
602
|
+
"os": "Linux",
|
|
603
|
+
"arch": "X64",
|
|
604
|
+
"name": "GitHub Actions 2",
|
|
605
|
+
"tool_cache": "/opt/hostedtoolcache",
|
|
606
|
+
"temp": "/home/runner/work/_temp"
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Safe Variable Interpolation
|
|
611
|
+
|
|
612
|
+
**Best Practice - Use env context:**
|
|
613
|
+
```yaml
|
|
614
|
+
# ✅ SAFE: Interpolate before runner execution
|
|
615
|
+
- name: Greet user
|
|
616
|
+
env:
|
|
617
|
+
GREETING: ${{ env.Greeting }}
|
|
618
|
+
FIRST_NAME: ${{ env.First_Name }}
|
|
619
|
+
DAY: ${{ env.DAY_OF_WEEK }}
|
|
620
|
+
run: echo "$GREETING $FIRST_NAME. Today is $DAY!"
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
This approach ensures variables are resolved by GitHub Actions before execution, providing consistent behavior.
|
|
624
|
+
|
|
625
|
+
## Tips and Best Practices
|
|
626
|
+
|
|
627
|
+
1. **Implicit vs Explicit `${{ }}`:**
|
|
628
|
+
- `if` conditions don't need `${{ }}` (implicit)
|
|
629
|
+
- Other contexts require explicit `${{ }}`
|
|
630
|
+
|
|
631
|
+
2. **String Comparisons:**
|
|
632
|
+
- Always use quotes for string literals
|
|
633
|
+
- Case-sensitive by default
|
|
634
|
+
|
|
635
|
+
3. **Boolean Values:**
|
|
636
|
+
- Use `true` and `false` without quotes
|
|
637
|
+
- Empty strings evaluate to `false`
|
|
638
|
+
|
|
639
|
+
4. **Default Values:**
|
|
640
|
+
```yaml
|
|
641
|
+
# Use || for default values
|
|
642
|
+
environment: ${{ inputs.environment || 'dev' }}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
5. **Multi-line Expressions:**
|
|
646
|
+
```yaml
|
|
647
|
+
if: |
|
|
648
|
+
github.event_name == 'push' &&
|
|
649
|
+
github.ref == 'refs/heads/main' &&
|
|
650
|
+
!contains(github.event.head_commit.message, '[skip ci]')
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
6. **Security Best Practices:**
|
|
654
|
+
- Always use `env` context for untrusted input
|
|
655
|
+
- Never directly interpolate user-controlled values
|
|
656
|
+
- Use `::add-mask::` for sensitive values
|
|
657
|
+
|
|
658
|
+
7. **Dynamic Environment Names:**
|
|
659
|
+
```yaml
|
|
660
|
+
environment:
|
|
661
|
+
name: ${{ github.ref_name }} # Dynamic based on branch
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
8. **Debugging Expressions:**
|
|
665
|
+
```yaml
|
|
666
|
+
# Print entire context with pretty formatting
|
|
667
|
+
- run: echo '${{ toJson(github) }}'
|
|
668
|
+
|
|
669
|
+
# Print specific values
|
|
670
|
+
- run: |
|
|
671
|
+
echo "Event: ${{ github.event_name }}"
|
|
672
|
+
echo "Ref: ${{ github.ref }}"
|
|
673
|
+
echo "SHA: ${{ github.sha }}"
|
|
674
|
+
echo "Actor: ${{ github.actor }}"
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
## Summary
|
|
678
|
+
|
|
679
|
+
- Use `${{ }}` for dynamic values
|
|
680
|
+
- Access contexts like `github`, `env`, `secrets`, `matrix`, `runner`, etc.
|
|
681
|
+
- Use functions for string manipulation, hashing, and type conversion (`toJSON`, `hashFiles`, `contains`, etc.)
|
|
682
|
+
- Combine operators for complex conditions
|
|
683
|
+
- **Always validate and sanitize user inputs for security**
|
|
684
|
+
- Use `env` context for untrusted input instead of direct interpolation
|
|
685
|
+
- Debug with `toJSON()` to dump context information
|
|
686
|
+
- Expressions are evaluated before job execution on the runner
|
|
687
|
+
|
|
688
|
+
**Security Warning:** Never directly interpolate untrusted input (PR titles, issue bodies, user input) in `run` commands. Always use environment variables via the `env` context.
|