@htekdev/actions-debugger 1.0.13 → 1.0.15
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/dist/db/search.js +3 -1
- package/dist/db/search.js.map +1 -1
- package/dist/tools/suggest-fix.d.ts.map +1 -1
- package/dist/tools/suggest-fix.js +5 -1
- package/dist/tools/suggest-fix.js.map +1 -1
- package/errors/caching-artifacts/cache-key-too-long.yml +93 -0
- package/errors/caching-artifacts/cache-path-not-exist-skipped.yml +152 -0
- package/errors/caching-artifacts/docker-buildx-gha-cache-capacity.yml +107 -0
- package/errors/caching-artifacts/setup-ruby-bundler-ephemeral-workdir-cache-miss.yml +147 -0
- package/errors/caching-artifacts/upload-artifact-v3-retirement-blocked.yml +123 -0
- package/errors/concurrency-timing/always-cleanup-5min-forced-kill.yml +140 -0
- package/errors/concurrency-timing/concurrency-group-env-context-undefined.yml +99 -0
- package/errors/concurrency-timing/required-check-pending-path-filter-skip.yml +160 -0
- package/errors/concurrency-timing/wait-timer-cancel-in-progress-starvation.yml +125 -0
- package/errors/known-unsolved/composite-action-step-timeout-minutes-ignored.yml +146 -0
- package/errors/known-unsolved/reusable-workflow-no-composite-action-call.yml +116 -0
- package/errors/known-unsolved/schedule-trigger-default-branch-only.yml +113 -0
- package/errors/known-unsolved/secrets-not-allowed-in-if-conditions.yml +149 -0
- package/errors/permissions-auth/dependabot-pr-secrets-unavailable.yml +133 -0
- package/errors/permissions-auth/fine-grained-pat-deployment-write-required.yml +146 -0
- package/errors/permissions-auth/github-app-installation-token-new-format.yml +124 -0
- package/errors/permissions-auth/github-packages-read-requires-packages-permission.yml +128 -0
- package/errors/permissions-auth/oidc-id-token-write-permission-missing.yml +169 -0
- package/errors/permissions-auth/permissions-empty-block-removes-contents-read.yml +97 -0
- package/errors/permissions-auth/reusable-workflow-permissions-not-inherited.yml +114 -0
- package/errors/runner-environment/az-powershell-14-to-15-breaking.yml +108 -0
- package/errors/runner-environment/checkout-windows-ebusy-lock.yml +124 -0
- package/errors/runner-environment/deprecated-action-version-auto-rejected.yml +89 -0
- package/errors/runner-environment/github-hosted-runner-disk-space-full.yml +85 -0
- package/errors/runner-environment/github-path-same-step-not-found.yml +114 -0
- package/errors/runner-environment/github-script-v6-octokit-rest-actions-not-function.yml +87 -0
- package/errors/runner-environment/macos-15-mono-nuget-removed.yml +151 -0
- package/errors/runner-environment/macos-15-xcode-simulator-sdk-policy.yml +141 -0
- package/errors/runner-environment/runner-oom-exit-code-137.yml +117 -0
- package/errors/runner-environment/setup-go-go123-telemetry-cache-failure.yml +92 -0
- package/errors/runner-environment/setup-java-distribution-required.yml +108 -0
- package/errors/runner-environment/ubuntu-2204-precached-docker-removed.yml +110 -0
- package/errors/runner-environment/windows-latest-d-drive-removed.yml +104 -0
- package/errors/runner-environment/windows-msvc-ltcg-mixed-image-versions.yml +112 -0
- package/errors/runner-environment/windows-vs2026-cuda-host-compiler-unsupported.yml +145 -0
- package/errors/silent-failures/app-store-ios26-sdk-required.yml +113 -0
- package/errors/silent-failures/event-commits-empty-on-workflow-dispatch.yml +110 -0
- package/errors/silent-failures/fetch-tags-depth-one-silent-no-op.yml +77 -0
- package/errors/silent-failures/github-env-multiline-value-truncated.yml +127 -0
- package/errors/silent-failures/github-sha-pr-merge-commit-not-head.yml +150 -0
- package/errors/silent-failures/job-output-masked-as-secret-empty.yml +147 -0
- package/errors/silent-failures/upload-artifact-permissions-stripped.yml +98 -0
- package/errors/triggers/pull-request-branches-filter-matches-base-not-head.yml +140 -0
- package/errors/triggers/push-event-fires-on-branch-delete.yml +129 -0
- package/errors/triggers/push-first-commit-before-sha-zeros.yml +160 -0
- package/errors/yaml-syntax/fromjson-empty-string-crash.yml +99 -0
- package/errors/yaml-syntax/if-bang-negation-yaml-tag.yml +145 -0
- package/errors/yaml-syntax/local-action-path-always-top-level.yml +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
id: yaml-syntax-021
|
|
2
|
+
title: "fromJSON() on empty or undefined step output throws Unexpected end of JSON input"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- fromjson
|
|
7
|
+
- outputs
|
|
8
|
+
- expression
|
|
9
|
+
- json
|
|
10
|
+
- step-outputs
|
|
11
|
+
- dynamic-matrix
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "Unexpected end of JSON input"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Invalid JSON for parameter"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "is not valid JSON"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "fromJSON.*failed"
|
|
20
|
+
flags: "i"
|
|
21
|
+
error_messages:
|
|
22
|
+
- "Unexpected end of JSON input"
|
|
23
|
+
- "Error: Invalid JSON for parameter 'matrix': Unexpected end of JSON input"
|
|
24
|
+
- "Error: The expression result is not valid JSON"
|
|
25
|
+
root_cause: |
|
|
26
|
+
fromJSON() is a GitHub Actions expression function that parses a JSON string.
|
|
27
|
+
When the input string is empty ("") — which happens when a step output was
|
|
28
|
+
never set or when the step that set it was skipped due to an if: condition —
|
|
29
|
+
fromJSON() throws a fatal parse error: "Unexpected end of JSON input".
|
|
30
|
+
|
|
31
|
+
This is especially common in dynamic matrix strategies:
|
|
32
|
+
|
|
33
|
+
matrix:
|
|
34
|
+
include: ${{ fromJSON(steps.generate.outputs.matrix) }}
|
|
35
|
+
|
|
36
|
+
If the generate step was skipped (e.g., if: github.event_name == 'push'),
|
|
37
|
+
steps.generate.outputs.matrix evaluates to empty string, and fromJSON("")
|
|
38
|
+
crashes the entire job before any steps run.
|
|
39
|
+
|
|
40
|
+
The expression evaluator does NOT treat empty string as null or as valid
|
|
41
|
+
empty JSON — it passes the raw empty string directly to the JSON parser,
|
|
42
|
+
which rejects it immediately.
|
|
43
|
+
fix: |
|
|
44
|
+
Provide a fallback JSON value using the || operator so that fromJSON always
|
|
45
|
+
receives valid JSON even when the output is empty:
|
|
46
|
+
|
|
47
|
+
fromJSON(steps.generate.outputs.matrix || '[]')
|
|
48
|
+
fromJSON(steps.generate.outputs.config || '{}')
|
|
49
|
+
|
|
50
|
+
For dynamic matrix strategies, also ensure the generating step always
|
|
51
|
+
outputs valid JSON (at minimum '[]' or '{}') rather than leaving the
|
|
52
|
+
output unset when there is nothing to process.
|
|
53
|
+
|
|
54
|
+
Add an if: condition on downstream jobs to skip entirely when the matrix
|
|
55
|
+
output is empty or equals the empty-array sentinel.
|
|
56
|
+
fix_code:
|
|
57
|
+
- language: yaml
|
|
58
|
+
label: "Guard fromJSON with a valid JSON fallback using the || operator"
|
|
59
|
+
code: |
|
|
60
|
+
jobs:
|
|
61
|
+
compute-matrix:
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
outputs:
|
|
64
|
+
matrix: ${{ steps.gen.outputs.matrix }}
|
|
65
|
+
steps:
|
|
66
|
+
- id: gen
|
|
67
|
+
run: |
|
|
68
|
+
# Always emit valid JSON — even when there is nothing to build
|
|
69
|
+
TARGETS=$(cat targets.json 2>/dev/null || echo '[]')
|
|
70
|
+
echo "matrix=$TARGETS" >> $GITHUB_OUTPUT
|
|
71
|
+
|
|
72
|
+
build:
|
|
73
|
+
needs: compute-matrix
|
|
74
|
+
if: ${{ needs.compute-matrix.outputs.matrix != '[]' }}
|
|
75
|
+
strategy:
|
|
76
|
+
matrix:
|
|
77
|
+
# fromJSON never sees empty string — falls back to []
|
|
78
|
+
include: ${{ fromJSON(needs.compute-matrix.outputs.matrix || '[]') }}
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- run: echo "Building ${{ matrix.target }}"
|
|
82
|
+
- language: yaml
|
|
83
|
+
label: "Inline fallback for dynamic matrix include"
|
|
84
|
+
code: |
|
|
85
|
+
strategy:
|
|
86
|
+
matrix:
|
|
87
|
+
include: ${{ fromJSON(needs.setup.outputs.matrix || '[{"env":"default"}]') }}
|
|
88
|
+
prevention:
|
|
89
|
+
- "Always provide a valid JSON fallback: fromJSON(steps.x.outputs.val || '{}')"
|
|
90
|
+
- "Ensure output-producing steps always write a value even if it is an empty array or object"
|
|
91
|
+
- "Add if: conditions to skip downstream jobs entirely when the matrix output is empty"
|
|
92
|
+
- "Validate fromJSON expressions with an empty-output test scenario in a draft workflow"
|
|
93
|
+
docs:
|
|
94
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#fromjson"
|
|
95
|
+
label: "GitHub Docs — fromJSON expression function"
|
|
96
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/passing-information-between-jobs"
|
|
97
|
+
label: "GitHub Docs — Passing information between jobs using outputs"
|
|
98
|
+
- url: "https://github.com/orgs/community/discussions/26671"
|
|
99
|
+
label: "GitHub Community #26671 — fromJSON fails when output is empty string"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
id: yaml-syntax-020
|
|
2
|
+
title: "if: !cancelled() Triggers YAML Tag Parse Error — Must Quote or Use Expression Syntax"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- if-condition
|
|
7
|
+
- cancelled
|
|
8
|
+
- yaml-tag
|
|
9
|
+
- expression-syntax
|
|
10
|
+
- negation
|
|
11
|
+
- bang-operator
|
|
12
|
+
- always-run
|
|
13
|
+
- parse-error
|
|
14
|
+
patterns:
|
|
15
|
+
- regex: "if:\\s*!(?:cancelled|failure|success|always)\\(\\)"
|
|
16
|
+
flags: "im"
|
|
17
|
+
- regex: "mapping values are not allowed here|did not find expected key|could not find expected"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "yaml.*tag.*!\\w+|Unknown tag"
|
|
20
|
+
flags: "i"
|
|
21
|
+
error_messages:
|
|
22
|
+
- "mapping values are not allowed here"
|
|
23
|
+
- "could not find expected ':'"
|
|
24
|
+
- "did not find expected key"
|
|
25
|
+
- "Error: YAMLException: bad indentation of a mapping entry"
|
|
26
|
+
- "Invalid workflow file: You have an error in your yaml syntax"
|
|
27
|
+
root_cause: |
|
|
28
|
+
In YAML, `!` is a reserved indicator used to specify **explicit type tags**
|
|
29
|
+
(e.g., `!!str`, `!python/object`). When you write an unquoted `if:` value starting
|
|
30
|
+
with `!`, the YAML parser interprets it as a tag application — NOT as boolean negation.
|
|
31
|
+
|
|
32
|
+
For example:
|
|
33
|
+
```
|
|
34
|
+
if: !cancelled() # YAML reads this as: apply tag "cancelled()" to null value
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Because `!cancelled()` is an invalid YAML tag application (no value follows the tag,
|
|
38
|
+
or the parentheses make it syntactically invalid as a tag identifier), this causes a
|
|
39
|
+
YAML parse error and the entire workflow file is rejected with messages like
|
|
40
|
+
"mapping values are not allowed here" or "bad indentation of a mapping entry".
|
|
41
|
+
|
|
42
|
+
This is a common mistake because developers familiar with programming languages expect
|
|
43
|
+
`!` to be a boolean NOT operator, which it is inside GitHub Actions expressions
|
|
44
|
+
(`${{ !cancelled() }}`), but NOT in bare YAML string values.
|
|
45
|
+
|
|
46
|
+
Affected operators:
|
|
47
|
+
- `if: !cancelled()` → YAML tag error
|
|
48
|
+
- `if: !failure()` → YAML tag error
|
|
49
|
+
- `if: !success()` → YAML tag error (rare, but same pattern)
|
|
50
|
+
|
|
51
|
+
The fix is either:
|
|
52
|
+
1. Wrap in expression delimiters: `if: ${{ !cancelled() }}`
|
|
53
|
+
2. Quote the value: `if: "!cancelled()"`
|
|
54
|
+
Both forms are valid GitHub Actions `if:` conditions.
|
|
55
|
+
|
|
56
|
+
Source: GitHub Community Discussion — common YAML parse error with if: conditions
|
|
57
|
+
Source: GitHub Actions documentation — Expressions syntax
|
|
58
|
+
fix: |
|
|
59
|
+
Choose one of two equivalent fixes:
|
|
60
|
+
|
|
61
|
+
Option 1 — Use expression syntax (recommended, more explicit):
|
|
62
|
+
`if: ${{ !cancelled() }}`
|
|
63
|
+
|
|
64
|
+
Option 2 — Quote the string (also valid):
|
|
65
|
+
`if: "!cancelled()"`
|
|
66
|
+
|
|
67
|
+
Both options tell the YAML parser to treat the value as a plain string / expression,
|
|
68
|
+
bypassing the tag interpretation.
|
|
69
|
+
|
|
70
|
+
Note: Inside `${{ }}` expression blocks, `!` IS the boolean NOT operator and works
|
|
71
|
+
as expected. Outside those blocks, bare YAML values starting with `!` are parsed as
|
|
72
|
+
YAML type tags.
|
|
73
|
+
fix_code:
|
|
74
|
+
- language: yaml
|
|
75
|
+
label: "Fix: use ${{ }} expression syntax for negation"
|
|
76
|
+
code: |
|
|
77
|
+
jobs:
|
|
78
|
+
cleanup:
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
# ❌ WRONG: YAML parse error — ! is a YAML tag indicator
|
|
82
|
+
- name: Run unless cancelled (broken)
|
|
83
|
+
if: !cancelled()
|
|
84
|
+
run: ./cleanup.sh
|
|
85
|
+
|
|
86
|
+
# ✅ CORRECT: wrap in expression delimiters
|
|
87
|
+
- name: Run unless cancelled (fixed)
|
|
88
|
+
if: ${{ !cancelled() }}
|
|
89
|
+
run: ./cleanup.sh
|
|
90
|
+
|
|
91
|
+
# ✅ ALSO CORRECT: quote the string
|
|
92
|
+
- name: Run unless cancelled (also fixed)
|
|
93
|
+
if: "!cancelled()"
|
|
94
|
+
run: ./cleanup.sh
|
|
95
|
+
|
|
96
|
+
- language: yaml
|
|
97
|
+
label: "Common patterns: negating status check functions"
|
|
98
|
+
code: |
|
|
99
|
+
jobs:
|
|
100
|
+
notify:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
steps:
|
|
103
|
+
# Run step if previous steps did NOT fail
|
|
104
|
+
- name: Send success notification
|
|
105
|
+
if: ${{ !failure() }}
|
|
106
|
+
run: ./notify-success.sh
|
|
107
|
+
|
|
108
|
+
# Run if job was NOT cancelled (catch failures too)
|
|
109
|
+
- name: Always-ish cleanup (skips on cancel)
|
|
110
|
+
if: ${{ !cancelled() }}
|
|
111
|
+
run: ./cleanup.sh
|
|
112
|
+
|
|
113
|
+
# Job-level condition: run this job if parent was not skipped or failed
|
|
114
|
+
# (equivalent to always() but excluding explicitly-failed states)
|
|
115
|
+
|
|
116
|
+
- language: yaml
|
|
117
|
+
label: "Using always() instead of !cancelled() when appropriate"
|
|
118
|
+
code: |
|
|
119
|
+
jobs:
|
|
120
|
+
report:
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
# always() runs regardless of success, failure, OR cancellation
|
|
123
|
+
# !cancelled() runs on success OR failure, but NOT cancellation
|
|
124
|
+
steps:
|
|
125
|
+
- name: Report always (even if cancelled)
|
|
126
|
+
if: always()
|
|
127
|
+
run: ./post-report.sh
|
|
128
|
+
|
|
129
|
+
- name: Report unless cancelled
|
|
130
|
+
if: ${{ !cancelled() }}
|
|
131
|
+
run: ./post-report-unless-cancelled.sh
|
|
132
|
+
|
|
133
|
+
prevention:
|
|
134
|
+
- "Always wrap boolean expressions using `!`, `&&`, or `||` inside `${{ }}` delimiters in `if:` conditions."
|
|
135
|
+
- "Quote any `if:` value that starts with `!` if you prefer not to use expression syntax."
|
|
136
|
+
- "Use `always()` when you want to run regardless of success, failure, AND cancellation."
|
|
137
|
+
- "Use `!cancelled()` (inside `${{ }}`) when you want to run on success or failure, but not cancellation."
|
|
138
|
+
- "Lint workflows with `actionlint` locally — it catches YAML tag parse errors before push."
|
|
139
|
+
docs:
|
|
140
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#operators"
|
|
141
|
+
label: "GitHub Docs: Expressions — operators (! boolean NOT)"
|
|
142
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#status-check-functions"
|
|
143
|
+
label: "GitHub Docs: Expressions — status check functions (cancelled, failure, success)"
|
|
144
|
+
- url: "https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsif"
|
|
145
|
+
label: "GitHub Docs: Workflow syntax — steps.if"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
id: yaml-syntax-019
|
|
2
|
+
title: "Local Composite Action 'uses:' Paths Always Resolve From Repository Root"
|
|
3
|
+
category: yaml-syntax
|
|
4
|
+
severity: error
|
|
5
|
+
tags:
|
|
6
|
+
- composite-action
|
|
7
|
+
- local-action
|
|
8
|
+
- uses
|
|
9
|
+
- path-resolution
|
|
10
|
+
- runner
|
|
11
|
+
- file-not-found
|
|
12
|
+
patterns:
|
|
13
|
+
- regex: "Can't find '.*action\\.ya?ml'"
|
|
14
|
+
flags: "i"
|
|
15
|
+
- regex: "Unable to resolve action.*local"
|
|
16
|
+
flags: "i"
|
|
17
|
+
- regex: "Action.*not found.*\\./"
|
|
18
|
+
flags: "i"
|
|
19
|
+
- regex: "Error.*action.ya?ml.*does not exist"
|
|
20
|
+
flags: "i"
|
|
21
|
+
error_messages:
|
|
22
|
+
- "Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/repo/repo/actions/my-action'. Did you forget to run actions/checkout?"
|
|
23
|
+
- "Error: Unable to resolve action `./actions/my-action`, unable to find action at path: /home/runner/work/repo/repo/actions/my-action"
|
|
24
|
+
- "Error: Can't find action.yml at referenced path ./relative/path/to/action"
|
|
25
|
+
root_cause: |
|
|
26
|
+
When referencing a **local composite action** with a relative path (`uses: ./path/to/action`),
|
|
27
|
+
the GitHub Actions runner **always resolves the path relative to the root of the repository
|
|
28
|
+
that was checked out**, regardless of where the calling workflow or action lives.
|
|
29
|
+
|
|
30
|
+
This surprises developers who expect relative paths to resolve from the current file's
|
|
31
|
+
location (like `import './relative'` in Node.js or `include` in languages). GitHub Actions
|
|
32
|
+
does not work that way.
|
|
33
|
+
|
|
34
|
+
**Common mistake — calling a composite action from another composite action:**
|
|
35
|
+
```yaml
|
|
36
|
+
# In .github/actions/build/action.yml
|
|
37
|
+
runs:
|
|
38
|
+
using: composite
|
|
39
|
+
steps:
|
|
40
|
+
- uses: ./actions/shared/setup # Developer expects: relative to THIS file's location
|
|
41
|
+
# Reality: resolves from repo root → correct if structure matches
|
|
42
|
+
# BUT: when called FROM another repo, it resolves in the caller's repo
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Cross-repo misunderstanding:**
|
|
46
|
+
When a reusable workflow or composite action is stored in a **different repository** and
|
|
47
|
+
called externally (e.g., `uses: org/shared-actions/.github/workflows/build.yml@main`),
|
|
48
|
+
local `./` paths inside that called action resolve from the **caller's** repository root,
|
|
49
|
+
not the shared action's repository. The files don't exist there.
|
|
50
|
+
|
|
51
|
+
**Why it fails:**
|
|
52
|
+
- The runner checks out the correct repo but resolves `./` from that checkout root
|
|
53
|
+
- Nested relative paths in composite actions called from another repo fail entirely
|
|
54
|
+
- Error messages mention the runner's workspace path, making the root cause unclear
|
|
55
|
+
|
|
56
|
+
Source: actions/runner#1348
|
|
57
|
+
fix: |
|
|
58
|
+
**Option 1 (recommended): Use absolute repository-relative paths from the repo root**
|
|
59
|
+
|
|
60
|
+
Design your repository layout so all local action references make sense from the repo root.
|
|
61
|
+
All `uses: ./` paths must be valid paths starting from the repository root.
|
|
62
|
+
|
|
63
|
+
**Option 2: Publish shared actions as versioned releases**
|
|
64
|
+
|
|
65
|
+
For actions shared across repositories, publish them as proper GitHub Actions in their
|
|
66
|
+
own repository and reference them with `uses: org/repo/path@version` rather than
|
|
67
|
+
relative paths.
|
|
68
|
+
|
|
69
|
+
**Option 3: Avoid nesting composite actions that reference other local actions**
|
|
70
|
+
|
|
71
|
+
Flatten composite action steps so they do not call other local composite actions with
|
|
72
|
+
relative paths — inline the shared steps or extract them into a single action.
|
|
73
|
+
fix_code:
|
|
74
|
+
- language: yaml
|
|
75
|
+
label: "Broken — relative path in composite action misunderstood as file-relative"
|
|
76
|
+
code: |
|
|
77
|
+
# ❌ BROKEN: Developer expects ./setup to resolve relative to this action file
|
|
78
|
+
# File: .github/actions/build/action.yml
|
|
79
|
+
runs:
|
|
80
|
+
using: composite
|
|
81
|
+
steps:
|
|
82
|
+
# This resolves from REPO ROOT as ./setup — NOT from .github/actions/build/
|
|
83
|
+
- uses: ./setup # Fails if there is no 'setup/action.yml' at repo root
|
|
84
|
+
- uses: ./shared/lint # Same problem
|
|
85
|
+
|
|
86
|
+
# ✅ What the developer meant (but is not how it works):
|
|
87
|
+
# ./setup → .github/actions/build/setup/action.yml (WRONG assumption)
|
|
88
|
+
# What the runner does:
|
|
89
|
+
# ./setup → <repo-root>/setup/action.yml (CORRECT behavior)
|
|
90
|
+
- language: yaml
|
|
91
|
+
label: "Fixed — use full repo-root-relative paths"
|
|
92
|
+
code: |
|
|
93
|
+
# ✅ FIXED: Use paths that are correct relative to the repo root
|
|
94
|
+
# Repo layout:
|
|
95
|
+
# .github/actions/build/action.yml
|
|
96
|
+
# .github/actions/setup/action.yml ← shared action
|
|
97
|
+
|
|
98
|
+
# File: .github/actions/build/action.yml
|
|
99
|
+
runs:
|
|
100
|
+
using: composite
|
|
101
|
+
steps:
|
|
102
|
+
- uses: ./.github/actions/setup # ✅ Correct: resolves from repo root
|
|
103
|
+
- language: yaml
|
|
104
|
+
label: "Fixed — publish shared action to its own repo for cross-repo use"
|
|
105
|
+
code: |
|
|
106
|
+
# ✅ FIXED: For cross-repo shared actions, publish as a versioned action
|
|
107
|
+
# Instead of local ./path references, use:
|
|
108
|
+
runs:
|
|
109
|
+
using: composite
|
|
110
|
+
steps:
|
|
111
|
+
- uses: org/shared-actions/setup@v1 # ✅ Explicit repo + version reference
|
|
112
|
+
|
|
113
|
+
# This avoids ALL path resolution ambiguity when calling across repositories
|
|
114
|
+
- language: yaml
|
|
115
|
+
label: "Fixed — flatten composite action to avoid nested local references"
|
|
116
|
+
code: |
|
|
117
|
+
# ✅ ALTERNATIVE: Inline shared steps instead of nesting composite calls
|
|
118
|
+
# File: .github/actions/build/action.yml
|
|
119
|
+
runs:
|
|
120
|
+
using: composite
|
|
121
|
+
steps:
|
|
122
|
+
# Inline what ./setup would have done:
|
|
123
|
+
- name: Setup Node
|
|
124
|
+
uses: actions/setup-node@v4
|
|
125
|
+
with:
|
|
126
|
+
node-version: '20'
|
|
127
|
+
- name: Install dependencies
|
|
128
|
+
run: npm ci
|
|
129
|
+
shell: bash
|
|
130
|
+
prevention:
|
|
131
|
+
- "Always verify that local `uses: ./path` references point to valid paths from the **repository root**, not from the file containing the reference."
|
|
132
|
+
- "Use `ls .github/actions/` and verify the path structure before expecting `./` local action references to resolve correctly."
|
|
133
|
+
- "For actions used across multiple repositories, always use a versioned `org/repo/path@ref` reference — never `./` relative paths."
|
|
134
|
+
- "Avoid deeply nested composite actions that call other local composite actions; flatten where possible to reduce path resolution complexity."
|
|
135
|
+
- "When a composite action is called from an external repo via `uses: org/repo/.github/workflows/...`, remember that all `./` paths inside it resolve in the CALLER's repo."
|
|
136
|
+
docs:
|
|
137
|
+
- url: "https://github.com/actions/runner/issues/1348"
|
|
138
|
+
label: "actions/runner#1348 — Local composite action path resolution always from top-level repo"
|
|
139
|
+
- url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions#using-an-action-in-the-same-repository-as-a-workflow"
|
|
140
|
+
label: "GitHub Docs: Using a local action in the same repository"
|
|
141
|
+
- url: "https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action"
|
|
142
|
+
label: "GitHub Docs: Creating a composite action"
|
package/package.json
CHANGED