@htekdev/actions-debugger 1.0.120 → 1.0.122
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/errors/caching-artifacts/caching-artifacts-071.yml +114 -0
- package/errors/runner-environment/runner-environment-219.yml +120 -0
- package/errors/runner-environment/runner-environment-220.yml +123 -0
- package/errors/runner-environment/runner-environment-221.yml +145 -0
- package/errors/triggers/triggers-071.yml +117 -0
- package/errors/yaml-syntax/yaml-syntax-074.yml +130 -0
- package/package.json +1 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
id: caching-artifacts-071
|
|
2
|
+
title: 'actions/cache Fails on Self-Hosted Runner with IPv6 Cache Server URL'
|
|
3
|
+
category: caching-artifacts
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- cache
|
|
7
|
+
- ipv6
|
|
8
|
+
- self-hosted
|
|
9
|
+
- getaddrinfo
|
|
10
|
+
- ENOTFOUND
|
|
11
|
+
- internal-cache
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'getaddrinfo ENOTFOUND \[[\da-fA-F:]+\]'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'getCacheEntry failed.*getaddrinfo ENOTFOUND'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'reserveCache failed.*getaddrinfo ENOTFOUND.*\['
|
|
18
|
+
flags: 'i'
|
|
19
|
+
error_messages:
|
|
20
|
+
- "::warning::Failed to restore: getCacheEntry failed: getaddrinfo ENOTFOUND [2001:bc8:1d90:1fc1:dc00:ff:fe2b:3f97]"
|
|
21
|
+
- "::warning::Failed to save: reserveCache failed: getaddrinfo ENOTFOUND [2001:db8::1]"
|
|
22
|
+
root_cause: |
|
|
23
|
+
When GitHub Actions self-hosted runner infrastructure uses an IPv6 address for
|
|
24
|
+
the internal cache service URL (ACTIONS_CACHE_URL), the @actions/http-client
|
|
25
|
+
in the toolkit fails to connect because it treats the bracketed IPv6 literal
|
|
26
|
+
as a hostname string instead of an address.
|
|
27
|
+
|
|
28
|
+
DNS resolution of `[2001:bc8:...]` fails with ENOTFOUND because the brackets
|
|
29
|
+
are IANA-standard URL notation for IPv6 literals in HTTP URLs
|
|
30
|
+
(RFC 2732 / RFC 3986 section 3.2.2), but the toolkit's Node.js http-client
|
|
31
|
+
was passing the bracketed string directly to `getaddrinfo()` without stripping
|
|
32
|
+
the brackets first. getaddrinfo does not accept bracket-wrapped IPv6 literals
|
|
33
|
+
and returns ENOTFOUND.
|
|
34
|
+
|
|
35
|
+
This affects any self-hosted runner environment where:
|
|
36
|
+
- The cache service is configured with an IPv6 address directly in the URL
|
|
37
|
+
(e.g., ACTIONS_CACHE_URL=http://[2001:bc8::1]:3000/)
|
|
38
|
+
- This includes ARC (Actions Runner Controller) on IPv6-only Kubernetes clusters,
|
|
39
|
+
enterprise GitHub Actions server deployments, and any on-prem cache proxy
|
|
40
|
+
bound to an IPv6 interface
|
|
41
|
+
|
|
42
|
+
The fix (strip brackets before passing to http-client) was submitted as PR
|
|
43
|
+
actions/toolkit#2298. Until merged and released in a new version of actions/cache,
|
|
44
|
+
the bug is present in actions/cache@v3, v4, and v5.
|
|
45
|
+
fix: |
|
|
46
|
+
Short-term workarounds (choose one):
|
|
47
|
+
|
|
48
|
+
1. Configure the internal cache service to also listen on an IPv4 address or
|
|
49
|
+
hostname and set ACTIONS_CACHE_URL to use the IPv4 address or hostname:
|
|
50
|
+
export ACTIONS_CACHE_URL=http://cache.internal:3000/
|
|
51
|
+
export ACTIONS_CACHE_URL=http://192.168.1.10:3000/
|
|
52
|
+
|
|
53
|
+
2. Set ACTIONS_CACHE_URL to use the hostname that resolves to the IPv6 address
|
|
54
|
+
(DNS-based resolution of the hostname works; the issue is only with bare
|
|
55
|
+
IPv6 literals in brackets):
|
|
56
|
+
export ACTIONS_CACHE_URL=http://cache-server.local:3000/
|
|
57
|
+
|
|
58
|
+
3. Add the cache service IPv6 address to /etc/hosts with a hostname alias on
|
|
59
|
+
the runner and use that hostname in ACTIONS_CACHE_URL.
|
|
60
|
+
|
|
61
|
+
Long-term: Track actions/toolkit#2298 for the upstream fix. Once merged and
|
|
62
|
+
actions/cache releases a new version using the patched toolkit, upgrade to
|
|
63
|
+
that version.
|
|
64
|
+
fix_code:
|
|
65
|
+
- language: yaml
|
|
66
|
+
label: 'Broken — ACTIONS_CACHE_URL with IPv6 literal causes ENOTFOUND'
|
|
67
|
+
code: |
|
|
68
|
+
# Runner environment configuration (runsvc.sh or .env file):
|
|
69
|
+
# ACTIONS_CACHE_URL=http://[2001:bc8:1d90:1fc1:dc00:ff:fe2b:3f97]:3000/
|
|
70
|
+
#
|
|
71
|
+
# Workflow sees:
|
|
72
|
+
# ::warning::Failed to restore: getCacheEntry failed: getaddrinfo ENOTFOUND [2001:bc8:...]
|
|
73
|
+
|
|
74
|
+
- uses: actions/cache@v5
|
|
75
|
+
with:
|
|
76
|
+
path: ~/.npm
|
|
77
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
|
78
|
+
# Warning: cache restore/save fails silently with ENOTFOUND
|
|
79
|
+
|
|
80
|
+
- language: yaml
|
|
81
|
+
label: 'Fixed — set ACTIONS_CACHE_URL to hostname or IPv4 instead of IPv6 literal'
|
|
82
|
+
code: |
|
|
83
|
+
# Runner environment configuration — use hostname instead of IPv6 literal:
|
|
84
|
+
# ACTIONS_CACHE_URL=http://cache.internal:3000/
|
|
85
|
+
# -or-
|
|
86
|
+
# ACTIONS_CACHE_URL=http://192.168.1.10:3000/
|
|
87
|
+
#
|
|
88
|
+
# The cache action now resolves the hostname normally:
|
|
89
|
+
- uses: actions/cache@v5
|
|
90
|
+
with:
|
|
91
|
+
path: ~/.npm
|
|
92
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
|
93
|
+
|
|
94
|
+
- language: yaml
|
|
95
|
+
label: 'Diagnostic — detect IPv6 ENOTFOUND cache failures in workflow output'
|
|
96
|
+
code: |
|
|
97
|
+
- name: Check cache URL for IPv6 literal
|
|
98
|
+
run: |
|
|
99
|
+
if [[ "${ACTIONS_CACHE_URL:-}" =~ ^\[.*\] ]] || [[ "${ACTIONS_CACHE_URL:-}" == *"["* ]]; then
|
|
100
|
+
echo "::warning::ACTIONS_CACHE_URL contains an IPv6 literal: ${ACTIONS_CACHE_URL}"
|
|
101
|
+
echo "::warning::Cache actions will fail with ENOTFOUND. Use a hostname or IPv4 address instead."
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
prevention:
|
|
105
|
+
- 'Always configure ACTIONS_CACHE_URL with a hostname or IPv4 address, not a bare IPv6 literal in brackets.'
|
|
106
|
+
- 'When deploying ARC or enterprise runner infrastructure on IPv6-only Kubernetes nodes, set up a hostname alias for the cache service.'
|
|
107
|
+
- 'Test cache operations with a simple cache-hit workflow on a new self-hosted runner before deploying to production.'
|
|
108
|
+
docs:
|
|
109
|
+
- url: 'https://github.com/actions/cache/issues/1718'
|
|
110
|
+
label: 'actions/cache#1718 — Caching fails on IPv6 cache server'
|
|
111
|
+
- url: 'https://github.com/actions/toolkit/pull/2298'
|
|
112
|
+
label: 'actions/toolkit#2298 — Fix: correctly handle IPv6 literals in http-client'
|
|
113
|
+
- url: 'https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2'
|
|
114
|
+
label: 'RFC 3986 §3.2.2 — IPv6 literals in URL host component (bracket notation)'
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
id: runner-environment-219
|
|
2
|
+
title: 'pnpm/action-setup@v6.0.0 Always Installs pnpm v11 Regardless of Requested Version'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- pnpm
|
|
7
|
+
- action-setup
|
|
8
|
+
- pnpm-v11
|
|
9
|
+
- version-mismatch
|
|
10
|
+
- path-priority
|
|
11
|
+
- lockfile
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'ERR_PNPM_UNSUPPORTED_ENGINE.*Unsupported environment'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
- regex: 'Expected version:.*Got:.*11\.'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
- regex: 'ERR_PNPM_LOCKFILE_CONFIG_MISMATCH.*frozen installation'
|
|
18
|
+
flags: 'i'
|
|
19
|
+
- regex: 'ERR_PNPM_BROKEN_LOCKFILE.*expected a single document'
|
|
20
|
+
flags: 'i'
|
|
21
|
+
error_messages:
|
|
22
|
+
- "ERR_PNPM_UNSUPPORTED_ENGINE Unsupported environment (bad pnpm and/or Node.js version)"
|
|
23
|
+
- "Expected version: 10\n Got: 11.0.0-beta.4-1"
|
|
24
|
+
- "ERR_PNPM_LOCKFILE_CONFIG_MISMATCH Cannot proceed with the frozen installation. The current \"overrides\" configuration doesn't match the value found in the lockfile"
|
|
25
|
+
- "ERR_PNPM_BROKEN_LOCKFILE The lockfile at \"<path>/pnpm-lock.yaml\" is broken: expected a single document in the stream, but found more"
|
|
26
|
+
root_cause: |
|
|
27
|
+
pnpm/action-setup@v6.0.0 introduced a "self-managed" bootstrap mechanism where
|
|
28
|
+
pnpm installs itself using pnpm. The action downloads a bootstrap binary (pnpm v11)
|
|
29
|
+
and uses it to self-update to the requested version. However, in v6.0.0 through
|
|
30
|
+
v6.0.7, a PATH priority bug caused the bootstrap binary to shadow the correctly
|
|
31
|
+
installed version at runtime:
|
|
32
|
+
|
|
33
|
+
addPath(path.join(pnpmHome, 'bin')) // correct binary installed here
|
|
34
|
+
addPath(pnpmHome) // bootstrap v11 binary lives here
|
|
35
|
+
|
|
36
|
+
Because addPath prepends in reverse call order, PNPM_HOME (containing the bootstrap
|
|
37
|
+
v11 binary) was always first on PATH, shadowing PNPM_HOME/bin (containing the
|
|
38
|
+
self-updated target version). Any workflow step that ran `pnpm` therefore used v11
|
|
39
|
+
regardless of the `version:` input.
|
|
40
|
+
|
|
41
|
+
Side effects of this bug:
|
|
42
|
+
1. workflows specifying `version: 10` run with pnpm v11, triggering
|
|
43
|
+
ERR_PNPM_UNSUPPORTED_ENGINE if engines.pnpm is set in package.json
|
|
44
|
+
2. pnpm v11 writes `configDependencies` blocks into pnpm-lock.yaml during any
|
|
45
|
+
install, corrupting the lockfile from pnpm v10's perspective; subsequent
|
|
46
|
+
`--frozen-lockfile` installs fail with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH
|
|
47
|
+
3. When using `package_json_file:` input, the wrong version is read because pnpm
|
|
48
|
+
v11 changed lockfile format, causing ERR_PNPM_BROKEN_LOCKFILE when the v11
|
|
49
|
+
bootstrap writes partial YAML to the lockfile before the correct version takes
|
|
50
|
+
over
|
|
51
|
+
|
|
52
|
+
The fix (addPath call order swap) was merged in PR #230 and released in v6.0.1.
|
|
53
|
+
A separate bootstrap bundle update for pnpm 11.0.0-rc.2 was released in v6.0.3.
|
|
54
|
+
Full stability for most scenarios reached v6.0.8.
|
|
55
|
+
fix: |
|
|
56
|
+
Upgrade to pnpm/action-setup@v6.0.8 or later. The PATH priority bug and
|
|
57
|
+
configDependencies lockfile corruption are fixed in v6.0.1+.
|
|
58
|
+
|
|
59
|
+
If you cannot upgrade, pin back to v5:
|
|
60
|
+
|
|
61
|
+
- uses: pnpm/action-setup@v5
|
|
62
|
+
with:
|
|
63
|
+
version: 10
|
|
64
|
+
|
|
65
|
+
If you are on v6 and seeing lockfile corruption: delete the corrupted
|
|
66
|
+
pnpm-lock.yaml and regenerate it with the correct pnpm version locally
|
|
67
|
+
before re-running CI. Do NOT run pnpm install in the corrupted-lockfile
|
|
68
|
+
state as it will write a v11 lockfile into your repo.
|
|
69
|
+
fix_code:
|
|
70
|
+
- language: yaml
|
|
71
|
+
label: 'Broken — pnpm/action-setup@v6.0.0 installs v11 regardless of version input'
|
|
72
|
+
code: |
|
|
73
|
+
- uses: pnpm/action-setup@v6 # v6.0.0: PATH bug installs v11 always
|
|
74
|
+
with:
|
|
75
|
+
version: 10 # Ignored — v11 ends up on PATH
|
|
76
|
+
- uses: actions/setup-node@v4
|
|
77
|
+
with:
|
|
78
|
+
node-version: '22'
|
|
79
|
+
cache: 'pnpm'
|
|
80
|
+
- run: pnpm install --frozen-lockfile
|
|
81
|
+
# Fails: ERR_PNPM_LOCKFILE_CONFIG_MISMATCH or ERR_PNPM_UNSUPPORTED_ENGINE
|
|
82
|
+
|
|
83
|
+
- language: yaml
|
|
84
|
+
label: 'Fixed — upgrade to v6.0.8+ (PATH priority bug resolved)'
|
|
85
|
+
code: |
|
|
86
|
+
- uses: pnpm/action-setup@v6.0.8 # v6.0.8: PATH priority fixed, stable
|
|
87
|
+
with:
|
|
88
|
+
version: 10
|
|
89
|
+
- uses: actions/setup-node@v4
|
|
90
|
+
with:
|
|
91
|
+
node-version: '22'
|
|
92
|
+
cache: 'pnpm'
|
|
93
|
+
- run: pnpm install --frozen-lockfile
|
|
94
|
+
|
|
95
|
+
- language: yaml
|
|
96
|
+
label: 'Alternative fix — pin back to v5 until v6 is stable for your project'
|
|
97
|
+
code: |
|
|
98
|
+
- uses: pnpm/action-setup@v5
|
|
99
|
+
with:
|
|
100
|
+
version: 10
|
|
101
|
+
- uses: actions/setup-node@v4
|
|
102
|
+
with:
|
|
103
|
+
node-version: '22'
|
|
104
|
+
cache: 'pnpm'
|
|
105
|
+
- run: pnpm install --frozen-lockfile
|
|
106
|
+
|
|
107
|
+
prevention:
|
|
108
|
+
- 'Pin pnpm/action-setup to a specific minor/patch version (e.g. @v6.0.8) rather than @v6 to avoid silent major-bump breakage from Dependabot.'
|
|
109
|
+
- 'After upgrading pnpm/action-setup, verify `pnpm --version` in the first step matches the requested version before running install.'
|
|
110
|
+
- 'If pnpm-lock.yaml is corrupted by this bug, delete it and regenerate locally with the correct pnpm version — do not attempt to fix by re-running CI.'
|
|
111
|
+
- 'Set `engines.pnpm` in package.json to detect unexpected version mismatches early with ERR_PNPM_UNSUPPORTED_ENGINE rather than silent wrong-behavior.'
|
|
112
|
+
docs:
|
|
113
|
+
- url: 'https://github.com/pnpm/action-setup/issues/225'
|
|
114
|
+
label: 'pnpm/action-setup#225 — v6.0.0 always installs v11 (51 reactions)'
|
|
115
|
+
- url: 'https://github.com/pnpm/action-setup/issues/226'
|
|
116
|
+
label: 'pnpm/action-setup#226 — v6.0.0 modifies pnpm-lock.yaml (lockfile corruption)'
|
|
117
|
+
- url: 'https://github.com/pnpm/action-setup/pull/230'
|
|
118
|
+
label: 'pnpm/action-setup#230 — Fix: swap addPath call order (merged)'
|
|
119
|
+
- url: 'https://github.com/pnpm/action-setup/releases'
|
|
120
|
+
label: 'pnpm/action-setup releases — v6.0.1 contains the PATH fix'
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
id: runner-environment-220
|
|
2
|
+
title: 'Node.js 20 JavaScript Actions Runtime Deprecated — Forced Migration to Node.js 24 (June 2026)'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: warning
|
|
5
|
+
tags:
|
|
6
|
+
- nodejs
|
|
7
|
+
- node20
|
|
8
|
+
- node24
|
|
9
|
+
- javascript-actions
|
|
10
|
+
- deprecation
|
|
11
|
+
- runtime
|
|
12
|
+
- actions-upgrade
|
|
13
|
+
patterns:
|
|
14
|
+
- regex: 'Node\.js 20 actions are deprecated'
|
|
15
|
+
flags: 'i'
|
|
16
|
+
- regex: 'running on Node\.js 20 and may not work as expected'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'Actions will be forced to run with Node\.js 24 by default'
|
|
19
|
+
flags: 'i'
|
|
20
|
+
- regex: 'FORCE_JAVASCRIPT_ACTIONS_TO_NODE24'
|
|
21
|
+
flags: 'i'
|
|
22
|
+
error_messages:
|
|
23
|
+
- "Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: actions/deploy-pages@v4."
|
|
24
|
+
- "Actions will be forced to run with Node.js 24 by default starting June 2nd, 2026."
|
|
25
|
+
- "Please check if updated versions of these actions are available that support Node.js 24."
|
|
26
|
+
root_cause: |
|
|
27
|
+
GitHub Actions JavaScript action runtimes follow Node.js LTS lifecycle.
|
|
28
|
+
Node.js 20 reached end-of-life in April 2026, and GitHub deprecated it as a
|
|
29
|
+
supported JavaScript actions runtime in September 2025:
|
|
30
|
+
|
|
31
|
+
- Sept 2025: Deprecation announced. Warning annotation added to workflow runs.
|
|
32
|
+
- Feb 2026: Runner v2.322+ begins emitting "Node.js 20 actions are deprecated"
|
|
33
|
+
annotation for any action whose package.json specifies "main" with runs.using: node20.
|
|
34
|
+
- June 2, 2026: Forced migration. Actions using node20 runtime are automatically
|
|
35
|
+
upgraded to run on Node.js 24 unless ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true
|
|
36
|
+
is set.
|
|
37
|
+
|
|
38
|
+
Actions affected are those that declare `runs.using: node20` in their action.yml.
|
|
39
|
+
This is a property of the action itself, not the workflow caller. Common examples
|
|
40
|
+
that shipped with node20 and required major version bumps:
|
|
41
|
+
- actions/deploy-pages@v4 → upgrade to @v5
|
|
42
|
+
- actions/upload-pages-artifact@v3 → upgrade to @v4
|
|
43
|
+
- Third-party actions on older major versions
|
|
44
|
+
|
|
45
|
+
The warning does NOT cause workflow failures in most cases — the runner upgrades
|
|
46
|
+
the action to run under Node.js 24 automatically starting June 2, 2026. However:
|
|
47
|
+
1. Actions using APIs removed or changed between Node.js 20 and 24 (e.g., internal
|
|
48
|
+
crypto or buffer APIs) may silently produce wrong results or throw runtime errors
|
|
49
|
+
2. The warning annotation shows up in every workflow run's annotation panel,
|
|
50
|
+
cluttering the UI and masking real warnings
|
|
51
|
+
3. Some security-conscious pipelines treat any annotation as a build failure
|
|
52
|
+
via fail-on-annotations settings
|
|
53
|
+
fix: |
|
|
54
|
+
1. Identify which actions in your workflow are still on node20 runtime:
|
|
55
|
+
Look for "Node.js 20 actions are deprecated" annotations in the Workflow Annotations
|
|
56
|
+
panel (gear icon next to workflow run summary).
|
|
57
|
+
|
|
58
|
+
2. Upgrade the pinned version of the affected action to a release that uses node24:
|
|
59
|
+
- actions/deploy-pages@v4 → @v5
|
|
60
|
+
- actions/upload-pages-artifact@v3 → @v4
|
|
61
|
+
- For third-party actions: check their releases for "node24" or "Node.js 24" mentions
|
|
62
|
+
|
|
63
|
+
3. If no node24 version of a required action exists yet, set the opt-out env var
|
|
64
|
+
as a temporary measure (not recommended for production):
|
|
65
|
+
env:
|
|
66
|
+
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: 'true'
|
|
67
|
+
|
|
68
|
+
4. To opt into Node.js 24 early for a specific workflow (before June 2 deadline):
|
|
69
|
+
env:
|
|
70
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
|
|
71
|
+
fix_code:
|
|
72
|
+
- language: yaml
|
|
73
|
+
label: 'Broken — actions/deploy-pages@v4 uses node20 runtime (shows deprecation warning)'
|
|
74
|
+
code: |
|
|
75
|
+
jobs:
|
|
76
|
+
deploy:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- name: Deploy to GitHub Pages
|
|
80
|
+
uses: actions/deploy-pages@v4 # node20 runtime — triggers deprecation warning
|
|
81
|
+
|
|
82
|
+
- language: yaml
|
|
83
|
+
label: 'Fixed — upgrade to v5 which uses node24 runtime'
|
|
84
|
+
code: |
|
|
85
|
+
jobs:
|
|
86
|
+
deploy:
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
steps:
|
|
89
|
+
- name: Deploy to GitHub Pages
|
|
90
|
+
uses: actions/deploy-pages@v5 # node24 runtime — no deprecation warning
|
|
91
|
+
|
|
92
|
+
- language: yaml
|
|
93
|
+
label: 'Temporary opt-out — allow node20 actions to run (not recommended long-term)'
|
|
94
|
+
code: |
|
|
95
|
+
jobs:
|
|
96
|
+
deploy:
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
env:
|
|
99
|
+
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: 'true' # Suppresses forced upgrade
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/deploy-pages@v4 # Still runs on node20 (insecure)
|
|
102
|
+
|
|
103
|
+
- language: yaml
|
|
104
|
+
label: 'Find all node20 actions in your workflow via actionlint annotation grep'
|
|
105
|
+
code: |
|
|
106
|
+
# Run actionlint locally or in CI to list all outdated action runtimes:
|
|
107
|
+
# actionlint .github/workflows/*.yml | grep "node20"
|
|
108
|
+
#
|
|
109
|
+
# Or use gh CLI to scan your workflow annotation after a run:
|
|
110
|
+
# gh run view <run-id> --json annotations --jq '.annotations[] | select(.message | contains("Node.js 20"))'
|
|
111
|
+
|
|
112
|
+
prevention:
|
|
113
|
+
- 'Subscribe to the GitHub Actions changelog (https://github.blog/changelog/label/github-actions/) to catch runtime deprecation announcements early.'
|
|
114
|
+
- 'Use Dependabot for GitHub Actions to get automatic PRs when new major versions of actions are released with updated runtimes.'
|
|
115
|
+
- 'Run actionlint in CI — it can detect actions using deprecated node runtime versions.'
|
|
116
|
+
- 'When pinning third-party actions to SHA hashes, periodically check if newer major versions with updated runtimes have been released.'
|
|
117
|
+
docs:
|
|
118
|
+
- url: 'https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/'
|
|
119
|
+
label: 'GitHub Changelog — Deprecation of Node.js 20 on GitHub Actions runners (Sept 2025)'
|
|
120
|
+
- url: 'https://github.com/actions/deploy-pages/issues/410'
|
|
121
|
+
label: 'actions/deploy-pages#410 — Support Node.js 24 (36 reactions)'
|
|
122
|
+
- url: 'https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#runsusing'
|
|
123
|
+
label: 'GitHub Docs — runs.using in action.yml (supported runtime versions)'
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
id: runner-environment-221
|
|
2
|
+
title: 'actions/checkout@v6 Hangs at git-credential-osxkeychain on macOS Self-Hosted Runners with Concurrent Jobs'
|
|
3
|
+
category: runner-environment
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- checkout
|
|
7
|
+
- macos
|
|
8
|
+
- osxkeychain
|
|
9
|
+
- credential-helper
|
|
10
|
+
- deadlock
|
|
11
|
+
- self-hosted
|
|
12
|
+
- concurrent
|
|
13
|
+
- v6
|
|
14
|
+
- hang
|
|
15
|
+
patterns:
|
|
16
|
+
- regex: 'trace: start_command:.*git-credential-osxkeychain store'
|
|
17
|
+
flags: 'i'
|
|
18
|
+
- regex: 'trace: run_command: .?git credential-osxkeychain store.?$'
|
|
19
|
+
flags: 'im'
|
|
20
|
+
- regex: 'credential-osxkeychain store.*\n.*\n.*\n.*\n.*checkout.*hang'
|
|
21
|
+
flags: 'im'
|
|
22
|
+
error_messages:
|
|
23
|
+
- "trace: run_command: 'git credential-osxkeychain store'"
|
|
24
|
+
- "trace: start_command: /bin/sh -c 'git credential-osxkeychain store' 'git credential-osxkeychain store'"
|
|
25
|
+
- "trace: exec: git-credential-osxkeychain store"
|
|
26
|
+
- "trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git-credential-osxkeychain store"
|
|
27
|
+
root_cause: |
|
|
28
|
+
On macOS self-hosted runners, Git uses git-credential-osxkeychain as the default
|
|
29
|
+
credential helper. When actions/checkout@v6 runs with persist-credentials: true
|
|
30
|
+
(the default), it stores the GITHUB_TOKEN in the macOS Keychain via the osxkeychain
|
|
31
|
+
credential helper.
|
|
32
|
+
|
|
33
|
+
The macOS Keychain grants exclusive write locks to one process at a time. When two or
|
|
34
|
+
more jobs run actions/checkout@v6 concurrently on the same self-hosted runner machine,
|
|
35
|
+
both jobs attempt to call `git credential-osxkeychain store` simultaneously. One process
|
|
36
|
+
acquires the Keychain lock and proceeds; the other blocks indefinitely waiting for the
|
|
37
|
+
lock to be released — which never happens because the macOS Keychain's IPC mechanism
|
|
38
|
+
can deadlock under concurrent access from multiple git processes sharing the same runner
|
|
39
|
+
session.
|
|
40
|
+
|
|
41
|
+
The hung checkout step produces no error output — the last visible log lines are the
|
|
42
|
+
`git-credential-osxkeychain store` trace entries. The job appears to be running but
|
|
43
|
+
makes no progress. Without a step-level timeout, GitHub's 6-hour job timeout eventually
|
|
44
|
+
cancels it.
|
|
45
|
+
|
|
46
|
+
Affected environment:
|
|
47
|
+
- actions/checkout@v6 (v6.0.x, the version that changed credential handling)
|
|
48
|
+
- macOS self-hosted runners, including macOS 26 Tahoe (runner 2.331.0+)
|
|
49
|
+
- Reproduced when ≥2 jobs on the same runner machine execute checkout concurrently
|
|
50
|
+
- Not specific to runner 2.331.0 — also reported on earlier macOS self-hosted setups
|
|
51
|
+
since checkout@v2, but became more frequent with v6's credential handling changes
|
|
52
|
+
|
|
53
|
+
Distinct from runner-environment-032 (persist-credentials: false breaks subsequent
|
|
54
|
+
git push auth — the opposite direction: fixing the push but needing credentials).
|
|
55
|
+
fix: |
|
|
56
|
+
Two workarounds — try Option 1 first, fall back to Option 2 if the deadlock persists:
|
|
57
|
+
|
|
58
|
+
Option 1 — Disable credential persistence for checkout (avoids Keychain writes):
|
|
59
|
+
|
|
60
|
+
- uses: actions/checkout@v6
|
|
61
|
+
with:
|
|
62
|
+
persist-credentials: false
|
|
63
|
+
|
|
64
|
+
This prevents checkout from calling `git credential-osxkeychain store` entirely,
|
|
65
|
+
eliminating the deadlock. Note: if your workflow's later steps need to push changes
|
|
66
|
+
to the repo using git directly (not via GH_TOKEN env var), you must pass the token
|
|
67
|
+
explicitly in the remote URL or use a separate authentication step.
|
|
68
|
+
|
|
69
|
+
Option 2 — Clean workspace before checkout (forces clean lock state):
|
|
70
|
+
|
|
71
|
+
- name: Clean workspace before checkout
|
|
72
|
+
run: |
|
|
73
|
+
find "$GITHUB_WORKSPACE" -mindepth 1 -maxdepth 1 -exec rm -rf {} + \
|
|
74
|
+
|| echo "::warning::Workspace cleanup had warnings (non-fatal)"
|
|
75
|
+
- uses: actions/checkout@v6
|
|
76
|
+
|
|
77
|
+
This removes any pre-existing files that might be holding Git process locks
|
|
78
|
+
from a previous job, allowing checkout to complete cleanly. This is an uglier
|
|
79
|
+
workaround but more effective when persist-credentials: false alone does not help.
|
|
80
|
+
|
|
81
|
+
Option 3 — Disable the macOS credential helper globally for CI git operations:
|
|
82
|
+
|
|
83
|
+
- name: Disable osxkeychain credential helper for CI
|
|
84
|
+
run: git config --global credential.helper ''
|
|
85
|
+
- uses: actions/checkout@v6
|
|
86
|
+
|
|
87
|
+
For git push steps that use an explicit token URL, also set GIT_TERMINAL_PROMPT=0:
|
|
88
|
+
|
|
89
|
+
- name: Push changes
|
|
90
|
+
env:
|
|
91
|
+
GIT_TERMINAL_PROMPT: '0'
|
|
92
|
+
run: |
|
|
93
|
+
git -c credential.helper='' push --force \
|
|
94
|
+
"https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" \
|
|
95
|
+
HEAD:gh-pages
|
|
96
|
+
fix_code:
|
|
97
|
+
- language: yaml
|
|
98
|
+
label: 'Fix 1 — persist-credentials: false prevents Keychain write (preferred)'
|
|
99
|
+
code: |
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v6
|
|
102
|
+
with:
|
|
103
|
+
persist-credentials: false # Avoids git-credential-osxkeychain store call
|
|
104
|
+
|
|
105
|
+
- language: yaml
|
|
106
|
+
label: 'Fix 2 — clean workspace before checkout to resolve concurrent lock conflicts'
|
|
107
|
+
code: |
|
|
108
|
+
steps:
|
|
109
|
+
- name: Clean workspace before checkout
|
|
110
|
+
run: |
|
|
111
|
+
find "$GITHUB_WORKSPACE" -mindepth 1 -maxdepth 1 -exec rm -rf {} + \
|
|
112
|
+
|| echo "::warning::Cleanup warnings are non-fatal"
|
|
113
|
+
|
|
114
|
+
- uses: actions/checkout@v6
|
|
115
|
+
|
|
116
|
+
- language: yaml
|
|
117
|
+
label: 'Fix 3 — disable osxkeychain globally and use explicit token for git push'
|
|
118
|
+
code: |
|
|
119
|
+
steps:
|
|
120
|
+
- name: Disable macOS keychain credential helper for CI
|
|
121
|
+
run: git config --global credential.helper ''
|
|
122
|
+
|
|
123
|
+
- uses: actions/checkout@v6
|
|
124
|
+
|
|
125
|
+
# Later, for git push steps:
|
|
126
|
+
- name: Push to gh-pages
|
|
127
|
+
env:
|
|
128
|
+
GIT_TERMINAL_PROMPT: '0'
|
|
129
|
+
run: |
|
|
130
|
+
git -c credential.helper='' push --force \
|
|
131
|
+
"https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" \
|
|
132
|
+
HEAD:gh-pages
|
|
133
|
+
|
|
134
|
+
prevention:
|
|
135
|
+
- 'Always set persist-credentials: false on actions/checkout@v6 for macOS self-hosted runners if your jobs do not need subsequent git operations using the GITHUB_TOKEN credential helper.'
|
|
136
|
+
- 'Add a timeout-minutes: on checkout steps on macOS self-hosted runners to bound hang duration (e.g., timeout-minutes: 5) rather than waiting for the 6-hour job timeout.'
|
|
137
|
+
- 'Serialize concurrent jobs on the same macOS runner using a concurrency group, or ensure jobs that checkout concurrently run on different runner instances.'
|
|
138
|
+
- 'Set GIT_TERMINAL_PROMPT=0 in macOS self-hosted runner environments to prevent git from waiting for interactive input from any credential helper.'
|
|
139
|
+
docs:
|
|
140
|
+
- url: 'https://github.com/actions/checkout/issues/550'
|
|
141
|
+
label: 'actions/checkout#550 — Actions checkout gets stuck forever randomly (open, 2021–2026)'
|
|
142
|
+
- url: 'https://stackoverflow.com/questions/79881327/github-actions-self-hosted-runner-on-macos-tries-to-checkout-repository-forever'
|
|
143
|
+
label: 'SO q/79881327 — Github Actions self hosted runner on macOS tries to checkout repository forever (Feb 2026)'
|
|
144
|
+
- url: 'https://github.com/actions/checkout#usage'
|
|
145
|
+
label: 'actions/checkout README — persist-credentials input documentation'
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
id: triggers-071
|
|
2
|
+
title: 'on: branches: Filter with Only Negation Patterns Silently Never Triggers'
|
|
3
|
+
category: triggers
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- branches-filter
|
|
7
|
+
- push
|
|
8
|
+
- pull_request
|
|
9
|
+
- negation
|
|
10
|
+
- glob
|
|
11
|
+
- workflow-not-triggering
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: 'branches:\s*\n(\s+-\s+[''"]?!)'
|
|
14
|
+
flags: 'm'
|
|
15
|
+
- regex: 'branches:\s*\[\s*[''"]?!'
|
|
16
|
+
flags: 'i'
|
|
17
|
+
error_messages:
|
|
18
|
+
- "# No error message — workflow simply never appears in the Actions run queue"
|
|
19
|
+
root_cause: |
|
|
20
|
+
GitHub Actions branch filters evaluate patterns sequentially against the ref name. The
|
|
21
|
+
documented rule is: "the workflow only runs if at least one pattern matches the ref name."
|
|
22
|
+
|
|
23
|
+
When a branches: (or branches-ignore's inverse: branches:) filter list contains ONLY
|
|
24
|
+
negation patterns (entries starting with !), no positive match is ever established.
|
|
25
|
+
Negation patterns can only EXCLUDE from an existing positive match set — they cannot
|
|
26
|
+
create a match on their own. The evaluation starts with zero matches, negations find
|
|
27
|
+
nothing to remove, and the result is always "no match" → workflow never fires.
|
|
28
|
+
|
|
29
|
+
This is a silent failure: no error is raised, no annotation appears, and the workflow
|
|
30
|
+
simply never shows up in the Actions tab when the target branch is pushed to. It is
|
|
31
|
+
especially confusing because the workflow file is syntactically valid and GitHub accepts it.
|
|
32
|
+
|
|
33
|
+
Common mistake patterns:
|
|
34
|
+
branches:
|
|
35
|
+
- '!main' # ← Only a negation — zero positive matches → never triggers
|
|
36
|
+
|
|
37
|
+
branches:
|
|
38
|
+
- '!master' # ← Same problem — always zero triggers
|
|
39
|
+
- '!release/**'
|
|
40
|
+
|
|
41
|
+
The branches-ignore filter does NOT have this problem because it operates on the
|
|
42
|
+
complement: it matches everything EXCEPT the listed patterns. Use branches-ignore when
|
|
43
|
+
you want to exclude specific branches.
|
|
44
|
+
|
|
45
|
+
Source: SO q/57699839 (144 votes) "GitHub Actions: how to target all branches EXCEPT
|
|
46
|
+
master?" — accepted answer (242 votes) documents the required positive+negative combo.
|
|
47
|
+
fix: |
|
|
48
|
+
To target all branches EXCEPT specific ones, choose one of two approaches:
|
|
49
|
+
|
|
50
|
+
Option 1 — Add wildcard positive patterns before the negation (order matters):
|
|
51
|
+
|
|
52
|
+
on:
|
|
53
|
+
push:
|
|
54
|
+
branches:
|
|
55
|
+
- '*' # matches every branch without a '/' (e.g. main, develop)
|
|
56
|
+
- '*/*' # matches single-slash branches (e.g. feature/x)
|
|
57
|
+
- '**' # matches all remaining branches
|
|
58
|
+
- '!main' # now excludes main from the positive matches above
|
|
59
|
+
|
|
60
|
+
Option 2 — Use branches-ignore instead (simpler and cleaner):
|
|
61
|
+
|
|
62
|
+
on:
|
|
63
|
+
push:
|
|
64
|
+
branches-ignore:
|
|
65
|
+
- main
|
|
66
|
+
- 'release/**'
|
|
67
|
+
|
|
68
|
+
Do NOT combine branches: and branches-ignore: on the same event — GitHub rejects that
|
|
69
|
+
combination with a YAML validation error.
|
|
70
|
+
fix_code:
|
|
71
|
+
- language: yaml
|
|
72
|
+
label: 'Broken — only negation in branches: filter, workflow never runs'
|
|
73
|
+
code: |
|
|
74
|
+
# This workflow NEVER triggers for any branch push — negation-only matches nothing:
|
|
75
|
+
on:
|
|
76
|
+
push:
|
|
77
|
+
branches:
|
|
78
|
+
- '!main' # WRONG: no positive pattern to negate from
|
|
79
|
+
|
|
80
|
+
- language: yaml
|
|
81
|
+
label: 'Fixed — positive wildcard patterns before negation'
|
|
82
|
+
code: |
|
|
83
|
+
# Correct approach: include positive patterns first, then exclude specific branches:
|
|
84
|
+
on:
|
|
85
|
+
push:
|
|
86
|
+
branches:
|
|
87
|
+
- '*' # matches branches without '/' in name
|
|
88
|
+
- '*/*' # matches single-level slash branches
|
|
89
|
+
- '**' # matches all remaining branches
|
|
90
|
+
- '!main' # now excludes main from the above positive matches
|
|
91
|
+
|
|
92
|
+
- language: yaml
|
|
93
|
+
label: 'Alternative fix — use branches-ignore (simplest for exclusion only)'
|
|
94
|
+
code: |
|
|
95
|
+
# Use branches-ignore when you want to exclude specific branches entirely:
|
|
96
|
+
on:
|
|
97
|
+
push:
|
|
98
|
+
branches-ignore:
|
|
99
|
+
- main
|
|
100
|
+
- 'release/**'
|
|
101
|
+
- 'hotfix/**'
|
|
102
|
+
pull_request:
|
|
103
|
+
branches-ignore:
|
|
104
|
+
- main
|
|
105
|
+
|
|
106
|
+
prevention:
|
|
107
|
+
- 'When you want to exclude branches, prefer branches-ignore: over branches: with negation — it is simpler and has no positive-pattern requirement.'
|
|
108
|
+
- 'If you must use branches: with negation, always include at least one positive glob (like ** or *) before the negation patterns.'
|
|
109
|
+
- 'Remember that pattern order matters: a positive match AFTER a negative pattern re-includes the ref; a negative match AFTER a positive match excludes it.'
|
|
110
|
+
- 'Use actionlint or act --list to verify your workflow would trigger before relying on pushes to test it.'
|
|
111
|
+
docs:
|
|
112
|
+
- url: 'https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushbranchestagsbranches-ignoretags-ignore'
|
|
113
|
+
label: 'GitHub Docs — on.push.branches filter syntax and negation patterns'
|
|
114
|
+
- url: 'https://stackoverflow.com/questions/57699839/github-actions-how-to-target-all-branches-except-master'
|
|
115
|
+
label: 'SO q/57699839 (144 votes) — GitHub Actions: how to target all branches EXCEPT master?'
|
|
116
|
+
- url: 'https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet'
|
|
117
|
+
label: 'GitHub Docs — Filter pattern cheat sheet (glob syntax reference)'
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
id: yaml-syntax-074
|
|
2
|
+
title: 'Workflow YAML File in Nested Subdirectory of .github/workflows/ Is Silently Ignored'
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: silent-failure
|
|
5
|
+
tags:
|
|
6
|
+
- workflow-placement
|
|
7
|
+
- subdirectory
|
|
8
|
+
- nested-folder
|
|
9
|
+
- file-location
|
|
10
|
+
- workflow-not-appearing
|
|
11
|
+
- silent-failure
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: '\.github/workflows/[^/\s]+/[^/\s]+\.ya?ml'
|
|
14
|
+
flags: 'i'
|
|
15
|
+
error_messages:
|
|
16
|
+
- "# No error — workflow YAML in .github/workflows/subdir/name.yml is silently ignored"
|
|
17
|
+
- "# Workflow never appears in Actions tab; no annotation is created"
|
|
18
|
+
root_cause: |
|
|
19
|
+
GitHub Actions only scans for workflow files in the DIRECT children of
|
|
20
|
+
`.github/workflows/` — it does NOT recurse into subdirectories. Files placed in
|
|
21
|
+
nested paths such as:
|
|
22
|
+
|
|
23
|
+
.github/workflows/ci/build.yml
|
|
24
|
+
.github/workflows/scripts/deploy.yaml
|
|
25
|
+
.github/workflows/reusable/my-caller.yml
|
|
26
|
+
|
|
27
|
+
are completely invisible to GitHub Actions. The runner does not parse them, does not
|
|
28
|
+
validate them, and emits no error or warning of any kind. The workflow simply never
|
|
29
|
+
appears in the repository's Actions tab, regardless of how correct the YAML content is.
|
|
30
|
+
|
|
31
|
+
This is a documented but easy-to-overlook constraint in the GitHub Actions architecture.
|
|
32
|
+
The scanner uses a shallow file glob equivalent to `.github/workflows/*.yml` and
|
|
33
|
+
`.github/workflows/*.yaml` — NOT `.github/workflows/**/*.yml`.
|
|
34
|
+
|
|
35
|
+
Common causes:
|
|
36
|
+
1. Developers organize workflows into subdirectories for clarity (e.g., `ci/`, `deploy/`),
|
|
37
|
+
not realizing GitHub won't pick them up.
|
|
38
|
+
2. Copy-pasting a workflow into a folder that already holds related shell scripts or
|
|
39
|
+
configuration files, creating an unintended nested path.
|
|
40
|
+
3. Renaming or restructuring the .github directory and accidentally moving workflow files
|
|
41
|
+
one level too deep.
|
|
42
|
+
4. Reusable workflow files placed in a `reusable/` or `shared/` subdirectory under
|
|
43
|
+
workflows/ — these also won't be discovered by GitHub as callable workflows.
|
|
44
|
+
|
|
45
|
+
Note: This affects ALL workflow types — regular workflows, reusable workflows
|
|
46
|
+
(workflow_call), scheduled workflows, and manually dispatched workflows alike.
|
|
47
|
+
|
|
48
|
+
Source: SO q/61989951 answer (score 9, from the 158-vote "GitHub Action workflow not
|
|
49
|
+
running" thread) and GitHub Actions documentation.
|
|
50
|
+
fix: |
|
|
51
|
+
Move all workflow YAML files directly into `.github/workflows/` (one level deep).
|
|
52
|
+
Do not create subdirectories inside `.github/workflows/` for workflow YAML files.
|
|
53
|
+
|
|
54
|
+
If you want to organize workflows logically, use naming prefixes instead of folders:
|
|
55
|
+
|
|
56
|
+
.github/workflows/ci-build.yml
|
|
57
|
+
.github/workflows/ci-test.yml
|
|
58
|
+
.github/workflows/deploy-staging.yml
|
|
59
|
+
.github/workflows/deploy-production.yml
|
|
60
|
+
|
|
61
|
+
For scripts, configs, and helper files that are referenced by workflows, place them
|
|
62
|
+
in a separate directory OUTSIDE `.github/workflows/`, for example:
|
|
63
|
+
.github/scripts/
|
|
64
|
+
.github/actions/my-local-action/
|
|
65
|
+
|
|
66
|
+
Note: Local composite actions (in `.github/actions/`) CAN be in subdirectories — the
|
|
67
|
+
subdirectory restriction only applies to workflow YAML files inside `.github/workflows/`.
|
|
68
|
+
fix_code:
|
|
69
|
+
- language: yaml
|
|
70
|
+
label: 'Broken — workflow file in nested subdirectory (silently ignored)'
|
|
71
|
+
code: |
|
|
72
|
+
# .github/workflows/ci/build.yml ← WRONG LOCATION, never discovered
|
|
73
|
+
name: Build CI
|
|
74
|
+
|
|
75
|
+
on:
|
|
76
|
+
push:
|
|
77
|
+
branches: ['**']
|
|
78
|
+
|
|
79
|
+
jobs:
|
|
80
|
+
build:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- uses: actions/checkout@v4
|
|
84
|
+
- run: npm ci && npm run build
|
|
85
|
+
|
|
86
|
+
- language: yaml
|
|
87
|
+
label: 'Fixed — workflow file at root of .github/workflows/'
|
|
88
|
+
code: |
|
|
89
|
+
# .github/workflows/ci-build.yml ← CORRECT LOCATION, discovered by GitHub
|
|
90
|
+
name: Build CI
|
|
91
|
+
|
|
92
|
+
on:
|
|
93
|
+
push:
|
|
94
|
+
branches: ['**']
|
|
95
|
+
|
|
96
|
+
jobs:
|
|
97
|
+
build:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
- run: npm ci && npm run build
|
|
102
|
+
|
|
103
|
+
- language: yaml
|
|
104
|
+
label: 'Organization pattern — use prefixes instead of subdirectories'
|
|
105
|
+
code: |
|
|
106
|
+
# Use name prefixes to group related workflows at the root level:
|
|
107
|
+
# .github/workflows/ci-build.yml
|
|
108
|
+
# .github/workflows/ci-lint.yml
|
|
109
|
+
# .github/workflows/ci-test.yml
|
|
110
|
+
# .github/workflows/deploy-staging.yml
|
|
111
|
+
# .github/workflows/deploy-production.yml
|
|
112
|
+
# .github/workflows/release-tag.yml
|
|
113
|
+
#
|
|
114
|
+
# Helper scripts/configs can be in subdirectories outside workflows/:
|
|
115
|
+
# .github/scripts/deploy.sh
|
|
116
|
+
# .github/actions/my-composite-action/action.yml ← composite actions CAN be nested
|
|
117
|
+
|
|
118
|
+
prevention:
|
|
119
|
+
- 'Keep all workflow YAML files (.yml / .yaml) directly in .github/workflows/ — never in subdirectories of that folder.'
|
|
120
|
+
- 'For workflow organization, use descriptive filename prefixes (ci-, deploy-, release-) instead of subdirectories.'
|
|
121
|
+
- 'Place helper shell scripts in .github/scripts/ and composite actions in .github/actions/<name>/ — subdirectories are fine there but not for workflow files.'
|
|
122
|
+
- 'After creating a new workflow file, immediately check that it appears in the repository Actions tab before relying on it for CI.'
|
|
123
|
+
- 'Use actionlint or the GitHub Actions VS Code extension to validate placement — both tools warn about unrecognized workflow file locations.'
|
|
124
|
+
docs:
|
|
125
|
+
- url: 'https://docs.github.com/en/actions/using-workflows/about-workflows#workflow-basics'
|
|
126
|
+
label: 'GitHub Docs — About workflows: file placement requirements'
|
|
127
|
+
- url: 'https://stackoverflow.com/questions/61989951/github-action-workflow-not-running'
|
|
128
|
+
label: 'SO q/61989951 (158 votes) — GitHub Action workflow not running (answer: nested subfolder not recognized)'
|
|
129
|
+
- url: 'https://docs.github.com/en/actions/creating-actions/creating-a-composite-action'
|
|
130
|
+
label: 'GitHub Docs — Composite actions (can be in .github/actions/ subdirectories)'
|
package/package.json
CHANGED