com.wallstop-studios.dxmessaging 2.1.5 → 2.1.6
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/.artifacts/SourceGenerators.Tests/obj/Debug/net9.0/WallstopStudios.DxMessaging.SourceGenerators.Tests.AssemblyInfo.cs +1 -1
- package/.cspell.json +4 -1
- package/.github/workflows/actionlint.yml +11 -1
- package/.github/workflows/csharpier-autofix.yml +34 -3
- package/.github/workflows/dotnet-tests.yml +13 -0
- package/.github/workflows/format-on-demand.yml +38 -44
- package/.github/workflows/json-format-check.yml +24 -0
- package/.github/workflows/lint-doc-links.yml +13 -0
- package/.github/workflows/markdown-json.yml +21 -4
- package/.github/workflows/markdown-link-text-check.yml +10 -0
- package/.github/workflows/markdown-link-validity.yml +10 -0
- package/.github/workflows/markdownlint.yml +7 -5
- package/.github/workflows/prettier-autofix.yml +67 -11
- package/.github/workflows/release-drafter.yml +2 -2
- package/.github/workflows/sync-wiki.yml +3 -3
- package/.github/workflows/yaml-format-lint.yml +26 -0
- package/.llm/context.md +113 -3
- package/.llm/skills/documentation/changelog-management.md +38 -0
- package/.llm/skills/documentation/documentation-style-guide.md +18 -0
- package/.llm/skills/documentation/documentation-update-workflow.md +2 -0
- package/.llm/skills/documentation/documentation-updates.md +2 -0
- package/.llm/skills/documentation/markdown-compatibility.md +476 -0
- package/.llm/skills/documentation/mermaid-theming.md +326 -0
- package/.llm/skills/documentation/mkdocs-navigation.md +290 -0
- package/.llm/skills/github-actions/git-renormalize-patterns.md +231 -0
- package/.llm/skills/github-actions/workflow-consistency.md +346 -0
- package/.llm/skills/index.md +53 -27
- package/.llm/skills/scripting/javascript-code-quality.md +417 -0
- package/.llm/skills/scripting/regex-documentation.md +461 -0
- package/.llm/skills/scripting/shell-best-practices.md +55 -4
- package/.llm/skills/scripting/validation-patterns.md +418 -0
- package/.llm/skills/specification.md +4 -1
- package/.llm/skills/testing/test-code-quality.md +243 -0
- package/.llm/skills/testing/test-production-code.md +348 -0
- package/CHANGELOG.md +11 -0
- package/README.md +0 -11
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +1 -6
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +1 -1
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +1 -1
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +1 -1
- package/coverage/clover.xml +216 -3
- package/coverage/clover.xml.meta +7 -7
- package/coverage/coverage-final.json +2 -1
- package/coverage/coverage-final.json.meta +7 -7
- package/coverage/lcov-report/base.css.meta +1 -1
- package/coverage/lcov-report/block-navigation.js.meta +1 -1
- package/coverage/lcov-report/favicon.png.meta +1 -1
- package/coverage/lcov-report/index.html +25 -10
- package/coverage/lcov-report/index.html.meta +7 -7
- package/coverage/lcov-report/prettify.css.meta +1 -1
- package/coverage/lcov-report/prettify.js.meta +1 -1
- package/coverage/lcov-report/sort-arrow-sprite.png.meta +1 -1
- package/coverage/lcov-report/sorter.js.meta +1 -1
- package/coverage/lcov-report/transform-docs-to-wiki.js.html +1 -1
- package/coverage/lcov-report/transform-docs-to-wiki.js.html.meta +7 -7
- package/coverage/lcov-report/vendor.meta +1 -1
- package/coverage/lcov-report.meta +8 -8
- package/coverage/lcov.info +365 -0
- package/coverage/lcov.info.meta +7 -7
- package/docs/architecture/design-and-architecture.md +0 -1
- package/docs/concepts/index.md +37 -0
- package/docs/concepts/index.md.meta +7 -0
- package/docs/concepts/interceptors-and-ordering.md +0 -2
- package/docs/concepts/mental-model.md +390 -0
- package/docs/concepts/mental-model.md.meta +7 -0
- package/docs/concepts/message-types.md +0 -1
- package/docs/getting-started/getting-started.md +1 -0
- package/docs/getting-started/index.md +6 -5
- package/docs/getting-started/overview.md +1 -0
- package/docs/getting-started/quick-start.md +2 -1
- package/docs/getting-started/visual-guide.md +4 -10
- package/docs/hooks.py +10 -1
- package/docs/images/DxMessaging-banner.svg +1 -1
- package/docs/index.md +7 -7
- package/docs/javascripts/mermaid-config.js +44 -4
- package/docs/reference/helpers.md +130 -154
- package/docs/reference/quick-reference.md +5 -1
- package/docs/reference/reference.md +124 -130
- package/mkdocs.yml +2 -0
- package/package.json +1 -1
- package/scripts/__tests__/generate-skills-index.test.js +397 -0
- package/scripts/__tests__/generate-skills-index.test.js.meta +7 -0
- package/scripts/__tests__/mermaid-config.test.js +467 -0
- package/scripts/__tests__/mermaid-config.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-optional-fields.test.js +1474 -0
- package/scripts/__tests__/validate-skills-optional-fields.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-required-fields.test.js +188 -0
- package/scripts/__tests__/validate-skills-required-fields.test.js.meta +7 -0
- package/scripts/__tests__/validate-skills-tags.test.js +353 -0
- package/scripts/__tests__/validate-skills-tags.test.js.meta +7 -0
- package/scripts/__tests__/validate-workflows.test.js +188 -0
- package/scripts/__tests__/validate-workflows.test.js.meta +7 -0
- package/scripts/generate-skills-index.js +88 -3
- package/scripts/validate-skills.js +230 -30
- package/scripts/validate-workflows.js +272 -0
- package/scripts/validate-workflows.js.meta +7 -0
- package/site/404.html +1 -1
- package/site/advanced/emit-shorthands/index.html +2 -2
- package/site/advanced/message-bus-providers/index.html +2 -2
- package/site/advanced/registration-builders/index.html +2 -2
- package/site/advanced/runtime-configuration/index.html +2 -2
- package/site/advanced/string-messages/index.html +2 -2
- package/site/advanced.meta +1 -1
- package/site/architecture/comparisons/index.html +2 -2
- package/site/architecture/design-and-architecture/index.html +2 -2
- package/site/architecture/performance/index.html +1 -1
- package/site/architecture.meta +1 -1
- package/site/concepts/index.html +1 -0
- package/site/concepts/index.html.meta +7 -0
- package/site/concepts/interceptors-and-ordering/index.html +4 -4
- package/site/concepts/listening-patterns/index.html +2 -2
- package/site/concepts/mental-model/index.html +146 -0
- package/site/concepts/mental-model/index.html.meta +7 -0
- package/site/concepts/mental-model.meta +8 -0
- package/site/concepts/message-types/index.html +2 -2
- package/site/concepts/targeting-and-context/index.html +2 -2
- package/site/concepts.meta +1 -1
- package/site/examples/end-to-end/index.html +2 -2
- package/site/examples/end-to-end-scene-transitions/index.html +2 -2
- package/site/examples.meta +1 -1
- package/site/getting-started/getting-started/index.html +3 -3
- package/site/getting-started/index.html +4 -4
- package/site/getting-started/install/index.html +3 -3
- package/site/getting-started/overview/index.html +2 -2
- package/site/getting-started/quick-start/index.html +2 -2
- package/site/getting-started/visual-guide/index.html +11 -11
- package/site/getting-started.meta +1 -1
- package/site/guides/advanced/index.html +2 -2
- package/site/guides/diagnostics/index.html +2 -2
- package/site/guides/migration-guide/index.html +2 -2
- package/site/guides/patterns/index.html +2 -2
- package/site/guides/testing/index.html +2 -2
- package/site/guides/unity-integration/index.html +2 -2
- package/site/guides.meta +1 -1
- package/site/hooks.py.meta +1 -1
- package/site/images/DxMessaging-banner.svg +119 -0
- package/site/images/DxMessaging-banner.svg.meta +7 -0
- package/site/images.meta +8 -0
- package/site/index.html +2 -2
- package/site/integrations/index.html +2 -2
- package/site/integrations/reflex/index.html +2 -2
- package/site/integrations/vcontainer/index.html +2 -2
- package/site/integrations/zenject/index.html +2 -2
- package/site/integrations.meta +1 -1
- package/site/javascripts/csharp-highlight.js.meta +7 -7
- package/site/javascripts/mermaid-config.js +4 -1
- package/site/javascripts/mermaid-config.js.meta +1 -1
- package/site/javascripts.meta +1 -1
- package/site/reference/compatibility/index.html +1 -1
- package/site/reference/faq/index.html +1 -1
- package/site/reference/glossary/index.html +2 -2
- package/site/reference/helpers/index.html +15 -15
- package/site/reference/quick-reference/index.html +3 -3
- package/site/reference/reference/index.html +37 -37
- package/site/reference/troubleshooting/index.html +1 -1
- package/site/reference.meta +1 -1
- package/site/search/search_index.json +1 -1
- package/site/sitemap.xml +46 -38
- package/site/sitemap.xml.gz +0 -0
- package/site/stylesheets/extra.css.meta +1 -1
- package/site/stylesheets.meta +1 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Git Renormalize Pattern Validation"
|
|
3
|
+
id: "git-renormalize-patterns"
|
|
4
|
+
category: "github-actions"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
created: "2026-01-28"
|
|
7
|
+
updated: "2026-01-28"
|
|
8
|
+
|
|
9
|
+
source:
|
|
10
|
+
repository: "wallstop/DxMessaging"
|
|
11
|
+
files:
|
|
12
|
+
- path: ".github/workflows/"
|
|
13
|
+
url: "https://github.com/wallstop/DxMessaging"
|
|
14
|
+
|
|
15
|
+
tags:
|
|
16
|
+
- "github-actions"
|
|
17
|
+
- "git"
|
|
18
|
+
- "ci-cd"
|
|
19
|
+
- "line-endings"
|
|
20
|
+
- "gitattributes"
|
|
21
|
+
|
|
22
|
+
complexity:
|
|
23
|
+
level: "intermediate"
|
|
24
|
+
reasoning: "Requires understanding of git pathspecs, gitattributes, and CI failure modes"
|
|
25
|
+
|
|
26
|
+
impact:
|
|
27
|
+
performance:
|
|
28
|
+
rating: "low"
|
|
29
|
+
details: "No performance impact; this is about correctness"
|
|
30
|
+
maintainability:
|
|
31
|
+
rating: "high"
|
|
32
|
+
details: "Prevents CI failures and ensures pattern synchronization"
|
|
33
|
+
testability:
|
|
34
|
+
rating: "low"
|
|
35
|
+
details: "Validated by actionlint and manual file existence checks"
|
|
36
|
+
|
|
37
|
+
prerequisites:
|
|
38
|
+
- "Understanding of git pathspec patterns"
|
|
39
|
+
- "Familiarity with .gitattributes line ending normalization"
|
|
40
|
+
- "Knowledge of GitHub Actions workflow structure"
|
|
41
|
+
|
|
42
|
+
dependencies:
|
|
43
|
+
packages: []
|
|
44
|
+
skills:
|
|
45
|
+
- "workflow-consistency"
|
|
46
|
+
- "cross-platform-compatibility"
|
|
47
|
+
|
|
48
|
+
applies_to:
|
|
49
|
+
languages:
|
|
50
|
+
- "YAML"
|
|
51
|
+
frameworks:
|
|
52
|
+
- "GitHub Actions"
|
|
53
|
+
versions:
|
|
54
|
+
github-actions: "current"
|
|
55
|
+
|
|
56
|
+
aliases:
|
|
57
|
+
- "git add renormalize"
|
|
58
|
+
- "pathspec validation"
|
|
59
|
+
- "line ending normalization"
|
|
60
|
+
|
|
61
|
+
related:
|
|
62
|
+
- "workflow-consistency"
|
|
63
|
+
- "cross-platform-compatibility"
|
|
64
|
+
- "git-workflow-robustness"
|
|
65
|
+
|
|
66
|
+
status: "stable"
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
# Git Renormalize Pattern Validation
|
|
70
|
+
|
|
71
|
+
> **One-line summary**: Ensure `git add --renormalize` patterns match actual repository
|
|
72
|
+
> files to prevent CI failures from unmatched pathspecs.
|
|
73
|
+
|
|
74
|
+
## Overview
|
|
75
|
+
|
|
76
|
+
The `git add --renormalize` command applies `.gitattributes` normalization rules to files
|
|
77
|
+
matching specified patterns. This command **fails with exit code 128** when a pathspec
|
|
78
|
+
pattern matches zero files. This skill documents best practices for pattern validation
|
|
79
|
+
and synchronization across workflow sections.
|
|
80
|
+
|
|
81
|
+
## Solution
|
|
82
|
+
|
|
83
|
+
Apply these requirements when using `git add --renormalize` in CI:
|
|
84
|
+
|
|
85
|
+
1. **Use per-extension loops** (REQUIRED) - Process each extension separately with existence checks
|
|
86
|
+
1. **Validate patterns** match at least one file in the repository
|
|
87
|
+
1. **Synchronize patterns** between `git add --renormalize`, `file_pattern`, and path triggers
|
|
88
|
+
|
|
89
|
+
### Required Pattern: Per-Extension Loop
|
|
90
|
+
|
|
91
|
+
**ALWAYS** use this pattern when renormalizing multiple file types:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# REQUIRED: Per-extension loop with existence check
|
|
95
|
+
# yaml excluded: dotfiles match git ls-files but not git add globs
|
|
96
|
+
for ext in cs md json asmdef yml; do
|
|
97
|
+
if git ls-files "*.$ext" "**/*.$ext" | grep -q .; then
|
|
98
|
+
git add --renormalize -- "*.$ext" "**/*.$ext"
|
|
99
|
+
fi
|
|
100
|
+
done
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**NEVER** use single-line multi-pattern commands (fails with exit 128 if any pattern matches no files):
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# FORBIDDEN: Fails if ANY pattern matches no files
|
|
107
|
+
git add --renormalize -- '*.md' '**/*.md' '*.json' '**/*.json'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## The Problem
|
|
111
|
+
|
|
112
|
+
When `git add --renormalize` is given a pattern that matches no files, it fails with exit code 128:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
fatal: pathspec '*.markdown' did not match any files
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Dotfile Glob Behavior Difference
|
|
119
|
+
|
|
120
|
+
**CRITICAL**: `git ls-files` matches dotfiles but `git add` does not:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git ls-files "*.yaml" # Returns: .pre-commit-config.yaml
|
|
124
|
+
git add --renormalize -- "*.yaml" # FAILS: pathspec did not match any files
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Solution**: Exclude `yaml` from extension loops since `.yaml` files are typically dotfiles.
|
|
128
|
+
Use `yml` for non-dotfile YAML files.
|
|
129
|
+
|
|
130
|
+
**Generalized rule**: Exclude any extension when ALL tracked files of that extension are
|
|
131
|
+
dotfiles. Verify with: `git ls-files "*.$ext" "**/*.$ext"` — if all results start with `.`,
|
|
132
|
+
exclude that extension.
|
|
133
|
+
|
|
134
|
+
### `file_pattern` in `git-auto-commit-action`
|
|
135
|
+
|
|
136
|
+
The same dotfile limitation applies to `file_pattern`:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
# CORRECT: Exclude yaml if all .yaml files are dotfiles
|
|
140
|
+
file_pattern: "**/*.md **/*.json **/*.yml"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Command Behavior
|
|
144
|
+
|
|
145
|
+
| Scenario | Exit Code |
|
|
146
|
+
| ---------------------------- | --------- |
|
|
147
|
+
| All patterns match files | 0 |
|
|
148
|
+
| Any pattern matches no files | 128 |
|
|
149
|
+
| No `.gitattributes` rules | 0 |
|
|
150
|
+
|
|
151
|
+
## Best Practices
|
|
152
|
+
|
|
153
|
+
### Validate Patterns Match Actual Files
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Count files by extension
|
|
157
|
+
git ls-files | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -10
|
|
158
|
+
|
|
159
|
+
# Find all unique extensions
|
|
160
|
+
git ls-files | grep -E '\.[^/]+$' | sed 's/.*\./\./' | sort -u
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Keep Workflow Triggers Synchronized
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
# GOOD: Only patterns that match existing files
|
|
167
|
+
on:
|
|
168
|
+
pull_request:
|
|
169
|
+
paths:
|
|
170
|
+
- "**/*.md" # Verified: files exist
|
|
171
|
+
- "**/*.json" # Verified: files exist
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Use Consistent Pattern Syntax
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
# Preferred: Double-star for recursive matching
|
|
178
|
+
- "**/*.md"
|
|
179
|
+
- "**/*.json"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Common Mistakes
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
# Mistake 1: Assuming success when pattern matches nothing
|
|
186
|
+
- run: git add --renormalize -- '*.markdown' # Fails if no .markdown files
|
|
187
|
+
|
|
188
|
+
# Mistake 2: Case sensitivity on Linux
|
|
189
|
+
git ls-files '*.MD' # Different from '*.md' on Linux
|
|
190
|
+
|
|
191
|
+
# Mistake 3: Over-broad patterns (stages everything)
|
|
192
|
+
- run: git add --renormalize . # Use per-extension loop instead
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Integration with Workflow Consistency
|
|
196
|
+
|
|
197
|
+
This skill complements the [Workflow Consistency skill](./workflow-consistency.md) by
|
|
198
|
+
ensuring pattern validation for renormalize commands and path trigger synchronization.
|
|
199
|
+
|
|
200
|
+
## Validation Checklist
|
|
201
|
+
|
|
202
|
+
- [ ] Uses per-extension loop pattern with existence checks (REQUIRED)
|
|
203
|
+
- [ ] All path patterns match at least one file
|
|
204
|
+
- [ ] Patterns consistent between `pull_request` and `pull_request_target`
|
|
205
|
+
- [ ] No patterns for dotfile-only extensions (e.g., `yaml`)
|
|
206
|
+
|
|
207
|
+
## Verification
|
|
208
|
+
|
|
209
|
+
Test patterns locally before committing:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Verify file types exist
|
|
213
|
+
for ext in cs md json asmdef yml; do
|
|
214
|
+
count=$(git ls-files "*.$ext" "**/*.$ext" | wc -l)
|
|
215
|
+
echo "$ext: $count files"
|
|
216
|
+
done
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Run automated validation:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
node scripts/validate-workflows.js
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
This validation runs in CI (via actionlint workflow) but not in pre-commit hooks.
|
|
226
|
+
|
|
227
|
+
## See Also
|
|
228
|
+
|
|
229
|
+
- [Workflow Consistency skill](./workflow-consistency.md) - General workflow structure requirements
|
|
230
|
+
- [Cross-Platform Compatibility skill](../scripting/cross-platform-compatibility.md) - Path handling across OSes
|
|
231
|
+
- [Git Workflow Robustness skill](../testing/git-workflow-robustness.md) - Git operations in CI
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "GitHub Actions Workflow Consistency"
|
|
3
|
+
id: "workflow-consistency"
|
|
4
|
+
category: "github-actions"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
created: "2026-01-28"
|
|
7
|
+
updated: "2026-01-28"
|
|
8
|
+
|
|
9
|
+
source:
|
|
10
|
+
repository: "wallstop/DxMessaging"
|
|
11
|
+
files:
|
|
12
|
+
- path: ".github/workflows/"
|
|
13
|
+
url: "https://github.com/wallstop/DxMessaging"
|
|
14
|
+
|
|
15
|
+
tags:
|
|
16
|
+
- "github-actions"
|
|
17
|
+
- "ci-cd"
|
|
18
|
+
- "workflow"
|
|
19
|
+
- "security"
|
|
20
|
+
- "consistency"
|
|
21
|
+
- "yaml"
|
|
22
|
+
|
|
23
|
+
complexity:
|
|
24
|
+
level: "intermediate"
|
|
25
|
+
reasoning: "Requires understanding of GitHub Actions features and security best practices"
|
|
26
|
+
|
|
27
|
+
impact:
|
|
28
|
+
performance:
|
|
29
|
+
rating: "medium"
|
|
30
|
+
details: "Concurrency controls prevent resource waste from duplicate runs"
|
|
31
|
+
maintainability:
|
|
32
|
+
rating: "high"
|
|
33
|
+
details: "Consistent structure makes workflows easier to review and modify"
|
|
34
|
+
testability:
|
|
35
|
+
rating: "medium"
|
|
36
|
+
details: "Proper path filters ensure workflows run when needed"
|
|
37
|
+
|
|
38
|
+
prerequisites:
|
|
39
|
+
- "Understanding of GitHub Actions workflow syntax"
|
|
40
|
+
- "Familiarity with YAML formatting"
|
|
41
|
+
- "Knowledge of security best practices for CI/CD"
|
|
42
|
+
|
|
43
|
+
dependencies:
|
|
44
|
+
packages: []
|
|
45
|
+
skills:
|
|
46
|
+
- "cross-platform-compatibility"
|
|
47
|
+
|
|
48
|
+
applies_to:
|
|
49
|
+
languages:
|
|
50
|
+
- "YAML"
|
|
51
|
+
frameworks:
|
|
52
|
+
- "GitHub Actions"
|
|
53
|
+
versions:
|
|
54
|
+
github-actions: "current"
|
|
55
|
+
|
|
56
|
+
aliases:
|
|
57
|
+
- "Workflow standards"
|
|
58
|
+
- "CI/CD consistency"
|
|
59
|
+
- "Actions best practices"
|
|
60
|
+
|
|
61
|
+
related:
|
|
62
|
+
- "cross-platform-compatibility"
|
|
63
|
+
- "shell-best-practices"
|
|
64
|
+
- "git-renormalize-patterns"
|
|
65
|
+
|
|
66
|
+
status: "stable"
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
# GitHub Actions Workflow Consistency
|
|
70
|
+
|
|
71
|
+
> **One-line summary**: Ensure all GitHub Actions workflows follow consistent structure,
|
|
72
|
+
> security practices, and formatting to maintain reliability and reviewability.
|
|
73
|
+
|
|
74
|
+
## Overview
|
|
75
|
+
|
|
76
|
+
GitHub Actions workflows in this project must follow strict conventions for structure,
|
|
77
|
+
security, and formatting. This skill documents the required patterns to ensure all workflows
|
|
78
|
+
are consistent, secure, and maintainable.
|
|
79
|
+
|
|
80
|
+
## Solution
|
|
81
|
+
|
|
82
|
+
Apply these requirements to every workflow file:
|
|
83
|
+
|
|
84
|
+
1. Use consistent property ordering: `name` → `on` → `concurrency` → `permissions` → `jobs`
|
|
85
|
+
1. Always include a concurrency group with `cancel-in-progress: true`
|
|
86
|
+
1. Declare explicit minimal permissions
|
|
87
|
+
1. Set `timeout-minutes` on every job
|
|
88
|
+
1. Use `persist-credentials: false` on checkout steps (unless pushing)
|
|
89
|
+
1. Include `.github/workflows/**` in path filters for self-referential workflows
|
|
90
|
+
1. Use double quotes for strings (Prettier default)
|
|
91
|
+
|
|
92
|
+
## Required Property Order
|
|
93
|
+
|
|
94
|
+
All workflow files MUST use this exact property ordering at the top level:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
name: Workflow Name
|
|
98
|
+
|
|
99
|
+
on:
|
|
100
|
+
# triggers
|
|
101
|
+
|
|
102
|
+
concurrency:
|
|
103
|
+
# concurrency settings
|
|
104
|
+
|
|
105
|
+
permissions:
|
|
106
|
+
# permission declarations
|
|
107
|
+
|
|
108
|
+
jobs:
|
|
109
|
+
# job definitions
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Why Order Matters
|
|
113
|
+
|
|
114
|
+
1. **Readability**: Consistent ordering makes workflows scannable
|
|
115
|
+
1. **Review efficiency**: Reviewers know where to find specific sections
|
|
116
|
+
1. **Prettier compatibility**: Maintains formatting after auto-formatting
|
|
117
|
+
|
|
118
|
+
## Required Elements
|
|
119
|
+
|
|
120
|
+
Every workflow MUST include these elements:
|
|
121
|
+
|
|
122
|
+
### 1. Concurrency Group
|
|
123
|
+
|
|
124
|
+
Prevents duplicate workflow runs and cancels in-progress runs when new commits are pushed:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
concurrency:
|
|
128
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
129
|
+
cancel-in-progress: true
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 2. Explicit Permissions
|
|
133
|
+
|
|
134
|
+
Always declare the minimum required permissions. Default to read-only:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
# Read-only access (most workflows)
|
|
138
|
+
permissions:
|
|
139
|
+
contents: read
|
|
140
|
+
|
|
141
|
+
# For workflows that push changes
|
|
142
|
+
permissions:
|
|
143
|
+
contents: write
|
|
144
|
+
pull-requests: write
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Never omit permissions**—implicit permissions are overly broad.
|
|
148
|
+
|
|
149
|
+
### 3. Job Timeout
|
|
150
|
+
|
|
151
|
+
Every job MUST have a `timeout-minutes` to prevent runaway jobs:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
jobs:
|
|
155
|
+
build:
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
timeout-minutes: 10 # Required on every job
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Recommended timeouts:
|
|
161
|
+
|
|
162
|
+
- **Lint/format checks**: 5 minutes
|
|
163
|
+
- **Build/compile**: 15-30 minutes
|
|
164
|
+
- **Full test suites**: 30-60 minutes
|
|
165
|
+
- **Deployment**: 10-15 minutes
|
|
166
|
+
|
|
167
|
+
### 4. Secure Checkout
|
|
168
|
+
|
|
169
|
+
Use `persist-credentials: false` on checkout steps unless credentials are explicitly needed:
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
- name: Checkout
|
|
173
|
+
uses: actions/checkout@v6
|
|
174
|
+
with:
|
|
175
|
+
persist-credentials: false
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Only omit this when the workflow needs to push commits (e.g., auto-fix workflows).
|
|
179
|
+
|
|
180
|
+
## Path Filters
|
|
181
|
+
|
|
182
|
+
### Self-Referential Workflows
|
|
183
|
+
|
|
184
|
+
Workflows that check formatting or linting of specific file types MUST include
|
|
185
|
+
`.github/workflows/**` in their path filters. This ensures the workflow runs when
|
|
186
|
+
its own definition changes.
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
on:
|
|
190
|
+
pull_request:
|
|
191
|
+
paths:
|
|
192
|
+
- "**/*.yml"
|
|
193
|
+
- "**/*.yaml"
|
|
194
|
+
- ".github/workflows/**" # Critical: include workflow files
|
|
195
|
+
- ".prettierrc*"
|
|
196
|
+
- "package.json"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Common Path Filter Patterns
|
|
200
|
+
|
|
201
|
+
| Workflow Type | Required Paths |
|
|
202
|
+
| ------------- | --------------------------------------------------------------------------------- |
|
|
203
|
+
| YAML lint | `**/*.yml`, `**/*.yaml`, `.github/workflows/**`, `.yamllint.yaml`, `.prettierrc*` |
|
|
204
|
+
| Markdown lint | `**/*.md`, `**/*.markdown`, `.markdownlint*`, `package.json` |
|
|
205
|
+
| JSON format | `**/*.json`, `**/*.asmdef`, `**/*.asmref`, `.prettierrc*` |
|
|
206
|
+
| C# build | `**/*.cs`, `**/*.csproj`, `**/*.sln`, `Directory.Build.props` |
|
|
207
|
+
| Tests | Source paths + test paths + workflow config |
|
|
208
|
+
|
|
209
|
+
### Trigger Best Practices
|
|
210
|
+
|
|
211
|
+
Include both `pull_request` and `push` triggers for validation workflows:
|
|
212
|
+
|
|
213
|
+
```yaml
|
|
214
|
+
on:
|
|
215
|
+
pull_request:
|
|
216
|
+
paths:
|
|
217
|
+
# file patterns
|
|
218
|
+
push:
|
|
219
|
+
branches:
|
|
220
|
+
- main
|
|
221
|
+
- master
|
|
222
|
+
paths:
|
|
223
|
+
# same file patterns as pull_request
|
|
224
|
+
workflow_dispatch: # Allow manual triggering
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Formatting Requirements
|
|
228
|
+
|
|
229
|
+
### Quote Style
|
|
230
|
+
|
|
231
|
+
Use **double quotes** for all strings (matches Prettier YAML defaults):
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
# Correct
|
|
235
|
+
node-version: "20"
|
|
236
|
+
cache: "npm"
|
|
237
|
+
|
|
238
|
+
# Incorrect
|
|
239
|
+
node-version: '20'
|
|
240
|
+
cache: 'npm'
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Indentation
|
|
244
|
+
|
|
245
|
+
Use **2 spaces** for YAML indentation (not 4):
|
|
246
|
+
|
|
247
|
+
```yaml
|
|
248
|
+
jobs:
|
|
249
|
+
build:
|
|
250
|
+
runs-on: ubuntu-latest
|
|
251
|
+
steps:
|
|
252
|
+
- name: Checkout
|
|
253
|
+
uses: actions/checkout@v6
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Complete Workflow Template
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
name: Example Workflow
|
|
260
|
+
|
|
261
|
+
on:
|
|
262
|
+
pull_request:
|
|
263
|
+
paths:
|
|
264
|
+
- "**/*.ext"
|
|
265
|
+
- ".github/workflows/**"
|
|
266
|
+
- "config-file"
|
|
267
|
+
push:
|
|
268
|
+
branches:
|
|
269
|
+
- main
|
|
270
|
+
- master
|
|
271
|
+
paths:
|
|
272
|
+
- "**/*.ext"
|
|
273
|
+
- ".github/workflows/**"
|
|
274
|
+
- "config-file"
|
|
275
|
+
workflow_dispatch:
|
|
276
|
+
|
|
277
|
+
concurrency:
|
|
278
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
279
|
+
cancel-in-progress: true
|
|
280
|
+
|
|
281
|
+
permissions:
|
|
282
|
+
contents: read
|
|
283
|
+
|
|
284
|
+
jobs:
|
|
285
|
+
example-job:
|
|
286
|
+
name: Descriptive job name
|
|
287
|
+
runs-on: ubuntu-latest
|
|
288
|
+
timeout-minutes: 10
|
|
289
|
+
steps:
|
|
290
|
+
- name: Checkout
|
|
291
|
+
uses: actions/checkout@v6
|
|
292
|
+
with:
|
|
293
|
+
persist-credentials: false
|
|
294
|
+
|
|
295
|
+
- name: Setup Node
|
|
296
|
+
uses: actions/setup-node@v6
|
|
297
|
+
with:
|
|
298
|
+
node-version: "20"
|
|
299
|
+
cache: "npm"
|
|
300
|
+
cache-dependency-path: package.json
|
|
301
|
+
|
|
302
|
+
- name: Install dependencies
|
|
303
|
+
run: |
|
|
304
|
+
if [ -f package-lock.json ]; then
|
|
305
|
+
npm ci
|
|
306
|
+
else
|
|
307
|
+
npm i --no-audit --no-fund
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
- name: Run checks
|
|
311
|
+
run: npm run check
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Common Mistakes
|
|
315
|
+
|
|
316
|
+
| Mistake | Problem | Fix |
|
|
317
|
+
| --------------------------------------- | -------------------------------------------- | ------------------------------------------------- |
|
|
318
|
+
| Missing `.github/workflows/**` in paths | Workflow won't run when its own file changes | Add to path filters |
|
|
319
|
+
| Missing concurrency group | Duplicate runs waste resources | Add concurrency block |
|
|
320
|
+
| Missing permissions block | Implicit permissions are too broad | Declare explicit minimal permissions |
|
|
321
|
+
| Missing `persist-credentials: false` | Git credentials persist unnecessarily | Add to checkout step |
|
|
322
|
+
| Missing `timeout-minutes` | Jobs can run indefinitely | Add timeout to every job |
|
|
323
|
+
| Single quotes for strings | Inconsistent with Prettier | Use double quotes |
|
|
324
|
+
| Wrong property order | Hard to review, fails formatting | Use: name → on → concurrency → permissions → jobs |
|
|
325
|
+
|
|
326
|
+
## Validation Checklist
|
|
327
|
+
|
|
328
|
+
Before committing a workflow, verify:
|
|
329
|
+
|
|
330
|
+
- [ ] Properties ordered: `name` → `on` → `concurrency` → `permissions` → `jobs`
|
|
331
|
+
- [ ] Concurrency group defined with `cancel-in-progress: true`
|
|
332
|
+
- [ ] Explicit `permissions` block with minimal required permissions
|
|
333
|
+
- [ ] Every job has `timeout-minutes`
|
|
334
|
+
- [ ] Checkout steps use `persist-credentials: false` (unless pushing)
|
|
335
|
+
- [ ] Path filters include `.github/workflows/**` for self-referential checks
|
|
336
|
+
- [ ] Double quotes used for strings
|
|
337
|
+
- [ ] 2-space indentation throughout
|
|
338
|
+
|
|
339
|
+
## See Also
|
|
340
|
+
|
|
341
|
+
- [Git Renormalize Pattern Validation](./git-renormalize-patterns.md) — ensuring pathspec patterns
|
|
342
|
+
match actual repository files to prevent CI failures
|
|
343
|
+
- [Cross-Platform Compatibility](../scripting/cross-platform-compatibility.md) — handling platform
|
|
344
|
+
differences in CI scripts
|
|
345
|
+
- [Shell Best Practices](../scripting/shell-best-practices.md) — patterns for shell commands in
|
|
346
|
+
workflow steps
|